Merge branch 'master' into authorization-api

Conflicts:
	openid-connect-common/src/main/java/org/mitre/oauth2/service/SystemScopeService.java
	openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml
	openid-connect-server/src/main/java/org/mitre/discovery/web/DiscoveryEndpoint.java
	openid-connect-server/src/main/java/org/mitre/oauth2/web/IntrospectionEndpoint.java
	openid-connect-server/src/main/java/org/mitre/openid/connect/web/ClientAPI.java
	openid-connect-server/src/test/java/org/mitre/oauth2/service/impl/TestDefaultIntrospectionAuthorizer.java
pull/708/merge
Justin Richer 2015-03-13 18:39:26 -04:00
commit 8352145d82
119 changed files with 1788 additions and 1006 deletions

View File

@ -16,8 +16,6 @@
*******************************************************************************/
package org.mitre.oauth2.introspectingfilter;
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.SECRET_BASIC;
import java.io.IOException;
import java.net.URI;
import java.util.Date;
@ -55,6 +53,8 @@ import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.nimbusds.jose.util.Base64;
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.SECRET_BASIC;
/**
* This ResourceServerTokenServices implementation introspects incoming tokens at a
* server's introspection endpoint URL and passes an Authentication object along

View File

@ -16,10 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.client;
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.PRIVATE_KEY;
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.SECRET_BASIC;
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.SECRET_JWT;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URI;
@ -79,6 +75,10 @@ import com.nimbusds.jwt.PlainJWT;
import com.nimbusds.jwt.ReadOnlyJWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.PRIVATE_KEY;
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.SECRET_BASIC;
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.SECRET_JWT;
/**
* OpenID Connect Authentication Filter class
*

View File

@ -19,13 +19,6 @@
*/
package org.mitre.openid.connect.client.service.impl;
import static org.mitre.util.JsonUtils.getAsBoolean;
import static org.mitre.util.JsonUtils.getAsEncryptionMethodList;
import static org.mitre.util.JsonUtils.getAsJweAlgorithmList;
import static org.mitre.util.JsonUtils.getAsJwsAlgorithmList;
import static org.mitre.util.JsonUtils.getAsString;
import static org.mitre.util.JsonUtils.getAsStringList;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@ -48,6 +41,13 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import static org.mitre.util.JsonUtils.getAsBoolean;
import static org.mitre.util.JsonUtils.getAsEncryptionMethodList;
import static org.mitre.util.JsonUtils.getAsJweAlgorithmList;
import static org.mitre.util.JsonUtils.getAsJwsAlgorithmList;
import static org.mitre.util.JsonUtils.getAsString;
import static org.mitre.util.JsonUtils.getAsStringList;
/**
*
* Dynamically fetches OpenID Connect server configurations based on the issuer. Caches the server configurations.

View File

@ -16,10 +16,6 @@
*******************************************************************************/
package org.mitre.oauth2.introspectingfilter;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import java.util.Collections;
import java.util.Date;
import java.util.Set;
@ -29,6 +25,11 @@ import org.junit.Test;
import com.google.common.collect.ImmutableSet;
import com.google.gson.JsonObject;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
public class TestOAuth2AccessTokenImpl {
private static String tokenString = "thisisatokenstring";

View File

@ -16,11 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.client.service.impl;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -32,6 +27,12 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
/**
* @author wkim
*

View File

@ -17,11 +17,6 @@
package org.mitre.openid.connect.client.service.impl;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -32,6 +27,12 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
/**
* @author wkim
*

View File

@ -16,9 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.client.service.impl;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
import java.util.Map;
import org.junit.Before;
@ -31,6 +28,10 @@ import org.springframework.security.authentication.AuthenticationServiceExceptio
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertThat;
/**
* @author wkim
*

View File

@ -16,10 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.client.service.impl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
@ -50,6 +46,10 @@ import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.jwt.ReadOnlyJWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author wkim
*

View File

@ -16,12 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.client.service.impl;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.HashMap;
import java.util.Map;
@ -34,6 +28,13 @@ import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
/**
* @author wkim
*

View File

@ -16,12 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.client.service.impl;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.HashMap;
import java.util.Map;
@ -32,6 +26,13 @@ import org.mitre.openid.connect.config.ServerConfiguration;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
/**
* @author wkim
*

View File

@ -16,10 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.client.service.impl;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import javax.servlet.http.HttpServletRequest;
import org.junit.Before;
@ -30,6 +26,11 @@ import org.springframework.security.authentication.AuthenticationServiceExceptio
import com.google.common.collect.Sets;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
/**
* @author wkim
*

View File

@ -33,11 +33,17 @@ import org.springframework.security.oauth2.provider.OAuth2Authentication;
@Entity
@Table(name = "authentication_holder")
@NamedQueries ({
@NamedQuery(name = "AuthenticationHolderEntity.getAll", query = "select a from AuthenticationHolderEntity a"),
@NamedQuery(name = "AuthenticationHolderEntity.getUnusedAuthenticationHolders", query = "select a from AuthenticationHolderEntity a where a.id not in (select t.authenticationHolder.id from OAuth2AccessTokenEntity t) and a.id not in (select r.authenticationHolder.id from OAuth2RefreshTokenEntity r)")
@NamedQuery(name = AuthenticationHolderEntity.QUERY_ALL, query = "select a from AuthenticationHolderEntity a"),
@NamedQuery(name = AuthenticationHolderEntity.QUERY_GET_UNUSED, query = "select a from AuthenticationHolderEntity a where " +
"a.id not in (select t.authenticationHolder.id from OAuth2AccessTokenEntity t) and " +
"a.id not in (select r.authenticationHolder.id from OAuth2RefreshTokenEntity r) and " +
"a.id not in (select c.authenticationHolder.id from AuthorizationCodeEntity c)")
})
public class AuthenticationHolderEntity {
public static final String QUERY_GET_UNUSED = "AuthenticationHolderEntity.getUnusedAuthenticationHolders";
public static final String QUERY_ALL = "AuthenticationHolderEntity.getAll";
private Long id;
private OAuth2Authentication authentication;

View File

@ -16,19 +16,20 @@
*******************************************************************************/
package org.mitre.oauth2.model;
import java.util.Date;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import javax.persistence.Temporal;
/**
* Entity class for authorization codes
@ -39,15 +40,23 @@ import org.springframework.security.oauth2.provider.OAuth2Authentication;
@Entity
@Table(name = "authorization_code")
@NamedQueries({
@NamedQuery(name = "AuthorizationCodeEntity.getByValue", query = "select a from AuthorizationCodeEntity a where a.code = :code")
@NamedQuery(name = AuthorizationCodeEntity.QUERY_BY_VALUE, query = "select a from AuthorizationCodeEntity a where a.code = :code"),
@NamedQuery(name = AuthorizationCodeEntity.QUERY_EXPIRATION_BY_DATE, query = "select a from AuthorizationCodeEntity a where a.expiration <= :" + AuthorizationCodeEntity.PARAM_DATE)
})
public class AuthorizationCodeEntity {
public static final String QUERY_BY_VALUE = "AuthorizationCodeEntity.getByValue";
public static final String QUERY_EXPIRATION_BY_DATE = "AuthorizationCodeEntity.expirationByDate";
public static final String PARAM_DATE = "date";
private Long id;
private String code;
private OAuth2Authentication authentication;
private AuthenticationHolderEntity authenticationHolder;
private Date expiration;
/**
* Default constructor.
@ -62,9 +71,10 @@ public class AuthorizationCodeEntity {
* @param code the authorization code
* @param authRequest the AuthoriztionRequestHolder associated with the original code request
*/
public AuthorizationCodeEntity(String code, OAuth2Authentication authRequest) {
public AuthorizationCodeEntity(String code, AuthenticationHolderEntity authenticationHolder, Date expiration) {
this.code = code;
this.authentication = authRequest;
this.authenticationHolder = authenticationHolder;
this.expiration = expiration;
}
/**
@ -101,20 +111,30 @@ public class AuthorizationCodeEntity {
}
/**
* The authentication in place when this token was created.
* @return the authentication
*/
@Lob
@Basic(fetch=FetchType.EAGER)
@Column(name="authentication")
public OAuth2Authentication getAuthentication() {
return authentication;
@ManyToOne
@JoinColumn(name = "auth_holder_id")
public AuthenticationHolderEntity getAuthenticationHolder() {
return authenticationHolder;
}
/**
* @param authentication the authentication to set
*/
public void setAuthentication(OAuth2Authentication authentication) {
this.authentication = authentication;
public void setAuthenticationHolder(AuthenticationHolderEntity authenticationHolder) {
this.authenticationHolder = authenticationHolder;
}
@Basic
@Temporal(javax.persistence.TemporalType.TIMESTAMP)
@Column(name = "expiration")
public Date getExpiration() {
return expiration;
}
public void setExpiration(Date expiration) {
this.expiration = expiration;
}
}

View File

@ -66,14 +66,16 @@ import com.nimbusds.jose.JWSAlgorithm;
@Entity
@Table(name = "client_details")
@NamedQueries({
@NamedQuery(name = "ClientDetailsEntity.findAll", query = "SELECT c FROM ClientDetailsEntity c"),
@NamedQuery(name = "ClientDetailsEntity.getByClientId", query = "select c from ClientDetailsEntity c where c.clientId = :clientId")
@NamedQuery(name = ClientDetailsEntity.QUERY_ALL, query = "SELECT c FROM ClientDetailsEntity c"),
@NamedQuery(name = ClientDetailsEntity.QUERY_BY_CLIENT_ID, query = "select c from ClientDetailsEntity c where c.clientId = :" + ClientDetailsEntity.PARAM_CLIENT_ID)
})
public class ClientDetailsEntity implements ClientDetails {
/**
*
*/
public static final String QUERY_BY_CLIENT_ID = "ClientDetailsEntity.getByClientId";
public static final String QUERY_ALL = "ClientDetailsEntity.findAll";
public static final String PARAM_CLIENT_ID = "clientId";
private static final int DEFAULT_ID_TOKEN_VALIDITY_SECONDS = 600;
private static final long serialVersionUID = -1617727085733786296L;

View File

@ -61,13 +61,13 @@ import com.nimbusds.jwt.JWTParser;
@Entity
@Table(name = "access_token")
@NamedQueries({
@NamedQuery(name = "OAuth2AccessTokenEntity.getAll", query = "select a from OAuth2AccessTokenEntity a"),
@NamedQuery(name = "OAuth2AccessTokenEntity.getAllExpiredByDate", query = "select a from OAuth2AccessTokenEntity a where a.expiration <= :date"),
@NamedQuery(name = "OAuth2AccessTokenEntity.getByRefreshToken", query = "select a from OAuth2AccessTokenEntity a where a.refreshToken = :refreshToken"),
@NamedQuery(name = "OAuth2AccessTokenEntity.getByClient", query = "select a from OAuth2AccessTokenEntity a where a.client = :client"),
@NamedQuery(name = "OAuth2AccessTokenEntity.getByAuthentication", query = "select a from OAuth2AccessTokenEntity a where a.authenticationHolder.authentication = :authentication"),
@NamedQuery(name = "OAuth2AccessTokenEntity.getByIdToken", query = "select a from OAuth2AccessTokenEntity a where a.idToken = :idToken"),
@NamedQuery(name = "OAuth2AccessTokenEntity.getByTokenValue", query = "select a from OAuth2AccessTokenEntity a where a.value = :tokenValue")
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_ALL, query = "select a from OAuth2AccessTokenEntity a"),
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_EXPIRED_BY_DATE, query = "select a from OAuth2AccessTokenEntity a where a.expiration <= :" + OAuth2AccessTokenEntity.PARAM_DATE),
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_REFRESH_TOKEN, query = "select a from OAuth2AccessTokenEntity a where a.refreshToken = :" + OAuth2AccessTokenEntity.PARAM_REFERSH_TOKEN),
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_CLIENT, query = "select a from OAuth2AccessTokenEntity a where a.client = :" + OAuth2AccessTokenEntity.PARAM_CLIENT),
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_AUTHENTICATION, query = "select a from OAuth2AccessTokenEntity a where a.authenticationHolder.authentication = :" + OAuth2AccessTokenEntity.PARAM_AUTHENTICATION),
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_ID_TOKEN, query = "select a from OAuth2AccessTokenEntity a where a.idToken = :" + OAuth2AccessTokenEntity.PARAM_ID_TOKEN),
@NamedQuery(name = OAuth2AccessTokenEntity.QUERY_BY_TOKEN_VALUE, query = "select a from OAuth2AccessTokenEntity a where a.value = :" + OAuth2AccessTokenEntity.PARAM_TOKEN_VALUE)
})
@org.codehaus.jackson.map.annotate.JsonSerialize(using = OAuth2AccessTokenJackson1Serializer.class)
@org.codehaus.jackson.map.annotate.JsonDeserialize(using = OAuth2AccessTokenJackson1Deserializer.class)
@ -75,6 +75,21 @@ import com.nimbusds.jwt.JWTParser;
@com.fasterxml.jackson.databind.annotation.JsonDeserialize(using = OAuth2AccessTokenJackson2Deserializer.class)
public class OAuth2AccessTokenEntity implements OAuth2AccessToken {
public static final String QUERY_BY_TOKEN_VALUE = "OAuth2AccessTokenEntity.getByTokenValue";
public static final String QUERY_BY_ID_TOKEN = "OAuth2AccessTokenEntity.getByIdToken";
public static final String QUERY_BY_AUTHENTICATION = "OAuth2AccessTokenEntity.getByAuthentication";
public static final String QUERY_BY_CLIENT = "OAuth2AccessTokenEntity.getByClient";
public static final String QUERY_BY_REFRESH_TOKEN = "OAuth2AccessTokenEntity.getByRefreshToken";
public static final String QUERY_EXPIRED_BY_DATE = "OAuth2AccessTokenEntity.getAllExpiredByDate";
public static final String QUERY_ALL = "OAuth2AccessTokenEntity.getAll";
public static final String PARAM_TOKEN_VALUE = "tokenValue";
public static final String PARAM_ID_TOKEN = "idToken";
public static final String PARAM_AUTHENTICATION = "authentication";
public static final String PARAM_CLIENT = "client";
public static final String PARAM_REFERSH_TOKEN = "refreshToken";
public static final String PARAM_DATE = "date";
public static String ID_TOKEN_FIELD_NAME = "id_token";
private Long id;

View File

@ -49,14 +49,25 @@ import com.nimbusds.jwt.JWTParser;
@Entity
@Table(name = "refresh_token")
@NamedQueries({
@NamedQuery(name = "OAuth2RefreshTokenEntity.getAll", query = "select r from OAuth2RefreshTokenEntity r"),
@NamedQuery(name = "OAuth2RefreshTokenEntity.getAllExpiredByDate", query = "select r from OAuth2RefreshTokenEntity r where r.expiration <= :date"),
@NamedQuery(name = "OAuth2RefreshTokenEntity.getByClient", query = "select r from OAuth2RefreshTokenEntity r where r.client = :client"),
@NamedQuery(name = "OAuth2RefreshTokenEntity.getByTokenValue", query = "select r from OAuth2RefreshTokenEntity r where r.value = :tokenValue"),
@NamedQuery(name = "OAuth2RefreshTokenEntity.getByAuthentication", query = "select r from OAuth2RefreshTokenEntity r where r.authenticationHolder.authentication = :authentication")
@NamedQuery(name = OAuth2RefreshTokenEntity.QUERY_ALL, query = "select r from OAuth2RefreshTokenEntity r"),
@NamedQuery(name = OAuth2RefreshTokenEntity.QUERY_EXPIRED_BY_DATE, query = "select r from OAuth2RefreshTokenEntity r where r.expiration <= :" + OAuth2RefreshTokenEntity.PARAM_DATE),
@NamedQuery(name = OAuth2RefreshTokenEntity.QUERY_BY_CLIENT, query = "select r from OAuth2RefreshTokenEntity r where r.client = :" + OAuth2RefreshTokenEntity.PARAM_CLIENT),
@NamedQuery(name = OAuth2RefreshTokenEntity.QUERY_BY_TOKEN_VALUE, query = "select r from OAuth2RefreshTokenEntity r where r.value = :" + OAuth2RefreshTokenEntity.PARAM_TOKEN_VALUE),
@NamedQuery(name = OAuth2RefreshTokenEntity.QUERY_BY_AUTHENTICATION, query = "select r from OAuth2RefreshTokenEntity r where r.authenticationHolder.authentication = :" + OAuth2RefreshTokenEntity.PARAM_AUTHENTICATION)
})
public class OAuth2RefreshTokenEntity implements OAuth2RefreshToken {
public static final String QUERY_BY_AUTHENTICATION = "OAuth2RefreshTokenEntity.getByAuthentication";
public static final String QUERY_BY_TOKEN_VALUE = "OAuth2RefreshTokenEntity.getByTokenValue";
public static final String QUERY_BY_CLIENT = "OAuth2RefreshTokenEntity.getByClient";
public static final String QUERY_EXPIRED_BY_DATE = "OAuth2RefreshTokenEntity.getAllExpiredByDate";
public static final String QUERY_ALL = "OAuth2RefreshTokenEntity.getAll";
public static final String PARAM_AUTHENTICATION = "authentication";
public static final String PARAM_TOKEN_VALUE = "tokenValue";
public static final String PARAM_CLIENT = "client";
public static final String PARAM_DATE = "date";
private Long id;
private AuthenticationHolderEntity authenticationHolder;

View File

@ -37,11 +37,16 @@ import javax.persistence.Transient;
@Entity
@Table(name = "system_scope")
@NamedQueries({
@NamedQuery(name = "SystemScope.findAll", query = "select s from SystemScope s ORDER BY s.id"),
@NamedQuery(name = "SystemScope.getByValue", query = "select s from SystemScope s WHERE s.value = :value")
@NamedQuery(name = SystemScope.QUERY_ALL, query = "select s from SystemScope s ORDER BY s.id"),
@NamedQuery(name = SystemScope.QUERY_BY_VALUE, query = "select s from SystemScope s WHERE s.value = :" + SystemScope.PARAM_VALUE)
})
public class SystemScope {
public static final String QUERY_BY_VALUE = "SystemScope.getByValue";
public static final String QUERY_ALL = "SystemScope.findAll";
public static final String PARAM_VALUE = "value";
private Long id;
private String value; // scope value
private String description; // human-readable description

View File

@ -19,7 +19,6 @@ package org.mitre.oauth2.repository;
import java.util.List;
import org.mitre.oauth2.model.AuthenticationHolderEntity;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
public interface AuthenticationHolderRepository {
public List<AuthenticationHolderEntity> getAll();

View File

@ -16,9 +16,9 @@
*******************************************************************************/
package org.mitre.oauth2.repository;
import java.util.Collection;
import org.mitre.oauth2.model.AuthorizationCodeEntity;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
/**
* Interface for saving and consuming OAuth2 authorization codes as AuthorizationCodeEntitys.
@ -37,12 +37,23 @@ public interface AuthorizationCodeRepository {
public AuthorizationCodeEntity save(AuthorizationCodeEntity authorizationCode);
/**
* Consume an authorization code.
* Get an authorization code from the repository by value.
*
* @param code the authorization code value
* @return the authentication associated with the code
* @throws InvalidGrantException if no AuthorizationCodeEntity is found with the given value
*/
public OAuth2Authentication consume(String code) throws InvalidGrantException;
public AuthorizationCodeEntity getByCode(String code);
/**
* Remove an authorization code from the repository
*
* @param authorizationCodeEntity
*/
public void remove(AuthorizationCodeEntity authorizationCodeEntity);
/**
* @return A collection of all expired codes.
*/
public Collection<AuthorizationCodeEntity> getExpiredCodes();
}

View File

@ -32,7 +32,7 @@ import com.google.common.collect.Sets;
public interface SystemScopeService {
public static final String OFFLINE_ACCESS = "offline_access";
public static final Object OPENID_SCOPE = "openid";
public static final String OPENID_SCOPE = "openid";
public static final String ID_TOKEN_SCOPE = "id-token"; // ID tokens are generated using this scope
public static final String REGISTRATION_TOKEN_SCOPE = "registration-token"; // this scope manages dynamic client registrations
public static final String RESOURCE_TOKEN_SCOPE = "resource-token"; // this scope manages client-style protected resources

View File

@ -20,6 +20,19 @@
package org.mitre.openid.connect;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.oauth2.model.ClientDetailsEntity.AppType;
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
import org.mitre.oauth2.model.ClientDetailsEntity.SubjectType;
import org.mitre.oauth2.model.RegisteredClient;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Sets;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import static org.mitre.oauth2.model.RegisteredClientFields.APPLICATION_TYPE;
import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_ID;
import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_ID_ISSUED_AT;
@ -64,19 +77,6 @@ import static org.mitre.util.JsonUtils.getAsJwsAlgorithm;
import static org.mitre.util.JsonUtils.getAsString;
import static org.mitre.util.JsonUtils.getAsStringSet;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.oauth2.model.ClientDetailsEntity.AppType;
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
import org.mitre.oauth2.model.ClientDetailsEntity.SubjectType;
import org.mitre.oauth2.model.RegisteredClient;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Sets;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
* @author jricher
*

View File

@ -45,13 +45,21 @@ import com.google.common.collect.Sets;
@Entity
@Table(name="approved_site")
@NamedQueries({
@NamedQuery(name = "ApprovedSite.getAll", query = "select a from ApprovedSite a"),
@NamedQuery(name = "ApprovedSite.getByUserId", query = "select a from ApprovedSite a where a.userId = :userId"),
@NamedQuery(name = "ApprovedSite.getByClientId", query = "select a from ApprovedSite a where a.clientId = :clientId"),
@NamedQuery(name = "ApprovedSite.getByClientIdAndUserId", query = "select a from ApprovedSite a where a.clientId = :clientId and a.userId = :userId")
@NamedQuery(name = ApprovedSite.QUERY_ALL, query = "select a from ApprovedSite a"),
@NamedQuery(name = ApprovedSite.QUERY_BY_USER_ID, query = "select a from ApprovedSite a where a.userId = :" + ApprovedSite.PARAM_USER_ID),
@NamedQuery(name = ApprovedSite.QUERY_BY_CLIENT_ID, query = "select a from ApprovedSite a where a.clientId = :" + ApprovedSite.PARAM_CLIENT_ID),
@NamedQuery(name = ApprovedSite.QUERY_BY_CLIENT_ID_AND_USER_ID, query = "select a from ApprovedSite a where a.clientId = :" + ApprovedSite.PARAM_CLIENT_ID + " and a.userId = :" + ApprovedSite.PARAM_USER_ID)
})
public class ApprovedSite {
public static final String QUERY_BY_CLIENT_ID_AND_USER_ID = "ApprovedSite.getByClientIdAndUserId";
public static final String QUERY_BY_CLIENT_ID = "ApprovedSite.getByClientId";
public static final String QUERY_BY_USER_ID = "ApprovedSite.getByUserId";
public static final String QUERY_ALL = "ApprovedSite.getAll";
public static final String PARAM_CLIENT_ID = "clientId";
public static final String PARAM_USER_ID = "userId";
// unique id
private Long id;

View File

@ -36,10 +36,12 @@ import javax.persistence.Table;
@Entity
@Table(name="blacklisted_site")
@NamedQueries({
@NamedQuery(name = "BlacklistedSite.getAll", query = "select b from BlacklistedSite b")
@NamedQuery(name = BlacklistedSite.QUERY_ALL, query = "select b from BlacklistedSite b")
})
public class BlacklistedSite {
public static final String QUERY_ALL = "BlacklistedSite.getAll";
// unique id
private Long id;

View File

@ -33,13 +33,14 @@ import com.google.gson.JsonObject;
@Entity
@Table(name="user_info")
@NamedQueries({
@NamedQuery(name="DefaultUserInfo.getByUsername", query = "select u from DefaultUserInfo u WHERE u.preferredUsername = :username")
@NamedQuery(name=DefaultUserInfo.QUERY_BY_USERNAME, query = "select u from DefaultUserInfo u WHERE u.preferredUsername = :" + DefaultUserInfo.PARAM_USERNAME)
})
public class DefaultUserInfo implements UserInfo {
/**
*
*/
public static final String QUERY_BY_USERNAME = "DefaultUserInfo.getByUsername";
public static final String PARAM_USERNAME = "username";
private static final long serialVersionUID = 6078310513185681918L;
private Long id;
private String sub;

View File

@ -39,11 +39,17 @@ import javax.persistence.Table;
@Entity
@Table(name = "pairwise_identifier")
@NamedQueries({
@NamedQuery(name="PairwiseIdentifier.getAll", query = "select p from PairwiseIdentifier p"),
@NamedQuery(name="PairwiseIdentifier.getBySectorIdentifier", query = "select p from PairwiseIdentifier p WHERE p.userSub = :sub AND p.sectorIdentifier = :sectorIdentifier")
@NamedQuery(name=PairwiseIdentifier.QUERY_ALL, query = "select p from PairwiseIdentifier p"),
@NamedQuery(name=PairwiseIdentifier.QUERY_BY_SECTOR_IDENTIFIER, query = "select p from PairwiseIdentifier p WHERE p.userSub = :" + PairwiseIdentifier.PARAM_SUB + " AND p.sectorIdentifier = :" + PairwiseIdentifier.PARAM_SECTOR_IDENTIFIER)
})
public class PairwiseIdentifier {
public static final String QUERY_BY_SECTOR_IDENTIFIER = "PairwiseIdentifier.getBySectorIdentifier";
public static final String QUERY_ALL = "PairwiseIdentifier.getAll";
public static final String PARAM_SECTOR_IDENTIFIER = "sectorIdentifier";
public static final String PARAM_SUB = "sub";
private Long id;
private String identifier;
private String userSub;
@ -86,7 +92,7 @@ public class PairwiseIdentifier {
* @return the userSub
*/
@Basic
@Column(name = "sub")
@Column(name = PairwiseIdentifier.PARAM_SUB)
public String getUserSub() {
return userSub;
}

View File

@ -41,12 +41,19 @@ import javax.persistence.Table;
@Entity
@Table(name="whitelisted_site")
@NamedQueries({
@NamedQuery(name = "WhitelistedSite.getAll", query = "select w from WhitelistedSite w"),
@NamedQuery(name = "WhitelistedSite.getByClientId", query = "select w from WhitelistedSite w where w.clientId = :clientId"),
@NamedQuery(name = "WhitelistedSite.getByCreatoruserId", query = "select w from WhitelistedSite w where w.creatorUserId = :userId")
@NamedQuery(name = WhitelistedSite.QUERY_ALL, query = "select w from WhitelistedSite w"),
@NamedQuery(name = WhitelistedSite.QUERY_BY_CLIENT_ID, query = "select w from WhitelistedSite w where w.clientId = :" + WhitelistedSite.PARAM_CLIENT_ID),
@NamedQuery(name = WhitelistedSite.QUERY_BY_CREATOR, query = "select w from WhitelistedSite w where w.creatorUserId = :" + WhitelistedSite.PARAM_USER_ID)
})
public class WhitelistedSite {
public static final String QUERY_BY_CREATOR = "WhitelistedSite.getByCreatoruserId";
public static final String QUERY_BY_CLIENT_ID = "WhitelistedSite.getByClientId";
public static final String QUERY_ALL = "WhitelistedSite.getAll";
public static final String PARAM_USER_ID = "userId";
public static final String PARAM_CLIENT_ID = "clientId";
// unique id
private Long id;

View File

@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.view.AbstractView;
@ -51,7 +52,7 @@ public class JWKSetView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
response.setContentType("application/json");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
//BiMap<String, PublicKey> keyMap = (BiMap<String, PublicKey>) model.get("keys");

View File

@ -16,13 +16,13 @@
*******************************************************************************/
package org.mitre.discovery.util;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.springframework.web.util.UriComponents;
import com.google.common.collect.ImmutableMap;
import static org.junit.Assert.assertEquals;
/**
* @author wkim
*

View File

@ -19,14 +19,14 @@
*/
package org.mitre.jose;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.JWSAlgorithm;
import static org.junit.Assert.assertEquals;
/**
*
* These tests make sure that the algorithm name processing

View File

@ -16,9 +16,6 @@
*******************************************************************************/
package org.mitre.jose;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@ -39,6 +36,9 @@ import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.util.Base64URL;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author tsitkov

View File

@ -16,11 +16,6 @@
*******************************************************************************/
package org.mitre.jwt.encryption.service.impl;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.text.ParseException;
@ -49,6 +44,12 @@ import com.nimbusds.jwt.EncryptedJWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.ReadOnlyJWTClaimsSet;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
/**
* @author wkim

View File

@ -19,8 +19,6 @@
*/
package org.mitre.oauth2.model;
import static org.junit.Assert.assertEquals;
import java.util.Date;
import org.junit.Test;
@ -29,6 +27,8 @@ import com.google.common.collect.ImmutableSet;
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JWEAlgorithm;
import static org.junit.Assert.assertEquals;
/**
* @author jricher
*

View File

@ -19,8 +19,6 @@
*/
package org.mitre.oauth2.model;
import static org.junit.Assert.assertEquals;
import java.sql.Date;
import org.junit.Test;
@ -29,6 +27,8 @@ import com.google.common.collect.ImmutableSet;
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JWEAlgorithm;
import static org.junit.Assert.assertEquals;
/**
* @author jricher
*

View File

@ -19,9 +19,6 @@
*/
package org.mitre.openid.connect;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.sql.Date;
import org.junit.Test;
@ -34,6 +31,9 @@ import com.google.gson.JsonObject;
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JWEAlgorithm;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* @author jricher
*

View File

@ -19,12 +19,12 @@
*/
package org.mitre.openid.connect.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
/**
* @author jricher
*

View File

@ -19,11 +19,11 @@
*/
package org.mitre.openid.connect.config;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
/**
* @author jricher
*

View File

@ -47,6 +47,12 @@
<nonFilteredFileExtension>jpg</nonFilteredFileExtension>
<nonFilteredFileExtension>png</nonFilteredFileExtension>
<nonFilteredFileExtension>pdf</nonFilteredFileExtension>
<nonFilteredFileExtension>eot</nonFilteredFileExtension>
<nonFilteredFileExtension>woff</nonFilteredFileExtension>
<nonFilteredFileExtension>ttf</nonFilteredFileExtension>
<nonFilteredFileExtension>svg</nonFilteredFileExtension>
<nonFilteredFileExtension>jwks</nonFilteredFileExtension>
<nonFilteredFileExtension>json</nonFilteredFileExtension>
</nonFilteredFileExtensions>
<webResources>
<resource>

View File

@ -52,7 +52,8 @@ CREATE TABLE IF NOT EXISTS client_authority (
CREATE TABLE IF NOT EXISTS authorization_code (
id BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 1) PRIMARY KEY,
code VARCHAR(256),
authentication LONGVARBINARY
auth_holder_id BIGINT,
expiration TIMESTAMP
);
CREATE TABLE IF NOT EXISTS client_grant_type (

View File

@ -52,7 +52,8 @@ CREATE TABLE IF NOT EXISTS client_authority (
CREATE TABLE IF NOT EXISTS authorization_code (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
code VARCHAR(256),
authentication LONGBLOB
auth_holder_id BIGINT,
expiration TIMESTAMP NULL
);
CREATE TABLE IF NOT EXISTS client_grant_type (

View File

@ -1,107 +0,0 @@
###############################################################################
# Copyright 2015 The MITRE Corporation
# and the MIT Kerberos and Internet Trust Consortium
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
###############################################################################
copyright=Powered by <a href="https://github.com/mitreid-connect/">MITREid Connect <span class="label">{0}</span></a> <span class="pull-right">&copy; 2015 The MITRE Corporation and MIT KIT.</span>.
about.title=About
about.body=\
This OpenID Connect service is built from the MITREid Connect Open Source project, from \
<a href="http://www.mitre.org/">The MITRE Corporation</a> and the <a href="http://kit.mit.edu/">MIT Kerberos and Internet Trust Consortium</a>.\
</p>\
<p>\
More information about the project can be found at \
<a href="http://github.com/mitreid-connect/">MITREid Connect on GitHub</a>. \
There, you can submit bug reports, give feedback, or even contribute code patches for additional features you'd like to see.
statistics.title=Statistics
statistics.number_users=Number of users: <span class="label label-info" id="userCount">{0}</span>
statistics.number_clients=Authorized clients: <span class="label label-info" id="clientCount">{0}</span>
statistics.number_approvals=Approved sites: <span class="label label-info" id="approvalCount">{0}</span>
home.welcome=Welcome!
home.welcome.body=\
OpenID Connect is an internet-scale federated identity protocol built on top of the OAuth2 authorization framework. \
OpenID Connect lets you log into a remote site using your identity without exposing your credentials, like a username and password.</p>\
<p><a class="btn btn-primary btn-large" href="http://openid.net/connect/">Learn more &raquo;</a>
home.more=More
home.about=About
home.about.body=This OpenID Connect service is built from the MITREid Connect Open Source project, from \
<a href="http://www.mitre.org/">The MITRE Corporation</a> and the <a href="http://kit.mit.edu/">MIT Kerberos and Internet Trust Consortium</a>.
home.contact=Contact
home.contact.body=\
For more information or support, contact the administrators of this system.</p>\
<p><a class="btn" href="mailto:idp@example.com?Subject=OpenID Connect">Email &raquo;</a>
home.statistics=Current Statistics
home.statistics.loading=Loading...
home.statistics.number_users=Number of users: <span class="label label-info" id="userCount">{0}</span>
home.statistics.number_clients=Authorized clients: <span class="label label-info" id="clientCount">{0}</span>
home.statistics.number_approvals=Approved sites: <span class="label label-info" id="approvalCount">{0}</span>
contact.title=Contact
contact.body=To report bugs with the MITREid Connect software itself, use the \
<a href="https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/issues">GitHub issue tracker</a>. \
For problems relating to this server, contact the server's administrator.
topbar.about=About
topbar.contact=Contact
topbar.statistics=Statistics
topbar.home=Home
topbar.login=Log in
topbar.logout=Log out
sidebar.administrative=Administrative
sidebar.administrative.manage_clients=Manage Clients
sidebar.administrative.whitelisted_clients=Whitelisted Clients
sidebar.administrative.blacklisted_clients=Blacklisted Clients
sidebar.administrative.system_scopes=System Scopes
sidebar.personal=Personal
sidebar.personal.approved_sites=Manage Approved Sites
sidebar.personal.active_tokens=Manage Active Tokens
sidebar.personal.profile_information=View Profile Information
sidebar.developer=Developer
sidebar.developer.client_registration=Self-service client registration
sidebar.developer.resource_registration=Self-service protected resource registration
manage.ok=OK
manage.loading=Loading
manage.title=Management Console
approve.title=Approve Access
approve.error.not_granted=Access could not be granted.
approve.required_for=Approval Required for
approve.dynamically_registered=This client was dynamically registered
approve.caution=Caution
approve.caution.message.none=It has never been approved previously.
approve.caution.message.singular=It has been approved <span class="label">{0}</span> time previously.
approve.caution.message.plural=It has been approved <span class="label">{0}</span> times previously.
approve.more_information=more information
approve.home_page=Home page
approve.policy=Policy
approve.terms=Terms of Service
approve.contacts=Administrative Contacts
approve.warning=Warning
approve.no_request_uri=This client does not have any redirect URIs registered and someone could be using a malicious URI here.
approve.redirect_uri=You will be redirected to the following page if you click Approve: <code>{0}</code>
approve.pairwise=This client uses a <b>pairwise</b> identifier, which makes it more difficult to correlate your identity between sites.
approve.no_scopes=This client does not have any scopes registered and is therefore allowed to request <em>any</em> scopes available on the system. Proceed with caution.
approve.access_to=Access to
approve.remember=Remember this decision
approve.remember.until_revoke=remember this decision until I revoke it
approve.remember.one_hour=remember this decision for one hour
approve.remember.next_time=prompt me again next time
approve.do_authorize=Do you authorize
approve.label.authorize=Authorize
approve.label.deny=Deny

View File

@ -1,112 +0,0 @@
###############################################################################
# Copyright 2015 The MITRE Corporation
# and the MIT Kerberos and Internet Trust Consortium
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
###############################################################################
copyright=Levererat av <a href="https://github.com/mitreid-connect/">MITREid Connect <span class="label">{0}</span></a> <span class="pull-right">&copy; 2015 MITRE Corporation och MIT KIT.</span>.
about.title=Om&nbsp;tjänsten
about.body=\
Denna OpenID Connect-tjänst är baserad på öppen källkod ifrån projektet MITREid, skapat av \
<a href="http://www.mitre.org/">MITRE Corporation</a> och <a href="http://kit.mit.edu/">MIT Kerberos and Internet Trust Consortium</a>.\
</p>\
<p>\
Mer information om projektet kan finns i projektet \
<a href="http://github.com/mitreid-connect/">MITREid Connect på GitHub</a>. \
Där kan du skicka in felrapporter, komma med återkoppling, eller till och med bidra med kodtillägg för ytterligare funktioner du skulle vilja ha.
statistics.title=Statistik
statistics.number_users=Antal användare: <span class="label label-info" id="userCount">{0}</span>
statistics.number_clients=Auktoriserade klienter: <span class="label label-info" id="clientCount">{0}</span>
statistics.number_approvals=Godkända webbplatser: <span class="label label-info" id="approvalCount">{0}</span>
# {2,choice,1#point|1<points}
home.title=Hem
home.welcome=Välkommen!
home.welcome.body=\
OpenID Connect är ett internet-kapabelt federerat identitetsprotokoll byggt ovanpå autentiseringsramverket OAuth2. \
OpenID Connect låter dig logga in på en webbplats med din identitet utan att avslöja dina inloggningshemligheter, som ett användarnamn och lösenord.</p>\
<p><a class="btn btn-primary btn-large" href="http://openid.net/connect/">Lär dig mer &raquo;</a>
home.more=Mer
home.about=Om&nbsp;tjänsten
home.about.body=\
Denna OpenID Connect-tjänst är byggd från det öpnna källkodsprojektet MITREid, av \
<a href="http://www.mitre.org/">MITRE Corporation</a> och <a href="http://kit.mit.edu/">MIT Kerberos and Internet Trust Consortium</a>.
home.contact=Kontakt
home.contact.body=\
För mer information eller användarstöd, kontakta administratörerna av detta system.</p>\
<p><a class="btn" href="mailto:idp@example.com?Subject=OpenID Connect">E-post &raquo;</a>
home.statistics=Nuvarande statistik
home.statistics.loading=Laddar...
home.statistics.number_users=Antal användare: <span class="label label-info" id="userCount">{0}</span>
home.statistics.number_clients=Auktoriserade klienter: <span class="label label-info" id="clientCount">{0}</span>
home.statistics.number_approvals=Godkända webbplatser: <span class="label label-info" id="approvalCount">{0}</span>
contact.title=Kontakt
contact.body=\
För att rapportera fel i själva programvaran MITREid Connect, använd \
<a href="https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/issues">GitHub issue tracker</a>. \
För problem som är specifika för denna server, kontakta tjänstens administrator.
topbar.about=Om&nbsp;tjänsten
topbar.contact=Kontakt
topbar.statistics=Statistik
topbar.home=Hem
topbar.login=Logga in
topbar.logout=Logga ut
sidebar.administrative=Administrativt
sidebar.administrative.manage_clients=Hantera klienter
sidebar.administrative.whitelisted_clients=Vitlistade klienter
sidebar.administrative.blacklisted_clients=Svartlistade klienter
sidebar.administrative.system_scopes=System-scope
sidebar.personal=Personligt
sidebar.personal.approved_sites=Hantera godkända platser
sidebar.personal.active_tokens=Hantera aktiva biljetter
sidebar.personal.profile_information=Visa profilinformation
sidebar.developer=Utvecklare
sidebar.developer.client_registration=Self-service klientregistering
sidebar.developer.resource_registration=Self-service registrering av skyddad resurs
manage.ok=OK
manage.loading=Laddar
manage.title=Administrationsgränssnitt
approve.title=Medge åtkomst
approve.error.not_granted=Åtkomst kunde inte medges.
approve.required_for=Åtkomst måste medges för
approve.dynamically_registered=Denna klient blev registrerad dynamiskt
approve.caution=Försiktigt
approve.caution.message.none=Den har aldrig tidigare blivit medgiven åtkomst.
approve.caution.message.singular=Den har tidigare blivit medgiven åtkomst <span class="label">{0}</span> gång.
approve.caution.message.plural=Den har tidigare blivit medgiven åtkomst <span class="label">{0}</span> gånger.
approve.more_information=mer information
approve.home_page=Hemsida
approve.policy=Policy
approve.terms=Användarvillkor
approve.contacts=Administrativ kontakt
approve.warning=Varning
approve.no_request_uri=Denna klient har inte någon omdirigerings URI registrerad och någon kan använda en skadlig URI hit.
approve.redirect_uri=Du kommer att omdirigeras till denna sida om du medger åtkomst: <code>{0}</code>
approve.pairwise=Denna klient använder en <b>pairwise</b>-identifierare, vilket gör det svårare att koppla samman dina identititer mellan olika webbplatser.
approve.no_scopes=Denna klient har inga "scopes" registrerade och kan därför begära <em>alla</em> scope som finns tillgängliga i systemet. Iakttag försiktighet.
approve.access_to=Åtkomst till
approve.remember=Kom ihåg detta val
approve.remember.until_revoke=tills jag återkallar det
approve.remember.one_hour=i en timme
approve.remember.next_time=fråga igen nästa gång
approve.do_authorize=Medger du åtkomst för
approve.label.authorize=Medge åtkomst
approve.label.deny=Avbryt

View File

@ -22,10 +22,12 @@
xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">
@ -80,19 +82,19 @@
<security:intercept-url pattern="/token" access="isAuthenticated()" />
<security:http-basic entry-point-ref="oauthAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request parameters -->
<security:custom-filter ref="clientAssertionTokenEndpointFilter" after="PRE_AUTH_FILTER" /> <!-- this one has to go first -->
<security:custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
<security:custom-filter ref="clientAssertionEndpointFilter" after="PRE_AUTH_FILTER" /> <!-- this one has to go first -->
<security:custom-filter ref="clientCredentialsEndpointFilter" after="BASIC_AUTH_FILTER" />
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>
<!-- Allow open access to required endpoints -->
<security:http pattern="/jwk**" use-expressions="true" entry-point-ref="http403EntryPoint" create-session="stateless">
<security:intercept-url pattern="/jwk**" access="permitAll"/>
<!-- Allow open access to discovery endpoints -->
<security:http pattern="/#{T(org.mitre.openid.connect.web.JWKSetPublishingEndpoint).URL}**" use-expressions="true" entry-point-ref="http403EntryPoint" create-session="stateless">
<security:intercept-url pattern="/#{T(org.mitre.openid.connect.web.JWKSetPublishingEndpoint).URL}**" access="permitAll"/>
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
</security:http>
<security:http pattern="/.well-known/**" use-expressions="true" entry-point-ref="http403EntryPoint" create-session="stateless">
<security:intercept-url pattern="/.well-known/**" access="permitAll"/>
<security:http pattern="/#{T(org.mitre.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" use-expressions="true" entry-point-ref="http403EntryPoint" create-session="stateless">
<security:intercept-url pattern="/#{T(org.mitre.discovery.web.DiscoveryEndpoint).WELL_KNOWN_URL}/**" access="permitAll"/>
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
</security:http>
@ -103,14 +105,14 @@
</security:http>
<!-- OAuth-protect API and other endpoints -->
<security:http pattern="/register/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless">
<security:http pattern="/#{T(org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless">
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
<security:expression-handler ref="oauthWebExpressionHandler" />
<security:intercept-url pattern="/register/**" access="permitAll"/>
</security:http>
<security:http pattern="/resource/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless">
<security:http pattern="/#{T(org.mitre.openid.connect.web.ProtectedResourceRegistrationEndpoint).URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless">
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
<security:expression-handler ref="oauthWebExpressionHandler" />
@ -129,39 +131,39 @@
<security:expression-handler ref="oauthWebExpressionHandler" />
</security:http>
<security:http pattern="/userinfo**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless">
<security:http pattern="/#{T(org.mitre.openid.connect.web.UserInfoEndpoint).URL}**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="stateless">
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
<security:expression-handler ref="oauthWebExpressionHandler" />
</security:http>
<security:http pattern="/api/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="never">
<security:http pattern="/#{T(org.mitre.openid.connect.web.RootController).API_URL}/**" use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint" create-session="never">
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<security:expression-handler ref="oauthWebExpressionHandler" />
</security:http>
<security:http pattern="/introspect**"
<security:http pattern="/#{T(org.mitre.oauth2.web.IntrospectionEndpoint).URL}**"
use-expressions="true"
entry-point-ref="oauthAuthenticationEntryPoint"
create-session="stateless"
authentication-manager-ref="clientAuthenticationManager">
<security:http-basic entry-point-ref="oauthAuthenticationEntryPoint" />
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<security:custom-filter ref="clientAssertionIntrospectionEndpointFilter" after="PRE_AUTH_FILTER" /> <!-- this one has to go first -->
<security:custom-filter ref="clientAssertionEndpointFilter" after="PRE_AUTH_FILTER" /> <!-- this one has to go first -->
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
<security:custom-filter ref="clientCredentialsIntrospectionEndpointFilter" after="BASIC_AUTH_FILTER" />
<security:custom-filter ref="clientCredentialsEndpointFilter" after="BASIC_AUTH_FILTER" />
</security:http>
<security:http pattern="/revoke**"
<security:http pattern="/#{T(org.mitre.oauth2.web.RevocationEndpoint).URL}**"
use-expressions="true"
entry-point-ref="oauthAuthenticationEntryPoint"
create-session="stateless"
authentication-manager-ref="clientAuthenticationManager">
<security:http-basic entry-point-ref="oauthAuthenticationEntryPoint" />
<!-- <security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" /> -->
<security:custom-filter ref="clientAssertionRevocationEndpointFilter" after="PRE_AUTH_FILTER" /> <!-- this one has to go first -->
<security:custom-filter ref="clientAssertionEndpointFilter" after="PRE_AUTH_FILTER" /> <!-- this one has to go first -->
<security:custom-filter ref="corsFilter" after="SECURITY_CONTEXT_FILTER" />
<security:custom-filter ref="clientCredentialsRevocationEndpointFilter" after="BASIC_AUTH_FILTER" />
<security:custom-filter ref="clientCredentialsEndpointFilter" after="BASIC_AUTH_FILTER" />
</security:http>
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
@ -174,36 +176,28 @@
<import resource="authz-config.xml" />
<bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
<property name="filterProcessesUrl" value="/token"/>
</bean>
<bean id="clientCredentialsIntrospectionEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
<property name="filterProcessesUrl" value="/introspect"/>
<bean id="oauth2ExceptionTranslator" class="org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator" />
<bean id="clientAuthMatcher" class="org.mitre.openid.connect.filter.MultiUrlRequestMatcher">
<constructor-arg name="filterProcessesUrls">
<set>
<value>/introspect</value>
<value>/revoke</value>
<value>/token</value>
</set>
</constructor-arg>
</bean>
<bean id="clientCredentialsRevocationEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<bean id="clientCredentialsEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
<property name="filterProcessesUrl" value="/revoke"/>
<property name="requiresAuthenticationRequestMatcher" ref="clientAuthMatcher" />
</bean>
<bean id="clientAssertionTokenEndpointFilter" class="org.mitre.openid.connect.assertion.JWTBearerClientAssertionTokenEndpointFilter">
<bean id="clientAssertionEndpointFilter" class="org.mitre.openid.connect.assertion.JWTBearerClientAssertionTokenEndpointFilter">
<constructor-arg name="additionalMatcher" ref="clientAuthMatcher" />
<property name="authenticationManager" ref="clientAssertionAuthenticationManager" />
<property name="filterProcessesUrl" value="/token" />
</bean>
<bean id="clientAssertionIntrospectionEndpointFilter" class="org.mitre.openid.connect.assertion.JWTBearerClientAssertionTokenEndpointFilter">
<property name="authenticationManager" ref="clientAssertionAuthenticationManager" />
<property name="filterProcessesUrl" value="/introspect" />
</bean>
<bean id="clientAssertionRevocationEndpointFilter" class="org.mitre.openid.connect.assertion.JWTBearerClientAssertionTokenEndpointFilter">
<property name="authenticationManager" ref="clientAssertionAuthenticationManager" />
<property name="filterProcessesUrl" value="/revoke" />
</bean>
<security:authentication-manager id="clientAuthenticationManager">
<security:authentication-provider user-service-ref="clientUserDetailsService" />
</security:authentication-manager>
@ -215,18 +209,8 @@
<bean id="clientAssertionAuthenticationProvider" class="org.mitre.openid.connect.assertion.JWTBearerAuthenticationProvider" />
<!-- Configure locale information -->
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:custom_messages</value>
<value>classpath:messages</value>
</list>
</property>
<property name="fallbackToSystemLocale" value="false" />
<property name="cacheSeconds" value="180" />
<property name="defaultEncoding" value="UTF-8" />
<property name="useCodeAsDefaultMessage" value="true" />
<bean id="messageSource" class="org.mitre.openid.connect.config.JsonMessageSource">
<property name="baseDirectory" value="/resources/js/locale/" />
</bean>
<!-- user services -->

View File

@ -3,18 +3,18 @@
<%@ taglib prefix="security"
uri="http://www.springframework.org/security/tags"%>
<security:authorize access="hasRole('ROLE_ADMIN')">
<li class="nav-header"><spring:message code="sidebar.administrative"/></li>
<li class="nav-header"><spring:message code="sidebar.administrative.title"/></li>
<li><a href="manage/#admin/clients" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.administrative.manage_clients"/></a></li>
<li><a href="manage/#admin/whitelists" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.administrative.whitelisted_clients"/></a></li>
<li><a href="manage/#admin/blacklist" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.administrative.blacklisted_clients"/></a></li>
<li><a href="manage/#admin/scope" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.administrative.system_scopes"/></a></li>
<li class="divider"></li>
</security:authorize>
<li class="nav-header"><spring:message code="sidebar.personal"/></li>
<li class="nav-header"><spring:message code="sidebar.personal.title"/></li>
<li><a href="manage/#user/approved" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.personal.approved_sites"/></a></li>
<li><a href="manage/#user/tokens" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.personal.active_tokens"/></a></li>
<li><a href="manage/#user/profile" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.personal.profile_information"/></a></li>
<li class="divider"></li>
<li class="nav-header"><spring:message code="sidebar.developer"/></li>
<li class="nav-header"><spring:message code="sidebar.developer.title"/></li>
<li><a href="manage/#dev/dynreg" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.developer.client_registration"/></a><li>
<li><a href="manage/#dev/resource" data-toggle="collapse" data-target=".nav-collapse"><spring:message code="sidebar.developer.resource_registration"/></a><li>

View File

@ -1,5 +1,5 @@
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<h2><spring:message code="home.about"/></h2>
<h2><spring:message code="home.about.title"/></h2>
<p><spring:message code="home.about.body"/></p>

View File

@ -1,5 +1,5 @@
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<h2><spring:message code="home.contact"/></h2>
<h2><spring:message code="home.contact.title"/></h2>
<p>
<spring:message code="home.contact.body"/>
</p>

View File

@ -1,5 +1,5 @@
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<h2><spring:message code="home.statistics"/></h2>
<h2><spring:message code="home.statistics.title"/></h2>
<p id="statsloader" class="muted"><spring:message code="home.statistics.loading"/></p>

View File

@ -3,7 +3,7 @@
<div class="span2 visible-desktop"><img src="resources/images/openid_connect_large.png"/></div>
<div class="span10">
<h1><spring:message code="home.welcome"/></h1>
<h1><spring:message code="home.welcome.title"/></h1>
<p><spring:message code="home.welcome.body"/></p>
</div>
</div>

View File

@ -30,6 +30,7 @@
<task:scheduled-tasks scheduler="taskScheduler">
<task:scheduled ref="defaultOAuth2ProviderTokenService" method="clearExpiredTokens" fixed-delay="300000" initial-delay="600000"/>
<task:scheduled ref="defaultApprovedSiteService" method="clearExpiredSites" fixed-delay="300000" initial-delay="600000"/>
<task:scheduled ref="defaultOAuth2AuthorizationCodeService" method="clearExpiredAuthorizationCodes" fixed-delay="300000" initial-delay="600000"/>
</task:scheduled-tasks>
</beans>

View File

@ -41,16 +41,15 @@
<div class="row">
<div class="span5 offset1 well-small" style="text-align: left">
<c:if test="${ client.dynamicallyRegistered }">
<fmt:formatDate type="both" value="${client.createdAt}" var="titleRegistrationTime"/>
<fmt:formatDate type="date" value="${client.createdAt}" var="registrationTime"/>
<c:choose>
<c:when test="${ gras }">
<!-- client is "generally recognized as safe, display a more muted block -->
<div>
<p class="alert alert-info">
<i class="icon-globe"></i>
<spring:message code="approve.dynamically_registered"/>
<span id="registrationTime" title='<c:out value="${titleRegistrationTime}"/>'> <c:out value="${registrationTime}"/></span>.
</p>
</div>
</c:when>
@ -58,10 +57,13 @@
<!-- client is dynamically registered -->
<div class="alert alert-block <c:out value="${ count eq 0 ? 'alert-error' : 'alert-warn' }" />">
<h4>
<i class="icon-globe"></i> <spring:message code="approve.caution"/>:
<i class="icon-globe"></i> <spring:message code="approve.caution.title"/>:
</h4>
<spring:message code="approve.dynamically_registered"/>
<span id="registrationTime" title='<c:out value="${titleRegistrationTime}"/>'> <c:out value="${registrationTime}"/></span>.
<p>
<spring:message code="approve.dynamically_registered" arguments="${ client.createdAt }"/>
</p>
<p>
<c:choose>
<c:when test="${count == 0}">
<spring:message code="approve.caution.message.none" arguments="${count}"/>
@ -73,6 +75,7 @@
<spring:message code="approve.caution.message.plural" arguments="${count}"/>
</c:otherwise>
</c:choose>
</p>
</div>
</c:otherwise>
</c:choose>
@ -143,7 +146,7 @@
<h4>
<i class="icon-info-sign"></i> <spring:message code="approve.warning"/>:
</h4>
<spring:message code="approve.no_request_uri"/>
<spring:message code="approve.no_redirect_uri"/>
<spring:message code="approve.redirect_uri" arguments="${redirect_uri}"/>
</div>
</c:when>
@ -225,7 +228,7 @@
</fieldset>
<fieldset style="text-align: left" class="well">
<legend style="margin-bottom: 0;"><spring:message code="approve.remember"/>:</legend>
<legend style="margin-bottom: 0;"><spring:message code="approve.remember.title"/>:</legend>
<label for="remember-forever" class="radio">
<input type="radio" name="remember" id="remember-forever" value="until-revoked" ${ !consent ? 'checked="checked"' : '' }>
<spring:message code="approve.remember.until_revoke"/>
@ -294,6 +297,25 @@ $(document).ready(function() {
$('#toggleMoreInformation i').attr('class', 'icon-chevron-down');
}
});
var creationDate = "<c:out value="${ client.createdAt }" />";
var displayCreationDate = $.t('approve.dynamically-registered-unkown');
var hoverCreationDate = "";
if (creationDate != null && moment(creationDate).isValid()) {
creationDate = moment(creationDate);
if (moment().diff(creationDate, 'months') < 6) {
displayCreationDate = creationDate.fromNow();
} else {
displayCreationDate = "on " + creationDate.format("LL");
}
hoverCreationDate = creationDate.format("LLL");
}
$('#registrationTime').html(displayCreationDate);
$('#registrationTime').attr('title', hoverCreationDate);
});
//-->

View File

@ -3,7 +3,7 @@
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags"%>
<spring:message code="home.welcome" var="title"/>
<spring:message code="home.title" var="title"/>
<o:header title="${title}" />
<o:topbar pageName="Home" />
<div class="container-fluid main">

View File

@ -224,19 +224,19 @@ var ClientView = Backbone.View.extend({
render:function (eventName) {
var creationDate = this.model.get('createdAt');
var displayCreationDate = "at an unknown time";
var displayCreationDate = $.t('client.client-table.unknown');
var hoverCreationDate = "";
if (creationDate == null || !moment(creationDate).isValid()) {
displayCreationDate = "at an unknown time";
displayCreationDate = $.t('client.client-table.unknown');
hoverCreationDate = "";
} else {
creationDate = moment(creationDate);
if (moment().diff(creationDate, 'months') < 6) {
displayCreationDate = creationDate.fromNow();
} else {
displayCreationDate = "on " + creationDate.format("MMMM Do, YYYY");
displayCreationDate = "on " + creationDate.format("LL");
}
hoverCreationDate = creationDate.format("MMMM Do, YYYY [at] h:mmA");
hoverCreationDate = creationDate.format("LLL");
}

View File

@ -158,6 +158,7 @@
"type": "Application Type",
"type-native": "Native",
"type-web": "Web",
"unknown": "(Unknown)",
"user-info-crypto-algorithm": "User Info Endpoint Encryption Algorithm",
"user-info-crypto-method": "User Info Endpoint Encryption Method",
"user-info-signing-algorithm": "User Info Endpoint Signing Algorithm"
@ -185,7 +186,8 @@
"no-redirect": "NO REDIRECT URI",
"registered": "Registrered",
"search": "Search...",
"whitelist": "Whitelist"
"whitelist": "Whitelist",
"unknown": "at an unknown time"
},
"manage": "Manage Clients",
"more-info": {
@ -335,5 +337,116 @@
"whitelist-table": {
"no-sites": "There are no whitelisted sites. Use the <strong>whitelist</strong> button on the client management page to create one."
}
}
},
"copyright": "Powered by <a href=\"https://github.com/mitreid-connect/\">MITREid Connect <span class=\"label\">{0}</span></a> <span class=\"pull-right\">&copy; 2015 The MITRE Corporation and MIT KIT.</span>.",
"about": {
"title": "About",
"body": "\nThis OpenID Connect service is built from the MITREid Connect Open Source project, from \n<a href=\"http://www.mitre.org/\">The MITRE Corporation</a> and the <a href=\"http://kit.mit.edu/\">MIT Kerberos and Internet Trust Consortium</a>.\n</p>\n<p>\nMore information about the project can be found at \n<a href=\"http://github.com/mitreid-connect/\">MITREid Connect on GitHub</a>. \nThere, you can submit bug reports, give feedback, or even contribute code patches for additional features you'd like to see."
},
"statistics": {
"title": "Statistics",
"number_users": "Number of users: <span class=\"label label-info\" id=\"userCount\">{0}</span>",
"number_clients": "Authorized clients: <span class=\"label label-info\" id=\"clientCount\">{0}</span>",
"number_approvals": "Approved sites: <span class=\"label label-info\" id=\"approvalCount\">{0}</span>"
},
"home": {
"title": "Home",
"welcome": {
"title": "Welcome!",
"body": "\nOpenID Connect is an internet-scale federated identity protocol built on top of the OAuth2 authorization framework. \nOpenID Connect lets you log into a remote site using your identity without exposing your credentials, like a username and password.</p>\n<p><a class=\"btn btn-primary btn-large\" href=\"http://openid.net/connect/\">Learn more &raquo;</a>"
},
"more": "More",
"about": {
"title": "About",
"body": "This OpenID Connect service is built from the MITREid Connect Open Source project, from \n<a href=\"http://www.mitre.org/\">The MITRE Corporation</a> and the <a href=\"http://kit.mit.edu/\">MIT Kerberos and Internet Trust Consortium</a>."
},
"contact": {
"title": "Contact",
"body": "\nFor more information or support, contact the administrators of this system.</p>\n<p><a class=\"btn\" href=\"mailto:idp@example.com?Subject=OpenID Connect\">Email &raquo;</a>"
},
"statistics": {
"title": "Current Statistics",
"loading": "Loading...",
"number_users": "Number of users: <span class=\"label label-info\" id=\"userCount\">{0}</span>",
"number_clients": "Authorized clients: <span class=\"label label-info\" id=\"clientCount\">{0}</span>",
"number_approvals": "Approved sites: <span class=\"label label-info\" id=\"approvalCount\">{0}</span>"
}
},
"contact": {
"title": "Contact",
"body": "To report bugs with the MITREid Connect software itself, use the \n<a href=\"https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/issues\">GitHub issue tracker</a>. \nFor problems relating to this server, contact the server's administrator."
},
"topbar": {
"about": "About",
"contact": "Contact",
"statistics": "Statistics",
"home": "Home",
"login": "Log in",
"logout": "Log out"
},
"sidebar": {
"administrative": {
"title": "Administrative",
"manage_clients": "Manage Clients",
"whitelisted_clients": "Whitelisted Clients",
"blacklisted_clients": "Blacklisted Clients",
"system_scopes": "System Scopes"
},
"personal": {
"title": "Personal",
"approved_sites": "Manage Approved Sites",
"active_tokens": "Manage Active Tokens",
"profile_information": "View Profile Information"
},
"developer": {
"title": "Developer",
"client_registration": "Self-service client registration",
"resource_registration": "Self-service protected resource registration"
}
},
"manage": {
"ok": "OK",
"loading": "Loading",
"title": "Management Console"
},
"approve": {
"dynamically-registered-unknown": "at an unknown time",
"title": "Approve Access",
"error": {
"not_granted": "Access could not be granted."
},
"required_for": "Approval Required for",
"dynamically_registered": "This client was dynamically registered <span class=\"label label-info\" id=\"registrationTime\">{0}</span>.",
"caution": {
"title": "Caution",
"message": {
"none": "It has <span class=\"label label-important\">never</span> been approved previously.",
"singular": "It has been approved <span class=\"label label-warning\">{0}</span> time previously.",
"plural": "It has been approved <span class=\"label\">{0}</span> times previously."
}
},
"more_information": "more information",
"home_page": "Home page",
"policy": "Policy",
"terms": "Terms of Service",
"contacts": "Administrative Contacts",
"warning": "Warning",
"no_redirect_uri": "This client does not have any redirect URIs registered and someone could be using a malicious URI here.",
"redirect_uri": "You will be redirected to the following page if you click Approve: <code>{0}</code>",
"pairwise": "This client uses a <b>pairwise</b> identifier, which makes it more difficult to correlate your identity between sites.",
"no_scopes": "This client does not have any scopes registered and is therefore allowed to request <em>any</em> scopes available on the system. Proceed with caution.",
"access_to": "Access to",
"remember": {
"title": "Remember this decision",
"until_revoke": "remember this decision until I revoke it",
"one_hour": "remember this decision for one hour",
"next_time": "prompt me again next time"
},
"do_authorize": "Do you authorize",
"label": {
"authorize": "Authorize",
"deny": "Deny"
}
}
}

View File

@ -322,5 +322,115 @@
"whitelist-table": {
"no-sites": "Det finns inga vitlistade webbplatser. Använd knappen <strong>vitlista</strong> på klientadminstrationssidan för att skapa en."
}
}
},
"copyright": "Levererat av <a href=\"https://github.com/mitreid-connect/\">MITREid Connect <span class=\"label\">{0}</span></a> <span class=\"pull-right\">&copy; 2015 MITRE Corporation och MIT KIT.</span>.",
"about": {
"title": "Om&nbsp;tjänsten",
"body": "\nDenna OpenID Connect-tjänst är baserad på öppen källkod ifrån projektet MITREid, skapat av \n<a href=\"http://www.mitre.org/\">MITRE Corporation</a> och <a href=\"http://kit.mit.edu/\">MIT Kerberos and Internet Trust Consortium</a>.\n</p>\n<p>\nMer information om projektet kan finns i projektet \n<a href=\"http://github.com/mitreid-connect/\">MITREid Connect på GitHub</a>. \nDär kan du skicka in felrapporter, komma med återkoppling, eller till och med bidra med kodtillägg för ytterligare funktioner du skulle vilja ha."
},
"statistics": {
"title": "Statistik",
"number_users": "Antal användare: <span class=\"label label-info\" id=\"userCount\">{0}</span>",
"number_clients": "Auktoriserade klienter: <span class=\"label label-info\" id=\"clientCount\">{0}</span>",
"number_approvals": "Godkända webbplatser: <span class=\"label label-info\" id=\"approvalCount\">{0}</span>"
},
"home": {
"title": "Hem",
"welcome": {
"title": "Välkommen!",
"body": "\nOpenID Connect är ett internet-kapabelt federerat identitetsprotokoll byggt ovanpå autentiseringsramverket OAuth2. \nOpenID Connect låter dig logga in på en webbplats med din identitet utan att avslöja dina inloggningshemligheter, som ett användarnamn och lösenord.</p>\n<p><a class=\"btn btn-primary btn-large\" href=\"http://openid.net/connect/\">Lär dig mer &raquo;</a>"
},
"more": "Mer",
"about": {
"title": "Om&nbsp;tjänsten",
"body": "\nDenna OpenID Connect-tjänst är byggd från det öpnna källkodsprojektet MITREid, av \n<a href=\"http://www.mitre.org/\">MITRE Corporation</a> och <a href=\"http://kit.mit.edu/\">MIT Kerberos and Internet Trust Consortium</a>."
},
"contact": {
"title": "Kontakt",
"body": "\nFör mer information eller användarstöd, kontakta administratörerna av detta system.</p>\n<p><a class=\"btn\" href=\"mailto:idp@example.com?Subject=OpenID Connect\">E-post &raquo;</a>"
},
"statistics": {
"title": "Nuvarande statistik",
"loading": "Laddar...",
"number_users": "Antal användare: <span class=\"label label-info\" id=\"userCount\">{0}</span>",
"number_clients": "Auktoriserade klienter: <span class=\"label label-info\" id=\"clientCount\">{0}</span>",
"number_approvals": "Godkända webbplatser: <span class=\"label label-info\" id=\"approvalCount\">{0}</span>"
}
},
"contact": {
"title": "Kontakt",
"body": "\nFör att rapportera fel i själva programvaran MITREid Connect, använd \n<a href=\"https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/issues\">GitHub issue tracker</a>. \nFör problem som är specifika för denna server, kontakta tjänstens administrator."
},
"topbar": {
"about": "Om&nbsp;tjänsten",
"contact": "Kontakt",
"statistics": "Statistik",
"home": "Hem",
"login": "Logga in",
"logout": "Logga ut"
},
"sidebar": {
"administrative": {
"title": "Administrativt",
"manage_clients": "Hantera klienter",
"whitelisted_clients": "Vitlistade klienter",
"blacklisted_clients": "Svartlistade klienter",
"system_scopes": "System-scope"
},
"personal": {
"title": "Personligt",
"approved_sites": "Hantera godkända platser",
"active_tokens": "Hantera aktiva biljetter",
"profile_information": "Visa profilinformation"
},
"developer": {
"title": "Utvecklare",
"client_registration": "Self-service klientregistering",
"resource_registration": "Self-service registrering av skyddad resurs"
}
},
"manage": {
"ok": "OK",
"loading": "Laddar",
"title": "Administrationsgränssnitt"
},
"approve": {
"dynamically-registered-unknown": "(Okänt)",
"title": "Medge åtkomst",
"error": {
"not_granted": "Åtkomst kunde inte medges."
},
"required_for": "Åtkomst måste medges för",
"dynamically_registered": "Denna klient blev registrerad dynamiskt <span class=\"label label-info\" id=\"registrationTime\">{0}</span>.",
"caution": {
"title": "Försiktigt",
"message": {
"none": "Den har <span class=\"label label-important\">aldrig</span> tidigare blivit medgiven åtkomst.",
"singular": "Den har tidigare blivit medgiven åtkomst <span class=\"label label-warning\">{0}</span> gång.",
"plural": "Den har tidigare blivit medgiven åtkomst <span class=\"label\">{0}</span> gånger."
}
},
"more_information": "mer information",
"home_page": "Hemsida",
"policy": "Policy",
"terms": "Användarvillkor",
"contacts": "Administrativ kontakt",
"warning": "Varning",
"no_redirect_uri": "Denna klient har inte någon omdirigerings URI registrerad och någon kan använda en skadlig URI hit.",
"redirect_uri": "Du kommer att omdirigeras till denna sida om du medger åtkomst: <code>{0}</code>",
"pairwise": "Denna klient använder en <b>pairwise</b>-identifierare, vilket gör det svårare att koppla samman dina identititer mellan olika webbplatser.",
"no_scopes": "Denna klient har inga \"scopes\" registrerade och kan därför begära <em>alla</em> scope som finns tillgängliga i systemet. Iakttag försiktighet.",
"access_to": "Åtkomst till",
"remember": {
"title": "Kom ihåg detta val",
"until_revoke": "tills jag återkallar det",
"one_hour": "i en timme",
"next_time": "fråga igen nästa gång"
},
"do_authorize": "Medger du åtkomst för",
"label": {
"authorize": "Medge åtkomst",
"deny": "Avbryt"
}
}
}

View File

@ -195,7 +195,11 @@
<div class="control-group" id="createdAt">
<label class="control-label" data-i18n="client.client-form.registered">Registered at</label>
<div class="controls">
<%-createdAt%>
<% if (createdAt) { %>
<%-createdAt%>
<% } else { %>
<span data-i18n="client.client-form.unknown">Unknown</span>
<% } %>
</div>
</div>
@ -410,7 +414,7 @@
<label class="control-label" data-i18n="client.client-form.authentication-method">Token Endpoint Authentication Method</label>
<div class="controls">
<div>
<input type="radio" id="tokenEndpointAuthMethodBasic" name="tokenEndpointAuthMethod" value="SECRET_BASIC" <%-(tokenEndpointAuthMethod == 'SECRET_BASIC' ? 'checked' : '')%>>
<input type="radio" id="tokenEndpointAuthMethodBasic" name="tokenEndpointAuthMethod" value="SECRET_BASIC" <%-((tokenEndpointAuthMethod == 'SECRET_BASIC') || (!tokenEndpointAuthMethod) ? 'checked' : '')%>>
<label for="tokenEndpointAuthMethodBasic" class="radio" data-i18n="client.client-form.secret-http">Client Secret over HTTP Basic</label>
</div>
<div>

View File

@ -26,6 +26,7 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.mitre.openid.connect.view.HttpCodeView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
@ -81,7 +82,7 @@ public class WebfingerView extends AbstractView {
response.setContentType("application/jrd+json");
HttpStatus code = (HttpStatus) model.get("code");
HttpStatus code = (HttpStatus) model.get(HttpCodeView.CODE);
if (code == null) {
code = HttpStatus.OK; // default to 200
}

View File

@ -25,6 +25,8 @@ import org.mitre.discovery.util.WebfingerURLNormalizer;
import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService;
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
import org.mitre.oauth2.service.SystemScopeService;
import org.mitre.oauth2.web.IntrospectionEndpoint;
import org.mitre.oauth2.web.RevocationEndpoint;
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
import org.mitre.openid.connect.model.UserInfo;
import org.mitre.openid.connect.service.UserInfoService;
@ -32,10 +34,14 @@ import org.mitre.openid.connect.view.HttpCodeView;
import org.mitre.openid.connect.view.JsonEntityView;
import org.mitre.uma.web.PermissionRegistrationEndpoint;
import org.mitre.uma.web.ResourceSetRegistrationEndpoint;
import org.mitre.openid.connect.web.DynamicClientRegistrationEndpoint;
import org.mitre.openid.connect.web.JWKSetPublishingEndpoint;
import org.mitre.openid.connect.web.UserInfoEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@ -61,6 +67,10 @@ import com.nimbusds.jose.JWSAlgorithm;
@Controller
public class DiscoveryEndpoint {
public static final String WELL_KNOWN_URL = ".well-known";
public static final String OPENID_CONFIGURATION_URL = WELL_KNOWN_URL + "/openid-configuration";
public static final String WEBFINGER_URL = WELL_KNOWN_URL + "/webfinger";
/**
* Logger for this class
*/
@ -94,8 +104,8 @@ public class DiscoveryEndpoint {
}
};
@RequestMapping(value={"/.well-known/webfinger"},
params={"resource", "rel=http://openid.net/specs/connect/1.0/issuer"}, produces = "application/json")
@RequestMapping(value={"/" + WEBFINGER_URL},
params={"resource", "rel=http://openid.net/specs/connect/1.0/issuer"}, produces = MediaType.APPLICATION_JSON_VALUE)
public String webfinger(@RequestParam("resource") String resource, Model model) {
if (!resource.equals(config.getIssuer())) {
@ -111,7 +121,7 @@ public class DiscoveryEndpoint {
if (user == null) {
logger.info("User not found: " + resource);
model.addAttribute("code", HttpStatus.NOT_FOUND);
model.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
return HttpCodeView.VIEWNAME;
}
@ -119,14 +129,14 @@ public class DiscoveryEndpoint {
if (!Strings.nullToEmpty(issuerComponents.getHost())
.equals(Strings.nullToEmpty(resourceUri.getHost()))) {
logger.info("Host mismatch, expected " + issuerComponents.getHost() + " got " + resourceUri.getHost());
model.addAttribute("code", HttpStatus.NOT_FOUND);
model.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
return HttpCodeView.VIEWNAME;
}
} else {
logger.info("Unknown URI format: " + resource);
model.addAttribute("code", HttpStatus.NOT_FOUND);
model.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
return HttpCodeView.VIEWNAME;
}
}
@ -138,7 +148,7 @@ public class DiscoveryEndpoint {
return "webfingerView";
}
@RequestMapping("/.well-known/openid-configuration")
@RequestMapping("/" + OPENID_CONFIGURATION_URL)
public String providerConfiguration(Model model) {
/*
@ -277,11 +287,11 @@ public class DiscoveryEndpoint {
m.put("issuer", config.getIssuer());
m.put("authorization_endpoint", baseUrl + "authorize");
m.put("token_endpoint", baseUrl + "token");
m.put("userinfo_endpoint", baseUrl + "userinfo");
m.put("userinfo_endpoint", baseUrl + UserInfoEndpoint.URL);
//check_session_iframe
//end_session_endpoint
m.put("jwks_uri", baseUrl + "jwk");
m.put("registration_endpoint", baseUrl + "register");
m.put("jwks_uri", baseUrl + JWKSetPublishingEndpoint.URL);
m.put("registration_endpoint", baseUrl + DynamicClientRegistrationEndpoint.URL);
m.put("scopes_supported", scopeService.toStrings(scopeService.getUnrestricted())); // these are the scopes that you can dynamically register for, which is what matters for discovery
m.put("response_types_supported", Lists.newArrayList("code", "token")); // we don't support these yet: , "id_token", "id_token token"));
m.put("grant_types_supported", grantTypes);
@ -332,10 +342,10 @@ public class DiscoveryEndpoint {
m.put("op_policy_uri", baseUrl + "about");
m.put("op_tos_uri", baseUrl + "about");
m.put("introspection_endpoint", baseUrl + "introspect"); // token introspection endpoint for verifying tokens
m.put("revocation_endpoint", baseUrl + "revoke"); // token revocation endpoint
m.put("introspection_endpoint", baseUrl + IntrospectionEndpoint.URL); // token introspection endpoint for verifying tokens
m.put("revocation_endpoint", baseUrl + RevocationEndpoint.URL); // token revocation endpoint
model.addAttribute("entity", m);
model.addAttribute(JsonEntityView.ENTITY, m);
return JsonEntityView.VIEWNAME;
}

View File

@ -25,7 +25,6 @@ import javax.persistence.TypedQuery;
import org.mitre.oauth2.model.AuthenticationHolderEntity;
import org.mitre.oauth2.repository.AuthenticationHolderRepository;
import org.mitre.util.jpa.JpaUtil;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@ -40,7 +39,7 @@ public class JpaAuthenticationHolderRepository implements AuthenticationHolderRe
@Override
public List<AuthenticationHolderEntity> getAll() {
TypedQuery<AuthenticationHolderEntity> query = manager.createNamedQuery("AuthenticationHolderEntity.getAll", AuthenticationHolderEntity.class);
TypedQuery<AuthenticationHolderEntity> query = manager.createNamedQuery(AuthenticationHolderEntity.QUERY_ALL, AuthenticationHolderEntity.class);
return query.getResultList();
}
@ -69,7 +68,7 @@ public class JpaAuthenticationHolderRepository implements AuthenticationHolderRe
@Override
@Transactional
public List<AuthenticationHolderEntity> getOrphanedAuthenticationHolders() {
TypedQuery<AuthenticationHolderEntity> query = manager.createNamedQuery("AuthenticationHolderEntity.getUnusedAuthenticationHolders", AuthenticationHolderEntity.class);
TypedQuery<AuthenticationHolderEntity> query = manager.createNamedQuery(AuthenticationHolderEntity.QUERY_GET_UNUSED, AuthenticationHolderEntity.class);
query.setMaxResults(MAXEXPIREDRESULTS);
List<AuthenticationHolderEntity> unusedAuthenticationHolders = query.getResultList();
return unusedAuthenticationHolders;

View File

@ -19,6 +19,9 @@
*/
package org.mitre.oauth2.repository.impl;
import java.util.Collection;
import java.util.Date;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
@ -26,8 +29,6 @@ import javax.persistence.TypedQuery;
import org.mitre.oauth2.model.AuthorizationCodeEntity;
import org.mitre.oauth2.repository.AuthorizationCodeRepository;
import org.mitre.util.jpa.JpaUtil;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@ -56,27 +57,39 @@ public class JpaAuthorizationCodeRepository implements AuthorizationCodeReposito
}
/* (non-Javadoc)
* @see org.mitre.oauth2.repository.AuthorizationCodeRepository#consume(java.lang.String)
* @see org.mitre.oauth2.repository.AuthorizationCodeRepository#getByCode(java.lang.String)
*/
@Override
@Transactional
public OAuth2Authentication consume(String code) throws InvalidGrantException {
TypedQuery<AuthorizationCodeEntity> query = manager.createNamedQuery("AuthorizationCodeEntity.getByValue", AuthorizationCodeEntity.class);
public AuthorizationCodeEntity getByCode(String code) {
TypedQuery<AuthorizationCodeEntity> query = manager.createNamedQuery(AuthorizationCodeEntity.QUERY_BY_VALUE, AuthorizationCodeEntity.class);
query.setParameter("code", code);
AuthorizationCodeEntity result = JpaUtil.getSingleResult(query.getResultList());
if (result == null) {
throw new InvalidGrantException("JpaAuthorizationCodeRepository: no authorization code found for value " + code);
}
OAuth2Authentication authRequest = result.getAuthentication();
manager.remove(result);
return authRequest;
return result;
}
/* (non-Javadoc)
* @see org.mitre.oauth2.repository.AuthorizationCodeRepository#remove(org.mitre.oauth2.model.AuthorizationCodeEntity)
*/
@Override
public void remove(AuthorizationCodeEntity authorizationCodeEntity) {
AuthorizationCodeEntity found = manager.find(AuthorizationCodeEntity.class, authorizationCodeEntity.getId());
if (found != null) {
manager.remove(found);
}
}
/* (non-Javadoc)
* @see org.mitre.oauth2.repository.AuthorizationCodeRepository#getExpiredCodes()
*/
@Override
public Collection<AuthorizationCodeEntity> getExpiredCodes() {
TypedQuery<AuthorizationCodeEntity> query = manager.createNamedQuery(AuthorizationCodeEntity.QUERY_EXPIRATION_BY_DATE, AuthorizationCodeEntity.class);
query.setParameter(AuthorizationCodeEntity.PARAM_DATE, new Date()); // this gets anything that's already expired
return query.getResultList();
}
}

View File

@ -57,8 +57,8 @@ public class JpaOAuth2ClientRepository implements OAuth2ClientRepository {
*/
@Override
public ClientDetailsEntity getClientByClientId(String clientId) {
TypedQuery<ClientDetailsEntity> query = manager.createNamedQuery("ClientDetailsEntity.getByClientId", ClientDetailsEntity.class);
query.setParameter("clientId", clientId);
TypedQuery<ClientDetailsEntity> query = manager.createNamedQuery(ClientDetailsEntity.QUERY_BY_CLIENT_ID, ClientDetailsEntity.class);
query.setParameter(ClientDetailsEntity.PARAM_CLIENT_ID, clientId);
return JpaUtil.getSingleResult(query.getResultList());
}
@ -93,7 +93,7 @@ public class JpaOAuth2ClientRepository implements OAuth2ClientRepository {
@Override
public Collection<ClientDetailsEntity> getAllClients() {
TypedQuery<ClientDetailsEntity> query = manager.createNamedQuery("ClientDetailsEntity.findAll", ClientDetailsEntity.class);
TypedQuery<ClientDetailsEntity> query = manager.createNamedQuery(ClientDetailsEntity.QUERY_ALL, ClientDetailsEntity.class);
return query.getResultList();
}

View File

@ -44,21 +44,21 @@ public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
@Override
public Set<OAuth2AccessTokenEntity> getAllAccessTokens() {
TypedQuery<OAuth2AccessTokenEntity> query = manager.createNamedQuery("OAuth2AccessTokenEntity.getAll", OAuth2AccessTokenEntity.class);
TypedQuery<OAuth2AccessTokenEntity> query = manager.createNamedQuery(OAuth2AccessTokenEntity.QUERY_ALL, OAuth2AccessTokenEntity.class);
return new LinkedHashSet<OAuth2AccessTokenEntity>(query.getResultList());
}
@Override
public Set<OAuth2RefreshTokenEntity> getAllRefreshTokens() {
TypedQuery<OAuth2RefreshTokenEntity> query = manager.createNamedQuery("OAuth2RefreshTokenEntity.getAll", OAuth2RefreshTokenEntity.class);
TypedQuery<OAuth2RefreshTokenEntity> query = manager.createNamedQuery(OAuth2RefreshTokenEntity.QUERY_ALL, OAuth2RefreshTokenEntity.class);
return new LinkedHashSet<OAuth2RefreshTokenEntity>(query.getResultList());
}
@Override
public OAuth2AccessTokenEntity getAccessTokenByValue(String accessTokenValue) {
TypedQuery<OAuth2AccessTokenEntity> query = manager.createNamedQuery("OAuth2AccessTokenEntity.getByTokenValue", OAuth2AccessTokenEntity.class);
query.setParameter("tokenValue", accessTokenValue);
TypedQuery<OAuth2AccessTokenEntity> query = manager.createNamedQuery(OAuth2AccessTokenEntity.QUERY_BY_TOKEN_VALUE, OAuth2AccessTokenEntity.class);
query.setParameter(OAuth2AccessTokenEntity.PARAM_TOKEN_VALUE, accessTokenValue);
return JpaUtil.getSingleResult(query.getResultList());
}
@ -87,8 +87,8 @@ public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
@Override
@Transactional
public void clearAccessTokensForRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
TypedQuery<OAuth2AccessTokenEntity> query = manager.createNamedQuery("OAuth2AccessTokenEntity.getByRefreshToken", OAuth2AccessTokenEntity.class);
query.setParameter("refreshToken", refreshToken);
TypedQuery<OAuth2AccessTokenEntity> query = manager.createNamedQuery(OAuth2AccessTokenEntity.QUERY_BY_REFRESH_TOKEN, OAuth2AccessTokenEntity.class);
query.setParameter(OAuth2AccessTokenEntity.PARAM_REFERSH_TOKEN, refreshToken);
List<OAuth2AccessTokenEntity> accessTokens = query.getResultList();
for (OAuth2AccessTokenEntity accessToken : accessTokens) {
removeAccessToken(accessToken);
@ -97,8 +97,8 @@ public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
@Override
public OAuth2RefreshTokenEntity getRefreshTokenByValue(String refreshTokenValue) {
TypedQuery<OAuth2RefreshTokenEntity> query = manager.createNamedQuery("OAuth2RefreshTokenEntity.getByTokenValue", OAuth2RefreshTokenEntity.class);
query.setParameter("tokenValue", refreshTokenValue);
TypedQuery<OAuth2RefreshTokenEntity> query = manager.createNamedQuery(OAuth2RefreshTokenEntity.QUERY_BY_TOKEN_VALUE, OAuth2RefreshTokenEntity.class);
query.setParameter(OAuth2RefreshTokenEntity.PARAM_TOKEN_VALUE, refreshTokenValue);
return JpaUtil.getSingleResult(query.getResultList());
}
@ -127,14 +127,14 @@ public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
@Override
@Transactional
public void clearTokensForClient(ClientDetailsEntity client) {
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByClient", OAuth2AccessTokenEntity.class);
queryA.setParameter("client", client);
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery(OAuth2AccessTokenEntity.QUERY_BY_CLIENT, OAuth2AccessTokenEntity.class);
queryA.setParameter(OAuth2AccessTokenEntity.PARAM_CLIENT, client);
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
for (OAuth2AccessTokenEntity accessToken : accessTokens) {
removeAccessToken(accessToken);
}
TypedQuery<OAuth2RefreshTokenEntity> queryR = manager.createNamedQuery("OAuth2RefreshTokenEntity.getByClient", OAuth2RefreshTokenEntity.class);
queryR.setParameter("client", client);
TypedQuery<OAuth2RefreshTokenEntity> queryR = manager.createNamedQuery(OAuth2RefreshTokenEntity.QUERY_BY_CLIENT, OAuth2RefreshTokenEntity.class);
queryR.setParameter(OAuth2RefreshTokenEntity.PARAM_CLIENT, client);
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
for (OAuth2RefreshTokenEntity refreshToken : refreshTokens) {
removeRefreshToken(refreshToken);
@ -146,8 +146,8 @@ public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
*/
@Override
public List<OAuth2AccessTokenEntity> getAccessTokensForClient(ClientDetailsEntity client) {
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByClient", OAuth2AccessTokenEntity.class);
queryA.setParameter("client", client);
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery(OAuth2AccessTokenEntity.QUERY_BY_CLIENT, OAuth2AccessTokenEntity.class);
queryA.setParameter(OAuth2AccessTokenEntity.PARAM_CLIENT, client);
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
return accessTokens;
}
@ -157,16 +157,16 @@ public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
*/
@Override
public List<OAuth2RefreshTokenEntity> getRefreshTokensForClient(ClientDetailsEntity client) {
TypedQuery<OAuth2RefreshTokenEntity> queryR = manager.createNamedQuery("OAuth2RefreshTokenEntity.getByClient", OAuth2RefreshTokenEntity.class);
queryR.setParameter("client", client);
TypedQuery<OAuth2RefreshTokenEntity> queryR = manager.createNamedQuery(OAuth2RefreshTokenEntity.QUERY_BY_CLIENT, OAuth2RefreshTokenEntity.class);
queryR.setParameter(OAuth2RefreshTokenEntity.PARAM_CLIENT, client);
List<OAuth2RefreshTokenEntity> refreshTokens = queryR.getResultList();
return refreshTokens;
}
@Override
public OAuth2AccessTokenEntity getByAuthentication(OAuth2Authentication auth) {
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByAuthentication", OAuth2AccessTokenEntity.class);
queryA.setParameter("authentication", auth);
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery(OAuth2AccessTokenEntity.QUERY_BY_AUTHENTICATION, OAuth2AccessTokenEntity.class);
queryA.setParameter(OAuth2AccessTokenEntity.PARAM_AUTHENTICATION, auth);
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
return JpaUtil.getSingleResult(accessTokens);
}
@ -176,24 +176,24 @@ public class JpaOAuth2TokenRepository implements OAuth2TokenRepository {
*/
@Override
public OAuth2AccessTokenEntity getAccessTokenForIdToken(OAuth2AccessTokenEntity idToken) {
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery("OAuth2AccessTokenEntity.getByIdToken", OAuth2AccessTokenEntity.class);
queryA.setParameter("idToken", idToken);
TypedQuery<OAuth2AccessTokenEntity> queryA = manager.createNamedQuery(OAuth2AccessTokenEntity.QUERY_BY_ID_TOKEN, OAuth2AccessTokenEntity.class);
queryA.setParameter(OAuth2AccessTokenEntity.PARAM_ID_TOKEN, idToken);
List<OAuth2AccessTokenEntity> accessTokens = queryA.getResultList();
return JpaUtil.getSingleResult(accessTokens);
}
@Override
public Set<OAuth2AccessTokenEntity> getAllExpiredAccessTokens() {
TypedQuery<OAuth2AccessTokenEntity> query = manager.createNamedQuery("OAuth2AccessTokenEntity.getAllExpiredByDate", OAuth2AccessTokenEntity.class);
query.setParameter("date", new Date());
TypedQuery<OAuth2AccessTokenEntity> query = manager.createNamedQuery(OAuth2AccessTokenEntity.QUERY_EXPIRED_BY_DATE, OAuth2AccessTokenEntity.class);
query.setParameter(OAuth2AccessTokenEntity.PARAM_DATE, new Date());
query.setMaxResults(MAXEXPIREDRESULTS);
return new LinkedHashSet<OAuth2AccessTokenEntity>(query.getResultList());
}
@Override
public Set<OAuth2RefreshTokenEntity> getAllExpiredRefreshTokens() {
TypedQuery<OAuth2RefreshTokenEntity> query = manager.createNamedQuery("OAuth2RefreshTokenEntity.getAllExpiredByDate", OAuth2RefreshTokenEntity.class);
query.setParameter("date", new Date());
TypedQuery<OAuth2RefreshTokenEntity> query = manager.createNamedQuery(OAuth2RefreshTokenEntity.QUERY_EXPIRED_BY_DATE, OAuth2RefreshTokenEntity.class);
query.setParameter(OAuth2RefreshTokenEntity.PARAM_DATE, new Date());
query.setMaxResults(MAXEXPIREDRESULTS);
return new LinkedHashSet<OAuth2RefreshTokenEntity>(query.getResultList());
}

View File

@ -19,9 +19,6 @@
*/
package org.mitre.oauth2.repository.impl;
import static org.mitre.util.jpa.JpaUtil.getSingleResult;
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
import java.util.LinkedHashSet;
import java.util.Set;
@ -34,6 +31,9 @@ import org.mitre.oauth2.repository.SystemScopeRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import static org.mitre.util.jpa.JpaUtil.getSingleResult;
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
/**
* @author jricher
*
@ -50,7 +50,7 @@ public class JpaSystemScopeRepository implements SystemScopeRepository {
@Override
@Transactional
public Set<SystemScope> getAll() {
TypedQuery<SystemScope> query = em.createNamedQuery("SystemScope.findAll", SystemScope.class);
TypedQuery<SystemScope> query = em.createNamedQuery(SystemScope.QUERY_ALL, SystemScope.class);
return new LinkedHashSet<SystemScope>(query.getResultList());
}
@ -70,8 +70,8 @@ public class JpaSystemScopeRepository implements SystemScopeRepository {
@Override
@Transactional
public SystemScope getByValue(String value) {
TypedQuery<SystemScope> query = em.createNamedQuery("SystemScope.getByValue", SystemScope.class);
query.setParameter("value", value);
TypedQuery<SystemScope> query = em.createNamedQuery(SystemScope.QUERY_BY_VALUE, SystemScope.class);
query.setParameter(SystemScope.PARAM_VALUE, value);
return getSingleResult(query.getResultList());
}

View File

@ -16,13 +16,10 @@
*******************************************************************************/
package org.mitre.oauth2.service.impl;
import static com.google.common.collect.Maps.newLinkedHashMap;
import java.text.ParseException;
import java.util.Map;
import java.util.Set;
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
import org.mitre.oauth2.service.IntrospectionResultAssembler;
@ -35,6 +32,8 @@ import org.springframework.stereotype.Service;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import static com.google.common.collect.Maps.newLinkedHashMap;
/**
* Default implementation of the {@link IntrospectionResultAssembler} interface.
*/

View File

@ -19,7 +19,15 @@
*/
package org.mitre.oauth2.service.impl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Date;
import org.mitre.oauth2.model.AuthenticationHolderEntity;
import org.mitre.oauth2.model.AuthorizationCodeEntity;
import org.mitre.oauth2.repository.AuthenticationHolderRepository;
import org.mitre.oauth2.repository.AuthorizationCodeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
@ -27,6 +35,7 @@ import org.springframework.security.oauth2.common.util.RandomValueStringGenerato
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* Database-backed, random-value authorization code service implementation.
@ -34,11 +43,18 @@ import org.springframework.stereotype.Service;
* @author aanganes
*
*/
@Service
@Service("defaultOAuth2AuthorizationCodeService")
public class DefaultOAuth2AuthorizationCodeService implements AuthorizationCodeServices {
// Logger for this class
private static final Logger logger = LoggerFactory.getLogger(DefaultOAuth2AuthorizationCodeService.class);
@Autowired
private AuthorizationCodeRepository repository;
@Autowired
private AuthenticationHolderRepository authenticationHolderRepository;
private int authCodeExpirationSeconds = 60 * 5; // expire in 5 minutes by default
private RandomValueStringGenerator generator = new RandomValueStringGenerator();
@ -54,7 +70,15 @@ public class DefaultOAuth2AuthorizationCodeService implements AuthorizationCodeS
public String createAuthorizationCode(OAuth2Authentication authentication) {
String code = generator.generate();
AuthorizationCodeEntity entity = new AuthorizationCodeEntity(code, authentication);
// attach the authorization so that we can look it up later
AuthenticationHolderEntity authHolder = new AuthenticationHolderEntity();
authHolder.setAuthentication(authentication);
authHolder = authenticationHolderRepository.save(authHolder);
// set the auth code to expire
Date expiration = new Date(System.currentTimeMillis() + (getAuthCodeExpirationSeconds() * 1000L));
AuthorizationCodeEntity entity = new AuthorizationCodeEntity(code, authHolder, expiration);
repository.save(entity);
return code;
@ -73,9 +97,34 @@ public class DefaultOAuth2AuthorizationCodeService implements AuthorizationCodeS
@Override
public OAuth2Authentication consumeAuthorizationCode(String code) throws InvalidGrantException {
OAuth2Authentication auth = repository.consume(code);
AuthorizationCodeEntity result = repository.getByCode(code);
if (result == null) {
throw new InvalidGrantException("JpaAuthorizationCodeRepository: no authorization code found for value " + code);
}
OAuth2Authentication auth = result.getAuthenticationHolder().getAuthentication();
repository.remove(result);
return auth;
}
/**
* Find and remove all expired auth codes.
*/
@Transactional
public void clearExpiredAuthorizationCodes() {
Collection<AuthorizationCodeEntity> codes = repository.getExpiredCodes();
for (AuthorizationCodeEntity code : codes) {
repository.remove(code);
}
logger.info("Removed " + codes.size() + " expired authorization codes.");
}
/**
* @return the repository
@ -91,4 +140,18 @@ public class DefaultOAuth2AuthorizationCodeService implements AuthorizationCodeS
this.repository = repository;
}
/**
* @return the authCodeExpirationSeconds
*/
public int getAuthCodeExpirationSeconds() {
return authCodeExpirationSeconds;
}
/**
* @param authCodeExpirationSeconds the authCodeExpirationSeconds to set
*/
public void setAuthCodeExpirationSeconds(int authCodeExpirationSeconds) {
this.authCodeExpirationSeconds = authCodeExpirationSeconds;
}
}

View File

@ -29,7 +29,6 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.oauth2.model.SystemScope;

View File

@ -26,10 +26,12 @@ import javax.servlet.http.HttpServletResponse;
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
import org.mitre.openid.connect.view.HttpCodeView;
import org.mitre.openid.connect.view.JsonEntityView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.web.servlet.view.AbstractView;
@ -124,10 +126,10 @@ public class TokenApiView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
response.setContentType("application/json");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
HttpStatus code = (HttpStatus) model.get("code");
HttpStatus code = (HttpStatus) model.get(HttpCodeView.CODE);
if (code == null) {
code = HttpStatus.OK; // default to 200
}
@ -137,7 +139,7 @@ public class TokenApiView extends AbstractView {
try {
Writer out = response.getWriter();
Object obj = model.get("entity");
Object obj = model.get(JsonEntityView.ENTITY);
gson.toJson(obj, out);
} catch (IOException e) {

View File

@ -38,11 +38,15 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@ -54,6 +58,11 @@ import static org.mitre.oauth2.web.AuthenticationUtilities.ensureOAuthScope;
@Controller
public class IntrospectionEndpoint {
/**
*
*/
public static final String URL = "introspect";
@Autowired
private OAuth2TokenEntityService tokenServices;
@ -69,6 +78,9 @@ public class IntrospectionEndpoint {
@Autowired
private ResourceSetService resourceSetService;
@Autowired
private WebResponseExceptionTranslator providerExceptionHandler;
/**
* Logger for this class
*/
@ -82,7 +94,7 @@ public class IntrospectionEndpoint {
this.tokenServices = tokenServices;
}
@RequestMapping("/introspect")
@RequestMapping("/" + URL)
public String verify(@RequestParam("token") String tokenValue,
@RequestParam(value = "token_type_hint", required = false) String tokenType,
Authentication auth, Model model) {
@ -141,7 +153,7 @@ public class IntrospectionEndpoint {
if (Strings.isNullOrEmpty(tokenValue)) {
logger.error("Verify failed; token value is null");
Map<String,Boolean> entity = ImmutableMap.of("active", Boolean.FALSE);
model.addAttribute("entity", entity);
model.addAttribute(JsonEntityView.ENTITY, entity);
return JsonEntityView.VIEWNAME;
}
@ -176,8 +188,8 @@ public class IntrospectionEndpoint {
} catch (InvalidTokenException e2) {
logger.error("Invalid refresh token");
Map<String,Boolean> entity = ImmutableMap.of("active", Boolean.FALSE);
model.addAttribute("entity", entity);
Map<String,Boolean> entity = ImmutableMap.of(IntrospectionResultAssembler.ACTIVE, Boolean.FALSE);
model.addAttribute(JsonEntityView.ENTITY, entity);
return JsonEntityView.VIEWNAME;
}
}
@ -186,20 +198,27 @@ public class IntrospectionEndpoint {
if (accessToken != null) {
Map<String, Object> entity = introspectionResultAssembler.assembleFrom(accessToken, user, authScopes);
model.addAttribute("entity", entity);
model.addAttribute(JsonEntityView.ENTITY, entity);
} else if (refreshToken != null) {
Map<String, Object> entity = introspectionResultAssembler.assembleFrom(refreshToken, user, authScopes);
model.addAttribute("entity", entity);
model.addAttribute(JsonEntityView.ENTITY, entity);
} else {
// no tokens were found (we shouldn't get here)
logger.error("Verify failed; Invalid access/refresh token");
Map<String,Boolean> entity = ImmutableMap.of("active", Boolean.FALSE);
model.addAttribute("entity", entity);
Map<String,Boolean> entity = ImmutableMap.of(IntrospectionResultAssembler.ACTIVE, Boolean.FALSE);
model.addAttribute(JsonEntityView.ENTITY, entity);
return JsonEntityView.VIEWNAME;
}
return JsonEntityView.VIEWNAME;
}
@ExceptionHandler(OAuth2Exception.class)
public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
return providerExceptionHandler.translate(e);
}
}

View File

@ -19,8 +19,6 @@
*/
package org.mitre.oauth2.web;
import static org.mitre.openid.connect.request.ConnectRequestParameters.*;
import java.security.Principal;
import java.util.Date;
import java.util.HashMap;
@ -56,6 +54,12 @@ import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.google.gson.JsonObject;
import static org.mitre.openid.connect.request.ConnectRequestParameters.CSRF;
import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT;
import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT_CONSENT;
import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT_NONE;
import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT_SEPARATOR;
/**
* @author jricher
*
@ -105,7 +109,7 @@ public class OAuthConfirmationController {
if (prompts.contains(PROMPT_NONE)) {
// we're not supposed to prompt, so "return an error"
logger.info("Client requested no prompt, returning 403 from confirmation endpoint");
model.put("code", HttpStatus.FORBIDDEN);
model.put(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
return HttpCodeView.VIEWNAME;
}
@ -121,17 +125,17 @@ public class OAuthConfirmationController {
client = clientService.loadClientByClientId(authRequest.getClientId());
} catch (OAuth2Exception e) {
logger.error("confirmAccess: OAuth2Exception was thrown when attempting to load client", e);
model.put("code", HttpStatus.BAD_REQUEST);
model.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
return HttpCodeView.VIEWNAME;
} catch (IllegalArgumentException e) {
logger.error("confirmAccess: IllegalArgumentException was thrown when attempting to load client", e);
model.put("code", HttpStatus.BAD_REQUEST);
model.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
return HttpCodeView.VIEWNAME;
}
if (client == null) {
logger.error("confirmAccess: could not find client " + authRequest.getClientId());
model.put("code", HttpStatus.NOT_FOUND);
model.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
return HttpCodeView.VIEWNAME;
}

View File

@ -45,8 +45,10 @@ public class RevocationEndpoint {
*/
private static final Logger logger = LoggerFactory.getLogger(RevocationEndpoint.class);
public static final String URL = "revoke";
@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')")
@RequestMapping("/revoke")
@RequestMapping("/" + URL)
public String revoke(@RequestParam("token") String tokenValue, @RequestParam(value = "token_type_hint", required = false) String tokenType, Principal principal, Model model) {
// This is the token as passed in from OAuth (in case we need it some day)
@ -66,14 +68,14 @@ public class RevocationEndpoint {
// client acting on its own, make sure it owns the token
if (!accessToken.getClient().getClientId().equals(authRequest.getClientId())) {
// trying to revoke a token we don't own, throw a 403
model.addAttribute("code", HttpStatus.FORBIDDEN);
model.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
return HttpCodeView.VIEWNAME;
}
}
// if we got this far, we're allowed to do this
tokenServices.revokeAccessToken(accessToken);
model.addAttribute("code", HttpStatus.OK);
model.addAttribute(HttpCodeView.CODE, HttpStatus.OK);
return HttpCodeView.VIEWNAME;
} catch (InvalidTokenException e) {
@ -86,21 +88,21 @@ public class RevocationEndpoint {
// client acting on its own, make sure it owns the token
if (!refreshToken.getClient().getClientId().equals(authRequest.getClientId())) {
// trying to revoke a token we don't own, throw a 403
model.addAttribute("code", HttpStatus.FORBIDDEN);
model.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
return HttpCodeView.VIEWNAME;
}
}
// if we got this far, we're allowed to do this
tokenServices.revokeRefreshToken(refreshToken);
model.addAttribute("code", HttpStatus.OK);
model.addAttribute(HttpCodeView.CODE, HttpStatus.OK);
return HttpCodeView.VIEWNAME;
} catch (InvalidTokenException e1) {
// neither token type was found, simply say "OK" and be on our way.
model.addAttribute("code", HttpStatus.OK);
model.addAttribute(HttpCodeView.CODE, HttpStatus.OK);
return HttpCodeView.VIEWNAME;
}
}

View File

@ -26,13 +26,19 @@ import org.mitre.oauth2.service.SystemScopeService;
import org.mitre.openid.connect.view.HttpCodeView;
import org.mitre.openid.connect.view.JsonEntityView;
import org.mitre.openid.connect.view.JsonErrorView;
import org.mitre.openid.connect.web.RootController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@ -45,13 +51,18 @@ import com.google.gson.Gson;
*
*/
@Controller
@RequestMapping("/api/scopes")
@RequestMapping("/" + ScopeAPI.URL)
@PreAuthorize("hasRole('ROLE_USER')")
public class ScopeAPI {
public static final String URL = RootController.API_URL + "/scopes";
@Autowired
private SystemScopeService scopeService;
@Autowired
private WebResponseExceptionTranslator providerExceptionHandler;
/**
* Logger for this class
*/
@ -59,38 +70,38 @@ public class ScopeAPI {
private Gson gson = new Gson();
@RequestMapping(value = "", method = RequestMethod.GET, produces = "application/json")
@RequestMapping(value = "", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getAll(ModelMap m) {
Set<SystemScope> allScopes = scopeService.getAll();
m.put("entity", allScopes);
m.put(JsonEntityView.ENTITY, allScopes);
return JsonEntityView.VIEWNAME;
}
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = "application/json")
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getScope(@PathVariable("id") Long id, ModelMap m) {
SystemScope scope = scopeService.getById(id);
if (scope != null) {
m.put("entity", scope);
m.put(JsonEntityView.ENTITY, scope);
return JsonEntityView.VIEWNAME;
} else {
logger.error("getScope failed; scope not found: " + id);
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "The requested scope with id " + id + " could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "The requested scope with id " + id + " could not be found.");
return JsonErrorView.VIEWNAME;
}
}
@PreAuthorize("hasRole('ROLE_ADMIN')")
@RequestMapping(value = "/{id}", method = RequestMethod.PUT, produces = "application/json", consumes = "application/json")
@RequestMapping(value = "/{id}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public String updateScope(@PathVariable("id") Long id, @RequestBody String json, ModelMap m) {
SystemScope existing = scopeService.getById(id);
@ -104,7 +115,7 @@ public class ScopeAPI {
scope = scopeService.save(scope);
m.put("entity", scope);
m.put(JsonEntityView.ENTITY, scope);
return JsonEntityView.VIEWNAME;
} else {
@ -112,8 +123,8 @@ public class ScopeAPI {
logger.error("updateScope failed; scope ids to not match: got "
+ existing.getId() + " and " + scope.getId());
m.put("code", HttpStatus.BAD_REQUEST);
m.put("errorMessage", "Could not update scope. Scope ids to not match: got "
m.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.put(JsonErrorView.ERROR_MESSAGE, "Could not update scope. Scope ids to not match: got "
+ existing.getId() + " and " + scope.getId());
return JsonErrorView.VIEWNAME;
}
@ -121,14 +132,14 @@ public class ScopeAPI {
} else {
logger.error("updateScope failed; scope with id " + id + " not found.");
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "Could not update scope. The scope with id " + id + " could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "Could not update scope. The scope with id " + id + " could not be found.");
return JsonErrorView.VIEWNAME;
}
}
@PreAuthorize("hasRole('ROLE_ADMIN')")
@RequestMapping(value = "", method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
@RequestMapping(value = "", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public String createScope(@RequestBody String json, ModelMap m) {
SystemScope scope = gson.fromJson(json, SystemScope.class);
@ -136,8 +147,8 @@ public class ScopeAPI {
if (alreadyExists != null) {
//Error, cannot save a scope with the same value as an existing one
logger.error("Error: attempting to save a scope with a value that already exists: " + scope.getValue());
m.put("code", HttpStatus.CONFLICT);
m.put("errorMessage", "A scope with value " + scope.getValue() + " already exists, please choose a different value.");
m.put(HttpCodeView.CODE, HttpStatus.CONFLICT);
m.put(JsonErrorView.ERROR_MESSAGE, "A scope with value " + scope.getValue() + " already exists, please choose a different value.");
return JsonErrorView.VIEWNAME;
}
@ -145,14 +156,14 @@ public class ScopeAPI {
if (scope != null && scope.getId() != null) {
m.put("entity", scope);
m.put(JsonEntityView.ENTITY, scope);
return JsonEntityView.VIEWNAME;
} else {
logger.error("createScope failed; JSON was invalid: " + json);
m.put("code", HttpStatus.BAD_REQUEST);
m.put("errorMessage", "Could not save new scope " + scope + ". The scope service failed to return a saved entity.");
m.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.put(JsonErrorView.ERROR_MESSAGE, "Could not save new scope " + scope + ". The scope service failed to return a saved entity.");
return JsonErrorView.VIEWNAME;
}
@ -171,10 +182,15 @@ public class ScopeAPI {
} else {
logger.error("deleteScope failed; scope with id " + id + " not found.");
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "Could not delete scope. The requested scope with id " + id + " could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "Could not delete scope. The requested scope with id " + id + " could not be found.");
return JsonErrorView.VIEWNAME;
}
}
@ExceptionHandler(OAuth2Exception.class)
public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
return providerExceptionHandler.translate(e);
}
}

View File

@ -28,14 +28,21 @@ import org.mitre.oauth2.service.OAuth2TokenEntityService;
import org.mitre.oauth2.view.TokenApiView;
import org.mitre.openid.connect.service.OIDCTokenService;
import org.mitre.openid.connect.view.HttpCodeView;
import org.mitre.openid.connect.view.JsonEntityView;
import org.mitre.openid.connect.view.JsonErrorView;
import org.mitre.openid.connect.web.RootController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@ -46,10 +53,12 @@ import org.springframework.web.bind.annotation.RequestMethod;
*
*/
@Controller
@RequestMapping("/api/tokens")
@RequestMapping("/" + TokenAPI.URL)
@PreAuthorize("hasRole('ROLE_USER')")
public class TokenAPI {
public static final String URL = RootController.API_URL + "/tokens";
@Autowired
private OAuth2TokenEntityService tokenService;
@ -59,54 +68,57 @@ public class TokenAPI {
@Autowired
private OIDCTokenService oidcTokenService;
@Autowired
private WebResponseExceptionTranslator providerExceptionHandler;
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(TokenAPI.class);
@RequestMapping(value = "/access", method = RequestMethod.GET, produces = "application/json")
@RequestMapping(value = "/access", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getAllAccessTokens(ModelMap m, Principal p) {
Set<OAuth2AccessTokenEntity> allTokens = tokenService.getAllAccessTokensForUser(p.getName());
m.put("entity", allTokens);
m.put(JsonEntityView.ENTITY, allTokens);
return TokenApiView.VIEWNAME;
}
@RequestMapping(value = "/access/{id}", method = RequestMethod.GET, produces = "application/json")
@RequestMapping(value = "/access/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getAccessTokenById(@PathVariable("id") Long id, ModelMap m, Principal p) {
OAuth2AccessTokenEntity token = tokenService.getAccessTokenById(id);
if (token == null) {
logger.error("getToken failed; token not found: " + id);
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "The requested token with id " + id + " could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "The requested token with id " + id + " could not be found.");
return JsonErrorView.VIEWNAME;
} else if (!token.getAuthenticationHolder().getAuthentication().getName().equals(p.getName())) {
logger.error("getToken failed; token does not belong to principal " + p.getName());
m.put("code", HttpStatus.FORBIDDEN);
m.put("errorMessage", "You do not have permission to view this token");
m.put(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
m.put(JsonErrorView.ERROR_MESSAGE, "You do not have permission to view this token");
return JsonErrorView.VIEWNAME;
} else {
m.put("entity", token);
m.put(JsonEntityView.ENTITY, token);
return TokenApiView.VIEWNAME;
}
}
@RequestMapping(value = "/access/{id}", method = RequestMethod.DELETE, produces = "application/json")
@RequestMapping(value = "/access/{id}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE)
public String deleteAccessTokenById(@PathVariable("id") Long id, ModelMap m, Principal p) {
OAuth2AccessTokenEntity token = tokenService.getAccessTokenById(id);
if (token == null) {
logger.error("getToken failed; token not found: " + id);
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "The requested token with id " + id + " could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "The requested token with id " + id + " could not be found.");
return JsonErrorView.VIEWNAME;
} else if (!token.getAuthenticationHolder().getAuthentication().getName().equals(p.getName())) {
logger.error("getToken failed; token does not belong to principal " + p.getName());
m.put("code", HttpStatus.FORBIDDEN);
m.put("errorMessage", "You do not have permission to view this token");
m.put(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
m.put(JsonErrorView.ERROR_MESSAGE, "You do not have permission to view this token");
return JsonErrorView.VIEWNAME;
} else {
tokenService.revokeAccessToken(token);
@ -116,26 +128,26 @@ public class TokenAPI {
}
@PreAuthorize("hasRole('ROLE_ADMIN')")
@RequestMapping(value = "/client/{clientId}", method = RequestMethod.GET, produces = "application/json")
@RequestMapping(value = "/client/{clientId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getAccessTokensByClientId(@PathVariable("clientId") String clientId, ModelMap m, Principal p) {
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
if (client != null) {
List<OAuth2AccessTokenEntity> tokens = tokenService.getAccessTokensForClient(client);
m.put("entity", tokens);
m.put(JsonEntityView.ENTITY, tokens);
return TokenApiView.VIEWNAME;
} else {
// client not found
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "The requested client with id " + clientId + " could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "The requested client with id " + clientId + " could not be found.");
return JsonErrorView.VIEWNAME;
}
}
@PreAuthorize("hasRole('ROLE_ADMIN')")
@RequestMapping(value = "/registration/{clientId}", method = RequestMethod.GET, produces = "application/json")
@RequestMapping(value = "/registration/{clientId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getRegistrationTokenByClientId(@PathVariable("clientId") String clientId, ModelMap m, Principal p) {
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
@ -143,24 +155,24 @@ public class TokenAPI {
if (client != null) {
OAuth2AccessTokenEntity token = tokenService.getRegistrationAccessTokenForClient(client);
if (token != null) {
m.put("entity", token);
m.put(JsonEntityView.ENTITY, token);
return TokenApiView.VIEWNAME;
} else {
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "No registration token could be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "No registration token could be found.");
return JsonErrorView.VIEWNAME;
}
} else {
// client not found
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "The requested client with id " + clientId + " could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "The requested client with id " + clientId + " could not be found.");
return JsonErrorView.VIEWNAME;
}
}
@PreAuthorize("hasRole('ROLE_ADMIN')")
@RequestMapping(value = "/registration/{clientId}", method = RequestMethod.PUT, produces = "application/json")
@RequestMapping(value = "/registration/{clientId}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE)
public String rotateRegistrationTokenByClientId(@PathVariable("clientId") String clientId, ModelMap m, Principal p) {
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
@ -169,67 +181,67 @@ public class TokenAPI {
token = tokenService.saveAccessToken(token);
if (token != null) {
m.put("entity", token);
m.put(JsonEntityView.ENTITY, token);
return TokenApiView.VIEWNAME;
} else {
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "No registration token could be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "No registration token could be found.");
return JsonErrorView.VIEWNAME;
}
} else {
// client not found
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "The requested client with id " + clientId + " could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "The requested client with id " + clientId + " could not be found.");
return JsonErrorView.VIEWNAME;
}
}
@RequestMapping(value = "/refresh", method = RequestMethod.GET, produces = "application/json")
@RequestMapping(value = "/refresh", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getAllRefreshTokens(ModelMap m, Principal p) {
Set<OAuth2RefreshTokenEntity> allTokens = tokenService.getAllRefreshTokensForUser(p.getName());
m.put("entity", allTokens);
m.put(JsonEntityView.ENTITY, allTokens);
return TokenApiView.VIEWNAME;
}
@RequestMapping(value = "/refresh/{id}", method = RequestMethod.GET, produces = "application/json")
@RequestMapping(value = "/refresh/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getRefreshTokenById(@PathVariable("id") Long id, ModelMap m, Principal p) {
OAuth2RefreshTokenEntity token = tokenService.getRefreshTokenById(id);
if (token == null) {
logger.error("refresh token not found: " + id);
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "The requested token with id " + id + " could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "The requested token with id " + id + " could not be found.");
return JsonErrorView.VIEWNAME;
} else if (!token.getAuthenticationHolder().getAuthentication().getName().equals(p.getName())) {
logger.error("refresh token " + id + " does not belong to principal " + p.getName());
m.put("code", HttpStatus.FORBIDDEN);
m.put("errorMessage", "You do not have permission to view this token");
m.put(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
m.put(JsonErrorView.ERROR_MESSAGE, "You do not have permission to view this token");
return JsonErrorView.VIEWNAME;
} else {
m.put("entity", token);
m.put(JsonEntityView.ENTITY, token);
return TokenApiView.VIEWNAME;
}
}
@RequestMapping(value = "/refresh/{id}", method = RequestMethod.DELETE, produces = "application/json")
@RequestMapping(value = "/refresh/{id}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE)
public String deleteRefreshTokenById(@PathVariable("id") Long id, ModelMap m, Principal p) {
OAuth2RefreshTokenEntity token = tokenService.getRefreshTokenById(id);
if (token == null) {
logger.error("refresh token not found: " + id);
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "The requested token with id " + id + " could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "The requested token with id " + id + " could not be found.");
return JsonErrorView.VIEWNAME;
} else if (!token.getAuthenticationHolder().getAuthentication().getName().equals(p.getName())) {
logger.error("refresh token " + id + " does not belong to principal " + p.getName());
m.put("code", HttpStatus.FORBIDDEN);
m.put("errorMessage", "You do not have permission to view this token");
m.put(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
m.put(JsonErrorView.ERROR_MESSAGE, "You do not have permission to view this token");
return JsonErrorView.VIEWNAME;
} else {
tokenService.revokeRefreshToken(token);
@ -238,4 +250,9 @@ public class TokenAPI {
}
}
@ExceptionHandler(OAuth2Exception.class)
public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
return providerExceptionHandler.translate(e);
}
}

View File

@ -22,14 +22,23 @@ package org.mitre.openid.connect.assertion;
import java.io.IOException;
import java.text.ParseException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.mockito.AdditionalMatchers;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.exceptions.BadClientCredentialsException;
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter;
import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.util.matcher.RequestMatcher;
import com.google.common.base.Strings;
import com.nimbusds.jwt.JWT;
@ -41,14 +50,34 @@ import com.nimbusds.jwt.JWTParser;
* @author jricher
*
*/
public class JWTBearerClientAssertionTokenEndpointFilter extends ClientCredentialsTokenEndpointFilter {
public class JWTBearerClientAssertionTokenEndpointFilter extends AbstractAuthenticationProcessingFilter {
public JWTBearerClientAssertionTokenEndpointFilter() {
super();
private AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
public JWTBearerClientAssertionTokenEndpointFilter(RequestMatcher additionalMatcher) {
super(new ClientAssertionRequestMatcher(additionalMatcher));
// If authentication fails the type is "Form"
((OAuth2AuthenticationEntryPoint) authenticationEntryPoint).setTypeName("Form");
}
public JWTBearerClientAssertionTokenEndpointFilter(String path) {
super(path);
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
setAuthenticationFailureHandler(new AuthenticationFailureHandler() {
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
if (exception instanceof BadCredentialsException) {
exception = new BadCredentialsException(exception.getMessage(), new BadClientCredentialsException());
}
authenticationEntryPoint.commence(request, response, exception);
}
});
setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() {
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
// no-op - just allow filter chain to continue to token endpoint
}
});
}
/**
@ -74,42 +103,38 @@ public class JWTBearerClientAssertionTokenEndpointFilter extends ClientCredentia
}
}
/**
* Check to see if the "client_assertion_type" and "client_assertion" parameters are present and contain the right values.
*/
@Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
// check for appropriate parameters
String assertionType = request.getParameter("client_assertion_type");
String assertion = request.getParameter("client_assertion");
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response,
FilterChain chain, Authentication authResult) throws IOException, ServletException {
super.successfulAuthentication(request, response, chain, authResult);
chain.doFilter(request, response);
}
if (Strings.isNullOrEmpty(assertionType) || Strings.isNullOrEmpty(assertion)) {
return false;
} else if (!assertionType.equals("urn:ietf:params:oauth:client-assertion-type:jwt-bearer")) {
return false;
private static class ClientAssertionRequestMatcher implements RequestMatcher {
private RequestMatcher additionalMatcher;
public ClientAssertionRequestMatcher(RequestMatcher additionalMatcher) {
this.additionalMatcher = additionalMatcher;
}
@Override
public boolean matches(HttpServletRequest request) {
// check for appropriate parameters
String assertionType = request.getParameter("client_assertion_type");
String assertion = request.getParameter("client_assertion");
// Can't call to superclass here b/c client creds would break for lack of client_id
// return super.requiresAuthentication(request, response);
String uri = request.getRequestURI();
int pathParamIndex = uri.indexOf(';');
if (pathParamIndex > 0) {
// strip everything after the first semi-colon
uri = uri.substring(0, pathParamIndex);
if (Strings.isNullOrEmpty(assertionType) || Strings.isNullOrEmpty(assertion)) {
return false;
} else if (!assertionType.equals("urn:ietf:params:oauth:client-assertion-type:jwt-bearer")) {
return false;
}
return additionalMatcher.matches(request);
}
if ("".equals(request.getContextPath())) {
return uri.endsWith(getFilterProcessesUrl());
}
return uri.endsWith(request.getContextPath() + getFilterProcessesUrl());
}
}

View File

@ -0,0 +1,167 @@
/*******************************************************************************
* Copyright 2015 The MITRE Corporation
* and the MIT Kerberos and Internet Trust Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package org.mitre.openid.connect.config;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.AbstractMessageSource;
import org.springframework.core.io.Resource;
import com.google.common.base.Splitter;
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
/**
* @author jricher
*
*/
public class JsonMessageSource extends AbstractMessageSource {
// Logger for this class
private static final Logger logger = LoggerFactory.getLogger(JsonMessageSource.class);
private Resource baseDirectory;
private Locale fallbackLocale = new Locale("en"); // US English is the fallback language
private Map<Locale, JsonObject> languageMaps = new HashMap<>();
@Override
protected MessageFormat resolveCode(String code, Locale locale) {
JsonObject lang = getLanguageMap(locale);
String value = getValue(code, lang);
if (value == null) {
// if we haven't found anything, try the default locale
lang = getLanguageMap(fallbackLocale);
value = getValue(code, lang);
}
if (value == null) {
value = code;
}
MessageFormat mf = new MessageFormat(value, locale);
return mf;
}
/**
* @param code
* @param locale
* @param lang
* @return
*/
private String getValue(String code, JsonObject lang) {
// if there's no language map, nothing to look up
if (lang == null) {
return null;
}
JsonElement e = lang;
Iterable<String> parts = Splitter.on('.').split(code);
Iterator<String> it = parts.iterator();
String value = null;
while (it.hasNext()) {
String p = it.next();
if (e.isJsonObject()) {
JsonObject o = e.getAsJsonObject();
if (o.has(p)) {
e = o.get(p); // found the next level
if (!it.hasNext()) {
// we've reached a leaf, grab it
if (e.isJsonPrimitive()) {
value = e.getAsString();
}
}
} else {
// didn't find it, stop processing
break;
}
} else {
// didn't find it, stop processing
break;
}
}
return value;
}
/**
* @param locale
* @return
*/
private JsonObject getLanguageMap(Locale locale) {
if (!languageMaps.containsKey(locale)) {
try {
String filename = locale.getLanguage() + File.separator + "messages.json";
Resource r = getBaseDirectory().createRelative(filename);
logger.info("No locale loaded, trying to load from " + r);
JsonParser parser = new JsonParser();
JsonObject obj = (JsonObject) parser.parse(new InputStreamReader(r.getInputStream(), "UTF-8"));
languageMaps.put(locale, obj);
} catch (JsonIOException | JsonSyntaxException | IOException e) {
logger.error("Unable to load locale", e);
}
}
return languageMaps.get(locale);
}
/**
* @return the baseDirectory
*/
public Resource getBaseDirectory() {
return baseDirectory;
}
/**
* @param baseDirectory the baseDirectory to set
*/
public void setBaseDirectory(Resource baseDirectory) {
this.baseDirectory = baseDirectory;
}
}

View File

@ -19,9 +19,8 @@
*/
package org.mitre.openid.connect.filter;
import static org.mitre.openid.connect.request.ConnectRequestParameters.*;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@ -35,6 +34,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.http.client.utils.URIBuilder;
import org.mitre.oauth2.model.ClientDetailsEntity;
import org.mitre.oauth2.service.ClientDetailsEntityService;
import org.mitre.openid.connect.web.AuthenticationTimeStamper;
@ -46,12 +46,20 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.endpoint.RedirectResolver;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import static org.mitre.openid.connect.request.ConnectRequestParameters.*;
import static org.mitre.openid.connect.request.ConnectRequestParameters.MAX_AGE;
import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT;
import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT_SEPARATOR;
import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT_LOGIN;
import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT_NONE;
/**
* @author jricher
*
@ -72,6 +80,9 @@ public class AuthorizationRequestFilter extends GenericFilterBean {
@Autowired
private ClientDetailsEntityService clientService;
@Autowired
private RedirectResolver redirectResolver;
/**
*
@ -114,7 +125,7 @@ public class AuthorizationRequestFilter extends GenericFilterBean {
if (authRequest.getExtensions().get(PROMPT) != null) {
// we have a "prompt" parameter
String prompt = (String)authRequest.getExtensions().get(PROMPT);
List<String> prompts = Splitter.on(" ").splitToList(Strings.nullToEmpty(prompt));
List<String> prompts = Splitter.on(PROMPT_SEPARATOR).splitToList(Strings.nullToEmpty(prompt));
if (prompts.contains(PROMPT_NONE)) {
logger.info("Client requested no prompt");
@ -127,7 +138,32 @@ public class AuthorizationRequestFilter extends GenericFilterBean {
chain.doFilter(req, res);
} else {
// user hasn't been logged in, we need to "return an error"
logger.info("User not logged in, no prompt requested, returning 403 from filter");
logger.info("User not logged in, no prompt requested, returning error from filter");
if (client != null && authRequest.getRedirectUri() != null) {
// if we've got a redirect URI then we'll send it
String url = redirectResolver.resolveRedirect(authRequest.getRedirectUri(), client);
try {
URIBuilder uriBuilder = new URIBuilder(url);
uriBuilder.addParameter(ERROR, LOGIN_REQUIRED);
if (!Strings.isNullOrEmpty(authRequest.getState())) {
uriBuilder.addParameter(STATE, authRequest.getState()); // copy the state parameter if one was given
}
response.sendRedirect(uriBuilder.toString());
return;
} catch (URISyntaxException e) {
logger.error("Can't build redirect URI for prompt=none, sending error instead", e);
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
return;
}
}
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
return;
}

View File

@ -0,0 +1,73 @@
/*******************************************************************************
* Copyright 2015 The MITRE Corporation
* and the MIT Kerberos and Internet Trust Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package org.mitre.openid.connect.filter;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import com.google.common.collect.ImmutableSet;
/**
* @author jricher
*
*/
public class MultiUrlRequestMatcher implements RequestMatcher {
private final Set<String> filterProcessesUrls;
public MultiUrlRequestMatcher(Set<String> filterProcessesUrls) {
for (String filterProcessesUrl : filterProcessesUrls) {
Assert.hasLength(filterProcessesUrl, "filterProcessesUrl must be specified");
Assert.isTrue(UrlUtils.isValidRedirectUrl(filterProcessesUrl), filterProcessesUrl + " isn't a valid redirect URL");
}
this.filterProcessesUrls = ImmutableSet.copyOf(filterProcessesUrls);
}
public boolean matches(HttpServletRequest request) {
String uri = request.getRequestURI();
int pathParamIndex = uri.indexOf(';');
if (pathParamIndex > 0) {
// strip everything after the first semi-colon
uri = uri.substring(0, pathParamIndex);
}
if ("".equals(request.getContextPath())) {
// if any one of the URLs match, return true
for (String filterProcessesUrl : filterProcessesUrls) {
if (uri.endsWith(filterProcessesUrl)) {
return true;
}
}
return false;
}
for (String filterProcessesUrl : filterProcessesUrls) {
if (uri.endsWith(request.getContextPath() + filterProcessesUrl)) {
return true;
}
}
return false;
}
}

View File

@ -16,8 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.repository.impl;
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

View File

@ -16,8 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.repository.impl;
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
import java.util.Collection;
import javax.persistence.EntityManager;
@ -29,6 +27,8 @@ import org.mitre.openid.connect.repository.ApprovedSiteRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
/**
* JPA ApprovedSite repository implementation
*
@ -44,8 +44,7 @@ public class JpaApprovedSiteRepository implements ApprovedSiteRepository {
@Override
@Transactional
public Collection<ApprovedSite> getAll() {
TypedQuery<ApprovedSite> query = manager.createNamedQuery(
"ApprovedSite.getAll", ApprovedSite.class);
TypedQuery<ApprovedSite> query = manager.createNamedQuery(ApprovedSite.QUERY_ALL, ApprovedSite.class);
return query.getResultList();
}
@ -76,9 +75,9 @@ public class JpaApprovedSiteRepository implements ApprovedSiteRepository {
@Override
public Collection<ApprovedSite> getByClientIdAndUserId(String clientId, String userId) {
TypedQuery<ApprovedSite> query = manager.createNamedQuery("ApprovedSite.getByClientIdAndUserId", ApprovedSite.class);
query.setParameter("userId", userId);
query.setParameter("clientId", clientId);
TypedQuery<ApprovedSite> query = manager.createNamedQuery(ApprovedSite.QUERY_BY_CLIENT_ID_AND_USER_ID, ApprovedSite.class);
query.setParameter(ApprovedSite.PARAM_USER_ID, userId);
query.setParameter(ApprovedSite.PARAM_CLIENT_ID, clientId);
return query.getResultList();
}
@ -86,8 +85,8 @@ public class JpaApprovedSiteRepository implements ApprovedSiteRepository {
@Override
@Transactional
public Collection<ApprovedSite> getByUserId(String userId) {
TypedQuery<ApprovedSite> query = manager.createNamedQuery("ApprovedSite.getByUserId", ApprovedSite.class);
query.setParameter("userId", userId);
TypedQuery<ApprovedSite> query = manager.createNamedQuery(ApprovedSite.QUERY_BY_USER_ID, ApprovedSite.class);
query.setParameter(ApprovedSite.PARAM_USER_ID, userId);
return query.getResultList();
@ -96,8 +95,8 @@ public class JpaApprovedSiteRepository implements ApprovedSiteRepository {
@Override
@Transactional
public Collection<ApprovedSite> getByClientId(String clientId) {
TypedQuery<ApprovedSite> query = manager.createNamedQuery("ApprovedSite.getByClientId", ApprovedSite.class);
query.setParameter("clientId", clientId);
TypedQuery<ApprovedSite> query = manager.createNamedQuery(ApprovedSite.QUERY_BY_CLIENT_ID, ApprovedSite.class);
query.setParameter(ApprovedSite.PARAM_CLIENT_ID, clientId);
return query.getResultList();
}

View File

@ -19,8 +19,6 @@
*/
package org.mitre.openid.connect.repository.impl;
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
import java.util.Collection;
import javax.persistence.EntityManager;
@ -32,6 +30,8 @@ import org.mitre.openid.connect.repository.BlacklistedSiteRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
/**
* @author jricher
*
@ -48,7 +48,7 @@ public class JpaBlacklistedSiteRepository implements BlacklistedSiteRepository {
@Override
@Transactional
public Collection<BlacklistedSite> getAll() {
TypedQuery<BlacklistedSite> query = manager.createNamedQuery("BlacklistedSite.getAll", BlacklistedSite.class);
TypedQuery<BlacklistedSite> query = manager.createNamedQuery(BlacklistedSite.QUERY_ALL, BlacklistedSite.class);
return query.getResultList();
}

View File

@ -19,9 +19,6 @@
*/
package org.mitre.openid.connect.repository.impl;
import static org.mitre.util.jpa.JpaUtil.getSingleResult;
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
@ -31,6 +28,9 @@ import org.mitre.openid.connect.repository.PairwiseIdentifierRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import static org.mitre.util.jpa.JpaUtil.getSingleResult;
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
/**
* @author jricher
*
@ -46,9 +46,9 @@ public class JpaPairwiseIdentifierRepository implements PairwiseIdentifierReposi
*/
@Override
public PairwiseIdentifier getBySectorIdentifier(String sub, String sectorIdentifierUri) {
TypedQuery<PairwiseIdentifier> query = manager.createNamedQuery("PairwiseIdentifier.getBySectorIdentifier", PairwiseIdentifier.class);
query.setParameter("sub", sub);
query.setParameter("sectorIdentifier", sectorIdentifierUri);
TypedQuery<PairwiseIdentifier> query = manager.createNamedQuery(PairwiseIdentifier.QUERY_BY_SECTOR_IDENTIFIER, PairwiseIdentifier.class);
query.setParameter(PairwiseIdentifier.PARAM_SUB, sub);
query.setParameter(PairwiseIdentifier.PARAM_SECTOR_IDENTIFIER, sectorIdentifierUri);
return getSingleResult(query.getResultList());
}

View File

@ -16,9 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.repository.impl;
import static org.mitre.util.jpa.JpaUtil.getSingleResult;
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;
@ -27,7 +24,8 @@ import org.mitre.openid.connect.model.DefaultUserInfo;
import org.mitre.openid.connect.model.UserInfo;
import org.mitre.openid.connect.repository.UserInfoRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import static org.mitre.util.jpa.JpaUtil.getSingleResult;
/**
* JPA UserInfo repository implementation
@ -46,8 +44,8 @@ public class JpaUserInfoRepository implements UserInfoRepository {
*/
@Override
public UserInfo getByUsername(String username) {
TypedQuery<DefaultUserInfo> query = manager.createNamedQuery("DefaultUserInfo.getByUsername", DefaultUserInfo.class);
query.setParameter("username", username);
TypedQuery<DefaultUserInfo> query = manager.createNamedQuery(DefaultUserInfo.QUERY_BY_USERNAME, DefaultUserInfo.class);
query.setParameter(DefaultUserInfo.PARAM_USERNAME, username);
return getSingleResult(query.getResultList());

View File

@ -16,8 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.repository.impl;
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
import java.util.Collection;
import javax.persistence.EntityManager;
@ -30,6 +28,8 @@ import org.mitre.util.jpa.JpaUtil;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import static org.mitre.util.jpa.JpaUtil.saveOrUpdate;
/**
* JPA WhitelistedSite repository implementation
*
@ -45,7 +45,7 @@ public class JpaWhitelistedSiteRepository implements WhitelistedSiteRepository {
@Override
@Transactional
public Collection<WhitelistedSite> getAll() {
TypedQuery<WhitelistedSite> query = manager.createNamedQuery("WhitelistedSite.getAll", WhitelistedSite.class);
TypedQuery<WhitelistedSite> query = manager.createNamedQuery(WhitelistedSite.QUERY_ALL, WhitelistedSite.class);
return query.getResultList();
}
@ -85,16 +85,16 @@ public class JpaWhitelistedSiteRepository implements WhitelistedSiteRepository {
@Override
@Transactional
public WhitelistedSite getByClientId(String clientId) {
TypedQuery<WhitelistedSite> query = manager.createNamedQuery("WhitelistedSite.getByClientId", WhitelistedSite.class);
query.setParameter("clientId", clientId);
TypedQuery<WhitelistedSite> query = manager.createNamedQuery(WhitelistedSite.QUERY_BY_CLIENT_ID, WhitelistedSite.class);
query.setParameter(WhitelistedSite.PARAM_CLIENT_ID, clientId);
return JpaUtil.getSingleResult(query.getResultList());
}
@Override
@Transactional
public Collection<WhitelistedSite> getByCreator(String creatorId) {
TypedQuery<WhitelistedSite> query = manager.createNamedQuery("WhitelistedSite.getByCreaterUserId", WhitelistedSite.class);
query.setParameter("userId", creatorId);
TypedQuery<WhitelistedSite> query = manager.createNamedQuery(WhitelistedSite.QUERY_BY_CREATOR, WhitelistedSite.class);
query.setParameter(WhitelistedSite.PARAM_USER_ID, creatorId);
return query.getResultList();
}

View File

@ -16,8 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.request;
import static org.mitre.openid.connect.request.ConnectRequestParameters.*;
import java.text.ParseException;
import java.util.Collections;
import java.util.Map;
@ -55,6 +53,19 @@ import com.nimbusds.jwt.PlainJWT;
import com.nimbusds.jwt.ReadOnlyJWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import static org.mitre.openid.connect.request.ConnectRequestParameters.CLAIMS;
import static org.mitre.openid.connect.request.ConnectRequestParameters.CLIENT_ID;
import static org.mitre.openid.connect.request.ConnectRequestParameters.CSRF;
import static org.mitre.openid.connect.request.ConnectRequestParameters.DISPLAY;
import static org.mitre.openid.connect.request.ConnectRequestParameters.LOGIN_HINT;
import static org.mitre.openid.connect.request.ConnectRequestParameters.MAX_AGE;
import static org.mitre.openid.connect.request.ConnectRequestParameters.NONCE;
import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT;
import static org.mitre.openid.connect.request.ConnectRequestParameters.REDIRECT_URI;
import static org.mitre.openid.connect.request.ConnectRequestParameters.REQUEST;
import static org.mitre.openid.connect.request.ConnectRequestParameters.RESPONSE_TYPE;
import static org.mitre.openid.connect.request.ConnectRequestParameters.STATE;
@Component("connectOAuth2RequestFactory")
public class ConnectOAuth2RequestFactory extends DefaultOAuth2RequestFactory {

View File

@ -24,6 +24,8 @@ public interface ConnectRequestParameters {
public String CSRF = "csrf";
public String APPROVED_SITE = "approved_site";
// responses
public String ERROR = "error";
public String LOGIN_REQUIRED = "login_required";
}

View File

@ -16,10 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.service.impl;
import static org.mitre.util.JsonUtils.base64UrlDecodeObject;
import static org.mitre.util.JsonUtils.readMap;
import static org.mitre.util.JsonUtils.readSet;
import java.io.IOException;
import java.text.ParseException;
import java.util.Collection;
@ -66,6 +62,10 @@ import com.google.common.collect.Sets;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import static org.mitre.util.JsonUtils.base64UrlDecodeObject;
import static org.mitre.util.JsonUtils.readMap;
import static org.mitre.util.JsonUtils.readSet;
/**
*
* Data service to import MITREid 1.0 configuration.

View File

@ -16,10 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.service.impl;
import static org.mitre.util.JsonUtils.base64UrlDecodeObject;
import static org.mitre.util.JsonUtils.readMap;
import static org.mitre.util.JsonUtils.readSet;
import java.io.IOException;
import java.io.Serializable;
import java.text.ParseException;
@ -69,6 +65,10 @@ import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import static org.mitre.util.JsonUtils.base64UrlDecodeObject;
import static org.mitre.util.JsonUtils.readMap;
import static org.mitre.util.JsonUtils.readSet;
/**
*
* Data service to import MITREid 1.1 configuration.

View File

@ -16,12 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.service.impl;
import static org.mitre.util.JsonUtils.base64UrlDecodeObject;
import static org.mitre.util.JsonUtils.base64UrlEncodeObject;
import static org.mitre.util.JsonUtils.readMap;
import static org.mitre.util.JsonUtils.readSet;
import static org.mitre.util.JsonUtils.writeNullSafeArray;
import java.io.IOException;
import java.io.Serializable;
import java.text.ParseException;
@ -71,6 +65,12 @@ import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import static org.mitre.util.JsonUtils.base64UrlDecodeObject;
import static org.mitre.util.JsonUtils.base64UrlEncodeObject;
import static org.mitre.util.JsonUtils.readMap;
import static org.mitre.util.JsonUtils.readSet;
import static org.mitre.util.JsonUtils.writeNullSafeArray;
/**
*
* Data service to import and export MITREid 1.2 configuration.

View File

@ -16,8 +16,6 @@
*******************************************************************************/
package org.mitre.openid.connect.token;
import static org.mitre.openid.connect.request.ConnectRequestParameters.*;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
@ -49,6 +47,11 @@ import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import static org.mitre.openid.connect.request.ConnectRequestParameters.APPROVED_SITE;
import static org.mitre.openid.connect.request.ConnectRequestParameters.CSRF;
import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT;
import static org.mitre.openid.connect.request.ConnectRequestParameters.PROMPT_SEPARATOR;
/**
* Custom User Approval Handler implementation which uses a concept of a whitelist,
* blacklist, and greylist.

View File

@ -33,6 +33,7 @@ import org.mitre.jose.JWSAlgorithmEmbed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.view.AbstractView;
import com.google.gson.ExclusionStrategy;
@ -105,10 +106,10 @@ public abstract class AbstractClientEntityView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
response.setContentType("application/json");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
HttpStatus code = (HttpStatus) model.get("code");
HttpStatus code = (HttpStatus) model.get(HttpCodeView.CODE);
if (code == null) {
code = HttpStatus.OK; // default to 200
}
@ -118,7 +119,7 @@ public abstract class AbstractClientEntityView extends AbstractView {
try {
Writer out = response.getWriter();
Object obj = model.get("entity");
Object obj = model.get(JsonEntityView.ENTITY);
gson.toJson(obj, out);
} catch (IOException e) {

View File

@ -31,6 +31,7 @@ import org.mitre.openid.connect.ClientDetailsEntityJsonProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.view.AbstractView;
@ -65,13 +66,13 @@ public class ClientInformationResponseView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
response.setContentType("application/json");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
RegisteredClient c = (RegisteredClient) model.get("client");
//OAuth2AccessTokenEntity token = (OAuth2AccessTokenEntity) model.get("token");
//String uri = (String)model.get("uri"); //request.getRequestURL() + "/" + c.getClientId();
HttpStatus code = (HttpStatus) model.get("code");
HttpStatus code = (HttpStatus) model.get(HttpCodeView.CODE);
if (code == null) {
code = HttpStatus.OK;
}

View File

@ -37,10 +37,12 @@ import org.springframework.web.servlet.view.AbstractView;
public class HttpCodeView extends AbstractView {
public static final String VIEWNAME = "httpCodeView";
public static final String CODE = "code";
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
HttpStatus code = (HttpStatus) model.get("code");
HttpStatus code = (HttpStatus) model.get(CODE);
if (code == null) {
code = HttpStatus.OK; // default to 200
}

View File

@ -32,6 +32,7 @@ import org.mitre.openid.connect.model.WhitelistedSite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.web.servlet.view.AbstractView;
@ -98,10 +99,10 @@ public class JsonApprovedSiteView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
response.setContentType("application/json");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
HttpStatus code = (HttpStatus) model.get("code");
HttpStatus code = (HttpStatus) model.get(HttpCodeView.CODE);
if (code == null) {
code = HttpStatus.OK; // default to 200
}
@ -111,7 +112,7 @@ public class JsonApprovedSiteView extends AbstractView {
try {
Writer out = response.getWriter();
Object obj = model.get("entity");
Object obj = model.get(JsonEntityView.ENTITY);
gson.toJson(obj, out);
} catch (IOException e) {

View File

@ -29,6 +29,7 @@ import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.web.servlet.view.AbstractView;
@ -45,6 +46,8 @@ import com.google.gson.GsonBuilder;
@Component(JsonEntityView.VIEWNAME)
public class JsonEntityView extends AbstractView {
public static final String ENTITY = "entity";
/**
* Logger for this class
*/
@ -78,10 +81,10 @@ public class JsonEntityView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
response.setContentType("application/json");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
HttpStatus code = (HttpStatus) model.get("code");
HttpStatus code = (HttpStatus) model.get(HttpCodeView.CODE);
if (code == null) {
code = HttpStatus.OK; // default to 200
}
@ -91,7 +94,7 @@ public class JsonEntityView extends AbstractView {
try {
Writer out = response.getWriter();
Object obj = model.get("entity");
Object obj = model.get(ENTITY);
gson.toJson(obj, out);
} catch (IOException e) {

View File

@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.web.servlet.view.AbstractView;
@ -44,6 +45,16 @@ import com.google.gson.JsonObject;
@Component(JsonErrorView.VIEWNAME)
public class JsonErrorView extends AbstractView {
/**
*
*/
public static final String ERROR_MESSAGE = "errorMessage";
/**
*
*/
public static final String ERROR = "error";
/**
* Logger for this class
*/
@ -77,12 +88,12 @@ public class JsonErrorView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
response.setContentType("application/json");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
HttpStatus code = (HttpStatus) model.get("code");
HttpStatus code = (HttpStatus) model.get(HttpCodeView.CODE);
if (code == null) {
code = HttpStatus.OK; // default to 200
code = HttpStatus.INTERNAL_SERVER_ERROR; // default to 500
}
response.setStatus(code.value());
@ -91,11 +102,11 @@ public class JsonErrorView extends AbstractView {
Writer out = response.getWriter();
String errorTitle = (String) model.get("error");
String errorTitle = (String) model.get(ERROR);
if (Strings.isNullOrEmpty(errorTitle)) {
errorTitle = "Error";
errorTitle = "mitreid_error";
}
String errorMessage = (String) model.get("errorMessage");
String errorMessage = (String) model.get(ERROR_MESSAGE);
JsonObject obj = new JsonObject();
obj.addProperty("error", errorTitle);
obj.addProperty("error_description", errorMessage);

View File

@ -39,6 +39,7 @@ import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.google.common.base.Strings;
@ -59,6 +60,8 @@ import com.nimbusds.jwt.SignedJWT;
@Component(UserInfoJWTView.VIEWNAME)
public class UserInfoJWTView extends UserInfoView {
public static final String CLIENT = "client";
/**
* Logger for this class
*/
@ -66,6 +69,10 @@ public class UserInfoJWTView extends UserInfoView {
public static final String VIEWNAME = "userInfoJwtView";
public static final String JOSE_MEDIA_TYPE_VALUE = "application/jwt";
public static final MediaType JOSE_MEDIA_TYPE = new MediaType("application", "jwt");
@Autowired
private JWTSigningAndValidationService jwtService;
@ -83,13 +90,13 @@ public class UserInfoJWTView extends UserInfoView {
HttpServletRequest request, HttpServletResponse response) {
try {
ClientDetailsEntity client = (ClientDetailsEntity)model.get("client");
ClientDetailsEntity client = (ClientDetailsEntity)model.get(CLIENT);
// use the parser to import the user claims into the object
StringWriter writer = new StringWriter();
gson.toJson(json, writer);
response.setContentType("application/jwt");
response.setContentType(JOSE_MEDIA_TYPE_VALUE);
JWTClaimsSet claims = JWTClaimsSet.parse(writer.toString());

View File

@ -31,6 +31,7 @@ import org.mitre.openid.connect.service.ScopeClaimTranslationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.validation.BeanPropertyBindingResult;
import org.springframework.web.servlet.view.AbstractView;
@ -46,9 +47,14 @@ import com.google.gson.JsonParser;
@Component(UserInfoView.VIEWNAME)
public class UserInfoView extends AbstractView {
private static JsonParser jsonParser = new JsonParser();
public static final String REQUESTED_CLAIMS = "requestedClaims";
public static final String AUTHORIZED_CLAIMS = "authorizedClaims";
public static final String SCOPE = "scope";
public static final String USER_INFO = "userInfo";
public static final String VIEWNAME = "userInfoView";
private static JsonParser jsonParser = new JsonParser();
/**
* Logger for this class
@ -88,20 +94,20 @@ public class UserInfoView extends AbstractView {
@Override
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
UserInfo userInfo = (UserInfo) model.get("userInfo");
UserInfo userInfo = (UserInfo) model.get(USER_INFO);
Set<String> scope = (Set<String>) model.get("scope");
Set<String> scope = (Set<String>) model.get(SCOPE);
response.setContentType("application/json");
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
JsonObject authorizedClaims = null;
JsonObject requestedClaims = null;
if (model.get("authorizedClaims") != null) {
authorizedClaims = jsonParser.parse((String) model.get("authorizedClaims")).getAsJsonObject();
if (model.get(AUTHORIZED_CLAIMS) != null) {
authorizedClaims = jsonParser.parse((String) model.get(AUTHORIZED_CLAIMS)).getAsJsonObject();
}
if (model.get("requestedClaims") != null) {
requestedClaims = jsonParser.parse((String) model.get("requestedClaims")).getAsJsonObject();
if (model.get(REQUESTED_CLAIMS) != null) {
requestedClaims = jsonParser.parse((String) model.get(REQUESTED_CLAIMS)).getAsJsonObject();
}
JsonObject json = toJsonFromRequestObj(userInfo, scope, authorizedClaims, requestedClaims);

View File

@ -27,14 +27,20 @@ import org.mitre.openid.connect.model.ApprovedSite;
import org.mitre.openid.connect.service.ApprovedSiteService;
import org.mitre.openid.connect.view.HttpCodeView;
import org.mitre.openid.connect.view.JsonApprovedSiteView;
import org.mitre.openid.connect.view.JsonEntityView;
import org.mitre.openid.connect.view.JsonErrorView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@ -44,15 +50,20 @@ import org.springframework.web.bind.annotation.RequestMethod;
*
*/
@Controller
@RequestMapping("/api/approved")
@RequestMapping("/" + ApprovedSiteAPI.URL)
@PreAuthorize("hasRole('ROLE_USER')")
public class ApprovedSiteAPI {
public static final String URL = RootController.API_URL + "/approved";
@Autowired
private ApprovedSiteService approvedSiteService;
@Autowired
OAuth2TokenEntityService tokenServices;
private OAuth2TokenEntityService tokenServices;
@Autowired
private WebResponseExceptionTranslator providerExceptionHandler;
/**
* Logger for this class
@ -64,12 +75,12 @@ public class ApprovedSiteAPI {
* @param m
* @return
*/
@RequestMapping(method = RequestMethod.GET, produces = "application/json")
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getAllApprovedSites(ModelMap m, Principal p) {
Collection<ApprovedSite> all = approvedSiteService.getByUserId(p.getName());
m.put("entity", all);
m.put(JsonEntityView.ENTITY, all);
return JsonApprovedSiteView.VIEWNAME;
}
@ -84,17 +95,17 @@ public class ApprovedSiteAPI {
if (approvedSite == null) {
logger.error("deleteApprovedSite failed; no approved site found for id: " + id);
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "Could not delete approved site. The requested approved site with id: " + id + " could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "Could not delete approved site. The requested approved site with id: " + id + " could not be found.");
return JsonErrorView.VIEWNAME;
} else if (!approvedSite.getUserId().equals(p.getName())) {
logger.error("deleteApprovedSite failed; principal "
+ p.getName() + " does not own approved site" + id);
m.put("code", HttpStatus.FORBIDDEN);
m.put("errorMessage", "You do not have permission to delete this approved site. The approved site decision will not be deleted.");
m.put(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
m.put(JsonErrorView.ERROR_MESSAGE, "You do not have permission to delete this approved site. The approved site decision will not be deleted.");
return JsonErrorView.VIEWNAME;
} else {
m.put("code", HttpStatus.OK);
m.put(HttpCodeView.CODE, HttpStatus.OK);
approvedSiteService.remove(approvedSite);
}
@ -104,24 +115,30 @@ public class ApprovedSiteAPI {
/**
* Get a single approved site
*/
@RequestMapping(value="/{id}", method = RequestMethod.GET, produces = "application/json")
@RequestMapping(value="/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getApprovedSite(@PathVariable("id") Long id, ModelMap m, Principal p) {
ApprovedSite approvedSite = approvedSiteService.getById(id);
if (approvedSite == null) {
logger.error("getApprovedSite failed; no approved site found for id: " + id);
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "The requested approved site with id: " + id + " could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "The requested approved site with id: " + id + " could not be found.");
return JsonErrorView.VIEWNAME;
} else if (!approvedSite.getUserId().equals(p.getName())) {
logger.error("getApprovedSite failed; principal "
+ p.getName() + " does not own approved site" + id);
m.put("code", HttpStatus.FORBIDDEN);
m.put("errorMessage", "You do not have permission to view this approved site.");
m.put(HttpCodeView.CODE, HttpStatus.FORBIDDEN);
m.put(JsonErrorView.ERROR_MESSAGE, "You do not have permission to view this approved site.");
return JsonErrorView.VIEWNAME;
} else {
m.put("entity", approvedSite);
m.put(JsonEntityView.ENTITY, approvedSite);
return JsonApprovedSiteView.VIEWNAME;
}
}
@ExceptionHandler(OAuth2Exception.class)
public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
return providerExceptionHandler.translate(e);
}
}

View File

@ -31,9 +31,14 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@ -49,10 +54,12 @@ import com.google.gson.JsonSyntaxException;
*
*/
@Controller
@RequestMapping("/api/blacklist")
@RequestMapping("/" + BlacklistAPI.URL)
@PreAuthorize("hasRole('ROLE_ADMIN')")
public class BlacklistAPI {
public static final String URL = RootController.API_URL + "/blacklist";
@Autowired
private BlacklistedSiteService blacklistService;
@ -61,6 +68,9 @@ public class BlacklistAPI {
*/
private static final Logger logger = LoggerFactory.getLogger(BlacklistAPI.class);
@Autowired
private WebResponseExceptionTranslator providerExceptionHandler;
private Gson gson = new Gson();
private JsonParser parser = new JsonParser();
@ -69,12 +79,12 @@ public class BlacklistAPI {
* @param m
* @return
*/
@RequestMapping(method = RequestMethod.GET, produces = "application/json")
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getAllBlacklistedSites(ModelMap m) {
Collection<BlacklistedSite> all = blacklistService.getAll();
m.put("entity", all);
m.put(JsonEntityView.ENTITY, all);
return JsonEntityView.VIEWNAME;
}
@ -86,7 +96,7 @@ public class BlacklistAPI {
* @param p
* @return
*/
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public String addNewBlacklistedSite(@RequestBody String jsonString, ModelMap m, Principal p) {
JsonObject json;
@ -98,18 +108,18 @@ public class BlacklistAPI {
json = parser.parse(jsonString).getAsJsonObject();
blacklist = gson.fromJson(json, BlacklistedSite.class);
BlacklistedSite newBlacklist = blacklistService.saveNew(blacklist);
m.put("entity", newBlacklist);
m.put(JsonEntityView.ENTITY, newBlacklist);
}
catch (JsonSyntaxException e) {
logger.error("addNewBlacklistedSite failed due to JsonSyntaxException: ", e);
m.put("code", HttpStatus.BAD_REQUEST);
m.put("errorMessage", "Could not save new blacklisted site. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
m.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.put(JsonErrorView.ERROR_MESSAGE, "Could not save new blacklisted site. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
return JsonErrorView.VIEWNAME;
} catch (IllegalStateException e) {
logger.error("addNewBlacklistedSite failed due to IllegalStateException", e);
m.put("code", HttpStatus.BAD_REQUEST);
m.put("errorMessage", "Could not save new blacklisted site. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
m.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.put(JsonErrorView.ERROR_MESSAGE, "Could not save new blacklisted site. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
return JsonErrorView.VIEWNAME;
}
@ -120,7 +130,7 @@ public class BlacklistAPI {
/**
* Update an existing blacklisted site
*/
@RequestMapping(value="/{id}", method = RequestMethod.PUT, consumes = "application/json", produces = "application/json")
@RequestMapping(value="/{id}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public String updateBlacklistedSite(@PathVariable("id") Long id, @RequestBody String jsonString, ModelMap m, Principal p) {
JsonObject json;
@ -135,13 +145,13 @@ public class BlacklistAPI {
}
catch (JsonSyntaxException e) {
logger.error("updateBlacklistedSite failed due to JsonSyntaxException", e);
m.put("code", HttpStatus.BAD_REQUEST);
m.put("errorMessage", "Could not update blacklisted site. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
m.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.put(JsonErrorView.ERROR_MESSAGE, "Could not update blacklisted site. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
return JsonErrorView.VIEWNAME;
} catch (IllegalStateException e) {
logger.error("updateBlacklistedSite failed due to IllegalStateException", e);
m.put("code", HttpStatus.BAD_REQUEST);
m.put("errorMessage", "Could not update blacklisted site. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
m.put(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.put(JsonErrorView.ERROR_MESSAGE, "Could not update blacklisted site. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
return JsonErrorView.VIEWNAME;
}
@ -150,14 +160,14 @@ public class BlacklistAPI {
if (oldBlacklist == null) {
logger.error("updateBlacklistedSite failed; blacklist with id " + id + " could not be found");
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "Could not update blacklisted site. The requested blacklist with id " + id + "could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "Could not update blacklisted site. The requested blacklist with id " + id + "could not be found.");
return JsonErrorView.VIEWNAME;
} else {
BlacklistedSite newBlacklist = blacklistService.update(oldBlacklist, blacklist);
m.put("entity", newBlacklist);
m.put(JsonEntityView.ENTITY, newBlacklist);
return JsonEntityView.VIEWNAME;
}
@ -173,10 +183,10 @@ public class BlacklistAPI {
if (blacklist == null) {
logger.error("deleteBlacklistedSite failed; blacklist with id " + id + " could not be found");
m.put("errorMessage", "Could not delete bladklist. The requested bladklist with id " + id + " could not be found.");
m.put(JsonErrorView.ERROR_MESSAGE, "Could not delete bladklist. The requested bladklist with id " + id + " could not be found.");
return JsonErrorView.VIEWNAME;
} else {
m.put("code", HttpStatus.OK);
m.put(HttpCodeView.CODE, HttpStatus.OK);
blacklistService.remove(blacklist);
}
@ -186,20 +196,26 @@ public class BlacklistAPI {
/**
* Get a single blacklisted site
*/
@RequestMapping(value="/{id}", method = RequestMethod.GET, produces = "application/json")
@RequestMapping(value="/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String getBlacklistedSite(@PathVariable("id") Long id, ModelMap m) {
BlacklistedSite blacklist = blacklistService.getById(id);
if (blacklist == null) {
logger.error("getBlacklistedSite failed; blacklist with id " + id + " could not be found");
m.put("code", HttpStatus.NOT_FOUND);
m.put("errorMessage", "Could not delete bladklist. The requested bladklist with id " + id + " could not be found.");
m.put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.put(JsonErrorView.ERROR_MESSAGE, "Could not delete bladklist. The requested bladklist with id " + id + " could not be found.");
return JsonErrorView.VIEWNAME;
} else {
m.put("entity", blacklist);
m.put(JsonEntityView.ENTITY, blacklist);
return JsonEntityView.VIEWNAME;
}
}
@ExceptionHandler(OAuth2Exception.class)
public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
return providerExceptionHandler.translate(e);
}
}

View File

@ -30,15 +30,22 @@ import org.mitre.openid.connect.service.UserInfoService;
import org.mitre.openid.connect.view.ClientEntityViewForAdmins;
import org.mitre.openid.connect.view.ClientEntityViewForUsers;
import org.mitre.openid.connect.view.HttpCodeView;
import org.mitre.openid.connect.view.JsonEntityView;
import org.mitre.openid.connect.view.JsonErrorView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@ -61,16 +68,21 @@ import com.google.gson.JsonSyntaxException;
*/
@Controller
@RequestMapping("/api/clients")
@RequestMapping("/" + ClientAPI.URL)
@PreAuthorize("hasRole('ROLE_USER')")
public class ClientAPI {
public static final String URL = RootController.API_URL + "/clients";
@Autowired
private ClientDetailsEntityService clientService;
@Autowired
private UserInfoService userInfoService;
@Autowired
private WebResponseExceptionTranslator providerExceptionHandler;
private JsonParser parser = new JsonParser();
private Gson gson = new GsonBuilder()
@ -118,11 +130,11 @@ public class ClientAPI {
* @param modelAndView
* @return
*/
@RequestMapping(method = RequestMethod.GET, produces = "application/json")
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String apiGetAllClients(Model model, Authentication auth) {
Collection<ClientDetailsEntity> clients = clientService.getAllClients();
model.addAttribute("entity", clients);
model.addAttribute(JsonEntityView.ENTITY, clients);
if (AuthenticationUtilities.isAdmin(auth)) {
return ClientEntityViewForAdmins.VIEWNAME;
@ -139,7 +151,7 @@ public class ClientAPI {
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public String apiAddClient(@RequestBody String jsonString, Model m, Authentication auth) {
JsonObject json = null;
@ -151,13 +163,13 @@ public class ClientAPI {
}
catch (JsonSyntaxException e) {
logger.error("apiAddClient failed due to JsonSyntaxException", e);
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Could not save new client. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Could not save new client. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
return JsonErrorView.VIEWNAME;
} catch (IllegalStateException e) {
logger.error("apiAddClient failed due to IllegalStateException", e);
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Could not save new client. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Could not save new client. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
return JsonErrorView.VIEWNAME;
}
@ -186,8 +198,8 @@ public class ClientAPI {
if (Strings.isNullOrEmpty(client.getJwksUri())) {
logger.error("tried to create client with private key auth but no private key");
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Can not create a client with private key authentication without registering a key via the JWS Set URI.");
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Can not create a client with private key authentication without registering a key via the JWS Set URI.");
return JsonErrorView.VIEWNAME;
}
@ -197,8 +209,8 @@ public class ClientAPI {
} else {
logger.error("unknown auth method");
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Unknown auth method requested");
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Unknown auth method requested");
return JsonErrorView.VIEWNAME;
@ -207,7 +219,7 @@ public class ClientAPI {
client.setDynamicallyRegistered(false);
ClientDetailsEntity newClient = clientService.saveNewClient(client);
m.addAttribute("entity", newClient);
m.addAttribute(JsonEntityView.ENTITY, newClient);
if (AuthenticationUtilities.isAdmin(auth)) {
return ClientEntityViewForAdmins.VIEWNAME;
@ -225,7 +237,7 @@ public class ClientAPI {
* @return
*/
@PreAuthorize("hasRole('ROLE_ADMIN')")
@RequestMapping(value="/{id}", method = RequestMethod.PUT, consumes = "application/json", produces = "application/json")
@RequestMapping(value="/{id}", method = RequestMethod.PUT, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public String apiUpdateClient(@PathVariable("id") Long id, @RequestBody String jsonString, Model m, Authentication auth) {
JsonObject json = null;
@ -238,13 +250,13 @@ public class ClientAPI {
}
catch (JsonSyntaxException e) {
logger.error("apiUpdateClient failed due to JsonSyntaxException", e);
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Could not update client. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Could not update client. The server encountered a JSON syntax exception. Contact a system administrator for assistance.");
return JsonErrorView.VIEWNAME;
} catch (IllegalStateException e) {
logger.error("apiUpdateClient failed due to IllegalStateException", e);
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Could not update client. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Could not update client. The server encountered an IllegalStateException. Refresh and try again - if the problem persists, contact a system administrator for assistance.");
return JsonErrorView.VIEWNAME;
}
@ -252,8 +264,8 @@ public class ClientAPI {
if (oldClient == null) {
logger.error("apiUpdateClient failed; client with id " + id + " could not be found.");
m.addAttribute("code", HttpStatus.NOT_FOUND);
m.addAttribute("errorMessage", "Could not update client. The requested client with id " + id + "could not be found.");
m.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Could not update client. The requested client with id " + id + "could not be found.");
return JsonErrorView.VIEWNAME;
}
@ -282,8 +294,8 @@ public class ClientAPI {
if (Strings.isNullOrEmpty(client.getJwksUri())) {
logger.error("tried to create client with private key auth but no private key");
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Can not create a client with private key authentication without registering a key via the JWS Set URI.");
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Can not create a client with private key authentication without registering a key via the JWS Set URI.");
return JsonErrorView.VIEWNAME;
}
@ -293,15 +305,15 @@ public class ClientAPI {
} else {
logger.error("unknown auth method");
m.addAttribute("code", HttpStatus.BAD_REQUEST);
m.addAttribute("errorMessage", "Unknown auth method requested");
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST);
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Unknown auth method requested");
return JsonErrorView.VIEWNAME;
}
ClientDetailsEntity newClient = clientService.updateClient(oldClient, client);
m.addAttribute("entity", newClient);
m.addAttribute(JsonEntityView.ENTITY, newClient);
if (AuthenticationUtilities.isAdmin(auth)) {
return ClientEntityViewForAdmins.VIEWNAME;
@ -324,11 +336,11 @@ public class ClientAPI {
if (client == null) {
logger.error("apiDeleteClient failed; client with id " + id + " could not be found.");
modelAndView.getModelMap().put("code", HttpStatus.NOT_FOUND);
modelAndView.getModelMap().put("errorMessage", "Could not delete client. The requested client with id " + id + "could not be found.");
modelAndView.getModelMap().put(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
modelAndView.getModelMap().put(JsonErrorView.ERROR_MESSAGE, "Could not delete client. The requested client with id " + id + "could not be found.");
return JsonErrorView.VIEWNAME;
} else {
modelAndView.getModelMap().put("code", HttpStatus.OK);
modelAndView.getModelMap().put(HttpCodeView.CODE, HttpStatus.OK);
clientService.deleteClient(client);
}
@ -342,19 +354,19 @@ public class ClientAPI {
* @param modelAndView
* @return
*/
@RequestMapping(value="/{id}", method=RequestMethod.GET, produces = "application/json")
@RequestMapping(value="/{id}", method=RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String apiShowClient(@PathVariable("id") Long id, Model model, Authentication auth) {
ClientDetailsEntity client = clientService.getClientById(id);
if (client == null) {
logger.error("apiShowClient failed; client with id " + id + " could not be found.");
model.addAttribute("code", HttpStatus.NOT_FOUND);
model.addAttribute("errorMessage", "The requested client with id " + id + " could not be found.");
model.addAttribute(HttpCodeView.CODE, HttpStatus.NOT_FOUND);
model.addAttribute(JsonErrorView.ERROR_MESSAGE, "The requested client with id " + id + " could not be found.");
return JsonErrorView.VIEWNAME;
}
model.addAttribute("entity", client);
model.addAttribute(JsonEntityView.ENTITY, client);
if (AuthenticationUtilities.isAdmin(auth)) {
return ClientEntityViewForAdmins.VIEWNAME;
@ -362,4 +374,10 @@ public class ClientAPI {
return ClientEntityViewForUsers.VIEWNAME;
}
}
@ExceptionHandler(OAuth2Exception.class)
public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
return providerExceptionHandler.translate(e);
}
}

View File

@ -31,9 +31,14 @@ import org.mitre.openid.connect.service.impl.MITREidDataService_1_1;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@ -49,10 +54,12 @@ import com.google.gson.stream.JsonWriter;
*
*/
@Controller
@RequestMapping("/api/data")
@RequestMapping("/" + DataAPI.URL)
@PreAuthorize("hasRole('ROLE_ADMIN')") // you need to be an admin to even think about this -- this is a potentially dangerous API!!
public class DataAPI {
public static final String URL = RootController.API_URL + "/data";
/**
* Logger for this class
*/
@ -72,7 +79,10 @@ public class DataAPI {
@Autowired
private MITREidDataService_1_1 dataService_1_2;
@RequestMapping(method = RequestMethod.POST, consumes = "application/json")
@Autowired
private WebResponseExceptionTranslator providerExceptionHandler;
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
public String importData(Reader in, Model m) throws IOException {
JsonReader reader = new JsonReader(in);
@ -107,10 +117,10 @@ public class DataAPI {
return "httpCodeView";
}
@RequestMapping(method = RequestMethod.GET, produces = "application/json")
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public void exportData(HttpServletResponse resp, Principal prin) throws IOException {
resp.setContentType("application/json");
resp.setContentType(MediaType.APPLICATION_JSON_VALUE);
// this writer puts things out onto the wire
JsonWriter writer = new JsonWriter(resp.getWriter());
@ -140,5 +150,10 @@ public class DataAPI {
}
}
@ExceptionHandler(OAuth2Exception.class)
public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
return providerExceptionHandler.translate(e);
}
}

View File

@ -44,11 +44,16 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@ -61,9 +66,11 @@ import com.google.common.collect.Sets;
import com.google.gson.JsonSyntaxException;
@Controller
@RequestMapping(value = "register")
@RequestMapping(value = DynamicClientRegistrationEndpoint.URL)
public class DynamicClientRegistrationEndpoint {
public static final String URL = "register";
@Autowired
private ClientDetailsEntityService clientService;
@ -85,6 +92,9 @@ public class DynamicClientRegistrationEndpoint {
@Autowired
private OIDCTokenService connectTokenService;
@Autowired
private WebResponseExceptionTranslator providerExceptionHandler;
/**
* Logger for this class
*/
@ -97,7 +107,7 @@ public class DynamicClientRegistrationEndpoint {
* @param p
* @return
*/
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json")
@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public String registerNewClient(@RequestBody String jsonString, Model m) {
ClientDetailsEntity newClient = null;
@ -107,7 +117,7 @@ public class DynamicClientRegistrationEndpoint {
// bad parse
// didn't parse, this is a bad request
logger.error("registerNewClient failed; submitted JSON is malformed");
m.addAttribute("code", HttpStatus.BAD_REQUEST); // http 400
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); // http 400
return HttpCodeView.VIEWNAME;
}
@ -131,9 +141,9 @@ public class DynamicClientRegistrationEndpoint {
newClient = validateAuth(newClient);
} catch (ValidationException ve) {
// validation failed, return an error
m.addAttribute("error", ve.getError());
m.addAttribute("errorMessage", ve.getErrorDescription());
m.addAttribute("code", ve.getStatus());
m.addAttribute(JsonErrorView.ERROR, ve.getError());
m.addAttribute(JsonErrorView.ERROR_MESSAGE, ve.getErrorDescription());
m.addAttribute(HttpCodeView.CODE, ve.getStatus());
return JsonErrorView.VIEWNAME;
}
@ -172,26 +182,26 @@ public class DynamicClientRegistrationEndpoint {
RegisteredClient registered = new RegisteredClient(savedClient, token.getValue(), config.getIssuer() + "register/" + UriUtils.encodePathSegment(savedClient.getClientId(), "UTF-8"));
m.addAttribute("client", registered);
m.addAttribute("code", HttpStatus.CREATED); // http 201
m.addAttribute(HttpCodeView.CODE, HttpStatus.CREATED); // http 201
return ClientInformationResponseView.VIEWNAME;
} catch (UnsupportedEncodingException e) {
logger.error("Unsupported encoding", e);
m.addAttribute("code", HttpStatus.INTERNAL_SERVER_ERROR);
m.addAttribute(HttpCodeView.CODE, HttpStatus.INTERNAL_SERVER_ERROR);
return HttpCodeView.VIEWNAME;
} catch (IllegalArgumentException e) {
logger.error("Couldn't save client", e);
m.addAttribute("error", "invalid_client_metadata");
m.addAttribute("errorMessage", "Unable to save client due to invalid or inconsistent metadata.");
m.addAttribute("code", HttpStatus.BAD_REQUEST); // http 400
m.addAttribute(JsonErrorView.ERROR, "invalid_client_metadata");
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Unable to save client due to invalid or inconsistent metadata.");
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); // http 400
return JsonErrorView.VIEWNAME;
}
} else {
// didn't parse, this is a bad request
logger.error("registerNewClient failed; submitted JSON is malformed");
m.addAttribute("code", HttpStatus.BAD_REQUEST); // http 400
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); // http 400
return HttpCodeView.VIEWNAME;
}
@ -206,7 +216,7 @@ public class DynamicClientRegistrationEndpoint {
* @return
*/
@PreAuthorize("hasRole('ROLE_CLIENT') and #oauth2.hasScope('" + SystemScopeService.REGISTRATION_TOKEN_SCOPE + "')")
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = "application/json")
@RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public String readClientConfiguration(@PathVariable("id") String clientId, Model m, OAuth2Authentication auth) {
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
@ -219,12 +229,12 @@ public class DynamicClientRegistrationEndpoint {
// send it all out to the view
m.addAttribute("client", registered);
m.addAttribute("code", HttpStatus.OK); // http 200
m.addAttribute(HttpCodeView.CODE, HttpStatus.OK); // http 200
return ClientInformationResponseView.VIEWNAME;
} catch (UnsupportedEncodingException e) {
logger.error("Unsupported encoding", e);
m.addAttribute("code", HttpStatus.INTERNAL_SERVER_ERROR);
m.addAttribute(HttpCodeView.CODE, HttpStatus.INTERNAL_SERVER_ERROR);
return HttpCodeView.VIEWNAME;
}
@ -232,7 +242,7 @@ public class DynamicClientRegistrationEndpoint {
// client mismatch
logger.error("readClientConfiguration failed, client ID mismatch: "
+ clientId + " and " + auth.getOAuth2Request().getClientId() + " do not match.");
m.addAttribute("code", HttpStatus.FORBIDDEN); // http 403
m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); // http 403
return HttpCodeView.VIEWNAME;
}
@ -247,7 +257,7 @@ public class DynamicClientRegistrationEndpoint {
* @return
*/
@PreAuthorize("hasRole('ROLE_CLIENT') and #oauth2.hasScope('" + SystemScopeService.REGISTRATION_TOKEN_SCOPE + "')")
@RequestMapping(value = "/{id}", method = RequestMethod.PUT, produces = "application/json", consumes = "application/json")
@RequestMapping(value = "/{id}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public String updateClient(@PathVariable("id") String clientId, @RequestBody String jsonString, Model m, OAuth2Authentication auth) {
@ -258,7 +268,7 @@ public class DynamicClientRegistrationEndpoint {
// bad parse
// didn't parse, this is a bad request
logger.error("updateClient failed; submitted JSON is malformed");
m.addAttribute("code", HttpStatus.BAD_REQUEST); // http 400
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); // http 400
return HttpCodeView.VIEWNAME;
}
ClientDetailsEntity oldClient = clientService.loadClientByClientId(clientId);
@ -291,9 +301,9 @@ public class DynamicClientRegistrationEndpoint {
newClient = validateAuth(newClient);
} catch (ValidationException ve) {
// validation failed, return an error
m.addAttribute("error", ve.getError());
m.addAttribute("errorMessage", ve.getErrorDescription());
m.addAttribute("code", ve.getStatus());
m.addAttribute(JsonErrorView.ERROR, ve.getError());
m.addAttribute(JsonErrorView.ERROR_MESSAGE, ve.getErrorDescription());
m.addAttribute(HttpCodeView.CODE, ve.getStatus());
return JsonErrorView.VIEWNAME;
}
@ -307,19 +317,19 @@ public class DynamicClientRegistrationEndpoint {
// send it all out to the view
m.addAttribute("client", registered);
m.addAttribute("code", HttpStatus.OK); // http 200
m.addAttribute(HttpCodeView.CODE, HttpStatus.OK); // http 200
return ClientInformationResponseView.VIEWNAME;
} catch (UnsupportedEncodingException e) {
logger.error("Unsupported encoding", e);
m.addAttribute("code", HttpStatus.INTERNAL_SERVER_ERROR);
m.addAttribute(HttpCodeView.CODE, HttpStatus.INTERNAL_SERVER_ERROR);
return HttpCodeView.VIEWNAME;
} catch (IllegalArgumentException e) {
logger.error("Couldn't save client", e);
m.addAttribute("error", "invalid_client_metadata");
m.addAttribute("errorMessage", "Unable to save client due to invalid or inconsistent metadata.");
m.addAttribute("code", HttpStatus.BAD_REQUEST); // http 400
m.addAttribute(JsonErrorView.ERROR, "invalid_client_metadata");
m.addAttribute(JsonErrorView.ERROR_MESSAGE, "Unable to save client due to invalid or inconsistent metadata.");
m.addAttribute(HttpCodeView.CODE, HttpStatus.BAD_REQUEST); // http 400
return JsonErrorView.VIEWNAME;
}
@ -327,7 +337,7 @@ public class DynamicClientRegistrationEndpoint {
// client mismatch
logger.error("updateClient failed, client ID mismatch: "
+ clientId + " and " + auth.getOAuth2Request().getClientId() + " do not match.");
m.addAttribute("code", HttpStatus.FORBIDDEN); // http 403
m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); // http 403
return HttpCodeView.VIEWNAME;
}
@ -341,7 +351,7 @@ public class DynamicClientRegistrationEndpoint {
* @return
*/
@PreAuthorize("hasRole('ROLE_CLIENT') and #oauth2.hasScope('" + SystemScopeService.REGISTRATION_TOKEN_SCOPE + "')")
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = "application/json")
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_VALUE)
public String deleteClient(@PathVariable("id") String clientId, Model m, OAuth2Authentication auth) {
ClientDetailsEntity client = clientService.loadClientByClientId(clientId);
@ -350,14 +360,14 @@ public class DynamicClientRegistrationEndpoint {
clientService.deleteClient(client);
m.addAttribute("code", HttpStatus.NO_CONTENT); // http 204
m.addAttribute(HttpCodeView.CODE, HttpStatus.NO_CONTENT); // http 204
return HttpCodeView.VIEWNAME;
} else {
// client mismatch
logger.error("readClientConfiguration failed, client ID mismatch: "
+ clientId + " and " + auth.getOAuth2Request().getClientId() + " do not match.");
m.addAttribute("code", HttpStatus.FORBIDDEN); // http 403
m.addAttribute(HttpCodeView.CODE, HttpStatus.FORBIDDEN); // http 403
return HttpCodeView.VIEWNAME;
}
@ -559,4 +569,10 @@ public class DynamicClientRegistrationEndpoint {
return token;
}
}
@ExceptionHandler(OAuth2Exception.class)
public ResponseEntity<OAuth2Exception> handleException(Exception e) throws Exception {
logger.info("Handling error: " + e.getClass().getSimpleName() + ", " + e.getMessage());
return providerExceptionHandler.translate(e);
}
}

View File

@ -21,6 +21,7 @@ import java.util.Map;
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
import org.mitre.openid.connect.view.JWKSetView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@ -30,10 +31,12 @@ import com.nimbusds.jose.jwk.JWK;
@Controller
public class JWKSetPublishingEndpoint {
public static final String URL = "jwk";
@Autowired
private JWTSigningAndValidationService jwtService;
@RequestMapping(value = "/jwk", produces = "application/json")
@RequestMapping(value = "/" + URL, produces = MediaType.APPLICATION_JSON_VALUE)
public String getJwk(Model m) {
// map from key id to key

Some files were not shown because too many files have changed in this diff Show More