Merge branch 'master' into issue52
Conflicts: openid-connect-server/src/main/java/org/mitre/oauth2/service/impl/DefaultOAuth2ProviderTokenService.java openid-connect-server/src/main/webapp/WEB-INF/spring-servlet.xml openid-connect-server/src/main/webapp/WEB-INF/views/oauth/approve.jsppull/105/merge
commit
bbf9591c92
|
@ -1,3 +1,4 @@
|
|||
#Wed May 30 14:51:48 EDT 2012
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#Mon May 07 14:38:46 EDT 2012
|
||||
#Wed May 30 14:51:48 EDT 2012
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
|
|
|
@ -56,6 +56,6 @@ To test the default config, deploy to a servlet container, and request:
|
|||
|
||||
http://localhost:8080/account-chooser/?redirect_uri=http://www.google.com&client_id=FGWEUIASJK
|
||||
|
||||
Click **Submit** or **Cancel**, and you will be Google will open. Study the URL parameters of each.
|
||||
Click **Submit** or **Cancel**, and Google will open. Study the URL parameters of each.
|
||||
|
||||
[Issue #39]: http://github.com/jricher/OpenID-Connect-Java-Spring-Server/issues/39 "Issue #39 -- Multiple Point Client"
|
||||
[Issue #39]: http://github.com/jricher/OpenID-Connect-Java-Spring-Server/issues/39 "Issue #39 -- Multiple Point Client"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
protocol.md
|
|
@ -74,7 +74,7 @@ The following is non-normative example of a responses. Line wraps are for displa
|
|||
|
||||
A sequence diagram of a successful interaction would be:
|
||||
|
||||

|
||||

|
||||
|
||||
#### The Client ID is not Supported by the Account Chooser Application
|
||||
|
||||
|
@ -97,7 +97,7 @@ The following is a non-normative example. Line wraps after the second line are f
|
|||
|
||||
A sequence diagram of the interaction where the Account Chooser was not configured to support the Client would be:
|
||||
|
||||

|
||||

|
||||
|
||||
#### End-User refuses to select an Account
|
||||
|
||||
|
@ -119,7 +119,7 @@ The following is a non-normative example. Line wraps after the second line are f
|
|||
|
||||
A sequence diagram of an interaction where the End-User refused to select an Account would be:
|
||||
|
||||

|
||||

|
||||
|
||||
[OpenID Connect Standard]: http://openid.net/specs/openid-connect-standard-1_0.html "OpenID Connect Standard 1.0"
|
||||
[OpenID Connect Standard]: http://openid.net/specs/openid-connect-standard-1_0.html#code_flow "Authorization Code Flow, OpenID Connect Standard"
|
||||
|
|
|
@ -21,4 +21,22 @@ Managing OAuth clients:
|
|||
|
||||
|
||||
|
||||
Modules
|
||||
-------
|
||||
|
||||
The project uses a multi-level Maven and git repository sutrcture. The main project is split into the following modules:
|
||||
|
||||
- openid-connect-common: common classes, service and repository interfaces, and model code. Also includes full JWT library.
|
||||
- openid-connect-server: IdP/server implementation, includes implementations of services and repositories for use by server.
|
||||
- openid-connect-client: RP/client implementation, built around spring security filters.
|
||||
- spring-security-oauth: Git submodule that points to the Spring Security OAuth Git repository. Will be removed once a reliable milestone is reached upstream (see note above).
|
||||
|
||||
|
||||
|
||||
Maven War Overlay
|
||||
-----------------
|
||||
|
||||
One of the best ways to build a custom deployment of this system is to use the Maven War Overlay mechanism. In essence, you make a new Maven project with a "war" disposition and make it depend on the openid-connect-server module with the Maven Overlay plugin configured. Any files in your new project will be built and injected into the war from the other project. This action will also overwrite any existing files.
|
||||
|
||||
For instance, to overwrite the data source configuration in the main server war file, create a file named src/main/webapp/WEB-INF/data-context.xml that contains the dataSource bean. This file will completely replace the one that's in the originally built war.
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#Wed May 30 14:51:48 EDT 2012
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
## Overview
|
||||
|
||||
This is the Client, a Spring Security AuthenticationFilter, to OpenID Connect Java Spring Server described by [OpenID Connect Standard].
|
||||
This is the Client, a Spring Security AuthenticationFilter, to the OpenID Connect Java Spring Server following the [OpenID Connect Standard] described protocol.
|
||||
|
||||
## Configuration of OIDCAuthenticationFilter
|
||||
|
||||
Configure the OIDCAuthenticationFilter by adding the XML to your application context security like so:
|
||||
Configure the OIDCAuthenticationFilter by adding the XML to your application context security like so making changes where necessary for your deployment:
|
||||
|
||||
<security:http auto-config="false"
|
||||
use-expressions="true"
|
||||
|
@ -67,7 +67,7 @@ You will need to implement your own UserDetailsService and configure as the abov
|
|||
|
||||
The OIDCAuthenticationUsingChooserFilter was written in response to [Issue #39].
|
||||
|
||||
Th Authentication Filter use the *oidcServerConfigs* property, a map of OIDC servers, an *accountChooserURI* property to denote the URI of the Account Chooser, and an *accountChooserClient* property to identify the Client to the Account Chooser UI application like so:
|
||||
The Authentication Filter uses the *oidcServerConfigs* property, a map of OIDC servers; an *accountChooserURI* property to denote the URI of the Account Chooser; and an *accountChooserClient* property to identify the Client to the Account Chooser UI application like so with modifications specific to your deployment:
|
||||
|
||||
<bean id="openIdConnectAuthenticationFilter"
|
||||
class="org.mitre.openid.connect.client.OIDCAuthenticationUsingChooserFilter">
|
||||
|
@ -98,7 +98,96 @@ Th Authentication Filter use the *oidcServerConfigs* property, a map of OIDC ser
|
|||
|
||||
Again, you will need to implement your own UserDetailsService and configure as the above does with the reference to *myUserDetailsService*.
|
||||
|
||||
## Implementing your own UserDetailsService
|
||||
|
||||
An example UserDetailsService for the Rave Portal follows:
|
||||
|
||||
package org.mitre.mpn.service.impl;
|
||||
|
||||
import org.apache.rave.portal.model.NewUser;
|
||||
import org.apache.rave.portal.model.User;
|
||||
import org.apache.rave.portal.service.NewAccountService;
|
||||
import org.apache.rave.portal.service.UserService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
import org.mitre.openid.connect.client.OpenIdConnectAuthenticationToken;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Service(value = "myUserDetailsService")
|
||||
public class MyUserDetailsService implements UserDetailsService,
|
||||
AuthenticationUserDetailsService<OpenIdConnectAuthenticationToken> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MpnUserDetailsService.class);
|
||||
|
||||
private final UserService userService;
|
||||
private final NewAccountService newAccountService;
|
||||
|
||||
//TODO: This is temporarily hard-coded while we wait for the concept of Page Templates to be implemented in Rave
|
||||
private static final String DEFAULT_LAYOUT_CODE = "columns_3";
|
||||
|
||||
@Autowired
|
||||
public MyUserDetailsService(UserService userService, NewAccountService newAccountService) {
|
||||
this.userService = userService;
|
||||
this.newAccountService = newAccountService;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)
|
||||
*/
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
|
||||
log.debug("loadUserByUsername called with: {}", username);
|
||||
|
||||
User user = userService.getUserByUsername(username);
|
||||
|
||||
if (user == null) {
|
||||
throw new UsernameNotFoundException("User with username '" + username + "' was not found!");
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.core.userdetails.AuthenticationUserDetailsService#loadUserDetails(org.springframework.security.core.Authentication)
|
||||
*/
|
||||
public UserDetails loadUserDetails(OpenIdConnectAuthenticationToken token) throws UsernameNotFoundException {
|
||||
log.debug("loadUserDetails called with: {}", token);
|
||||
|
||||
User user = userService.getUserByUsername(token.getUserId());
|
||||
|
||||
if (user == null) {
|
||||
|
||||
NewUser newUser = new NewUser();
|
||||
newUser.setUsername(token.getUserId());
|
||||
newUser.setEmail(token.getUserId() + "@example.com");
|
||||
newUser.setPageLayout(DEFAULT_LAYOUT_CODE);
|
||||
newUser.setPassword(UUID.randomUUID().toString());
|
||||
|
||||
try {
|
||||
newAccountService.createNewAccount(newUser);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
user = userService.getUserByUsername(token.getName());
|
||||
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[OpenID Connect Standard]: http://openid.net/specs/openid-connect-standard-1_0.html "OpenID Connect Standard 1.0"
|
||||
[OpenID Connect Standard]: http://openid.net/specs/openid-connect-standard-1_0.html#code_flow "Authorization Code Flow, OpenID Connect Standard"
|
||||
[Issuer Identifier]: http://openid.net/specs/openid-connect-messages-1_0.html#issuer_identifier "Issuer Identifier"
|
||||
[Issue #39]: http://github.com/jricher/OpenID-Connect-Java-Spring-Server/issues/39 "Issue #39 -- Multiple Point Client"
|
||||
[Issue #39]: http://github.com/jricher/OpenID-Connect-Java-Spring-Server/issues/39 "Issue #39 -- Multiple Point Client"
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#Wed May 30 14:51:48 EDT 2012
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
|
|
|
@ -89,20 +89,18 @@ public class JwtSigningAndValidationServiceDefault implements
|
|||
|
||||
Map<String, PublicKey> map = new HashMap<String, PublicKey>();
|
||||
|
||||
PublicKey publicKey;
|
||||
|
||||
for (JwtSigner signer : signers.values()) {
|
||||
for (String signerId : signers.keySet()) {
|
||||
|
||||
JwtSigner signer = signers.get(signerId);
|
||||
|
||||
if (signer instanceof RsaSigner) {
|
||||
|
||||
publicKey = ((RsaSigner) signer).getPublicKey();
|
||||
RsaSigner rsa = (RsaSigner)signer;
|
||||
|
||||
PublicKey publicKey = rsa.getPublicKey();
|
||||
|
||||
if (publicKey != null) {
|
||||
// what's the index of this map for?
|
||||
map.put(((RSAPublicKey) publicKey).getModulus()
|
||||
.toString(16).toUpperCase()
|
||||
+ ((RSAPublicKey) publicKey).getPublicExponent()
|
||||
.toString(16).toUpperCase(), publicKey);
|
||||
map.put(signerId, publicKey);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,12 +20,13 @@ import java.util.List;
|
|||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
|
||||
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
|
||||
|
||||
public interface OAuth2TokenEntityService extends AuthorizationServerTokenServices, ResourceServerTokenServices {
|
||||
|
||||
public OAuth2AccessTokenEntity getAccessToken(String accessTokenValue);
|
||||
public OAuth2AccessTokenEntity readAccessToken(String accessTokenValue);
|
||||
|
||||
public OAuth2RefreshTokenEntity getRefreshToken(String refreshTokenValue);
|
||||
|
||||
|
@ -43,4 +44,6 @@ public interface OAuth2TokenEntityService extends AuthorizationServerTokenServic
|
|||
|
||||
public OAuth2RefreshTokenEntity saveRefreshToken(OAuth2RefreshTokenEntity refreshToken);
|
||||
|
||||
public OAuth2AccessTokenEntity getAccessToken(OAuth2Authentication authentication);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="org.eclipse.jst.component.dependency" value="/WEB-INF/lib"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
#Wed May 30 14:51:48 EDT 2012
|
||||
com.springsource.sts.maven.maven.automatically.update=true
|
||||
eclipse.preferences.version=1
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
CREATE TABLE clientdetails (
|
||||
clientId VARCHAR(256),
|
||||
clientSecret VARCHAR(2000),
|
||||
registeredRedirectUri VARCHAR(2000),
|
||||
clientName VARCHAR(256),
|
||||
clientDescription VARCHAR(2000),
|
||||
allowRefresh TINYINT,
|
|
@ -1,4 +1,4 @@
|
|||
CREATE TABLE redirect_uris (
|
||||
owner_id VARCHAR(256),
|
||||
registeredRedirectUri VARCHAR(256)
|
||||
registeredRedirectUri VARCHAR(2000)
|
||||
);
|
|
@ -157,9 +157,13 @@ public class DefaultOAuth2ClientDetailsEntityService implements ClientDetailsEnt
|
|||
@Override
|
||||
public ClientDetailsEntity saveClient(ClientDetailsEntity client) {
|
||||
|
||||
if (client.getClientSecret().equals("")) {
|
||||
client.setClientSecret(UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
// this must be a new client if we don't have a clientID
|
||||
// assign it a new ID
|
||||
if (client.getClientId() == null || this.loadClientByClientId(client.getClientId()) == null) {
|
||||
if (client.getClientId() == null || client.getClientId().equals("") || this.loadClientByClientId(client.getClientId()) == null) {
|
||||
client.setClientId(UUID.randomUUID().toString());
|
||||
return this.createClient(client);
|
||||
} else {
|
||||
|
|
|
@ -228,8 +228,11 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an access token from its token value.
|
||||
*/
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity getAccessToken(String accessTokenValue) throws AuthenticationException {
|
||||
public OAuth2AccessTokenEntity readAccessToken(String accessTokenValue) throws AuthenticationException {
|
||||
OAuth2AccessTokenEntity accessToken = tokenRepository.getAccessTokenByValue(accessTokenValue);
|
||||
if (accessToken == null) {
|
||||
throw new InvalidTokenException("Access token for value " + accessTokenValue + " was not found");
|
||||
|
@ -239,6 +242,9 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an access token by its authentication object.
|
||||
*/
|
||||
@Override
|
||||
public OAuth2AccessTokenEntity getAccessToken(OAuth2Authentication authentication) {
|
||||
|
||||
|
@ -247,6 +253,9 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
|
|||
return accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a refresh token by its token value.
|
||||
*/
|
||||
@Override
|
||||
public OAuth2RefreshTokenEntity getRefreshToken(String refreshTokenValue) throws AuthenticationException {
|
||||
OAuth2RefreshTokenEntity refreshToken = tokenRepository.getRefreshTokenByValue(refreshTokenValue);
|
||||
|
@ -258,12 +267,18 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke a refresh token and all access tokens issued to it.
|
||||
*/
|
||||
@Override
|
||||
public void revokeRefreshToken(OAuth2RefreshTokenEntity refreshToken) {
|
||||
tokenRepository.clearAccessTokensForRefreshToken(refreshToken);
|
||||
tokenRepository.removeRefreshToken(refreshToken);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke an access token.
|
||||
*/
|
||||
@Override
|
||||
public void revokeAccessToken(OAuth2AccessTokenEntity accessToken) {
|
||||
tokenRepository.removeAccessToken(accessToken);
|
||||
|
@ -352,12 +367,6 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public OAuth2AccessToken readAccessToken(String accessToken) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.mitre.oauth2.service.OAuth2TokenEntityService#saveAccessToken(org.mitre.oauth2.model.OAuth2AccessTokenEntity)
|
||||
*/
|
||||
|
@ -388,6 +397,4 @@ public class DefaultOAuth2ProviderTokenService implements OAuth2TokenEntityServi
|
|||
this.tokenEnhancer = tokenEnhancer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ public class IntrospectionEndpoint {
|
|||
@RequestMapping("/oauth/verify")
|
||||
public ModelAndView verify(@RequestParam("token") String tokenValue,
|
||||
ModelAndView modelAndView) {
|
||||
OAuth2AccessTokenEntity token = tokenServices.getAccessToken(tokenValue);
|
||||
OAuth2AccessTokenEntity token = tokenServices.readAccessToken(tokenValue);
|
||||
|
||||
if (token == null) {
|
||||
// if it's not a valid token, we'll print a 404
|
||||
|
|
|
@ -22,6 +22,8 @@ import org.mitre.oauth2.exception.ClientNotFoundException;
|
|||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.provider.AuthorizationRequest;
|
||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
******************************************************************************/
|
||||
package org.mitre.oauth2.web;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import org.mitre.oauth2.exception.PermissionDeniedException;
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.model.OAuth2RefreshTokenEntity;
|
||||
|
@ -47,23 +49,35 @@ public class RevocationEndpoint {
|
|||
// TODO
|
||||
@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_CLIENT')")
|
||||
@RequestMapping("/oauth/revoke")
|
||||
public ModelAndView revoke(@RequestParam("token") String tokenValue,
|
||||
public ModelAndView revoke(@RequestParam("token") String tokenValue, Principal principal,
|
||||
ModelAndView modelAndView) {
|
||||
|
||||
OAuth2RefreshTokenEntity refreshToken = tokenServices.getRefreshToken(tokenValue);
|
||||
OAuth2AccessTokenEntity accessToken = tokenServices.getAccessToken(tokenValue);
|
||||
|
||||
OAuth2RefreshTokenEntity refreshToken = null;
|
||||
OAuth2AccessTokenEntity accessToken = null;
|
||||
try {
|
||||
refreshToken = tokenServices.getRefreshToken(tokenValue);
|
||||
} catch (InvalidTokenException e) {
|
||||
// it's OK if either of these tokens are bad
|
||||
}
|
||||
|
||||
try {
|
||||
accessToken = tokenServices.readAccessToken(tokenValue);
|
||||
} catch (InvalidTokenException e) {
|
||||
// it's OK if either of these tokens are bad
|
||||
}
|
||||
|
||||
if (refreshToken == null && accessToken == null) {
|
||||
// TODO: this should throw a 400 with a JSON error code
|
||||
throw new InvalidTokenException("Invalid OAuth token: " + tokenValue);
|
||||
}
|
||||
|
||||
// TODO: there should be a way to do this in SPEL, right?
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (auth instanceof OAuth2Authentication) {
|
||||
if (principal instanceof OAuth2Authentication) {
|
||||
OAuth2AccessTokenEntity tok = tokenServices.getAccessToken((OAuth2Authentication) principal);
|
||||
|
||||
// we've got a client acting on its own behalf, not an admin
|
||||
//ClientAuthentication clientAuth = (ClientAuthenticationToken) ((OAuth2Authentication) auth).getClientAuthentication();
|
||||
AuthorizationRequest clientAuth = ((OAuth2Authentication) auth).getAuthorizationRequest();
|
||||
AuthorizationRequest clientAuth = ((OAuth2Authentication) principal).getAuthorizationRequest();
|
||||
|
||||
if (refreshToken != null) {
|
||||
if (!refreshToken.getClient().getClientId().equals(clientAuth.getClientId())) {
|
||||
|
|
|
@ -15,11 +15,20 @@
|
|||
******************************************************************************/
|
||||
package org.mitre.openid.connect.exception;
|
||||
|
||||
/**
|
||||
* @author aanganes, nemonik
|
||||
*
|
||||
*/
|
||||
public class ExpiredTokenException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ExpiredTokenException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ExpiredTokenException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,11 +15,20 @@
|
|||
******************************************************************************/
|
||||
package org.mitre.openid.connect.exception;
|
||||
|
||||
/**
|
||||
* @author aanganes, nemonik
|
||||
*
|
||||
*/
|
||||
public class InvalidJwtIssuerException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidJwtIssuerException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public InvalidJwtIssuerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,11 +15,20 @@
|
|||
******************************************************************************/
|
||||
package org.mitre.openid.connect.exception;
|
||||
|
||||
/**
|
||||
* @author aanganes, nemonik
|
||||
*
|
||||
*/
|
||||
public class InvalidJwtSignatureException extends RuntimeException {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public InvalidJwtSignatureException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public InvalidJwtSignatureException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2012 The MITRE Corporation
|
||||
*
|
||||
* 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.exception;
|
||||
|
||||
/**
|
||||
* @author aanganes, nemonik
|
||||
*
|
||||
*/
|
||||
public class UnknownUserInfoSchemaException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public UnknownUserInfoSchemaException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public UnknownUserInfoSchemaException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2012 The MITRE Corporation
|
||||
*
|
||||
* 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.view;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.servlet.view.AbstractView;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* @author nemonik
|
||||
*
|
||||
*/
|
||||
public class ExceptionAsJSONView extends AbstractView {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.web.servlet.view.AbstractView#renderMergedOutputModel
|
||||
* (java.util.Map, javax.servlet.http.HttpServletRequest,
|
||||
* javax.servlet.http.HttpServletResponse)
|
||||
*/
|
||||
@Override
|
||||
protected void renderMergedOutputModel(Map<String, Object> model,
|
||||
HttpServletRequest requesr, HttpServletResponse response)
|
||||
throws Exception {
|
||||
|
||||
response.setContentType("application/json");
|
||||
|
||||
final JsonObject jsonObject = new JsonObject();
|
||||
|
||||
Object ex = model.get("exception");
|
||||
|
||||
jsonObject.addProperty("error", ex.getClass().getName());
|
||||
jsonObject.addProperty("error_description",
|
||||
((Exception) ex).getMessage());
|
||||
|
||||
response.getWriter().write(jsonObject.toString());
|
||||
}
|
||||
|
||||
}
|
|
@ -21,6 +21,7 @@ import java.util.Map;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mitre.openid.connect.model.UserInfo;
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.web.servlet.view.AbstractView;
|
||||
|
||||
|
@ -28,6 +29,7 @@ import com.google.gson.ExclusionStrategy;
|
|||
import com.google.gson.FieldAttributes;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public class JSONUserInfoView extends AbstractView{
|
||||
|
||||
|
@ -37,6 +39,8 @@ public class JSONUserInfoView extends AbstractView{
|
|||
protected void renderMergedOutputModel(Map<String, Object> model,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
|
||||
UserInfo userInfo = (UserInfo) model.get("userInfo");
|
||||
|
||||
Gson gson = new GsonBuilder()
|
||||
.setExclusionStrategies(new ExclusionStrategy() {
|
||||
|
@ -57,15 +61,45 @@ public class JSONUserInfoView extends AbstractView{
|
|||
}).create();
|
||||
|
||||
response.setContentType("application/json");
|
||||
|
||||
Writer out = response.getWriter();
|
||||
|
||||
Object obj = model.get("entity");
|
||||
if (obj == null) {
|
||||
obj = model;
|
||||
}
|
||||
|
||||
gson.toJson(obj, out);
|
||||
gson.toJson(toJson(userInfo),out);
|
||||
}
|
||||
|
||||
private JsonObject toJson(UserInfo ui) {
|
||||
JsonObject obj = new JsonObject();
|
||||
|
||||
obj.addProperty("user_id", ui.getUserId());
|
||||
obj.addProperty("name", ui.getName());
|
||||
obj.addProperty("given_name", ui.getGivenName());
|
||||
obj.addProperty("family_name", ui.getFamilyName());
|
||||
obj.addProperty("middle_name", ui.getMiddleName());
|
||||
obj.addProperty("nickname", ui.getNickname());
|
||||
obj.addProperty("email", ui.getEmail());
|
||||
obj.addProperty("profile", ui.getProfile());
|
||||
obj.addProperty("picture", ui.getPicture());
|
||||
obj.addProperty("email", ui.getEmail());
|
||||
obj.addProperty("website", ui.getWebsite());
|
||||
obj.addProperty("verified", ui.getVerified());
|
||||
obj.addProperty("gender", ui.getGender());
|
||||
obj.addProperty("zone_info", ui.getZoneinfo());
|
||||
obj.addProperty("locale", ui.getLocale());
|
||||
obj.addProperty("phone_number", ui.getPhoneNumber());
|
||||
obj.addProperty("updated_time", ui.getUpdatedTime());
|
||||
|
||||
if (ui.getAddress() != null) {
|
||||
|
||||
JsonObject addr = new JsonObject();
|
||||
addr.addProperty("formatted", ui.getAddress().getFormatted());
|
||||
addr.addProperty("street_address", ui.getAddress().getStreetAddress());
|
||||
addr.addProperty("locality", ui.getAddress().getLocality());
|
||||
addr.addProperty("region", ui.getAddress().getRegion());
|
||||
addr.addProperty("postal_code", ui.getAddress().getPostalCode());
|
||||
addr.addProperty("country", ui.getAddress().getCountry());
|
||||
|
||||
obj.add("address", addr);
|
||||
}
|
||||
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,10 +33,12 @@ import org.apache.commons.codec.binary.Base64;
|
|||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.web.servlet.view.AbstractView;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.FieldAttributes;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
|
@ -67,50 +69,6 @@ public class JwkKeyListView extends AbstractView {
|
|||
return false;
|
||||
}
|
||||
|
||||
})
|
||||
.registerTypeHierarchyAdapter(PublicKey.class, new JsonSerializer<PublicKey>() {
|
||||
|
||||
@Override
|
||||
public JsonElement serialize(PublicKey src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
|
||||
|
||||
if (src instanceof RSAPublicKey) {
|
||||
|
||||
RSAPublicKey rsa = (RSAPublicKey)src;
|
||||
|
||||
|
||||
BigInteger mod = rsa.getModulus();
|
||||
BigInteger exp = rsa.getPublicExponent();
|
||||
|
||||
String m64 = Base64.encodeBase64URLSafeString(mod.toByteArray());
|
||||
String e64 = Base64.encodeBase64URLSafeString(exp.toByteArray());
|
||||
|
||||
JsonObject o = new JsonObject();
|
||||
|
||||
o.addProperty("use", "sig");
|
||||
o.addProperty("alg", "RSA");
|
||||
o.addProperty("mod", m64);
|
||||
o.addProperty("exp", e64);
|
||||
// TODO: get the key ID from the map
|
||||
return o;
|
||||
} else if (src instanceof ECPublicKey) {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
ECPublicKey ec = (ECPublicKey)src;
|
||||
|
||||
// TODO: serialize the EC
|
||||
|
||||
return null;
|
||||
|
||||
} else {
|
||||
|
||||
// skip this class ... we shouldn't have any keys in here that aren't encodable by this serializer
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
.create();
|
||||
|
||||
|
@ -119,10 +77,38 @@ public class JwkKeyListView extends AbstractView {
|
|||
|
||||
Writer out = response.getWriter();
|
||||
|
||||
Object obj = model.get("entity");
|
||||
if (obj == null) {
|
||||
obj = model;
|
||||
}
|
||||
BiMap<String, PublicKey> keyMap = (BiMap<String, PublicKey>) model.get("keys");
|
||||
|
||||
JsonObject obj = new JsonObject();
|
||||
JsonArray keys = new JsonArray();
|
||||
obj.add("keys", keys);
|
||||
|
||||
for (String keyId : keyMap.keySet()) {
|
||||
|
||||
PublicKey src = keyMap.get(keyId);
|
||||
|
||||
if (src instanceof RSAPublicKey) {
|
||||
|
||||
RSAPublicKey rsa = (RSAPublicKey)src;
|
||||
|
||||
|
||||
BigInteger mod = rsa.getModulus();
|
||||
BigInteger exp = rsa.getPublicExponent();
|
||||
|
||||
String m64 = Base64.encodeBase64URLSafeString(mod.toByteArray());
|
||||
String e64 = Base64.encodeBase64URLSafeString(exp.toByteArray());
|
||||
|
||||
JsonObject o = new JsonObject();
|
||||
|
||||
o.addProperty("use", "sig"); // since we don't do encryption yet
|
||||
o.addProperty("alg", "RSA"); // we know this is RSA
|
||||
o.addProperty("mod", m64);
|
||||
o.addProperty("exp", e64);
|
||||
o.addProperty("kid", keyId);
|
||||
|
||||
keys.add(o);
|
||||
}
|
||||
}
|
||||
|
||||
gson.toJson(obj, out);
|
||||
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2012 The MITRE Corporation
|
||||
*
|
||||
* 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.view;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mitre.openid.connect.model.UserInfo;
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.web.servlet.view.AbstractView;
|
||||
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.FieldAttributes;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
public class POCOUserInfoView extends AbstractView{
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.web.servlet.view.AbstractView#renderMergedOutputModel(java.util.Map, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
|
||||
*/
|
||||
protected void renderMergedOutputModel(Map<String, Object> model,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
|
||||
UserInfo userInfo = (UserInfo) model.get("userInfo");
|
||||
|
||||
Gson gson = new GsonBuilder()
|
||||
.setExclusionStrategies(new ExclusionStrategy() {
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
// skip the JPA binding wrapper
|
||||
if (clazz.equals(BeanPropertyBindingResult.class)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}).create();
|
||||
|
||||
response.setContentType("application/json");
|
||||
Writer out = response.getWriter();
|
||||
gson.toJson(toPoco(userInfo),out);
|
||||
}
|
||||
|
||||
private JsonObject toPoco(UserInfo ui) {
|
||||
JsonObject poco = new JsonObject();
|
||||
|
||||
// Envelope Info
|
||||
poco.addProperty("startIndex", 0);
|
||||
poco.addProperty("itemsPerPage", 1);
|
||||
poco.addProperty("totalResults", 1);
|
||||
|
||||
// Build the entry for this userInfo, then add it to entries, then add it to poco
|
||||
JsonObject entry = new JsonObject();
|
||||
entry.addProperty("id", ui.getUserId());
|
||||
entry.addProperty("displayName", ui.getNickname());
|
||||
|
||||
if(ui.getFamilyName() != null
|
||||
|| ui.getGivenName() != null
|
||||
|| ui.getMiddleName() != null
|
||||
|| ui.getName() != null) {
|
||||
JsonObject name = new JsonObject();
|
||||
name.addProperty("familyName", ui.getFamilyName());
|
||||
name.addProperty("givenName", ui.getGivenName());
|
||||
name.addProperty("middleName", ui.getMiddleName());
|
||||
name.addProperty("formatted", ui.getName());
|
||||
entry.add("name", name);
|
||||
}
|
||||
|
||||
entry.addProperty("gender", ui.getGender());
|
||||
|
||||
if(ui.getEmail() != null) {
|
||||
JsonObject email = new JsonObject();
|
||||
email.addProperty("value", ui.getEmail());
|
||||
|
||||
JsonArray emailArray = new JsonArray();
|
||||
emailArray.add(email);
|
||||
entry.add("emails", emailArray);
|
||||
}
|
||||
|
||||
if(ui.getPhoneNumber() != null){
|
||||
JsonObject phone = new JsonObject();
|
||||
phone.addProperty("value", ui.getPhoneNumber());
|
||||
|
||||
JsonArray phoneArray = new JsonArray();
|
||||
phoneArray.add(phone);
|
||||
entry.add("phoneNumbers", phoneArray);
|
||||
}
|
||||
|
||||
if(ui.getPicture() != null){
|
||||
JsonObject photo = new JsonObject();
|
||||
photo.addProperty("value", ui.getPicture());
|
||||
|
||||
JsonArray photoArray = new JsonArray();
|
||||
photoArray.add(photo);
|
||||
entry.add("photos", photoArray);
|
||||
}
|
||||
|
||||
if(ui.getWebsite() != null) {
|
||||
JsonObject website = new JsonObject();
|
||||
website.addProperty("value", ui.getWebsite());
|
||||
|
||||
JsonArray websiteArray = new JsonArray();
|
||||
websiteArray.add(website);
|
||||
entry.add("urls", websiteArray);
|
||||
}
|
||||
|
||||
if(ui.getAddress() != null) {
|
||||
JsonObject addr = new JsonObject();
|
||||
addr.addProperty("formatted", ui.getAddress().getFormatted());
|
||||
addr.addProperty("streetAddress", ui.getAddress().getStreetAddress());
|
||||
addr.addProperty("locality", ui.getAddress().getLocality());
|
||||
addr.addProperty("region", ui.getAddress().getRegion());
|
||||
addr.addProperty("postalCode", ui.getAddress().getPostalCode());
|
||||
addr.addProperty("country", ui.getAddress().getCountry());
|
||||
|
||||
JsonArray addrArray = new JsonArray();
|
||||
addrArray.add(addr);
|
||||
entry.add("addresses", addrArray);
|
||||
}
|
||||
|
||||
entry.addProperty("updated", ui.getUpdatedTime());
|
||||
|
||||
JsonArray entryArray = new JsonArray();
|
||||
entryArray.add(entry);
|
||||
poco.add("entry", entryArray);
|
||||
return poco;
|
||||
}
|
||||
|
||||
}
|
|
@ -25,6 +25,9 @@ import org.mitre.openid.connect.exception.InvalidJwtSignatureException;
|
|||
import org.mitre.openid.connect.model.IdToken;
|
||||
import org.mitre.util.Utility;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
@ -39,12 +42,15 @@ public class CheckIDEndpoint {
|
|||
@Autowired
|
||||
private ConfigurationPropertiesBean configBean;
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
@RequestMapping("/checkid")
|
||||
public ModelAndView checkID(@RequestParam("access_token") String tokenString, ModelAndView mav, HttpServletRequest request) {
|
||||
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
if (!jwtSignerService.validateSignature(tokenString)) {
|
||||
// can't validate
|
||||
throw new InvalidJwtSignatureException(); // TODO: attach a view to this exception
|
||||
throw new InvalidJwtSignatureException("The Signature could not be validated.");
|
||||
}
|
||||
|
||||
// it's a valid signature, parse the token
|
||||
|
@ -53,12 +59,12 @@ public class CheckIDEndpoint {
|
|||
// check the expiration
|
||||
if (jwtSignerService.isJwtExpired(token)) {
|
||||
// token has expired
|
||||
throw new ExpiredTokenException(); // TODO create a view for this exception
|
||||
throw new ExpiredTokenException("The token has expired.");
|
||||
}
|
||||
|
||||
// check the issuer (sanity check)
|
||||
if (!jwtSignerService.validateIssuedJwt(token, configBean.getIssuer())) {
|
||||
throw new InvalidJwtIssuerException(); // TODO: create a view for this exception
|
||||
throw new InvalidJwtIssuerException("The JWT issuer is invalid.");
|
||||
}
|
||||
|
||||
// pass the claims directly (the view doesn't care about other fields)
|
||||
|
|
|
@ -27,6 +27,10 @@ import org.springframework.stereotype.Controller;
|
|||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
@Controller
|
||||
public class JsonWebKeyEndpoint {
|
||||
|
||||
|
@ -36,14 +40,16 @@ public class JsonWebKeyEndpoint {
|
|||
@RequestMapping("/jwk")
|
||||
public ModelAndView getJwk() {
|
||||
|
||||
Collection<PublicKey> keys = jwtService.getAllPublicKeys().values();
|
||||
// get all public keys for display
|
||||
// map from key id to public key for that signer
|
||||
Map<String, PublicKey> keys = jwtService.getAllPublicKeys();
|
||||
|
||||
// put them into a bidirectional map to get at key IDs
|
||||
BiMap<String, PublicKey> biKeys = HashBiMap.create(keys);
|
||||
|
||||
// TODO: check if keys are empty, return a 404 here or just an empty list?
|
||||
|
||||
Map<String, Object> jwk = new HashMap<String, Object>();
|
||||
jwk.put("jwk", keys);
|
||||
|
||||
return new ModelAndView("jwkKeyList", "entity", jwk);
|
||||
return new ModelAndView("jwkKeyList", "keys", biKeys);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,12 +15,16 @@
|
|||
******************************************************************************/
|
||||
package org.mitre.openid.connect.web;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||
import org.mitre.oauth2.service.OAuth2TokenEntityService;
|
||||
import org.mitre.openid.connect.exception.UnknownUserInfoSchemaException;
|
||||
import org.mitre.openid.connect.model.UserInfo;
|
||||
import org.mitre.openid.connect.service.UserInfoService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
@ -42,6 +46,12 @@ public class UserInfoEndpoint {
|
|||
@Autowired
|
||||
UserInfoService userInfoService;
|
||||
|
||||
// Valid schemas and associated views
|
||||
private static final String openIdSchema = "openId";
|
||||
private static final String pocoSchema = "poco";
|
||||
private static final String jsonUserInfoViewName = "jsonUserInfoView";
|
||||
private static final String pocoUserInfoViewName = "pocoUserInfoView";
|
||||
|
||||
/**
|
||||
* Get information about the user as specified in the accessToken->idToken included in this request
|
||||
*
|
||||
|
@ -51,34 +61,25 @@ public class UserInfoEndpoint {
|
|||
* @return JSON or JWT response containing UserInfo data
|
||||
*/
|
||||
@RequestMapping(value="/userinfo", method= {RequestMethod.GET, RequestMethod.POST})
|
||||
public ModelAndView getInfo(@RequestParam("access_token") String accessToken, @RequestParam("schema") String schema, ModelAndView mav) {
|
||||
public ModelAndView getInfo(Principal p, @RequestParam("schema") String schema, ModelAndView mav) {
|
||||
|
||||
|
||||
//This will throw the proper error if the token cannot be found
|
||||
OAuth2AccessTokenEntity token = tokenService.getAccessToken(accessToken);
|
||||
|
||||
if (schema != "openid") {
|
||||
//openid is the ONLY defined schema and is a required parameter
|
||||
//Will we be defining other schemas?
|
||||
//if schema is unrecognized, throw an error?
|
||||
|
||||
if (p == null) {
|
||||
throw new UsernameNotFoundException("Invalid User");
|
||||
}
|
||||
|
||||
String userId = token.getIdToken().getTokenClaims().getUserId();
|
||||
|
||||
String viewName = null;
|
||||
if (schema.equalsIgnoreCase( openIdSchema )){
|
||||
viewName = jsonUserInfoViewName;
|
||||
} else if (schema.equalsIgnoreCase( pocoSchema )) {
|
||||
viewName = pocoUserInfoViewName;
|
||||
} else {
|
||||
throw new UnknownUserInfoSchemaException("Unknown User Info Schema: " + schema );
|
||||
}
|
||||
String userId = p.getName();
|
||||
UserInfo userInfo = userInfoService.getByUserId(userId);
|
||||
|
||||
ClientDetailsEntity client = token.getClient();
|
||||
|
||||
//if client wants plain JSON, give it JSON; if it wants a JWT, give it a JWT
|
||||
|
||||
//If returning JSON
|
||||
return new ModelAndView("jsonUserInfoView", "userInfo", userInfo);
|
||||
|
||||
// If returning JWT
|
||||
//Jwt jwt = new Jwt(new JwtHeader(), new JwtClaims(userInfo.toJson()), null);
|
||||
//sign jwt according to client's userinfo_signed_response_algs parameter
|
||||
//mav.addObject(jwt);
|
||||
//return mav;
|
||||
return new ModelAndView(viewName, "userInfo", userInfo);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/*******************************************************************************
|
||||
* Copyright 2012 The MITRE Corporation
|
||||
*
|
||||
* 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.swd.view;
|
||||
|
||||
import java.io.Writer;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.validation.BeanPropertyBindingResult;
|
||||
import org.springframework.web.servlet.view.AbstractView;
|
||||
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.FieldAttributes;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
*/
|
||||
public class XrdJsonResponse extends AbstractView {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.web.servlet.view.AbstractView#renderMergedOutputModel(java.util.Map, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
|
||||
*/
|
||||
@Override
|
||||
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
// skip the JPA binding wrapper
|
||||
if (clazz.equals(BeanPropertyBindingResult.class)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
.create();
|
||||
|
||||
response.setContentType("application/json");
|
||||
|
||||
Writer out = response.getWriter();
|
||||
|
||||
Map<String, String> links = (Map<String, String>) model.get("links");
|
||||
|
||||
JsonObject obj = new JsonObject();
|
||||
JsonArray linksList = new JsonArray();
|
||||
obj.add("links", linksList);
|
||||
|
||||
// map of "rel" -> "link" values
|
||||
for (Map.Entry<String, String> link : links.entrySet()) {
|
||||
JsonObject l = new JsonObject();
|
||||
l.addProperty("rel", link.getKey());
|
||||
l.addProperty("link", link.getValue());
|
||||
|
||||
linksList.add(l);
|
||||
}
|
||||
|
||||
gson.toJson(obj, out);
|
||||
}
|
||||
|
||||
}
|
|
@ -20,7 +20,9 @@ import java.util.Map;
|
|||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
||||
import org.mitre.util.Utility;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
@ -31,11 +33,14 @@ import com.google.common.collect.Lists;
|
|||
@Controller
|
||||
public class SimpleWebDiscoveryEndpoint {
|
||||
|
||||
@Autowired
|
||||
ConfigurationPropertiesBean config;
|
||||
|
||||
@RequestMapping(value="/.well-known/simple-web-discovery",
|
||||
params={"principal", "service=http://openid.net/specs/connect/1.0/issuer"})
|
||||
public ModelAndView openIdConnectIssuerDiscovery(@RequestParam("principal") String principal, ModelAndView modelAndView, HttpServletRequest request) {
|
||||
public ModelAndView openIdConnectIssuerDiscovery(@RequestParam("principal") String principal, ModelAndView modelAndView) {
|
||||
|
||||
String baseUrl = Utility.findBaseUrl(request);
|
||||
String baseUrl = config.getIssuer();
|
||||
|
||||
// look up user, see if they're local
|
||||
// if so, return this server
|
||||
|
@ -51,15 +56,26 @@ public class SimpleWebDiscoveryEndpoint {
|
|||
return modelAndView;
|
||||
}
|
||||
|
||||
@RequestMapping(value="/.well-known/host-meta",
|
||||
params={"resource", "rel=http://openid.net/specs/connect/1.0/issuer"})
|
||||
public ModelAndView xrdDiscovery(@RequestParam("resource") String resource, ModelAndView modelAndView) {
|
||||
|
||||
Map<String, String> relMap = new HashMap<String, String>();
|
||||
relMap.put("http://openid.net/specs/connect/1.0/issuer", config.getIssuer());
|
||||
|
||||
modelAndView.getModel().put("links", relMap);
|
||||
|
||||
modelAndView.setViewName("jsonXrdResponseView");
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
@RequestMapping("/.well-known/openid-configuration")
|
||||
public ModelAndView providerConfiguration(ModelAndView modelAndView, HttpServletRequest request) {
|
||||
public ModelAndView providerConfiguration(ModelAndView modelAndView) {
|
||||
|
||||
String baseUrl = Utility.findBaseUrl(request);
|
||||
|
||||
/*
|
||||
* version string Version of the provider response. "3.0" is the default.
|
||||
* issuer string The https: URL with no path component that the OP asserts as its Issuer Identifier
|
||||
* issuer string The https: URL that the OP asserts as its Issuer Identifier
|
||||
* authorization_endpoint string URL of the OP's Authentication and Authorization Endpoint [OpenID.Messages]
|
||||
* token_endpoint string URL of the OP's OAuth 2.0 Token Endpoint [OpenID.Messages]
|
||||
* userinfo_endpoint string URL of the OP's UserInfo Endpoint [OpenID.Messages]
|
||||
|
@ -81,18 +97,24 @@ public class SimpleWebDiscoveryEndpoint {
|
|||
* token_endpoint_auth_types_supported array A JSON array containing a list of authentication types supported by this Token Endpoint. The options are client_secret_post, client_secret_basic, client_secret_jwt, and private_key_jwt, as described in Section 2.2.1 of OpenID Connect Messages 1.0 [OpenID.Messages]. Other Authentication types may be defined by extension. If unspecified or omitted, the default is client_secret_basic HTTP Basic Authentication Scheme as specified in section 2.3.1 of OAuth 2.0 [OAuth2.0].
|
||||
* token_endpoint_auth_algs_supported array A JSON array containing a list of the JWS [JWS] signing algorithms supported by the Token Endpoint for the private_key_jwt method to encode the JWT [JWT]. Servers SHOULD support RS256.
|
||||
*/
|
||||
String baseUrl = config.getIssuer();
|
||||
|
||||
if (!baseUrl.endsWith("/")) {
|
||||
baseUrl = baseUrl.concat("/");
|
||||
}
|
||||
|
||||
Map<String, Object> m = new HashMap<String, Object>();
|
||||
m.put("version", "3.0");
|
||||
m.put("issuer", baseUrl);
|
||||
m.put("authorization_endpoint", baseUrl + "/authorize");
|
||||
m.put("token_endpoint", baseUrl + "/oauth");
|
||||
m.put("userinfo_endpoint", baseUrl + "/userinfo");
|
||||
m.put("check_id_endpoint", baseUrl + "/checkid");
|
||||
m.put("refresh_session_endpoint", baseUrl + "/refresh_session");
|
||||
m.put("end_session_endpoint", baseUrl + "/end_session");
|
||||
m.put("jwk_url", baseUrl + "/jwk");
|
||||
m.put("registration_endpoint", baseUrl + "/register_client");
|
||||
m.put("scopes_supported", Lists.newArrayList("openid"));
|
||||
m.put("issuer", config.getIssuer());
|
||||
m.put("authorization_endpoint", baseUrl + "openidconnect/auth");
|
||||
m.put("token_endpoint", baseUrl + "openidconnect/token");
|
||||
m.put("userinfo_endpoint", baseUrl + "userinfo");
|
||||
m.put("check_id_endpoint", baseUrl + "checkid");
|
||||
//m.put("refresh_session_endpoint", baseUrl + "/refresh_session");
|
||||
//m.put("end_session_endpoint", baseUrl + "/end_session");
|
||||
m.put("jwk_url", baseUrl + "jwk");
|
||||
//m.put("registration_endpoint", baseUrl + "/register_client");
|
||||
m.put("scopes_supported", Lists.newArrayList("openid", "email", "profile", "address", "phone"));
|
||||
m.put("response_types_supported", Lists.newArrayList("code"));
|
||||
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xmlns:task="http://www.springframework.org/schema/task"
|
||||
xmlns:task="http://www.springframework.org/schema/task"
|
||||
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
|
||||
http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
|
||||
|
@ -16,8 +16,9 @@
|
|||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
|
||||
|
||||
<!-- Scan for components -->
|
||||
<context:component-scan annotation-config="true" base-package="org.mitre"/>
|
||||
|
||||
<context:component-scan annotation-config="true"
|
||||
base-package="org.mitre" />
|
||||
|
||||
<!-- Enables the Spring MVC @Controller programming model -->
|
||||
<tx:annotation-driven transaction-manager="transactionManager" />
|
||||
<mvc:annotation-driven />
|
||||
|
@ -27,20 +28,29 @@
|
|||
<import resource="server-config.xml" />
|
||||
|
||||
<!-- Import the data context -->
|
||||
<import resource="data-context.xml" />
|
||||
<import resource="data-context.xml" />
|
||||
|
||||
<!-- Spring Security configuration -->
|
||||
<security:http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
|
||||
<!-- Spring Security configuration -->
|
||||
|
||||
<oauth:resource-server id="resourceServerFilter"
|
||||
token-services-ref="defaultOAuth2ProviderTokenService" />
|
||||
|
||||
<security:http pattern="/oauth/token" create-session="stateless"
|
||||
authentication-manager-ref="clientAuthenticationManager"
|
||||
entry-point-ref="oauthAuthenticationEntryPoint">
|
||||
<security:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
|
||||
<security:intercept-url pattern="/oauth/token"
|
||||
access="IS_AUTHENTICATED_FULLY" />
|
||||
<security:anonymous enabled="false" />
|
||||
<security:http-basic entry-point-ref="oauthAuthenticationEntryPoint" />
|
||||
<!-- include this only if you need to authenticate clients via request parameters -->
|
||||
<security:custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
|
||||
<!-- include this only if you need to authenticate clients via request
|
||||
parameters -->
|
||||
<security:custom-filter ref="clientCredentialsTokenEndpointFilter"
|
||||
before="BASIC_AUTH_FILTER" />
|
||||
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
|
||||
</security:http>
|
||||
|
||||
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
|
||||
<bean id="oauthAuthenticationEntryPoint"
|
||||
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
|
||||
<property name="realmName" value="openidconnect" />
|
||||
</bean>
|
||||
|
||||
|
@ -58,37 +68,46 @@
|
|||
<oauth:authorization-code authorization-code-services-ref="authCodeServices" />
|
||||
</oauth:authorization-server>
|
||||
|
||||
<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
|
||||
<bean id="oauthAccessDeniedHandler"
|
||||
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
|
||||
|
||||
<bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
|
||||
<bean id="clientCredentialsTokenEndpointFilter"
|
||||
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
|
||||
<property name="authenticationManager" ref="clientAuthenticationManager" />
|
||||
</bean>
|
||||
|
||||
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
|
||||
<authentication-manager id="clientAuthenticationManager"
|
||||
xmlns="http://www.springframework.org/schema/security">
|
||||
<authentication-provider user-service-ref="clientUserDetailsService" />
|
||||
</authentication-manager>
|
||||
|
||||
<bean id="authorizationRequestFactory" class="org.springframework.security.oauth2.provider.DefaultAuthorizationRequestFactory">
|
||||
<constructor-arg>
|
||||
<bean class="org.mitre.oauth2.service.impl.DefaultOAuth2ClientDetailsEntityService"/>
|
||||
<bean
|
||||
class="org.mitre.oauth2.service.impl.DefaultOAuth2ClientDetailsEntityService" />
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler" id="userApprovalHandler">
|
||||
<property name="tokenServices" ref="defaultOAuth2ProviderTokenService"/>
|
||||
</bean>
|
||||
|
||||
<bean id="authCodeServices" class="org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices"/>
|
||||
<bean
|
||||
class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler"
|
||||
id="userApprovalHandler">
|
||||
<property name="tokenServices" ref="defaultOAuth2ProviderTokenService" />
|
||||
</bean>
|
||||
|
||||
<bean id="authCodeServices"
|
||||
class="org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices" />
|
||||
|
||||
<!-- user services -->
|
||||
<import resource="user-context.xml" />
|
||||
|
||||
<!-- End Spring Security configuration -->
|
||||
|
||||
<!-- JPA -->
|
||||
|
||||
<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
|
||||
<property name="databasePlatform" value="org.eclipse.persistence.platform.database.MySQLPlatform" />
|
||||
<!-- End Spring Security configuration -->
|
||||
|
||||
<!-- JPA -->
|
||||
|
||||
<bean id="jpaAdapter"
|
||||
class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
|
||||
<property name="databasePlatform"
|
||||
value="org.eclipse.persistence.platform.database.MySQLPlatform" />
|
||||
<property name="showSql" value="true" />
|
||||
</bean>
|
||||
|
||||
|
@ -100,7 +119,7 @@
|
|||
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
|
||||
<property name="persistenceUnitName" value="openidPersistenceUnit" />
|
||||
<property name="dataSource" ref="dataSource" />
|
||||
<property name="jpaVendorAdapter" ref="jpaAdapter" />
|
||||
<property name="jpaVendorAdapter" ref="jpaAdapter" />
|
||||
<property name="jpaPropertyMap">
|
||||
<map>
|
||||
<entry key="eclipselink.weaving" value="false" />
|
||||
|
@ -110,16 +129,17 @@
|
|||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- End JPA -->
|
||||
<!-- End JPA -->
|
||||
|
||||
<!-- Crypto -->
|
||||
|
||||
<!-- Crypto -->
|
||||
|
||||
<bean id="defaultKeystore" class="org.mitre.jwt.signer.service.impl.KeyStore">
|
||||
<constructor-arg name="location" value="classpath:keystore.jks" />
|
||||
<constructor-arg name="password" value="changeit" />
|
||||
</bean>
|
||||
|
||||
<bean id="defaultsignerService" class="org.mitre.jwt.signer.service.impl.JwtSigningAndValidationServiceDefault">
|
||||
<bean id="defaultsignerService"
|
||||
class="org.mitre.jwt.signer.service.impl.JwtSigningAndValidationServiceDefault">
|
||||
<property name="signers">
|
||||
<map>
|
||||
<entry key="rsa1">
|
||||
|
@ -137,49 +157,77 @@
|
|||
</bean>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- End Crypto -->
|
||||
<!-- End Crypto -->
|
||||
|
||||
<!-- View configuration -->
|
||||
<!-- View configuration -->
|
||||
|
||||
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
|
||||
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
|
||||
up static resources in the ${webappRoot}/resources directory -->
|
||||
<mvc:resources mapping="/resources/**" location="/resources/" />
|
||||
|
||||
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
|
||||
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
|
||||
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
|
||||
<!-- Resolves views selected for rendering by @Controllers to .jsp resources
|
||||
in the /WEB-INF/views directory -->
|
||||
<bean
|
||||
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
|
||||
<property name="viewClass"
|
||||
value="org.springframework.web.servlet.view.JstlView" />
|
||||
<property name="prefix" value="/WEB-INF/views/" />
|
||||
<property name="suffix" value=".jsp" />
|
||||
<property name="order" value="2"/>
|
||||
<property name="order" value="2" />
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- Resolve views based on string names -->
|
||||
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" >
|
||||
<property name="order" value="1"/>
|
||||
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
|
||||
<property name="order" value="1" />
|
||||
</bean>
|
||||
|
||||
<!-- Map our custom exception classes to named views -->
|
||||
<!-- <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> -->
|
||||
<!-- <property name="exceptionMappings"> -->
|
||||
<!-- </property> -->
|
||||
<!-- </bean> -->
|
||||
<!-- <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> -->
|
||||
<!-- <property name="exceptionMappings"> -->
|
||||
<!-- </property> -->
|
||||
<!-- </bean> -->
|
||||
|
||||
<!-- JSON views for each type of model object -->
|
||||
|
||||
<bean id="jsonOpenIdConfigurationView" class="org.mitre.swd.view.JsonOpenIdConfigurationView" />
|
||||
<bean id="jsonSwdResponseView" class="org.mitre.swd.view.SwdResponse" />
|
||||
<bean id="jwkKeyList" class="org.mitre.openid.connect.view.JwkKeyListView" />
|
||||
<bean id="jsonXrdResponseView" class="org.mitre.swd.view.XrdJsonResponse" />
|
||||
|
||||
<bean id="jsonUserInfoView" class="org.mitre.openid.connect.view.JSONUserInfoView"/>
|
||||
<bean id="jsonIdTokenView" class="org.mitre.openid.connect.view.JSONIdTokenView"/>
|
||||
<bean id="jsonClientView" class="org.mitre.openid.connect.view.JSONClientView" />
|
||||
<bean id="jwkKeyList" class="org.mitre.openid.connect.view.JwkKeyListView" />
|
||||
|
||||
<!-- End view configuration -->
|
||||
<bean id="jsonUserInfoView" class="org.mitre.openid.connect.view.JSONUserInfoView" />
|
||||
<bean id="pocoUserInfoView" class="org.mitre.openid.connect.view.POCOUserInfoView" />
|
||||
<bean id="jsonIdTokenView" class="org.mitre.openid.connect.view.JSONIdTokenView" />
|
||||
<bean id="jsonClientView" class="org.mitre.openid.connect.view.JSONClientView" />
|
||||
|
||||
<bean name="exceptionAsJSONView" class="org.mitre.openid.connect.view.ExceptionAsJSONView" />
|
||||
|
||||
<bean
|
||||
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
|
||||
<property name="exceptionMappings">
|
||||
<props>
|
||||
<prop key="org.mitre.openid.connect.web.InvalidJwtSignatureException">
|
||||
exceptionAsJSONView
|
||||
</prop>
|
||||
<prop key="org.mitre.openid.connect.web.ExpiredTokenException">
|
||||
exceptionAsJSONView
|
||||
</prop>
|
||||
<prop key="org.mitre.openid.connect.web.InvalidJwtIssuerException">
|
||||
exceptionAsJSONView
|
||||
</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- End view configuration -->
|
||||
|
||||
<!-- scheduled tasks -->
|
||||
<!-- <task:scheduler id="taskScheduler" pool-size="10" /> -->
|
||||
<!-- <task:executor id="taskExecutor" pool-size="5" /> -->
|
||||
<!-- <task:annotation-driven scheduler="taskScheduler" executor="taskExecutor" /> -->
|
||||
<!-- <task:scheduler id="taskScheduler" pool-size="10" /> -->
|
||||
<!-- <task:executor id="taskExecutor" pool-size="5" /> -->
|
||||
<!-- <task:annotation-driven scheduler="taskScheduler" executor="taskExecutor"
|
||||
/> -->
|
||||
|
||||
</beans>
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
<security:http auto-config="true" disable-url-rewriting="true"> <!-- authentication-manager-ref="springSecurityAuthenticationManager" -->
|
||||
<security:intercept-url pattern="/oauth/**" access="ROLE_USER" />
|
||||
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
|
||||
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
|
||||
<security:anonymous />
|
||||
</security:http>
|
||||
|
||||
|
|
|
@ -21,14 +21,56 @@
|
|||
|
||||
<authz:authorize ifAnyGranted="ROLE_USER">
|
||||
|
||||
<div class="hero-unit" style="text-align:center">
|
||||
<h1>Please Confirm!</h1>
|
||||
<div class="well" style="text-align:center">
|
||||
<h1>Approve New Site</h1>
|
||||
|
||||
<p>I hereby authorize "<c:out value="${client.clientId}"/>" to access my protected resources.</p>
|
||||
<form name="confirmationForm" style="display:inline" action="<%=request.getContextPath()%>/oauth/authorize"
|
||||
method="post">
|
||||
<div class="row">
|
||||
<div class="span4 offset2 well-small" style="text-align:left">Do you authorize
|
||||
"<c:choose>
|
||||
<c:when test="${empty client.clientName}">
|
||||
<c:out value="${client.clientId}"/>
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:out value="${client.clientName}"/>
|
||||
</c:otherwise>
|
||||
</c:choose>" to sign you into their site
|
||||
using your identity?
|
||||
<a class="small" href="#" onclick="$('#description').toggle('fast')">more information</a>
|
||||
|
||||
<p>
|
||||
<blockquote id="description" style="display: none">
|
||||
<c:choose>
|
||||
<c:when test="${empty client.clientDescription}">
|
||||
No additional information available.
|
||||
</c:when>
|
||||
<c:otherwise>
|
||||
<c:out value="${client.clientDescription}"/>
|
||||
</c:otherwise>
|
||||
</c:choose>
|
||||
|
||||
</blockquote>
|
||||
</p>
|
||||
</div>
|
||||
<div class="span4">
|
||||
<fieldset style="text-align:left" class="well">
|
||||
<legend style="margin-bottom: 0;">Access to:</legend>
|
||||
<label for="option1"></label>
|
||||
<input type="checkbox" name="option1" id="option1" checked="checked"> basic profile information
|
||||
<label for="option2"></label>
|
||||
<input type="checkbox" name="option1" id="option2" checked="checked"> email address
|
||||
<label for="option3"></label>
|
||||
<input type="checkbox" name="option3" id="option3" checked="checked"> address
|
||||
<label for="option4"></label>
|
||||
<input type="checkbox" name="option4" id="option4" checked="checked"> phone number
|
||||
<label for="option5"></label>
|
||||
<input type="checkbox" name="option5" id="option5" checked="checked"> offline access
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<form name="confirmationForm" style="display:inline" action="<%=request.getContextPath()%>/oauth/authorize" method="post">
|
||||
|
||||
<div class="row">
|
||||
<input id="user_oauth_approval" name="user_oauth_approval" value="true" type="hidden"/>
|
||||
|
@ -39,18 +81,8 @@
|
|||
<input name="deny" value="Deny" type="submit" onclick="$('#user_oauth_approval').attr('value',false)"
|
||||
class="btn btn-secondary btn-large"/>
|
||||
</div>
|
||||
<div class="row control-group">
|
||||
<label for="option1"></label>
|
||||
<input name="option1" id="option1" type="checkbox"> Check me out
|
||||
|
||||
<label for="option2"></label>
|
||||
<input name="option2" id="option2" type="checkbox"> Check me out
|
||||
|
||||
</div>
|
||||
</form>
|
||||
<div>
|
||||
<a href="#" class="small">learn more</a>
|
||||
</div>
|
||||
|
||||
</authz:authorize>
|
||||
|
||||
|
|
|
@ -18,15 +18,15 @@
|
|||
|
||||
validate:{
|
||||
clientName:{
|
||||
required:true,
|
||||
/* required:true,
|
||||
pattern:/^[\w ]+$/,
|
||||
minlength:3,
|
||||
minlength:3,*/
|
||||
maxlength:100
|
||||
},
|
||||
clientDescription:{
|
||||
required:true,
|
||||
/*required:true,
|
||||
pattern:/^[\w ]+$/,
|
||||
minlength:3,
|
||||
minlength:3,*/
|
||||
maxlength:200
|
||||
},
|
||||
accessTokenTimeout: {
|
||||
|
@ -44,14 +44,15 @@
|
|||
|
||||
validateURI: function(attributeName, attributeValue) {
|
||||
|
||||
var expression = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi;
|
||||
var expression = /^(?:([a-z0-9+.-]+:\/\/)((?:(?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*)(:(?:\d*))?(\/(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?|([a-z0-9+.-]+:)(\/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})+(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?)(\?(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?(#(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?$/i;
|
||||
var regex = new RegExp(expression);
|
||||
|
||||
if (!attributeValue.every(function (url) {
|
||||
if (url.match(regex)) {
|
||||
return true;
|
||||
|
||||
for (var i in attributeValue) {
|
||||
if (!attributeValue[i].match(regex)) {
|
||||
return "Invalid URI";
|
||||
}
|
||||
})) return "Invalid URI";
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
@ -59,9 +60,10 @@
|
|||
// We can pass it default values.
|
||||
defaults:{
|
||||
clientName:"",
|
||||
clientSecret:"",
|
||||
registeredRedirectUri:[""],
|
||||
authorizedGrantTypes:[],
|
||||
scope:[""],
|
||||
scope:["openid"],
|
||||
authorities:[],
|
||||
clientDescription:"",
|
||||
clientId:null,
|
||||
|
@ -114,19 +116,22 @@
|
|||
|
||||
deleteClient:function () {
|
||||
|
||||
var self = this;
|
||||
if (confirm("Are you sure sure you would like to delete this client?")) {
|
||||
var self = this;
|
||||
|
||||
this.model.destroy({
|
||||
success:function () {
|
||||
self.$el.fadeTo("fast", 0.00, function(){ //fade
|
||||
$(this).slideUp("fast", function() { //slide up
|
||||
$(this).remove(); //then remove from the DOM
|
||||
this.model.destroy({
|
||||
success:function () {
|
||||
self.$el.fadeTo("fast", 0.00, function () { //fade
|
||||
$(this).slideUp("fast", function () { //slide up
|
||||
$(this).remove(); //then remove from the DOM
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.clientListView.delegateEvents();
|
||||
}
|
||||
|
||||
app.clientListView.delegateEvents();
|
||||
return false;
|
||||
},
|
||||
|
||||
|
@ -185,8 +190,9 @@
|
|||
|
||||
$('.control-group').removeClass('error');
|
||||
|
||||
this.model.set({
|
||||
var valid = this.model.set({
|
||||
clientName:$('#clientName input').val(),
|
||||
clientSecret:$('#clientSecret input').val(),
|
||||
registeredRedirectUri:$.trim($('#registeredRedirectUri textarea').val()).replace(/ /g,'').split("\n"),
|
||||
clientDescription:$('#clientDescription textarea').val(),
|
||||
allowRefresh:$('#allowRefresh').is(':checked'),
|
||||
|
@ -195,26 +201,28 @@
|
|||
scope:$.map($('#scope textarea').val().replace(/,$/,'').replace(/\s/g,' ').split(","), $.trim)
|
||||
});
|
||||
|
||||
this.model.save(this.model, {
|
||||
success:function () {
|
||||
app.navigate('clients', {trigger: true});
|
||||
},
|
||||
error:function() {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
if (this.model.isNew() && this.model.isValid()) {
|
||||
var self = this;
|
||||
app.clientList.create(this.model, {
|
||||
if (valid) {
|
||||
this.model.save(this.model, {
|
||||
success:function () {
|
||||
app.navigate('clients', {trigger: true});
|
||||
app.navigate('clients', {trigger:true});
|
||||
},
|
||||
error:function() {
|
||||
error:function () {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
if (this.model.isNew()) {
|
||||
var self = this;
|
||||
app.clientList.create(this.model, {
|
||||
success:function () {
|
||||
app.navigate('clients', {trigger:true});
|
||||
},
|
||||
error:function () {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
<script type="text/html" id="tmpl-client">
|
||||
<td>
|
||||
<%=clientId%>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<%=clientName%>
|
||||
|
@ -30,9 +33,7 @@
|
|||
<% } %>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<%=authorities[0]%>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<%=clientDescription%>
|
||||
</td>
|
||||
|
@ -57,11 +58,11 @@
|
|||
<table id="client-table" class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Name</th>
|
||||
<th>Redirect URI(s)</th>
|
||||
<th>Grant Types</th>
|
||||
<th>Scope</th>
|
||||
<th>Authority</th>
|
||||
<th>Description</th>
|
||||
<th>Refresh Tokens</th>
|
||||
<th class="span1"></th>
|
||||
|
@ -86,7 +87,7 @@
|
|||
<div class="">
|
||||
<form>
|
||||
<fieldset>
|
||||
<legend>Details</legend>
|
||||
<legend>Details <%=(clientId != null ? 'for ' + clientId : '')%></legend>
|
||||
|
||||
<div class="well">
|
||||
|
||||
|
@ -94,20 +95,22 @@
|
|||
<div class="span6">
|
||||
<span class="control-group" id="clientName">
|
||||
<label>Client name</label>
|
||||
<input value="<%=clientName%>" type="text" class="" placeholder="Type something"> <span class="help-inline">This must be more than three characters and can only be alpha-numeric </span>
|
||||
<input value="<%=clientName%>" maxlength="100" type="text" class="" placeholder="Type something"> <span class="help-inline"></span>
|
||||
</span>
|
||||
<span class="control-group" id="registeredRedirectUri">
|
||||
<label>Redirect URI(s)</label>
|
||||
<textarea class="input-xlarge" placeholder="http://"
|
||||
rows="3"><% for (var i in registeredRedirectUri) { %><%=registeredRedirectUri[i]+"\n"%><% } %></textarea> <span class="help-inline">You may enter multiple URLs separated by a new lines</span>
|
||||
rows="3"><% for (var i in registeredRedirectUri) { %><%=registeredRedirectUri[i]+"\n"%><% } %></textarea> <span class="help-inline">You may enter multiple URIs separated by a new lines</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<span class="control-group" id="clientDescription">
|
||||
<label>Description</label>
|
||||
<textarea class="input-xlarge" placeholder="Type a description"
|
||||
rows="3"><%=clientDescription%></textarea> <span class="help-inline">This must be more than three characters and can only be alpha-numeric</span>
|
||||
<textarea class="input-xlarge" placeholder="Type a description" maxlength="200"
|
||||
rows="3"><%=clientDescription%></textarea> <span class="help-inline"></span>
|
||||
</span>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -129,51 +132,23 @@
|
|||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span4 control-group">
|
||||
<div class="span4 control-group" id="scope">
|
||||
|
||||
<label class="control-label">Grant Types</label>
|
||||
<label class="control-label">Scope</label>
|
||||
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="grant-type-checkbox-list1" value="option1">
|
||||
Option one
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="grant-type-checkbox-list2" value="option2">
|
||||
Option two
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="grant-type-checkbox-list3" value="option3">
|
||||
Option three
|
||||
</label>
|
||||
|
||||
<p class="help-block"><strong>Note:</strong> Labels surround all the options for
|
||||
much larger click areas and a more usable form.</p>
|
||||
</div>
|
||||
<textarea rows="3" class="xlarge" placeholder="openid"
|
||||
id="textarea2" name="textarea2"><% for (var i in scope) { %><%=scope[i]+","%><% }%></textarea>
|
||||
<span class="help-block">
|
||||
Please enter scopes separated by commas
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="span4 control-group">
|
||||
<div class="span4 control-group" id="clientSecret">
|
||||
|
||||
<label class="control-label">Auth Types</label>
|
||||
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="auth-type-checkbox-list1" value="option1">
|
||||
Option one
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="auth-type-checkbox-list2" value="option2">
|
||||
Option two
|
||||
</label>
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="auth-type-checkbox-list3" value="option3">
|
||||
Option three
|
||||
</label>
|
||||
|
||||
<p class="help-block"><strong>Note:</strong> Labels surround all the options for
|
||||
much larger click areas and a more usable form.</p>
|
||||
</div>
|
||||
<label>Client Secret</label>
|
||||
<input value="<%=clientSecret%>" maxlength="100" type="text" class=""
|
||||
placeholder="Type a secret"> <span class="help-inline">If you leave this blank a client secret will be generated for you automatically.</span>
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -187,7 +162,7 @@
|
|||
<input type="text" class="" value="<%=accessTokenTimeout%>" id="access-token-timeout-seconds" size="16"><span
|
||||
class="add-on">seconds</span>
|
||||
</div>
|
||||
<span class="help-inline">Here's more help text</span>
|
||||
<span class="help-inline">Enter this time in seconds</span>
|
||||
</div>
|
||||
</span>
|
||||
<span class="control-group" id="refreshTokenTimeout">
|
||||
|
@ -199,25 +174,11 @@
|
|||
<input type="text" class="" value="<%=refreshTokenTimeout%>" id="refresh-token-timeout-seconds" size="16"><span
|
||||
class="add-on">seconds</span>
|
||||
</div>
|
||||
<span class="help-inline">Here's more help text</span>
|
||||
<span class="help-inline">Enter this time in seconds</span>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="scope" class="span12 control-group">
|
||||
<label for="textarea2">Scope</label>
|
||||
|
||||
<div class="input">
|
||||
<textarea rows="3" class="xlarge span10" placeholder="email,first name, last name"
|
||||
id="textarea2" name="textarea2"><% for (var i in scope) { %><%=scope[i]+","%><% } %></textarea>
|
||||
<span class="help-block">
|
||||
Please enter scopes separated by commas
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
|
|
@ -12,19 +12,19 @@
|
|||
<property name="scriptLocations" >
|
||||
<list>
|
||||
<!-- OpenID Connect Data model -->
|
||||
<value>file:src/main/webapp/db/tables/accesstoken.sql</value>
|
||||
<value>file:src/main/webapp/db/tables/address.sql</value>
|
||||
<value>file:src/main/webapp/db/tables/approvedsite.sql</value>
|
||||
<value>file:src/main/webapp/db/tables/authorities.sql</value>
|
||||
<value>file:src/main/webapp/db/tables/clientdetails.sql</value>
|
||||
<value>file:src/main/webapp/db/tables/event.sql</value>
|
||||
<value>file:src/main/webapp/db/tables/granttypes.sql</value>
|
||||
<value>file:src/main/webapp/db/tables/idtoken.sql</value>
|
||||
<value>file:src/main/webapp/db/tables/idtokenclaims.sql</value>
|
||||
<value>file:src/main/webapp/db/tables/refreshtoken.sql</value>
|
||||
<value>file:src/main/webapp/db/tables/scope.sql</value>
|
||||
<value>file:src/main/webapp/db/tables/userinfo.sql</value>
|
||||
<value>file:src/main/webapp/db/tables/whitelistedsite.sql</value>
|
||||
<value>file:db/tables/accesstoken.sql</value>
|
||||
<value>file:db/tables/address.sql</value>
|
||||
<value>file:db/tables/approvedsite.sql</value>
|
||||
<value>file:db/tables/authorities.sql</value>
|
||||
<value>file:db/tables/clientdetails.sql</value>
|
||||
<value>file:db/tables/event.sql</value>
|
||||
<value>file:db/tables/granttypes.sql</value>
|
||||
<value>file:db/tables/idtoken.sql</value>
|
||||
<value>file:db/tables/idtokenclaims.sql</value>
|
||||
<value>file:db/tables/refreshtoken.sql</value>
|
||||
<value>file:db/tables/scope.sql</value>
|
||||
<value>file:db/tables/userinfo.sql</value>
|
||||
<value>file:db/tables/whitelistedsite.sql</value>
|
||||
<!-- Preloaded data -->
|
||||
<value>classpath:test-data.sql</value>
|
||||
</list>
|
||||
|
|
Loading…
Reference in New Issue