Removed unnecessary modules

pull/1580/head
Dominik František Bučík 2020-05-29 10:36:52 +02:00 committed by Dominik Frantisek Bucik
parent c8ddea070e
commit f963790943
No known key found for this signature in database
GPG Key ID: 25014C8DB2E7E62D
226 changed files with 0 additions and 12446 deletions

View File

@ -1,12 +0,0 @@
local-values.conf
target
*~
bin
*.idea
*.iml
*.eml
.project
.settings
.classpath
/target
.springBeans

View File

@ -1,12 +0,0 @@
# OpenID Connect Client #
## Overview ##
This project contains an OpenID Connect Client implemented as a Spring Security AuthenticationFilter. The client facilitates a user's authentication into the secured application to an OpenID Connect Server following the OpenID Connect standard protocol.
## Configuring ##
For an example of the Client configuration, see the [Simple Web App](https://github.com/mitreid-connect/simple-web-app) project.
Full documentation is available on the [project documentation wiki pages](https://github.com/mitreid-connect/OpenID-Connect-Java-Spring-Server/wiki/Client-configuration).

View File

@ -1,76 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2018 The MIT Internet Trust Consortium
Portions copyright 2011-2013 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>openid-connect-parent</artifactId>
<groupId>org.mitre</groupId>
<version>1.3.4-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>openid-connect-client</artifactId>
<description>OpenID Connect Client filter for Spring Security</description>
<name>OpenID Connect Client</name>
<dependencies>
<dependency>
<groupId>org.mitre</groupId>
<artifactId>openid-connect-common</artifactId>
</dependency>
</dependencies>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
</configuration>
</plugin>
<!-- BUILD SOURCE FILES -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- BUILD JavaDoc FILES -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,3 +0,0 @@
Manifest-Version: 1.0
Class-Path:

View File

@ -1,392 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.oauth2.introspectingfilter;
import static org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod.SECRET_BASIC;
import java.io.IOException;
import java.net.URI;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.mitre.oauth2.introspectingfilter.service.IntrospectionAuthorityGranter;
import org.mitre.oauth2.introspectingfilter.service.IntrospectionConfigurationService;
import org.mitre.oauth2.introspectingfilter.service.impl.SimpleIntrospectionAuthorityGranter;
import org.mitre.oauth2.model.RegisteredClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.nimbusds.jose.util.Base64;
/**
* This ResourceServerTokenServices implementation introspects incoming tokens at a
* server's introspection endpoint URL and passes an Authentication object along
* based on the response from the introspection endpoint.
* @author jricher
*
*/
public class IntrospectingTokenService implements ResourceServerTokenServices {
private IntrospectionConfigurationService introspectionConfigurationService;
private IntrospectionAuthorityGranter introspectionAuthorityGranter = new SimpleIntrospectionAuthorityGranter();
private int defaultExpireTime = 300000; // 5 minutes in milliseconds
private boolean forceCacheExpireTime = false; // force removal of cached tokens based on default expire time
private boolean cacheNonExpiringTokens = false;
private boolean cacheTokens = true;
private HttpComponentsClientHttpRequestFactory factory;
public IntrospectingTokenService() {
this(HttpClientBuilder.create().useSystemProperties().build());
}
public IntrospectingTokenService(HttpClient httpClient) {
this.factory = new HttpComponentsClientHttpRequestFactory(httpClient);
}
// Inner class to store in the hash map
private class TokenCacheObject {
OAuth2AccessToken token;
OAuth2Authentication auth;
Date cacheExpire;
private TokenCacheObject(OAuth2AccessToken token, OAuth2Authentication auth) {
this.token = token;
this.auth = auth;
// we don't need to check the cacheTokens values, because this won't actually be added to the cache if cacheTokens is false
// if the token isn't null we use the token expire time
// if forceCacheExpireTime is also true, we also make sure that the token expire time is shorter than the default expire time
if ((this.token.getExpiration() != null) && (!forceCacheExpireTime || (forceCacheExpireTime && (this.token.getExpiration().getTime() - System.currentTimeMillis() <= defaultExpireTime)))) {
this.cacheExpire = this.token.getExpiration();
} else { // if the token doesn't have an expire time, or if the using forceCacheExpireTime the token expire time is longer than the default, then use the default expire time
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MILLISECOND, defaultExpireTime);
this.cacheExpire = cal.getTime();
}
}
}
private Map<String, TokenCacheObject> authCache = new HashMap<>();
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(IntrospectingTokenService.class);
/**
* @return the introspectionConfigurationService
*/
public IntrospectionConfigurationService getIntrospectionConfigurationService() {
return introspectionConfigurationService;
}
/**
* @param introspectionConfigurationService the introspectionConfigurationService to set
*/
public void setIntrospectionConfigurationService(IntrospectionConfigurationService introspectionUrlProvider) {
this.introspectionConfigurationService = introspectionUrlProvider;
}
/**
* @param introspectionAuthorityGranter the introspectionAuthorityGranter to set
*/
public void setIntrospectionAuthorityGranter(IntrospectionAuthorityGranter introspectionAuthorityGranter) {
this.introspectionAuthorityGranter = introspectionAuthorityGranter;
}
/**
* @return the introspectionAuthorityGranter
*/
public IntrospectionAuthorityGranter getIntrospectionAuthorityGranter() {
return introspectionAuthorityGranter;
}
/**
* get the default cache expire time in milliseconds
* @return
*/
public int getDefaultExpireTime() {
return defaultExpireTime;
}
/**
* set the default cache expire time in milliseconds
* @param defaultExpireTime
*/
public void setDefaultExpireTime(int defaultExpireTime) {
this.defaultExpireTime = defaultExpireTime;
}
/**
* check if forcing a cache expire time maximum value
* @return the forceCacheExpireTime setting
*/
public boolean isForceCacheExpireTime() {
return forceCacheExpireTime;
}
/**
* set forcing a cache expire time maximum value
* @param forceCacheExpireTime
*/
public void setForceCacheExpireTime(boolean forceCacheExpireTime) {
this.forceCacheExpireTime = forceCacheExpireTime;
}
/**
* Are non-expiring tokens cached using the default cache time
* @return state of cacheNonExpiringTokens
*/
public boolean isCacheNonExpiringTokens() {
return cacheNonExpiringTokens;
}
/**
* should non-expiring tokens be cached using the default cache timeout
* @param cacheNonExpiringTokens
*/
public void setCacheNonExpiringTokens(boolean cacheNonExpiringTokens) {
this.cacheNonExpiringTokens = cacheNonExpiringTokens;
}
/**
* Is the service caching tokens, or is it hitting the introspection end point every time
* @return true is caching tokens locally, false hits the introspection end point every time
*/
public boolean isCacheTokens() {
return cacheTokens;
}
/**
* Configure if the client should cache tokens locally or not
* @param cacheTokens
*/
public void setCacheTokens(boolean cacheTokens) {
this.cacheTokens = cacheTokens;
}
/**
* Check to see if the introspection end point response for a token has been cached locally
* This call will return the token if it has been cached and is still valid according to
* the cache expire time on the TokenCacheObject. If a cached value has been found but is
* expired, either by default expire times or the token's own expire time, then the token is
* removed from the cache and null is returned.
* @param key is the token to check
* @return the cached TokenCacheObject or null
*/
private TokenCacheObject checkCache(String key) {
if (cacheTokens && authCache.containsKey(key)) {
TokenCacheObject tco = authCache.get(key);
if (tco != null && tco.cacheExpire != null && tco.cacheExpire.after(new Date())) {
return tco;
} else {
// if the token is expired, don't keep things around.
authCache.remove(key);
}
}
return null;
}
private OAuth2Request createStoredRequest(final JsonObject token) {
String clientId = token.get("client_id").getAsString();
Set<String> scopes = new HashSet<>();
if (token.has("scope")) {
scopes.addAll(OAuth2Utils.parseParameterList(token.get("scope").getAsString()));
}
Map<String, String> parameters = new HashMap<>();
parameters.put("client_id", clientId);
parameters.put("scope", OAuth2Utils.formatParameterList(scopes));
OAuth2Request storedRequest = new OAuth2Request(parameters, clientId, null, true, scopes, null, null, null, null);
return storedRequest;
}
private Authentication createUserAuthentication(JsonObject token) {
JsonElement userId = token.get("user_id");
if(userId == null) {
userId = token.get("sub");
if (userId == null) {
return null;
}
}
return new PreAuthenticatedAuthenticationToken(userId.getAsString(), token, introspectionAuthorityGranter.getAuthorities(token));
}
private OAuth2AccessToken createAccessToken(final JsonObject token, final String tokenString) {
OAuth2AccessToken accessToken = new OAuth2AccessTokenImpl(token, tokenString);
return accessToken;
}
/**
* Validate a token string against the introspection endpoint,
* then parse it and store it in the local cache if caching is enabled.
*
* @param accessToken Token to pass to the introspection endpoint
* @return TokenCacheObject containing authentication and token if the token was valid, otherwise null
*/
private TokenCacheObject parseToken(String accessToken) {
// find out which URL to ask
String introspectionUrl;
RegisteredClient client;
try {
introspectionUrl = introspectionConfigurationService.getIntrospectionUrl(accessToken);
client = introspectionConfigurationService.getClientConfiguration(accessToken);
} catch (IllegalArgumentException e) {
logger.error("Unable to load introspection URL or client configuration", e);
return null;
}
// Use the SpringFramework RestTemplate to send the request to the
// endpoint
String validatedToken = null;
RestTemplate restTemplate;
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
final String clientId = client.getClientId();
final String clientSecret = client.getClientSecret();
if (SECRET_BASIC.equals(client.getTokenEndpointAuthMethod())){
// use BASIC auth if configured to do so
restTemplate = new RestTemplate(factory) {
@Override
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
ClientHttpRequest httpRequest = super.createRequest(url, method);
httpRequest.getHeaders().add("Authorization",
String.format("Basic %s", Base64.encode(String.format("%s:%s", clientId, clientSecret)) ));
return httpRequest;
}
};
} else { //Alternatively use form based auth
restTemplate = new RestTemplate(factory);
form.add("client_id", clientId);
form.add("client_secret", clientSecret);
}
form.add("token", accessToken);
try {
validatedToken = restTemplate.postForObject(introspectionUrl, form, String.class);
} catch (RestClientException rce) {
logger.error("validateToken", rce);
return null;
}
if (validatedToken != null) {
// parse the json
JsonElement jsonRoot = new JsonParser().parse(validatedToken);
if (!jsonRoot.isJsonObject()) {
return null; // didn't get a proper JSON object
}
JsonObject tokenResponse = jsonRoot.getAsJsonObject();
if (tokenResponse.get("error") != null) {
// report an error?
logger.error("Got an error back: " + tokenResponse.get("error") + ", " + tokenResponse.get("error_description"));
return null;
}
if (!tokenResponse.get("active").getAsBoolean()) {
// non-valid token
logger.info("Server returned non-active token");
return null;
}
// create an OAuth2Authentication
OAuth2Authentication auth = new OAuth2Authentication(createStoredRequest(tokenResponse), createUserAuthentication(tokenResponse));
// create an OAuth2AccessToken
OAuth2AccessToken token = createAccessToken(tokenResponse, accessToken);
if (token.getExpiration() == null || token.getExpiration().after(new Date())) {
// Store them in the cache
TokenCacheObject tco = new TokenCacheObject(token, auth);
if (cacheTokens && (cacheNonExpiringTokens || token.getExpiration() != null)) {
authCache.put(accessToken, tco);
}
return tco;
}
}
// when the token is invalid for whatever reason
return null;
}
@Override
public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException {
// First check if the in memory cache has an Authentication object, and
// that it is still valid
// If Valid, return it
TokenCacheObject cacheAuth = checkCache(accessToken);
if (cacheAuth != null) {
return cacheAuth.auth;
} else {
cacheAuth = parseToken(accessToken);
if (cacheAuth != null) {
return cacheAuth.auth;
} else {
return null;
}
}
}
@Override
public OAuth2AccessToken readAccessToken(String accessToken) {
// First check if the in memory cache has a Token object, and that it is
// still valid
// If Valid, return it
TokenCacheObject cacheAuth = checkCache(accessToken);
if (cacheAuth != null) {
return cacheAuth.token;
} else {
cacheAuth = parseToken(accessToken);
if (cacheAuth != null) {
return cacheAuth.token;
} else {
return null;
}
}
}
}

View File

@ -1,117 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.oauth2.introspectingfilter;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import com.google.common.base.Splitter;
import com.google.common.collect.Sets;
import com.google.gson.JsonObject;
public class OAuth2AccessTokenImpl implements OAuth2AccessToken {
private JsonObject introspectionResponse;
private String tokenString;
private Set<String> scopes = new HashSet<>();
private Date expireDate;
public OAuth2AccessTokenImpl(JsonObject introspectionResponse, String tokenString) {
this.setIntrospectionResponse(introspectionResponse);
this.tokenString = tokenString;
if (introspectionResponse.get("scope") != null) {
scopes = Sets.newHashSet(Splitter.on(" ").split(introspectionResponse.get("scope").getAsString()));
}
if (introspectionResponse.get("exp") != null) {
expireDate = new Date(introspectionResponse.get("exp").getAsLong() * 1000L);
}
}
@Override
public Map<String, Object> getAdditionalInformation() {
return null;
}
@Override
public Set<String> getScope() {
return scopes;
}
@Override
public OAuth2RefreshToken getRefreshToken() {
return null;
}
@Override
public String getTokenType() {
return BEARER_TYPE;
}
@Override
public boolean isExpired() {
if (expireDate != null && expireDate.before(new Date())) {
return true;
}
return false;
}
@Override
public Date getExpiration() {
return expireDate;
}
@Override
public int getExpiresIn() {
if (expireDate != null) {
return (int)TimeUnit.MILLISECONDS.toSeconds(expireDate.getTime() - (new Date()).getTime());
}
return 0;
}
@Override
public String getValue() {
return tokenString;
}
/**
* @return the token
*/
public JsonObject getIntrospectionResponse() {
return introspectionResponse;
}
/**
* @param token the token to set
*/
public void setIntrospectionResponse(JsonObject token) {
this.introspectionResponse = token;
}
}

View File

@ -1,37 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.oauth2.introspectingfilter.service;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import com.google.gson.JsonObject;
/**
* @author jricher
*
*/
public interface IntrospectionAuthorityGranter {
public List<GrantedAuthority> getAuthorities(JsonObject introspectionResponse);
}

View File

@ -1,47 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.oauth2.introspectingfilter.service;
import org.mitre.oauth2.model.RegisteredClient;
/**
* @author jricher
*
*/
public interface IntrospectionConfigurationService {
/**
* Get the introspection URL based on the access token.
* @param accessToken
* @return
*/
public String getIntrospectionUrl(String accessToken);
/**
* Get the client configuration to use to connect to the
* introspection endpoint. In particular, this cares about
* the clientId, clientSecret, and tokenEndpointAuthMethod
* fields.
*/
public RegisteredClient getClientConfiguration(String accessToken);
}

View File

@ -1,132 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.oauth2.introspectingfilter.service.impl;
import java.text.ParseException;
import org.mitre.oauth2.introspectingfilter.service.IntrospectionConfigurationService;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.client.service.ClientConfigurationService;
import org.mitre.openid.connect.client.service.ServerConfigurationService;
import org.mitre.openid.connect.config.ServerConfiguration;
import com.google.common.base.Strings;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTParser;
/**
*
* Parses the incoming accesstoken as a JWT and determines the issuer based on
* the "iss" field inside the JWT. Uses the ServerConfigurationService to determine
* the introspection URL for that issuer.
*
* @author jricher
*
*/
public class JWTParsingIntrospectionConfigurationService implements IntrospectionConfigurationService {
private ServerConfigurationService serverConfigurationService;
private ClientConfigurationService clientConfigurationService;
/**
* @return the serverConfigurationService
*/
public ServerConfigurationService getServerConfigurationService() {
return serverConfigurationService;
}
/**
* @param serverConfigurationService the serverConfigurationService to set
*/
public void setServerConfigurationService(ServerConfigurationService serverConfigurationService) {
this.serverConfigurationService = serverConfigurationService;
}
/**
* @param clientConfigurationService the clientConfigurationService to set
*/
public void setClientConfigurationService(ClientConfigurationService clientConfigurationService) {
this.clientConfigurationService = clientConfigurationService;
}
private String getIssuer(String accessToken) {
try {
JWT jwt = JWTParser.parse(accessToken);
String issuer = jwt.getJWTClaimsSet().getIssuer();
return issuer;
} catch (ParseException e) {
throw new IllegalArgumentException("Unable to parse JWT", e);
}
}
/* (non-Javadoc)
* @see org.mitre.oauth2.introspectingfilter.IntrospectionConfigurationService#getIntrospectionUrl(java.lang.String)
*/
@Override
public String getIntrospectionUrl(String accessToken) {
String issuer = getIssuer(accessToken);
if (!Strings.isNullOrEmpty(issuer)) {
ServerConfiguration server = serverConfigurationService.getServerConfiguration(issuer);
if (server != null) {
if (!Strings.isNullOrEmpty(server.getIntrospectionEndpointUri())) {
return server.getIntrospectionEndpointUri();
} else {
throw new IllegalArgumentException("Server does not have Introspection Endpoint defined");
}
} else {
throw new IllegalArgumentException("Could not find server configuration for issuer " + issuer);
}
} else {
throw new IllegalArgumentException("No issuer claim found in JWT");
}
}
/* (non-Javadoc)
* @see org.mitre.oauth2.introspectingfilter.service.IntrospectionConfigurationService#getClientConfiguration(java.lang.String)
*/
@Override
public RegisteredClient getClientConfiguration(String accessToken) {
String issuer = getIssuer(accessToken);
if (!Strings.isNullOrEmpty(issuer)) {
ServerConfiguration server = serverConfigurationService.getServerConfiguration(issuer);
if (server != null) {
RegisteredClient client = clientConfigurationService.getClientConfiguration(server);
if (client != null) {
return client;
} else {
throw new IllegalArgumentException("Could not find client configuration for issuer " + issuer);
}
} else {
throw new IllegalArgumentException("Could not find server configuration for issuer " + issuer);
}
} else {
throw new IllegalArgumentException("No issuer claim found in JWT");
}
}
}

View File

@ -1,71 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT 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.oauth2.introspectingfilter.service.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.mitre.oauth2.introspectingfilter.service.IntrospectionAuthorityGranter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import com.google.gson.JsonObject;
/**
* @author jricher
*
*/
public class ScopeBasedIntrospectionAuthoritiesGranter implements IntrospectionAuthorityGranter {
private List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_API");
/* (non-Javadoc)
* @see org.mitre.oauth2.introspectingfilter.IntrospectionAuthorityGranter#getAuthorities(net.minidev.json.JSONObject)
*/
@Override
public List<GrantedAuthority> getAuthorities(JsonObject introspectionResponse) {
List<GrantedAuthority> auth = new ArrayList<>(getAuthorities());
if (introspectionResponse.has("scope") && introspectionResponse.get("scope").isJsonPrimitive()) {
String scopeString = introspectionResponse.get("scope").getAsString();
Set<String> scopes = OAuth2Utils.parseParameterList(scopeString);
for (String scope : scopes) {
auth.add(new SimpleGrantedAuthority("OAUTH_SCOPE_" + scope));
}
}
return auth;
}
/**
* @return the authorities
*/
public List<GrantedAuthority> getAuthorities() {
return authorities;
}
/**
* @param authorities the authorities to set
*/
public void setAuthorities(List<GrantedAuthority> authorities) {
this.authorities = authorities;
}
}

View File

@ -1,64 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.oauth2.introspectingfilter.service.impl;
import java.util.List;
import org.mitre.oauth2.introspectingfilter.service.IntrospectionAuthorityGranter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import com.google.gson.JsonObject;
/**
*
* Grants the same set of authorities no matter what's passed in.
*
* @author jricher
*
*/
public class SimpleIntrospectionAuthorityGranter implements IntrospectionAuthorityGranter {
private List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_API");
/* (non-Javadoc)
* @see org.mitre.oauth2.introspectingfilter.IntrospectionAuthorityGranter#getAuthorities(net.minidev.json.JSONObject)
*/
@Override
public List<GrantedAuthority> getAuthorities(JsonObject introspectionResponse) {
return authorities;
}
/**
* @return the authorities
*/
public List<GrantedAuthority> getAuthorities() {
return authorities;
}
/**
* @param authorities the authorities to set
*/
public void setAuthorities(List<GrantedAuthority> authorities) {
this.authorities = authorities;
}
}

View File

@ -1,83 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.oauth2.introspectingfilter.service.impl;
import org.mitre.oauth2.introspectingfilter.service.IntrospectionConfigurationService;
import org.mitre.oauth2.model.RegisteredClient;
/**
*
* Always provides the (configured) IntrospectionURL and RegisteredClient regardless
* of token. Useful for talking to a single, trusted authorization server.
*
* @author jricher
*
*/
public class StaticIntrospectionConfigurationService implements IntrospectionConfigurationService {
private String introspectionUrl;
private RegisteredClient clientConfiguration;
/**
* @return the clientConfiguration
*/
public RegisteredClient getClientConfiguration() {
return clientConfiguration;
}
/**
* @param clientConfiguration the clientConfiguration to set
*/
public void setClientConfiguration(RegisteredClient client) {
this.clientConfiguration = client;
}
/**
* @return the introspectionUrl
*/
public String getIntrospectionUrl() {
return introspectionUrl;
}
/**
* @param introspectionUrl the introspectionUrl to set
*/
public void setIntrospectionUrl(String introspectionUrl) {
this.introspectionUrl = introspectionUrl;
}
/* (non-Javadoc)
* @see org.mitre.oauth2.introspectingfilter.IntrospectionConfigurationService#getIntrospectionUrl(java.lang.String)
*/
@Override
public String getIntrospectionUrl(String accessToken) {
return getIntrospectionUrl();
}
/* (non-Javadoc)
* @see org.mitre.oauth2.introspectingfilter.service.IntrospectionConfigurationService#getClientConfiguration(java.lang.String)
*/
@Override
public RegisteredClient getClientConfiguration(String accessToken) {
return getClientConfiguration();
}
}

View File

@ -1,56 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT 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.client;
import org.springframework.security.authentication.AuthenticationServiceException;
public class AuthorizationEndpointException extends AuthenticationServiceException {
private static final long serialVersionUID = 6953119789654778380L;
private String error;
private String errorDescription;
private String errorURI;
public AuthorizationEndpointException(String error, String errorDescription, String errorURI) {
super("Error from Authorization Endpoint: " + error + " " + errorDescription + " " + errorURI);
this.error = error;
this.errorDescription = errorDescription;
this.errorURI = errorURI;
}
public String getError() {
return error;
}
public String getErrorDescription() {
return errorDescription;
}
public String getErrorURI() {
return errorURI;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "AuthorizationEndpointException [error=" + error + ", errorDescription=" + errorDescription + ", errorURI=" + errorURI + "]";
}
}

View File

@ -1,92 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client;
import java.text.ParseException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.mitre.openid.connect.model.UserInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
/**
*
* Simple mapper that adds ROLE_USER to the authorities map for all queries,
* plus adds ROLE_ADMIN if the subject and issuer pair are found in the
* configurable "admins" set.
*
* @author jricher
*
*/
public class NamedAdminAuthoritiesMapper implements OIDCAuthoritiesMapper {
private static Logger logger = LoggerFactory.getLogger(NamedAdminAuthoritiesMapper.class);
private static final SimpleGrantedAuthority ROLE_ADMIN = new SimpleGrantedAuthority("ROLE_ADMIN");
private static final SimpleGrantedAuthority ROLE_USER = new SimpleGrantedAuthority("ROLE_USER");
private Set<SubjectIssuerGrantedAuthority> admins = new HashSet<>();
@Override
public Collection<? extends GrantedAuthority> mapAuthorities(JWT idToken, UserInfo userInfo) {
Set<GrantedAuthority> out = new HashSet<>();
try {
JWTClaimsSet claims = idToken.getJWTClaimsSet();
SubjectIssuerGrantedAuthority authority = new SubjectIssuerGrantedAuthority(claims.getSubject(), claims.getIssuer());
out.add(authority);
if (admins.contains(authority)) {
out.add(ROLE_ADMIN);
}
// everybody's a user by default
out.add(ROLE_USER);
} catch (ParseException e) {
logger.error("Unable to parse ID Token inside of authorities mapper (huh?)");
}
return out;
}
/**
* @return the admins
*/
public Set<SubjectIssuerGrantedAuthority> getAdmins() {
return admins;
}
/**
* @param admins the admins to set
*/
public void setAdmins(Set<SubjectIssuerGrantedAuthority> admins) {
this.admins = admins;
}
}

View File

@ -1,902 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.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;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.ParseException;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.HttpClientBuilder;
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
import org.mitre.jwt.signer.service.impl.JWKSetCacheService;
import org.mitre.jwt.signer.service.impl.SymmetricKeyJWTValidatorCacheService;
import org.mitre.oauth2.model.PKCEAlgorithm;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.client.model.IssuerServiceResponse;
import org.mitre.openid.connect.client.service.AuthRequestOptionsService;
import org.mitre.openid.connect.client.service.AuthRequestUrlBuilder;
import org.mitre.openid.connect.client.service.ClientConfigurationService;
import org.mitre.openid.connect.client.service.IssuerService;
import org.mitre.openid.connect.client.service.ServerConfigurationService;
import org.mitre.openid.connect.client.service.impl.StaticAuthRequestOptionsService;
import org.mitre.openid.connect.config.ServerConfiguration;
import org.mitre.openid.connect.model.PendingOIDCAuthenticationToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriUtils;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.nimbusds.jose.Algorithm;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.util.Base64;
import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.JWTParser;
import com.nimbusds.jwt.PlainJWT;
import com.nimbusds.jwt.SignedJWT;
/**
* OpenID Connect Authentication Filter class
*
* @author nemonik, jricher
*
*/
public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
protected final static String REDIRECT_URI_SESION_VARIABLE = "redirect_uri";
protected final static String CODE_VERIFIER_SESSION_VARIABLE = "code_verifier";
protected final static String STATE_SESSION_VARIABLE = "state";
protected final static String NONCE_SESSION_VARIABLE = "nonce";
protected final static String ISSUER_SESSION_VARIABLE = "issuer";
protected final static String TARGET_SESSION_VARIABLE = "target";
protected final static int HTTP_SOCKET_TIMEOUT = 30000;
public final static String FILTER_PROCESSES_URL = "/openid_connect_login";
// Allow for time sync issues by having a window of X seconds.
private int timeSkewAllowance = 300;
// fetches and caches public keys for servers
@Autowired(required=false)
private JWKSetCacheService validationServices;
// creates JWT signer/validators for symmetric keys
@Autowired(required=false)
private SymmetricKeyJWTValidatorCacheService symmetricCacheService;
// signer based on keypair for this client (for outgoing auth requests)
@Autowired(required=false)
private JWTSigningAndValidationService authenticationSignerService;
@Autowired(required=false)
private HttpClient httpClient;
/*
* Modular services to build out client filter.
*/
// looks at the request and determines which issuer to use for lookup on the server
private IssuerService issuerService;
// holds server information (auth URI, token URI, etc.), indexed by issuer
private ServerConfigurationService servers;
// holds client information (client ID, redirect URI, etc.), indexed by issuer of the server
private ClientConfigurationService clients;
// provides extra options to inject into the outbound request
private AuthRequestOptionsService authOptions = new StaticAuthRequestOptionsService(); // initialize with an empty set of options
// builds the actual request URI based on input from all other services
private AuthRequestUrlBuilder authRequestBuilder;
// private helpers to handle target link URLs
private TargetLinkURIAuthenticationSuccessHandler targetSuccessHandler = new TargetLinkURIAuthenticationSuccessHandler();
private TargetLinkURIChecker deepLinkFilter;
protected int httpSocketTimeout = HTTP_SOCKET_TIMEOUT;
/**
* OpenIdConnectAuthenticationFilter constructor
*/
public OIDCAuthenticationFilter() {
super(FILTER_PROCESSES_URL);
targetSuccessHandler.passthrough = super.getSuccessHandler();
super.setAuthenticationSuccessHandler(targetSuccessHandler);
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
// if our JOSE validators don't get wired in, drop defaults into place
if (validationServices == null) {
validationServices = new JWKSetCacheService();
}
if (symmetricCacheService == null) {
symmetricCacheService = new SymmetricKeyJWTValidatorCacheService();
}
}
/*
* This is the main entry point for the filter.
*
* (non-Javadoc)
*
* @see org.springframework.security.web.authentication.
* AbstractAuthenticationProcessingFilter
* #attemptAuthentication(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
*/
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
if (!Strings.isNullOrEmpty(request.getParameter("error"))) {
// there's an error coming back from the server, need to handle this
handleError(request, response);
return null; // no auth, response is sent to display page or something
} else if (!Strings.isNullOrEmpty(request.getParameter("code"))) {
// we got back the code, need to process this to get our tokens
Authentication auth = handleAuthorizationCodeResponse(request, response);
return auth;
} else {
// not an error, not a code, must be an initial login of some type
handleAuthorizationRequest(request, response);
return null; // no auth, response redirected to the server's Auth Endpoint (or possibly to the account chooser)
}
}
/**
* Initiate an Authorization request
*
* @param request
* The request from which to extract parameters and perform the
* authentication
* @param response
* @throws IOException
* If an input or output exception occurs
*/
protected void handleAuthorizationRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
HttpSession session = request.getSession();
IssuerServiceResponse issResp = issuerService.getIssuer(request);
if (issResp == null) {
logger.error("Null issuer response returned from service.");
throw new AuthenticationServiceException("No issuer found.");
}
if (issResp.shouldRedirect()) {
response.sendRedirect(issResp.getRedirectUrl());
} else {
String issuer = issResp.getIssuer();
if (!Strings.isNullOrEmpty(issResp.getTargetLinkUri())) {
// there's a target URL in the response, we should save this so we can forward to it later
session.setAttribute(TARGET_SESSION_VARIABLE, issResp.getTargetLinkUri());
}
if (Strings.isNullOrEmpty(issuer)) {
logger.error("No issuer found: " + issuer);
throw new AuthenticationServiceException("No issuer found: " + issuer);
}
ServerConfiguration serverConfig = servers.getServerConfiguration(issuer);
if (serverConfig == null) {
logger.error("No server configuration found for issuer: " + issuer);
throw new AuthenticationServiceException("No server configuration found for issuer: " + issuer);
}
session.setAttribute(ISSUER_SESSION_VARIABLE, serverConfig.getIssuer());
RegisteredClient clientConfig = clients.getClientConfiguration(serverConfig);
if (clientConfig == null) {
logger.error("No client configuration found for issuer: " + issuer);
throw new AuthenticationServiceException("No client configuration found for issuer: " + issuer);
}
String redirectUri = null;
if (clientConfig.getRegisteredRedirectUri() != null && clientConfig.getRegisteredRedirectUri().size() == 1) {
// if there's a redirect uri configured (and only one), use that
redirectUri = Iterables.getOnlyElement(clientConfig.getRegisteredRedirectUri());
} else {
// otherwise our redirect URI is this current URL, with no query parameters
redirectUri = request.getRequestURL().toString();
}
session.setAttribute(REDIRECT_URI_SESION_VARIABLE, redirectUri);
// this value comes back in the id token and is checked there
String nonce = createNonce(session);
// this value comes back in the auth code response
String state = createState(session);
Map<String, String> options = authOptions.getOptions(serverConfig, clientConfig, request);
// if we're using PKCE, handle the challenge here
if (clientConfig.getCodeChallengeMethod() != null) {
String codeVerifier = createCodeVerifier(session);
options.put("code_challenge_method", clientConfig.getCodeChallengeMethod().getName());
if (clientConfig.getCodeChallengeMethod().equals(PKCEAlgorithm.plain)) {
options.put("code_challenge", codeVerifier);
} else if (clientConfig.getCodeChallengeMethod().equals(PKCEAlgorithm.S256)) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
String hash = Base64URL.encode(digest.digest(codeVerifier.getBytes(StandardCharsets.US_ASCII))).toString();
options.put("code_challenge", hash);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
String authRequest = authRequestBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options, issResp.getLoginHint());
logger.debug("Auth Request: " + authRequest);
response.sendRedirect(authRequest);
}
}
/**
* @param request
* The request from which to extract parameters and perform the
* authentication
* @return The authenticated user token, or null if authentication is
* incomplete.
*/
protected Authentication handleAuthorizationCodeResponse(HttpServletRequest request, HttpServletResponse response) {
String authorizationCode = request.getParameter("code");
HttpSession session = request.getSession();
// check for state, if it doesn't match we bail early
String storedState = getStoredState(session);
String requestState = request.getParameter("state");
if (storedState == null || !storedState.equals(requestState)) {
throw new AuthenticationServiceException("State parameter mismatch on return. Expected " + storedState + " got " + requestState);
}
// look up the issuer that we set out to talk to
String issuer = getStoredSessionString(session, ISSUER_SESSION_VARIABLE);
// pull the configurations based on that issuer
ServerConfiguration serverConfig = servers.getServerConfiguration(issuer);
final RegisteredClient clientConfig = clients.getClientConfiguration(serverConfig);
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
form.add("grant_type", "authorization_code");
form.add("code", authorizationCode);
form.setAll(authOptions.getTokenOptions(serverConfig, clientConfig, request));
String codeVerifier = getStoredCodeVerifier(session);
if (codeVerifier != null) {
form.add("code_verifier", codeVerifier);
}
String redirectUri = getStoredSessionString(session, REDIRECT_URI_SESION_VARIABLE);
if (redirectUri != null) {
form.add("redirect_uri", redirectUri);
}
// Handle Token Endpoint interaction
if(httpClient == null) {
httpClient = HttpClientBuilder.create()
.useSystemProperties()
.setDefaultRequestConfig(RequestConfig.custom()
.setSocketTimeout(httpSocketTimeout)
.build())
.build();
}
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
RestTemplate restTemplate;
if (SECRET_BASIC.equals(clientConfig.getTokenEndpointAuthMethod())){
// use BASIC auth if configured to do so
restTemplate = new RestTemplate(factory) {
@Override
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
ClientHttpRequest httpRequest = super.createRequest(url, method);
httpRequest.getHeaders().add("Authorization",
String.format("Basic %s", Base64.encode(String.format("%s:%s",
UriUtils.encodePathSegment(clientConfig.getClientId(), "UTF-8"),
UriUtils.encodePathSegment(clientConfig.getClientSecret(), "UTF-8")))));
return httpRequest;
}
};
} else {
// we're not doing basic auth, figure out what other flavor we have
restTemplate = new RestTemplate(factory);
if (SECRET_JWT.equals(clientConfig.getTokenEndpointAuthMethod()) || PRIVATE_KEY.equals(clientConfig.getTokenEndpointAuthMethod())) {
// do a symmetric secret signed JWT for auth
JWTSigningAndValidationService signer = null;
JWSAlgorithm alg = clientConfig.getTokenEndpointAuthSigningAlg();
if (SECRET_JWT.equals(clientConfig.getTokenEndpointAuthMethod()) &&
(JWSAlgorithm.HS256.equals(alg)
|| JWSAlgorithm.HS384.equals(alg)
|| JWSAlgorithm.HS512.equals(alg))) {
// generate one based on client secret
signer = symmetricCacheService.getSymmetricValidtor(clientConfig.getClient());
} else if (PRIVATE_KEY.equals(clientConfig.getTokenEndpointAuthMethod())) {
// needs to be wired in to the bean
signer = authenticationSignerService;
if (alg == null) {
alg = authenticationSignerService.getDefaultSigningAlgorithm();
}
}
if (signer == null) {
throw new AuthenticationServiceException("Couldn't find required signer service for use with private key auth.");
}
JWTClaimsSet.Builder claimsSet = new JWTClaimsSet.Builder();
claimsSet.issuer(clientConfig.getClientId());
claimsSet.subject(clientConfig.getClientId());
claimsSet.audience(Lists.newArrayList(serverConfig.getTokenEndpointUri()));
claimsSet.jwtID(UUID.randomUUID().toString());
// TODO: make this configurable
Date exp = new Date(System.currentTimeMillis() + (60 * 1000)); // auth good for 60 seconds
claimsSet.expirationTime(exp);
Date now = new Date(System.currentTimeMillis());
claimsSet.issueTime(now);
claimsSet.notBeforeTime(now);
JWSHeader header = new JWSHeader(alg, null, null, null, null, null, null, null, null, null,
signer.getDefaultSignerKeyId(),
null, null);
SignedJWT jwt = new SignedJWT(header, claimsSet.build());
signer.signJwt(jwt, alg);
form.add("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
form.add("client_assertion", jwt.serialize());
} else {
//Alternatively use form based auth
form.add("client_id", clientConfig.getClientId());
form.add("client_secret", clientConfig.getClientSecret());
}
}
logger.debug("tokenEndpointURI = " + serverConfig.getTokenEndpointUri());
logger.debug("form = " + form);
String jsonString = null;
try {
jsonString = restTemplate.postForObject(serverConfig.getTokenEndpointUri(), form, String.class);
} catch (RestClientException e) {
// Handle error
logger.error("Token Endpoint error response: " + e.getMessage());
throw new AuthenticationServiceException("Unable to obtain Access Token: " + e.getMessage());
}
logger.debug("from TokenEndpoint jsonString = " + jsonString);
JsonElement jsonRoot = new JsonParser().parse(jsonString);
if (!jsonRoot.isJsonObject()) {
throw new AuthenticationServiceException("Token Endpoint did not return a JSON object: " + jsonRoot);
}
JsonObject tokenResponse = jsonRoot.getAsJsonObject();
if (tokenResponse.get("error") != null) {
// Handle error
String error = tokenResponse.get("error").getAsString();
logger.error("Token Endpoint returned: " + error);
throw new AuthenticationServiceException("Unable to obtain Access Token. Token Endpoint returned: " + error);
} else {
// Extract the id_token to insert into the
// OIDCAuthenticationToken
// get out all the token strings
String accessTokenValue = null;
String idTokenValue = null;
String refreshTokenValue = null;
if (tokenResponse.has("access_token")) {
accessTokenValue = tokenResponse.get("access_token").getAsString();
} else {
throw new AuthenticationServiceException("Token Endpoint did not return an access_token: " + jsonString);
}
if (tokenResponse.has("id_token")) {
idTokenValue = tokenResponse.get("id_token").getAsString();
} else {
logger.error("Token Endpoint did not return an id_token");
throw new AuthenticationServiceException("Token Endpoint did not return an id_token");
}
if (tokenResponse.has("refresh_token")) {
refreshTokenValue = tokenResponse.get("refresh_token").getAsString();
}
try {
JWT idToken = JWTParser.parse(idTokenValue);
// validate our ID Token over a number of tests
JWTClaimsSet idClaims = idToken.getJWTClaimsSet();
// check the signature
JWTSigningAndValidationService jwtValidator = null;
Algorithm tokenAlg = idToken.getHeader().getAlgorithm();
Algorithm clientAlg = clientConfig.getIdTokenSignedResponseAlg();
if (clientAlg != null) {
if (!clientAlg.equals(tokenAlg)) {
throw new AuthenticationServiceException("Token algorithm " + tokenAlg + " does not match expected algorithm " + clientAlg);
}
}
if (idToken instanceof PlainJWT) {
if (clientAlg == null) {
throw new AuthenticationServiceException("Unsigned ID tokens can only be used if explicitly configured in client.");
}
if (tokenAlg != null && !tokenAlg.equals(Algorithm.NONE)) {
throw new AuthenticationServiceException("Unsigned token received, expected signature with " + tokenAlg);
}
} else if (idToken instanceof SignedJWT) {
SignedJWT signedIdToken = (SignedJWT)idToken;
if (tokenAlg.equals(JWSAlgorithm.HS256)
|| tokenAlg.equals(JWSAlgorithm.HS384)
|| tokenAlg.equals(JWSAlgorithm.HS512)) {
// generate one based on client secret
jwtValidator = symmetricCacheService.getSymmetricValidtor(clientConfig.getClient());
} else {
// otherwise load from the server's public key
jwtValidator = validationServices.getValidator(serverConfig.getJwksUri());
}
if (jwtValidator != null) {
if(!jwtValidator.validateSignature(signedIdToken)) {
throw new AuthenticationServiceException("Signature validation failed");
}
} else {
logger.error("No validation service found. Skipping signature validation");
throw new AuthenticationServiceException("Unable to find an appropriate signature validator for ID Token.");
}
} // TODO: encrypted id tokens
// check the issuer
if (idClaims.getIssuer() == null) {
throw new AuthenticationServiceException("Id Token Issuer is null");
} else if (!idClaims.getIssuer().equals(serverConfig.getIssuer())){
throw new AuthenticationServiceException("Issuers do not match, expected " + serverConfig.getIssuer() + " got " + idClaims.getIssuer());
}
// check expiration
if (idClaims.getExpirationTime() == null) {
throw new AuthenticationServiceException("Id Token does not have required expiration claim");
} else {
// it's not null, see if it's expired
Date now = new Date(System.currentTimeMillis() - (timeSkewAllowance * 1000));
if (now.after(idClaims.getExpirationTime())) {
throw new AuthenticationServiceException("Id Token is expired: " + idClaims.getExpirationTime());
}
}
// check not before
if (idClaims.getNotBeforeTime() != null) {
Date now = new Date(System.currentTimeMillis() + (timeSkewAllowance * 1000));
if (now.before(idClaims.getNotBeforeTime())){
throw new AuthenticationServiceException("Id Token not valid untill: " + idClaims.getNotBeforeTime());
}
}
// check issued at
if (idClaims.getIssueTime() == null) {
throw new AuthenticationServiceException("Id Token does not have required issued-at claim");
} else {
// since it's not null, see if it was issued in the future
Date now = new Date(System.currentTimeMillis() + (timeSkewAllowance * 1000));
if (now.before(idClaims.getIssueTime())) {
throw new AuthenticationServiceException("Id Token was issued in the future: " + idClaims.getIssueTime());
}
}
// check audience
if (idClaims.getAudience() == null) {
throw new AuthenticationServiceException("Id token audience is null");
} else if (!idClaims.getAudience().contains(clientConfig.getClientId())) {
throw new AuthenticationServiceException("Audience does not match, expected " + clientConfig.getClientId() + " got " + idClaims.getAudience());
}
// compare the nonce to our stored claim
String nonce = idClaims.getStringClaim("nonce");
if (Strings.isNullOrEmpty(nonce)) {
logger.error("ID token did not contain a nonce claim.");
throw new AuthenticationServiceException("ID token did not contain a nonce claim.");
}
String storedNonce = getStoredNonce(session);
if (!nonce.equals(storedNonce)) {
logger.error("Possible replay attack detected! The comparison of the nonce in the returned "
+ "ID Token to the session " + NONCE_SESSION_VARIABLE + " failed. Expected " + storedNonce + " got " + nonce + ".");
throw new AuthenticationServiceException(
"Possible replay attack detected! The comparison of the nonce in the returned "
+ "ID Token to the session " + NONCE_SESSION_VARIABLE + " failed. Expected " + storedNonce + " got " + nonce + ".");
}
// construct an PendingOIDCAuthenticationToken and return a Authentication object w/the userId and the idToken
PendingOIDCAuthenticationToken token = new PendingOIDCAuthenticationToken(idClaims.getSubject(), idClaims.getIssuer(),
serverConfig,
idToken, accessTokenValue, refreshTokenValue);
Authentication authentication = this.getAuthenticationManager().authenticate(token);
return authentication;
} catch (ParseException e) {
throw new AuthenticationServiceException("Couldn't parse idToken: ", e);
}
}
}
/**
* Handle Authorization Endpoint error
*
* @param request
* The request from which to extract parameters and handle the
* error
* @param response
* The response, needed to do a redirect to display the error
* @throws IOException
* If an input or output exception occurs
*/
protected void handleError(HttpServletRequest request, HttpServletResponse response) throws IOException {
String error = request.getParameter("error");
String errorDescription = request.getParameter("error_description");
String errorURI = request.getParameter("error_uri");
throw new AuthorizationEndpointException(error, errorDescription, errorURI);
}
/**
* Get the named stored session variable as a string. Return null if not found or not a string.
* @param session
* @param key
* @return
*/
private static String getStoredSessionString(HttpSession session, String key) {
Object o = session.getAttribute(key);
if (o != null && o instanceof String) {
return o.toString();
} else {
return null;
}
}
/**
* Create a cryptographically random nonce and store it in the session
* @param session
* @return
*/
protected static String createNonce(HttpSession session) {
String nonce = new BigInteger(50, new SecureRandom()).toString(16);
session.setAttribute(NONCE_SESSION_VARIABLE, nonce);
return nonce;
}
/**
* Get the nonce we stored in the session
* @param session
* @return
*/
protected static String getStoredNonce(HttpSession session) {
return getStoredSessionString(session, NONCE_SESSION_VARIABLE);
}
/**
* Create a cryptographically random state and store it in the session
* @param session
* @return
*/
protected static String createState(HttpSession session) {
String state = new BigInteger(50, new SecureRandom()).toString(16);
session.setAttribute(STATE_SESSION_VARIABLE, state);
return state;
}
/**
* Get the state we stored in the session
* @param session
* @return
*/
protected static String getStoredState(HttpSession session) {
return getStoredSessionString(session, STATE_SESSION_VARIABLE);
}
/**
* Create a random code challenge and store it in the session
* @param session
* @return
*/
protected static String createCodeVerifier(HttpSession session) {
String challenge = new BigInteger(50, new SecureRandom()).toString(16);
session.setAttribute(CODE_VERIFIER_SESSION_VARIABLE, challenge);
return challenge;
}
/**
* Retrieve the stored challenge from our session
* @param session
* @return
*/
protected static String getStoredCodeVerifier(HttpSession session) {
return getStoredSessionString(session, CODE_VERIFIER_SESSION_VARIABLE);
}
@Override
public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
targetSuccessHandler.passthrough = successHandler;
super.setAuthenticationSuccessHandler(targetSuccessHandler);
}
/**
* Handle a successful authentication event. If the issuer service sets
* a target URL, we'll go to that. Otherwise we'll let the superclass handle
* it for us with the configured behavior.
*/
protected class TargetLinkURIAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private AuthenticationSuccessHandler passthrough;
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
HttpSession session = request.getSession();
// check to see if we've got a target
String target = getStoredSessionString(session, TARGET_SESSION_VARIABLE);
if (!Strings.isNullOrEmpty(target)) {
session.removeAttribute(TARGET_SESSION_VARIABLE);
if (deepLinkFilter != null) {
target = deepLinkFilter.filter(target);
}
response.sendRedirect(target);
} else {
// if the target was blank, use the default behavior here
passthrough.onAuthenticationSuccess(request, response, authentication);
}
}
}
//
// Getters and setters for configuration variables
//
public int getTimeSkewAllowance() {
return timeSkewAllowance;
}
public void setTimeSkewAllowance(int timeSkewAllowance) {
this.timeSkewAllowance = timeSkewAllowance;
}
/**
* @return the validationServices
*/
public JWKSetCacheService getValidationServices() {
return validationServices;
}
/**
* @param validationServices the validationServices to set
*/
public void setValidationServices(JWKSetCacheService validationServices) {
this.validationServices = validationServices;
}
/**
* @return the servers
*/
public ServerConfigurationService getServerConfigurationService() {
return servers;
}
/**
* @param servers the servers to set
*/
public void setServerConfigurationService(ServerConfigurationService servers) {
this.servers = servers;
}
/**
* @return the clients
*/
public ClientConfigurationService getClientConfigurationService() {
return clients;
}
/**
* @param clients the clients to set
*/
public void setClientConfigurationService(ClientConfigurationService clients) {
this.clients = clients;
}
/**
* @return the issuerService
*/
public IssuerService getIssuerService() {
return issuerService;
}
/**
* @param issuerService the issuerService to set
*/
public void setIssuerService(IssuerService issuerService) {
this.issuerService = issuerService;
}
/**
* @return the authRequestBuilder
*/
public AuthRequestUrlBuilder getAuthRequestUrlBuilder() {
return authRequestBuilder;
}
/**
* @param authRequestBuilder the authRequestBuilder to set
*/
public void setAuthRequestUrlBuilder(AuthRequestUrlBuilder authRequestBuilder) {
this.authRequestBuilder = authRequestBuilder;
}
/**
* @return the authOptions
*/
public AuthRequestOptionsService getAuthRequestOptionsService() {
return authOptions;
}
/**
* @param authOptions the authOptions to set
*/
public void setAuthRequestOptionsService(AuthRequestOptionsService authOptions) {
this.authOptions = authOptions;
}
public SymmetricKeyJWTValidatorCacheService getSymmetricCacheService() {
return symmetricCacheService;
}
public void setSymmetricCacheService(SymmetricKeyJWTValidatorCacheService symmetricCacheService) {
this.symmetricCacheService = symmetricCacheService;
}
public TargetLinkURIAuthenticationSuccessHandler getTargetLinkURIAuthenticationSuccessHandler() {
return targetSuccessHandler;
}
public void setTargetLinkURIAuthenticationSuccessHandler(
TargetLinkURIAuthenticationSuccessHandler targetSuccessHandler) {
this.targetSuccessHandler = targetSuccessHandler;
}
public TargetLinkURIChecker targetLinkURIChecker() {
return deepLinkFilter;
}
public void setTargetLinkURIChecker(TargetLinkURIChecker deepLinkFilter) {
this.deepLinkFilter = deepLinkFilter;
}
}

View File

@ -1,128 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client;
import java.util.Collection;
import org.mitre.openid.connect.model.OIDCAuthenticationToken;
import org.mitre.openid.connect.model.PendingOIDCAuthenticationToken;
import org.mitre.openid.connect.model.UserInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import com.google.common.base.Strings;
import com.nimbusds.jwt.JWT;
/**
* @author nemonik, Justin Richer
*
*/
public class OIDCAuthenticationProvider implements AuthenticationProvider {
private static Logger logger = LoggerFactory.getLogger(OIDCAuthenticationProvider.class);
private UserInfoFetcher userInfoFetcher = new UserInfoFetcher();
private OIDCAuthoritiesMapper authoritiesMapper = new NamedAdminAuthoritiesMapper();
/*
* (non-Javadoc)
*
* @see org.springframework.security.authentication.AuthenticationProvider#
* authenticate(org.springframework.security.core.Authentication)
*/
@Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException {
if (!supports(authentication.getClass())) {
return null;
}
if (authentication instanceof PendingOIDCAuthenticationToken) {
PendingOIDCAuthenticationToken token = (PendingOIDCAuthenticationToken) authentication;
// get the ID Token value out
JWT idToken = token.getIdToken();
// load the user info if we can
UserInfo userInfo = userInfoFetcher.loadUserInfo(token);
if (userInfo == null) {
// user info not found -- could be an error, could be fine
} else {
// if we found userinfo, double check it
if (!Strings.isNullOrEmpty(userInfo.getSub()) && !userInfo.getSub().equals(token.getSub())) {
// the userinfo came back and the user_id fields don't match what was in the id_token
throw new UsernameNotFoundException("user_id mismatch between id_token and user_info call: " + token.getSub() + " / " + userInfo.getSub());
}
}
return createAuthenticationToken(token, authoritiesMapper.mapAuthorities(idToken, userInfo), userInfo);
}
return null;
}
/**
* Override this function to return a different kind of Authentication, processes the authorities differently,
* or do post-processing based on the UserInfo object.
*
* @param token
* @param authorities
* @param userInfo
* @return
*/
protected Authentication createAuthenticationToken(PendingOIDCAuthenticationToken token, Collection<? extends GrantedAuthority> authorities, UserInfo userInfo) {
return new OIDCAuthenticationToken(token.getSub(),
token.getIssuer(),
userInfo, authorities,
token.getIdToken(), token.getAccessTokenValue(), token.getRefreshTokenValue());
}
/**
* @param userInfoFetcher
*/
public void setUserInfoFetcher(UserInfoFetcher userInfoFetcher) {
this.userInfoFetcher = userInfoFetcher;
}
/**
* @param authoritiesMapper
*/
public void setAuthoritiesMapper(OIDCAuthoritiesMapper authoritiesMapper) {
this.authoritiesMapper = authoritiesMapper;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.authentication.AuthenticationProvider#supports
* (java.lang.Class)
*/
@Override
public boolean supports(Class<?> authentication) {
return PendingOIDCAuthenticationToken.class.isAssignableFrom(authentication);
}
}

View File

@ -1,39 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT 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.client;
import java.util.Collection;
import org.mitre.openid.connect.model.UserInfo;
import org.springframework.security.core.GrantedAuthority;
import com.nimbusds.jwt.JWT;
/**
* @author jricher
*
*/
public interface OIDCAuthoritiesMapper {
/**
* @param idToken the ID Token (parsed as a JWT, cannot be @null)
* @param userInfo userInfo of the current user (could be @null)
* @return the set of authorities to map to this user
*/
Collection<? extends GrantedAuthority> mapAuthorities(JWT idToken, UserInfo userInfo);
}

View File

@ -1,48 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT 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.client;
/**
* Simple target URI checker, checks whether the string in question starts
* with a configured prefix. Returns "/" if the match fails.
*
* @author jricher
*
*/
public class StaticPrefixTargetLinkURIChecker implements TargetLinkURIChecker {
private String prefix = "";
@Override
public String filter(String target) {
if (target == null) {
return "/";
} else if (target.startsWith(prefix)) {
return target;
} else {
return "/";
}
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
}

View File

@ -1,125 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT 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.client;
import org.springframework.security.core.GrantedAuthority;
import com.google.common.base.Strings;
/**
*
* Simple authority representing a user at an issuer.
*
* @author jricher
*
*/
public class SubjectIssuerGrantedAuthority implements GrantedAuthority {
private static final long serialVersionUID = 5584978219226664794L;
private final String subject;
private final String issuer;
/**
* @param subject
* @param issuer
*/
public SubjectIssuerGrantedAuthority(String subject, String issuer) {
if (Strings.isNullOrEmpty(subject) || Strings.isNullOrEmpty(issuer)) {
throw new IllegalArgumentException("Neither subject nor issuer may be null or empty");
}
this.subject = subject;
this.issuer = issuer;
}
/**
* Returns a string formed by concatenating the subject with the issuer, separated by _ and prepended with OIDC_
*
* For example, the user "bob" from issuer "http://id.example.com/" would return the authority string of:
*
* OIDC_bob_http://id.example.com/
*/
@Override
public String getAuthority() {
return "OIDC_" + subject + "_" + issuer;
}
/**
* @return the subject
*/
public String getSubject() {
return subject;
}
/**
* @return the issuer
*/
public String getIssuer() {
return issuer;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((issuer == null) ? 0 : issuer.hashCode());
result = prime * result + ((subject == null) ? 0 : subject.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof SubjectIssuerGrantedAuthority)) {
return false;
}
SubjectIssuerGrantedAuthority other = (SubjectIssuerGrantedAuthority) obj;
if (issuer == null) {
if (other.issuer != null) {
return false;
}
} else if (!issuer.equals(other.issuer)) {
return false;
}
if (subject == null) {
if (other.subject != null) {
return false;
}
} else if (!subject.equals(other.subject)) {
return false;
}
return true;
}
@Override
public String toString() {
return getAuthority();
}
}

View File

@ -1,28 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT 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.client;
public interface TargetLinkURIChecker {
/**
* Check the parameter to make sure that it's a valid deep-link into this application.
*
* @param target
* @return
*/
public String filter(String target);
}

View File

@ -1,157 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.apache.http.client.HttpClient;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.HttpClientBuilder;
import org.mitre.openid.connect.config.ServerConfiguration;
import org.mitre.openid.connect.config.ServerConfiguration.UserInfoTokenMethod;
import org.mitre.openid.connect.model.DefaultUserInfo;
import org.mitre.openid.connect.model.PendingOIDCAuthenticationToken;
import org.mitre.openid.connect.model.UserInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import com.google.common.base.Strings;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
* Utility class to fetch userinfo from the userinfo endpoint, if available. Caches the results.
* @author jricher
*
*/
public class UserInfoFetcher {
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(UserInfoFetcher.class);
private LoadingCache<PendingOIDCAuthenticationToken, UserInfo> cache;
public UserInfoFetcher() {
this(HttpClientBuilder.create().useSystemProperties().build());
}
public UserInfoFetcher(HttpClient httpClient) {
cache = CacheBuilder.newBuilder()
.expireAfterWrite(1, TimeUnit.HOURS) // expires 1 hour after fetch
.maximumSize(100)
.build(new UserInfoLoader(httpClient));
}
public UserInfo loadUserInfo(final PendingOIDCAuthenticationToken token) {
try {
return cache.get(token);
} catch (UncheckedExecutionException | ExecutionException e) {
logger.warn("Couldn't load User Info from token: " + e.getMessage());
return null;
}
}
private class UserInfoLoader extends CacheLoader<PendingOIDCAuthenticationToken, UserInfo> {
private HttpComponentsClientHttpRequestFactory factory;
UserInfoLoader(HttpClient httpClient) {
this.factory = new HttpComponentsClientHttpRequestFactory(httpClient);
}
@Override
public UserInfo load(final PendingOIDCAuthenticationToken token) throws URISyntaxException {
ServerConfiguration serverConfiguration = token.getServerConfiguration();
if (serverConfiguration == null) {
logger.warn("No server configuration found.");
return null;
}
if (Strings.isNullOrEmpty(serverConfiguration.getUserInfoUri())) {
logger.warn("No userinfo endpoint, not fetching.");
return null;
}
String userInfoString = null;
if (serverConfiguration.getUserInfoTokenMethod() == null || serverConfiguration.getUserInfoTokenMethod().equals(UserInfoTokenMethod.HEADER)) {
RestTemplate restTemplate = new RestTemplate(factory) {
@Override
protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
ClientHttpRequest httpRequest = super.createRequest(url, method);
httpRequest.getHeaders().add("Authorization", String.format("Bearer %s", token.getAccessTokenValue()));
return httpRequest;
}
};
userInfoString = restTemplate.getForObject(serverConfiguration.getUserInfoUri(), String.class);
} else if (serverConfiguration.getUserInfoTokenMethod().equals(UserInfoTokenMethod.FORM)) {
MultiValueMap<String, String> form = new LinkedMultiValueMap<>();
form.add("access_token", token.getAccessTokenValue());
RestTemplate restTemplate = new RestTemplate(factory);
userInfoString = restTemplate.postForObject(serverConfiguration.getUserInfoUri(), form, String.class);
} else if (serverConfiguration.getUserInfoTokenMethod().equals(UserInfoTokenMethod.QUERY)) {
URIBuilder builder = new URIBuilder(serverConfiguration.getUserInfoUri());
builder.setParameter("access_token", token.getAccessTokenValue());
RestTemplate restTemplate = new RestTemplate(factory);
userInfoString = restTemplate.getForObject(builder.toString(), String.class);
}
if (!Strings.isNullOrEmpty(userInfoString)) {
JsonObject userInfoJson = new JsonParser().parse(userInfoString).getAsJsonObject();
UserInfo userInfo = fromJson(userInfoJson);
return userInfo;
} else {
// didn't get anything throw exception
throw new IllegalArgumentException("Unable to load user info");
}
}
}
protected UserInfo fromJson(JsonObject userInfoJson) {
return DefaultUserInfo.fromJson(userInfoJson);
}
}

View File

@ -1,130 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.keypublisher;
import java.util.Map;
import java.util.UUID;
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
import org.mitre.openid.connect.view.JWKSetView;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.web.servlet.ModelAndView;
import com.google.common.base.Strings;
import com.nimbusds.jose.jwk.JWK;
/**
* @author jricher
*
*/
public class ClientKeyPublisher implements BeanDefinitionRegistryPostProcessor {
private JWTSigningAndValidationService signingAndValidationService;
private String jwkPublishUrl;
private BeanDefinitionRegistry registry;
private String jwkViewName = JWKSetView.VIEWNAME;
/**
* If the jwkPublishUrl field is set on this bean, set up a listener on that URL to publish keys.
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (!Strings.isNullOrEmpty(getJwkPublishUrl())) {
// add a mapping to this class
BeanDefinitionBuilder clientKeyMapping = BeanDefinitionBuilder.rootBeanDefinition(ClientKeyPublisherMapping.class);
// custom view resolver
BeanDefinitionBuilder viewResolver = BeanDefinitionBuilder.rootBeanDefinition(JwkViewResolver.class);
if (!Strings.isNullOrEmpty(getJwkPublishUrl())) {
clientKeyMapping.addPropertyValue("jwkPublishUrl", getJwkPublishUrl());
// randomize view name to make sure it doesn't conflict with local views
jwkViewName = JWKSetView.VIEWNAME + "-" + UUID.randomUUID().toString();
viewResolver.addPropertyValue("jwkViewName", jwkViewName);
// view bean
BeanDefinitionBuilder jwkView = BeanDefinitionBuilder.rootBeanDefinition(JWKSetView.class);
registry.registerBeanDefinition(JWKSetView.VIEWNAME, jwkView.getBeanDefinition());
viewResolver.addPropertyReference("jwk", JWKSetView.VIEWNAME);
}
registry.registerBeanDefinition("clientKeyMapping", clientKeyMapping.getBeanDefinition());
registry.registerBeanDefinition("jwkViewResolver", viewResolver.getBeanDefinition());
}
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry(org.springframework.beans.factory.support.BeanDefinitionRegistry)
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
this.registry = registry;
}
/**
* Return a view to publish all keys in JWK format. Only used if jwkPublishUrl is set.
* @return
*/
public ModelAndView publishClientJwk() {
// map from key id to key
Map<String, JWK> keys = signingAndValidationService.getAllPublicKeys();
return new ModelAndView(jwkViewName, "keys", keys);
}
/**
* @return the jwkPublishUrl
*/
public String getJwkPublishUrl() {
return jwkPublishUrl;
}
/**
* @param jwkPublishUrl the jwkPublishUrl to set
*/
public void setJwkPublishUrl(String jwkPublishUrl) {
this.jwkPublishUrl = jwkPublishUrl;
}
/**
* @return the signingAndValidationService
*/
public JWTSigningAndValidationService getSigningAndValidationService() {
return signingAndValidationService;
}
/**
* @param signingAndValidationService the signingAndValidationService to set
*/
public void setSigningAndValidationService(JWTSigningAndValidationService signingAndValidationService) {
this.signingAndValidationService = signingAndValidationService;
}
}

View File

@ -1,82 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.keypublisher;
import java.lang.reflect.Method;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
/**
* @author jricher
*
*/
@Component
public class ClientKeyPublisherMapping extends RequestMappingInfoHandlerMapping {
private String jwkPublishUrl;
/* (non-Javadoc)
* @see org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#isHandler(java.lang.Class)
*/
@Override
protected boolean isHandler(Class<?> beanType) {
return beanType.equals(ClientKeyPublisher.class);
}
/**
* Map the "jwkKeyPublish" method to our jwkPublishUrl.
*/
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
if (method.getName().equals("publishClientJwk") && getJwkPublishUrl() != null) {
return new RequestMappingInfo(
new PatternsRequestCondition(new String[] {getJwkPublishUrl()}, getUrlPathHelper(), getPathMatcher(), false, false),
null,
null,
null,
null,
null,
null);
} else {
return null;
}
}
/**
* @return the jwkPublishUrl
*/
public String getJwkPublishUrl() {
return jwkPublishUrl;
}
/**
* @param jwkPublishUrl the jwkPublishUrl to set
*/
public void setJwkPublishUrl(String jwkPublishUrl) {
this.jwkPublishUrl = jwkPublishUrl;
}
}

View File

@ -1,103 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.keypublisher;
import java.util.Locale;
import org.springframework.core.Ordered;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
/**
*
* Simple view resolver to map JWK view names to appropriate beans
*
* @author jricher
*
*/
public class JwkViewResolver implements ViewResolver, Ordered {
private String jwkViewName = "jwkKeyList";
private View jwk;
private int order = HIGHEST_PRECEDENCE; // highest precedence, most specific -- avoids hitting the catch-all view resolvers
/**
* Map "jwkKeyList" to the jwk property on this bean.
* Everything else returns null
*/
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
if (viewName != null) {
if (viewName.equals(getJwkViewName())) {
return getJwk();
} else {
return null;
}
} else {
return null;
}
}
/**
* @return the jwk
*/
public View getJwk() {
return jwk;
}
/**
* @param jwk the jwk to set
*/
public void setJwk(View jwk) {
this.jwk = jwk;
}
/**
* @return the order
*/
@Override
public int getOrder() {
return order;
}
/**
* @param order the order to set
*/
public void setOrder(int order) {
this.order = order;
}
/**
* @return the jwkViewName
*/
public String getJwkViewName() {
return jwkViewName;
}
/**
* @param jwkViewName the jwkViewName to set
*/
public void setJwkViewName(String jwkViewName) {
this.jwkViewName = jwkViewName;
}
}

View File

@ -1,110 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.model;
/**
*
* Data container to facilitate returns from the IssuerService API.
*
* @author jricher
*
*/
public class IssuerServiceResponse {
private String issuer;
private String loginHint;
private String targetLinkUri;
private String redirectUrl;
/**
* @param issuer
* @param loginHint
* @param targetLinkUri
*/
public IssuerServiceResponse(String issuer, String loginHint, String targetLinkUri) {
this.issuer = issuer;
this.loginHint = loginHint;
this.targetLinkUri = targetLinkUri;
}
/**
* @param redirectUrl
*/
public IssuerServiceResponse(String redirectUrl) {
this.redirectUrl = redirectUrl;
}
/**
* @return the issuer
*/
public String getIssuer() {
return issuer;
}
/**
* @param issuer the issuer to set
*/
public void setIssuer(String issuer) {
this.issuer = issuer;
}
/**
* @return the loginHint
*/
public String getLoginHint() {
return loginHint;
}
/**
* @param loginHint the loginHint to set
*/
public void setLoginHint(String loginHint) {
this.loginHint = loginHint;
}
/**
* @return the targetLinkUri
*/
public String getTargetLinkUri() {
return targetLinkUri;
}
/**
* @param targetLinkUri the targetLinkUri to set
*/
public void setTargetLinkUri(String targetLinkUri) {
this.targetLinkUri = targetLinkUri;
}
/**
* @return the redirectUrl
*/
public String getRedirectUrl() {
return redirectUrl;
}
/**
* @param redirectUrl the redirectUrl to set
*/
public void setRedirectUrl(String redirectUrl) {
this.redirectUrl = redirectUrl;
}
/**
* If the redirect url has been set, then we should send a redirect using it instead of processing things.
*/
public boolean shouldRedirect() {
return this.redirectUrl != null;
}
}

View File

@ -1,61 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.config.ServerConfiguration;
/**
*
* This service provides any extra options that need to be passed to the authentication request,
* either through the authorization endpoint (getOptions) or the token endpoint (getTokenOptions).
* These options may depend on the server configuration, client configuration, or HTTP request.
*
* @author jricher
*
*/
public interface AuthRequestOptionsService {
/**
* The set of options needed at the authorization endpoint.
*
* @param server
* @param client
* @param request
* @return
*/
public Map<String, String> getOptions(ServerConfiguration server, RegisteredClient client, HttpServletRequest request);
/**
* The set of options needed at the token endpoint.
*
* @param server
* @param client
* @param request
* @return
*/
public Map<String, String> getTokenOptions(ServerConfiguration server, RegisteredClient client, HttpServletRequest request);
}

View File

@ -1,47 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service;
import java.util.Map;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.config.ServerConfiguration;
/**
* Builds a URL string to the IdP's authorization endpoint.
*
* @author jricher
*
*/
public interface AuthRequestUrlBuilder {
/**
* @param serverConfig
* @param clientConfig
* @param redirectUri
* @param nonce
* @param state
* @param loginHint
* @return
*/
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options, String loginHint);
}

View File

@ -1,34 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.config.ServerConfiguration;
/**
* @author jricher
*
*/
public interface ClientConfigurationService {
public RegisteredClient getClientConfiguration(ServerConfiguration issuer);
}

View File

@ -1,38 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service;
import javax.servlet.http.HttpServletRequest;
import org.mitre.openid.connect.client.model.IssuerServiceResponse;
/**
*
* Gets an issuer for the given request. Might do dynamic discovery, or might be statically configured.
*
* @author jricher
*
*/
public interface IssuerService {
public IssuerServiceResponse getIssuer(HttpServletRequest request);
}

View File

@ -1,48 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service;
import org.mitre.oauth2.model.RegisteredClient;
/**
* @author jricher
*
*/
public interface RegisteredClientService {
/**
* Get a remembered client (if one exists) to talk to the given issuer. This
* client likely doesn't have its full configuration information but contains
* the information needed to fetch it.
* @param issuer
* @return
*/
RegisteredClient getByIssuer(String issuer);
/**
* Save this client's information for talking to the given issuer. This will
* save only enough information to fetch the client's full configuration from
* the server.
* @param client
*/
void save(String issuer, RegisteredClient client);
}

View File

@ -1,33 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service;
import org.mitre.openid.connect.config.ServerConfiguration;
/**
* @author jricher
*
*/
public interface ServerConfigurationService {
public ServerConfiguration getServerConfiguration(String issuer);
}

View File

@ -1,247 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.ClientDetailsEntityJsonProcessor;
import org.mitre.openid.connect.client.service.ClientConfigurationService;
import org.mitre.openid.connect.client.service.RegisteredClientService;
import org.mitre.openid.connect.config.ServerConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
/**
* @author jricher
*
*/
public class DynamicRegistrationClientConfigurationService implements ClientConfigurationService {
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(DynamicRegistrationClientConfigurationService.class);
private LoadingCache<ServerConfiguration, RegisteredClient> clients;
private RegisteredClientService registeredClientService = new InMemoryRegisteredClientService();
private RegisteredClient template;
private Set<String> whitelist = new HashSet<>();
private Set<String> blacklist = new HashSet<>();
public DynamicRegistrationClientConfigurationService() {
this(HttpClientBuilder.create().useSystemProperties().build());
}
public DynamicRegistrationClientConfigurationService(HttpClient httpClient) {
clients = CacheBuilder.newBuilder().build(new DynamicClientRegistrationLoader(httpClient));
}
@Override
public RegisteredClient getClientConfiguration(ServerConfiguration issuer) {
try {
if (!whitelist.isEmpty() && !whitelist.contains(issuer.getIssuer())) {
throw new AuthenticationServiceException("Whitelist was nonempty, issuer was not in whitelist: " + issuer);
}
if (blacklist.contains(issuer.getIssuer())) {
throw new AuthenticationServiceException("Issuer was in blacklist: " + issuer);
}
return clients.get(issuer);
} catch (UncheckedExecutionException | ExecutionException e) {
logger.warn("Unable to get client configuration", e);
return null;
}
}
/**
* @return the template
*/
public RegisteredClient getTemplate() {
return template;
}
/**
* @param template the template to set
*/
public void setTemplate(RegisteredClient template) {
// make sure the template doesn't have unwanted fields set on it
if (template != null) {
template.setClientId(null);
template.setClientSecret(null);
template.setRegistrationClientUri(null);
template.setRegistrationAccessToken(null);
}
this.template = template;
}
/**
* @return the registeredClientService
*/
public RegisteredClientService getRegisteredClientService() {
return registeredClientService;
}
/**
* @param registeredClientService the registeredClientService to set
*/
public void setRegisteredClientService(RegisteredClientService registeredClientService) {
this.registeredClientService = registeredClientService;
}
/**
* @return the whitelist
*/
public Set<String> getWhitelist() {
return whitelist;
}
/**
* @param whitelist the whitelist to set
*/
public void setWhitelist(Set<String> whitelist) {
this.whitelist = whitelist;
}
/**
* @return the blacklist
*/
public Set<String> getBlacklist() {
return blacklist;
}
/**
* @param blacklist the blacklist to set
*/
public void setBlacklist(Set<String> blacklist) {
this.blacklist = blacklist;
}
/**
* Loader class that fetches the client information.
*
* If a client has been registered (ie, it's known to the RegisteredClientService), then this
* will fetch the client's configuration from the server.
*
* @author jricher
*
*/
public class DynamicClientRegistrationLoader extends CacheLoader<ServerConfiguration, RegisteredClient> {
private HttpComponentsClientHttpRequestFactory httpFactory;
private Gson gson = new Gson(); // note that this doesn't serialize nulls by default
public DynamicClientRegistrationLoader() {
this(HttpClientBuilder.create().useSystemProperties().build());
}
public DynamicClientRegistrationLoader(HttpClient httpClient) {
this.httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
}
@Override
public RegisteredClient load(ServerConfiguration serverConfig) throws Exception {
RestTemplate restTemplate = new RestTemplate(httpFactory);
RegisteredClient knownClient = registeredClientService.getByIssuer(serverConfig.getIssuer());
if (knownClient == null) {
// dynamically register this client
JsonObject jsonRequest = ClientDetailsEntityJsonProcessor.serialize(template);
String serializedClient = gson.toJson(jsonRequest);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Lists.newArrayList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<>(serializedClient, headers);
try {
String registered = restTemplate.postForObject(serverConfig.getRegistrationEndpointUri(), entity, String.class);
RegisteredClient client = ClientDetailsEntityJsonProcessor.parseRegistered(registered);
// save this client for later
registeredClientService.save(serverConfig.getIssuer(), client);
return client;
} catch (RestClientException rce) {
throw new InvalidClientException("Error registering client with server");
}
} else {
if (knownClient.getClientId() == null) {
// load this client's information from the server
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, knownClient.getRegistrationAccessToken()));
headers.setAccept(Lists.newArrayList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<>(headers);
try {
String registered = restTemplate.exchange(knownClient.getRegistrationClientUri(), HttpMethod.GET, entity, String.class).getBody();
// TODO: handle HTTP errors
RegisteredClient client = ClientDetailsEntityJsonProcessor.parseRegistered(registered);
return client;
} catch (RestClientException rce) {
throw new InvalidClientException("Error loading previously registered client information from server");
}
} else {
// it's got a client ID from the store, don't bother trying to load it
return knownClient;
}
}
}
}
}

View File

@ -1,215 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.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;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.mitre.openid.connect.client.service.ServerConfigurationService;
import org.mitre.openid.connect.config.ServerConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.web.client.RestTemplate;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
/**
*
* Dynamically fetches OpenID Connect server configurations based on the issuer. Caches the server configurations.
*
* @author jricher
*
*/
public class DynamicServerConfigurationService implements ServerConfigurationService {
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(DynamicServerConfigurationService.class);
// map of issuer -> server configuration, loaded dynamically from service discovery
private LoadingCache<String, ServerConfiguration> servers;
private Set<String> whitelist = new HashSet<>();
private Set<String> blacklist = new HashSet<>();
public DynamicServerConfigurationService() {
this(HttpClientBuilder.create().useSystemProperties().build());
}
public DynamicServerConfigurationService(HttpClient httpClient) {
// initialize the cache
servers = CacheBuilder.newBuilder().build(new OpenIDConnectServiceConfigurationFetcher(httpClient));
}
/**
* @return the whitelist
*/
public Set<String> getWhitelist() {
return whitelist;
}
/**
* @param whitelist the whitelist to set
*/
public void setWhitelist(Set<String> whitelist) {
this.whitelist = whitelist;
}
/**
* @return the blacklist
*/
public Set<String> getBlacklist() {
return blacklist;
}
/**
* @param blacklist the blacklist to set
*/
public void setBlacklist(Set<String> blacklist) {
this.blacklist = blacklist;
}
@Override
public ServerConfiguration getServerConfiguration(String issuer) {
try {
if (!whitelist.isEmpty() && !whitelist.contains(issuer)) {
throw new AuthenticationServiceException("Whitelist was nonempty, issuer was not in whitelist: " + issuer);
}
if (blacklist.contains(issuer)) {
throw new AuthenticationServiceException("Issuer was in blacklist: " + issuer);
}
return servers.get(issuer);
} catch (UncheckedExecutionException | ExecutionException e) {
logger.warn("Couldn't load configuration for " + issuer + ": " + e);
return null;
}
}
/**
* @author jricher
*
*/
private class OpenIDConnectServiceConfigurationFetcher extends CacheLoader<String, ServerConfiguration> {
private HttpComponentsClientHttpRequestFactory httpFactory;
private JsonParser parser = new JsonParser();
OpenIDConnectServiceConfigurationFetcher(HttpClient httpClient) {
this.httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
}
@Override
public ServerConfiguration load(String issuer) throws Exception {
RestTemplate restTemplate = new RestTemplate(httpFactory);
// data holder
ServerConfiguration conf = new ServerConfiguration();
// construct the well-known URI
String url = issuer + "/.well-known/openid-configuration";
// fetch the value
String jsonString = restTemplate.getForObject(url, String.class);
JsonElement parsed = parser.parse(jsonString);
if (parsed.isJsonObject()) {
JsonObject o = parsed.getAsJsonObject();
// sanity checks
if (!o.has("issuer")) {
throw new IllegalStateException("Returned object did not have an 'issuer' field");
}
if (!issuer.equals(o.get("issuer").getAsString())) {
logger.info("Issuer used for discover was " + issuer + " but final issuer is " + o.get("issuer").getAsString());
}
conf.setIssuer(o.get("issuer").getAsString());
conf.setAuthorizationEndpointUri(getAsString(o, "authorization_endpoint"));
conf.setTokenEndpointUri(getAsString(o, "token_endpoint"));
conf.setJwksUri(getAsString(o, "jwks_uri"));
conf.setUserInfoUri(getAsString(o, "userinfo_endpoint"));
conf.setRegistrationEndpointUri(getAsString(o, "registration_endpoint"));
conf.setIntrospectionEndpointUri(getAsString(o, "introspection_endpoint"));
conf.setAcrValuesSupported(getAsStringList(o, "acr_values_supported"));
conf.setCheckSessionIframe(getAsString(o, "check_session_iframe"));
conf.setClaimsLocalesSupported(getAsStringList(o, "claims_locales_supported"));
conf.setClaimsParameterSupported(getAsBoolean(o, "claims_parameter_supported"));
conf.setClaimsSupported(getAsStringList(o, "claims_supported"));
conf.setDisplayValuesSupported(getAsStringList(o, "display_values_supported"));
conf.setEndSessionEndpoint(getAsString(o, "end_session_endpoint"));
conf.setGrantTypesSupported(getAsStringList(o, "grant_types_supported"));
conf.setIdTokenSigningAlgValuesSupported(getAsJwsAlgorithmList(o, "id_token_signing_alg_values_supported"));
conf.setIdTokenEncryptionAlgValuesSupported(getAsJweAlgorithmList(o, "id_token_encryption_alg_values_supported"));
conf.setIdTokenEncryptionEncValuesSupported(getAsEncryptionMethodList(o, "id_token_encryption_enc_values_supported"));
conf.setOpPolicyUri(getAsString(o, "op_policy_uri"));
conf.setOpTosUri(getAsString(o, "op_tos_uri"));
conf.setRequestObjectEncryptionAlgValuesSupported(getAsJweAlgorithmList(o, "request_object_encryption_alg_values_supported"));
conf.setRequestObjectEncryptionEncValuesSupported(getAsEncryptionMethodList(o, "request_object_encryption_enc_values_supported"));
conf.setRequestObjectSigningAlgValuesSupported(getAsJwsAlgorithmList(o, "request_object_signing_alg_values_supported"));
conf.setRequestParameterSupported(getAsBoolean(o, "request_parameter_supported"));
conf.setRequestUriParameterSupported(getAsBoolean(o, "request_uri_parameter_supported"));
conf.setResponseTypesSupported(getAsStringList(o, "response_types_supported"));
conf.setScopesSupported(getAsStringList(o, "scopes_supported"));
conf.setSubjectTypesSupported(getAsStringList(o, "subject_types_supported"));
conf.setServiceDocumentation(getAsString(o, "service_documentation"));
conf.setTokenEndpointAuthMethodsSupported(getAsStringList(o, "token_endpoint_auth_methods"));
conf.setTokenEndpointAuthSigningAlgValuesSupported(getAsJwsAlgorithmList(o, "token_endpoint_auth_signing_alg_values_supported"));
conf.setUiLocalesSupported(getAsStringList(o, "ui_locales_supported"));
conf.setUserinfoEncryptionAlgValuesSupported(getAsJweAlgorithmList(o, "userinfo_encryption_alg_values_supported"));
conf.setUserinfoEncryptionEncValuesSupported(getAsEncryptionMethodList(o, "userinfo_encryption_enc_values_supported"));
conf.setUserinfoSigningAlgValuesSupported(getAsJwsAlgorithmList(o, "userinfo_signing_alg_values_supported"));
return conf;
} else {
throw new IllegalStateException("Couldn't parse server discovery results for " + url);
}
}
}
}

View File

@ -1,147 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.client.utils.URIBuilder;
import org.mitre.jwt.encryption.service.JWTEncryptionAndDecryptionService;
import org.mitre.jwt.signer.service.impl.JWKSetCacheService;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.client.service.AuthRequestUrlBuilder;
import org.mitre.openid.connect.config.ServerConfiguration;
import org.springframework.security.authentication.AuthenticationServiceException;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.JWEHeader;
import com.nimbusds.jwt.EncryptedJWT;
import com.nimbusds.jwt.JWTClaimsSet;
/**
* @author jricher
*
*/
public class EncryptedAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
private JWKSetCacheService encrypterService;
private JWEAlgorithm alg;
private EncryptionMethod enc;
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.AuthRequestUrlBuilder#buildAuthRequestUrl(org.mitre.openid.connect.config.ServerConfiguration, org.mitre.oauth2.model.RegisteredClient, java.lang.String, java.lang.String, java.lang.String, java.util.Map)
*/
@Override
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options, String loginHint) {
// create our signed JWT for the request object
JWTClaimsSet.Builder claims = new JWTClaimsSet.Builder();
//set parameters to JwtClaims
claims.claim("response_type", "code");
claims.claim("client_id", clientConfig.getClientId());
claims.claim("scope", Joiner.on(" ").join(clientConfig.getScope()));
// build our redirect URI
claims.claim("redirect_uri", redirectUri);
// this comes back in the id token
claims.claim("nonce", nonce);
// this comes back in the auth request return
claims.claim("state", state);
// Optional parameters
for (Entry<String, String> option : options.entrySet()) {
claims.claim(option.getKey(), option.getValue());
}
// if there's a login hint, send it
if (!Strings.isNullOrEmpty(loginHint)) {
claims.claim("login_hint", loginHint);
}
EncryptedJWT jwt = new EncryptedJWT(new JWEHeader(alg, enc), claims.build());
JWTEncryptionAndDecryptionService encryptor = encrypterService.getEncrypter(serverConfig.getJwksUri());
encryptor.encryptJwt(jwt);
try {
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
uriBuilder.addParameter("request", jwt.serialize());
// build out the URI
return uriBuilder.build().toString();
} catch (URISyntaxException e) {
throw new AuthenticationServiceException("Malformed Authorization Endpoint Uri", e);
}
}
/**
* @return the encrypterService
*/
public JWKSetCacheService getEncrypterService() {
return encrypterService;
}
/**
* @param encrypterService the encrypterService to set
*/
public void setEncrypterService(JWKSetCacheService encrypterService) {
this.encrypterService = encrypterService;
}
/**
* @return the alg
*/
public JWEAlgorithm getAlg() {
return alg;
}
/**
* @param alg the alg to set
*/
public void setAlg(JWEAlgorithm alg) {
this.alg = alg;
}
/**
* @return the enc
*/
public EncryptionMethod getEnc() {
return enc;
}
/**
* @param enc the enc to set
*/
public void setEnc(EncryptionMethod enc) {
this.enc = enc;
}
}

View File

@ -1,143 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.util.Map;
import java.util.Set;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.client.service.ClientConfigurationService;
import org.mitre.openid.connect.client.service.RegisteredClientService;
import org.mitre.openid.connect.config.ServerConfiguration;
/**
* Houses both a static client configuration and a dynamic client configuration
* service in one object. Checks the static service first, then falls through to
* the dynamic service.
*
* Provides configuration passthrough for the template, registered client service, whitelist,
* and blacklist for the dynamic service, and to the static service's client map.
*
* @author jricher
*
*/
public class HybridClientConfigurationService implements ClientConfigurationService {
private StaticClientConfigurationService staticClientService = new StaticClientConfigurationService();
private DynamicRegistrationClientConfigurationService dynamicClientService = new DynamicRegistrationClientConfigurationService();
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.ClientConfigurationService#getClientConfiguration(org.mitre.openid.connect.config.ServerConfiguration)
*/
@Override
public RegisteredClient getClientConfiguration(ServerConfiguration issuer) {
RegisteredClient client = staticClientService.getClientConfiguration(issuer);
if (client != null) {
return client;
} else {
return dynamicClientService.getClientConfiguration(issuer);
}
}
/**
* @return
* @see org.mitre.openid.connect.client.service.impl.StaticClientConfigurationService#getClients()
*/
public Map<String, RegisteredClient> getClients() {
return staticClientService.getClients();
}
/**
* @param clients
* @see org.mitre.openid.connect.client.service.impl.StaticClientConfigurationService#setClients(java.util.Map)
*/
public void setClients(Map<String, RegisteredClient> clients) {
staticClientService.setClients(clients);
}
/**
* @return
* @see org.mitre.openid.connect.client.service.impl.DynamicRegistrationClientConfigurationService#getTemplate()
*/
public RegisteredClient getTemplate() {
return dynamicClientService.getTemplate();
}
/**
* @param template
* @see org.mitre.openid.connect.client.service.impl.DynamicRegistrationClientConfigurationService#setTemplate(org.mitre.oauth2.model.RegisteredClient)
*/
public void setTemplate(RegisteredClient template) {
dynamicClientService.setTemplate(template);
}
/**
* @return
* @see org.mitre.openid.connect.client.service.impl.DynamicRegistrationClientConfigurationService#getRegisteredClientService()
*/
public RegisteredClientService getRegisteredClientService() {
return dynamicClientService.getRegisteredClientService();
}
/**
* @param registeredClientService
* @see org.mitre.openid.connect.client.service.impl.DynamicRegistrationClientConfigurationService#setRegisteredClientService(org.mitre.openid.connect.client.service.RegisteredClientService)
*/
public void setRegisteredClientService(RegisteredClientService registeredClientService) {
dynamicClientService.setRegisteredClientService(registeredClientService);
}
/**
* @return
* @see org.mitre.openid.connect.client.service.impl.DynamicRegistrationClientConfigurationService#getWhitelist()
*/
public Set<String> getWhitelist() {
return dynamicClientService.getWhitelist();
}
/**
* @param whitelist
* @see org.mitre.openid.connect.client.service.impl.DynamicRegistrationClientConfigurationService#setWhitelist(java.util.Set)
*/
public void setWhitelist(Set<String> whitelist) {
dynamicClientService.setWhitelist(whitelist);
}
/**
* @return
* @see org.mitre.openid.connect.client.service.impl.DynamicRegistrationClientConfigurationService#getBlacklist()
*/
public Set<String> getBlacklist() {
return dynamicClientService.getBlacklist();
}
/**
* @param blacklist
* @see org.mitre.openid.connect.client.service.impl.DynamicRegistrationClientConfigurationService#setBlacklist(java.util.Set)
*/
public void setBlacklist(Set<String> blacklist) {
dynamicClientService.setBlacklist(blacklist);
}
}

View File

@ -1,124 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.mitre.openid.connect.client.model.IssuerServiceResponse;
import org.mitre.openid.connect.client.service.IssuerService;
import com.google.common.collect.Sets;
/**
*
* Issuer service that tries to parse input from the inputs from a third-party
* account chooser service (if possible), but falls back to webfinger discovery
* if not.
*
* @author jricher
*
*/
public class HybridIssuerService implements IssuerService {
/**
* @return
* @see org.mitre.openid.connect.client.service.impl.ThirdPartyIssuerService#getAccountChooserUrl()
*/
public String getAccountChooserUrl() {
return thirdPartyIssuerService.getAccountChooserUrl();
}
/**
* @param accountChooserUrl
* @see org.mitre.openid.connect.client.service.impl.ThirdPartyIssuerService#setAccountChooserUrl(java.lang.String)
*/
public void setAccountChooserUrl(String accountChooserUrl) {
thirdPartyIssuerService.setAccountChooserUrl(accountChooserUrl);
}
/**
* @return
* @see org.mitre.openid.connect.client.service.impl.WebfingerIssuerService#isForceHttps()
*/
public boolean isForceHttps() {
return webfingerIssuerService.isForceHttps();
}
/**
* @param forceHttps
* @see org.mitre.openid.connect.client.service.impl.WebfingerIssuerService#setForceHttps(boolean)
*/
public void setForceHttps(boolean forceHttps) {
webfingerIssuerService.setForceHttps(forceHttps);
}
private ThirdPartyIssuerService thirdPartyIssuerService = new ThirdPartyIssuerService();
private WebfingerIssuerService webfingerIssuerService = new WebfingerIssuerService();
@Override
public IssuerServiceResponse getIssuer(HttpServletRequest request) {
IssuerServiceResponse resp = thirdPartyIssuerService.getIssuer(request);
if (resp.shouldRedirect()) {
// if it wants us to redirect, try the webfinger approach first
return webfingerIssuerService.getIssuer(request);
} else {
return resp;
}
}
public Set<String> getWhitelist() {
return Sets.union(thirdPartyIssuerService.getWhitelist(), webfingerIssuerService.getWhitelist());
}
public void setWhitelist(Set<String> whitelist) {
thirdPartyIssuerService.setWhitelist(whitelist);
webfingerIssuerService.setWhitelist(whitelist);
}
public Set<String> getBlacklist() {
return Sets.union(thirdPartyIssuerService.getBlacklist(), webfingerIssuerService.getWhitelist());
}
public void setBlacklist(Set<String> blacklist) {
thirdPartyIssuerService.setBlacklist(blacklist);
webfingerIssuerService.setBlacklist(blacklist);
}
public String getParameterName() {
return webfingerIssuerService.getParameterName();
}
public void setParameterName(String parameterName) {
webfingerIssuerService.setParameterName(parameterName);
}
public String getLoginPageUrl() {
return webfingerIssuerService.getLoginPageUrl();
}
public void setLoginPageUrl(String loginPageUrl) {
webfingerIssuerService.setLoginPageUrl(loginPageUrl);
thirdPartyIssuerService.setAccountChooserUrl(loginPageUrl); // set the same URL on both, but this one gets ignored
}
}

View File

@ -1,115 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.util.Map;
import java.util.Set;
import org.mitre.openid.connect.client.service.ServerConfigurationService;
import org.mitre.openid.connect.config.ServerConfiguration;
/**
* Houses both a static server configuration and a dynamic server configuration
* service in one object. Checks the static service first, then falls through to
* the dynamic service.
*
* Provides configuration passthrough to the dynamic service's whitelist and blacklist,
* and to the static service's server map.
*
*
* @author jricher
*
*/
public class HybridServerConfigurationService implements ServerConfigurationService {
private StaticServerConfigurationService staticServerService = new StaticServerConfigurationService();
private DynamicServerConfigurationService dynamicServerService = new DynamicServerConfigurationService();
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.ServerConfigurationService#getServerConfiguration(java.lang.String)
*/
@Override
public ServerConfiguration getServerConfiguration(String issuer) {
ServerConfiguration server = staticServerService.getServerConfiguration(issuer);
if (server != null) {
return server;
} else {
return dynamicServerService.getServerConfiguration(issuer);
}
}
/**
* @return
* @see org.mitre.openid.connect.client.service.impl.StaticServerConfigurationService#getServers()
*/
public Map<String, ServerConfiguration> getServers() {
return staticServerService.getServers();
}
/**
* @param servers
* @see org.mitre.openid.connect.client.service.impl.StaticServerConfigurationService#setServers(java.util.Map)
*/
public void setServers(Map<String, ServerConfiguration> servers) {
staticServerService.setServers(servers);
}
/**
* @return
* @see org.mitre.openid.connect.client.service.impl.DynamicServerConfigurationService#getWhitelist()
*/
public Set<String> getWhitelist() {
return dynamicServerService.getWhitelist();
}
/**
* @param whitelist
* @see org.mitre.openid.connect.client.service.impl.DynamicServerConfigurationService#setWhitelist(java.util.Set)
*/
public void setWhitelist(Set<String> whitelist) {
dynamicServerService.setWhitelist(whitelist);
}
/**
* @return
* @see org.mitre.openid.connect.client.service.impl.DynamicServerConfigurationService#getBlacklist()
*/
public Set<String> getBlacklist() {
return dynamicServerService.getBlacklist();
}
/**
* @param blacklist
* @see org.mitre.openid.connect.client.service.impl.DynamicServerConfigurationService#setBlacklist(java.util.Set)
*/
public void setBlacklist(Set<String> blacklist) {
dynamicServerService.setBlacklist(blacklist);
}
}

View File

@ -1,53 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.util.HashMap;
import java.util.Map;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.client.service.RegisteredClientService;
/**
* @author jricher
*
*/
public class InMemoryRegisteredClientService implements RegisteredClientService {
private Map<String, RegisteredClient> clients = new HashMap<>();
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.RegisteredClientService#getByIssuer(java.lang.String)
*/
@Override
public RegisteredClient getByIssuer(String issuer) {
return clients.get(issuer);
}
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.RegisteredClientService#save(org.mitre.oauth2.model.RegisteredClient)
*/
@Override
public void save(String issuer, RegisteredClient client) {
clients.put(issuer, client);
}
}

View File

@ -1,143 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.ClientDetailsEntityJsonProcessor;
import org.mitre.openid.connect.client.service.RegisteredClientService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
/**
* @author jricher
*
*/
public class JsonFileRegisteredClientService implements RegisteredClientService {
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(JsonFileRegisteredClientService.class);
private Gson gson = new GsonBuilder()
.registerTypeAdapter(RegisteredClient.class, new JsonSerializer<RegisteredClient>() {
@Override
public JsonElement serialize(RegisteredClient src, Type typeOfSrc, JsonSerializationContext context) {
return ClientDetailsEntityJsonProcessor.serialize(src);
}
})
.registerTypeAdapter(RegisteredClient.class, new JsonDeserializer<RegisteredClient>() {
@Override
public RegisteredClient deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return ClientDetailsEntityJsonProcessor.parseRegistered(json);
}
})
.setPrettyPrinting()
.create();
private File file;
private Map<String, RegisteredClient> clients = new HashMap<>();
public JsonFileRegisteredClientService(String filename) {
this.file = new File(filename);
load();
}
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.RegisteredClientService#getByIssuer(java.lang.String)
*/
@Override
public RegisteredClient getByIssuer(String issuer) {
return clients.get(issuer);
}
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.RegisteredClientService#save(java.lang.String, org.mitre.oauth2.model.RegisteredClient)
*/
@Override
public void save(String issuer, RegisteredClient client) {
clients.put(issuer, client);
write();
}
/**
* Sync the map of clients out to disk.
*/
@SuppressWarnings("serial")
private void write() {
try {
if (!file.exists()) {
// create a new file
logger.info("Creating saved clients list in " + file);
file.createNewFile();
}
FileWriter out = new FileWriter(file);
gson.toJson(clients, new TypeToken<Map<String, RegisteredClient>>(){}.getType(), out);
out.close();
} catch (IOException e) {
logger.error("Could not write to output file", e);
}
}
/**
* Load the map in from disk.
*/
@SuppressWarnings("serial")
private void load() {
try {
if (!file.exists()) {
logger.info("No sved clients file found in " + file);
return;
}
FileReader in = new FileReader(file);
clients = gson.fromJson(in, new TypeToken<Map<String, RegisteredClient>>(){}.getType());
in.close();
} catch (IOException e) {
logger.error("Could not read from input file", e);
}
}
}

View File

@ -1,84 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.client.utils.URIBuilder;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.client.service.AuthRequestUrlBuilder;
import org.mitre.openid.connect.config.ServerConfiguration;
import org.springframework.security.authentication.AuthenticationServiceException;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
/**
*
* Builds an auth request redirect URI with normal query parameters.
*
* @author jricher
*
*/
public class PlainAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.AuthRequestUrlBuilder#buildAuthRequest(javax.servlet.http.HttpServletRequest, org.mitre.openid.connect.config.ServerConfiguration, org.springframework.security.oauth2.provider.ClientDetails)
*/
@Override
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options, String loginHint) {
try {
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
uriBuilder.addParameter("response_type", "code");
uriBuilder.addParameter("client_id", clientConfig.getClientId());
uriBuilder.addParameter("scope", Joiner.on(" ").join(clientConfig.getScope()));
uriBuilder.addParameter("redirect_uri", redirectUri);
uriBuilder.addParameter("nonce", nonce);
uriBuilder.addParameter("state", state);
// Optional parameters:
for (Entry<String, String> option : options.entrySet()) {
uriBuilder.addParameter(option.getKey(), option.getValue());
}
// if there's a login hint, send it
if (!Strings.isNullOrEmpty(loginHint)) {
uriBuilder.addParameter("login_hint", loginHint);
}
return uriBuilder.build().toString();
} catch (URISyntaxException e) {
throw new AuthenticationServiceException("Malformed Authorization Endpoint Uri", e);
}
}
}

View File

@ -1,116 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.http.client.utils.URIBuilder;
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.client.service.AuthRequestUrlBuilder;
import org.mitre.openid.connect.config.ServerConfiguration;
import org.springframework.security.authentication.AuthenticationServiceException;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
/**
* @author jricher
*
*/
public class SignedAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
private JWTSigningAndValidationService signingAndValidationService;
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.AuthRequestUrlBuilder#buildAuthRequestUrl(org.mitre.openid.connect.config.ServerConfiguration, org.springframework.security.oauth2.provider.ClientDetails, java.lang.String, java.lang.String, java.lang.String)
*/
@Override
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options, String loginHint) {
// create our signed JWT for the request object
JWTClaimsSet.Builder claims = new JWTClaimsSet.Builder();
//set parameters to JwtClaims
claims.claim("response_type", "code");
claims.claim("client_id", clientConfig.getClientId());
claims.claim("scope", Joiner.on(" ").join(clientConfig.getScope()));
// build our redirect URI
claims.claim("redirect_uri", redirectUri);
// this comes back in the id token
claims.claim("nonce", nonce);
// this comes back in the auth request return
claims.claim("state", state);
// Optional parameters
for (Entry<String, String> option : options.entrySet()) {
claims.claim(option.getKey(), option.getValue());
}
// if there's a login hint, send it
if (!Strings.isNullOrEmpty(loginHint)) {
claims.claim("login_hint", loginHint);
}
JWSAlgorithm alg = clientConfig.getRequestObjectSigningAlg();
if (alg == null) {
alg = signingAndValidationService.getDefaultSigningAlgorithm();
}
SignedJWT jwt = new SignedJWT(new JWSHeader(alg), claims.build());
signingAndValidationService.signJwt(jwt, alg);
try {
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
uriBuilder.addParameter("request", jwt.serialize());
// build out the URI
return uriBuilder.build().toString();
} catch (URISyntaxException e) {
throw new AuthenticationServiceException("Malformed Authorization Endpoint Uri", e);
}
}
/**
* @return the signingAndValidationService
*/
public JWTSigningAndValidationService getSigningAndValidationService() {
return signingAndValidationService;
}
/**
* @param signingAndValidationService the signingAndValidationService to set
*/
public void setSigningAndValidationService(JWTSigningAndValidationService signingAndValidationService) {
this.signingAndValidationService = signingAndValidationService;
}
}

View File

@ -1,88 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.client.service.AuthRequestOptionsService;
import org.mitre.openid.connect.config.ServerConfiguration;
/**
*
* Always returns the same set of options.
*
* @author jricher
*
*/
public class StaticAuthRequestOptionsService implements AuthRequestOptionsService {
private Map<String, String> options = new HashMap<>();
private Map<String, String> tokenOptions = new HashMap<>();
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.AuthRequestOptionsService#getOptions(org.mitre.openid.connect.config.ServerConfiguration, org.mitre.oauth2.model.RegisteredClient, javax.servlet.http.HttpServletRequest)
*/
@Override
public Map<String, String> getOptions(ServerConfiguration server, RegisteredClient client, HttpServletRequest request) {
return options;
}
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.AuthRequestOptionsService#getTokenOptions(org.mitre.openid.connect.config.ServerConfiguration, org.mitre.oauth2.model.RegisteredClient, javax.servlet.http.HttpServletRequest)
*/
@Override
public Map<String, String> getTokenOptions(ServerConfiguration server, RegisteredClient client, HttpServletRequest request) {
return tokenOptions;
}
/**
* @return the options object directly
*/
public Map<String, String> getOptions() {
return options;
}
/**
* @param options the options to set
*/
public void setOptions(Map<String, String> options) {
this.options = options;
}
/**
* @return the tokenOptions
*/
public Map<String, String> getTokenOptions() {
return tokenOptions;
}
/**
* @param tokenOptions the tokenOptions to set
*/
public void setTokenOptions(Map<String, String> tokenOptions) {
this.tokenOptions = tokenOptions;
}
}

View File

@ -1,77 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.client.service.ClientConfigurationService;
import org.mitre.openid.connect.config.ServerConfiguration;
/**
* Client configuration service that holds a static map from issuer URL to a ClientDetails object to use at that issuer.
*
* Designed to be configured as a bean.
*
* @author jricher
*
*/
public class StaticClientConfigurationService implements ClientConfigurationService {
// Map of issuer URL -> client configuration information
private Map<String, RegisteredClient> clients;
/**
* @return the clients
*/
public Map<String, RegisteredClient> getClients() {
return clients;
}
/**
* @param clients the clients to set
*/
public void setClients(Map<String, RegisteredClient> clients) {
this.clients = clients;
}
/**
* Get the client configured for this issuer
*
* @see org.mitre.openid.connect.client.service.ClientConfigurationService#getClientConfiguration(java.lang.String)
*/
@Override
public RegisteredClient getClientConfiguration(ServerConfiguration issuer) {
return clients.get(issuer.getIssuer());
}
@PostConstruct
public void afterPropertiesSet() {
if (clients == null || clients.isEmpty()) {
throw new IllegalArgumentException("Clients map cannot be null or empty");
}
}
}

View File

@ -1,71 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.mitre.openid.connect.client.service.ServerConfigurationService;
import org.mitre.openid.connect.config.ServerConfiguration;
/**
* Statically configured server configuration service that maps issuer URLs to server configurations to use at that issuer.
*
* @author jricher
*
*/
public class StaticServerConfigurationService implements ServerConfigurationService {
// map of issuer url -> server configuration information
private Map<String, ServerConfiguration> servers;
/**
* @return the servers
*/
public Map<String, ServerConfiguration> getServers() {
return servers;
}
/**
* @param servers the servers to set
*/
public void setServers(Map<String, ServerConfiguration> servers) {
this.servers = servers;
}
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.ServerConfigurationService#getServerConfiguration(java.lang.String)
*/
@Override
public ServerConfiguration getServerConfiguration(String issuer) {
return servers.get(issuer);
}
@PostConstruct
public void afterPropertiesSet() {
if (servers == null || servers.isEmpty()) {
throw new IllegalArgumentException("Servers map cannot be null or empty.");
}
}
}

View File

@ -1,72 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import org.mitre.openid.connect.client.model.IssuerServiceResponse;
import org.mitre.openid.connect.client.service.IssuerService;
import com.google.common.base.Strings;
/**
* @author jricher
*
*/
public class StaticSingleIssuerService implements IssuerService {
private String issuer;
/**
* @return the issuer
*/
public String getIssuer() {
return issuer;
}
/**
* @param issuer the issuer to set
*/
public void setIssuer(String issuer) {
this.issuer = issuer;
}
/**
* Always returns the configured issuer URL
*
* @see org.mitre.openid.connect.client.service.IssuerService#getIssuer(javax.servlet.http.HttpServletRequest)
*/
@Override
public IssuerServiceResponse getIssuer(HttpServletRequest request) {
return new IssuerServiceResponse(getIssuer(), null, null);
}
@PostConstruct
public void afterPropertiesSet() {
if (Strings.isNullOrEmpty(issuer)) {
throw new IllegalArgumentException("Issuer must not be null or empty.");
}
}
}

View File

@ -1,139 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import org.apache.http.client.utils.URIBuilder;
import org.mitre.openid.connect.client.model.IssuerServiceResponse;
import org.mitre.openid.connect.client.service.IssuerService;
import org.springframework.security.authentication.AuthenticationServiceException;
import com.google.common.base.Strings;
/**
*
* Determines the issuer using an account chooser or other third-party-initiated login
*
* @author jricher
*
*/
public class ThirdPartyIssuerService implements IssuerService {
private String accountChooserUrl;
private Set<String> whitelist = new HashSet<>();
private Set<String> blacklist = new HashSet<>();
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.IssuerService#getIssuer(javax.servlet.http.HttpServletRequest)
*/
@Override
public IssuerServiceResponse getIssuer(HttpServletRequest request) {
// if the issuer is passed in, return that
String iss = request.getParameter("iss");
if (!Strings.isNullOrEmpty(iss)) {
if (!whitelist.isEmpty() && !whitelist.contains(iss)) {
throw new AuthenticationServiceException("Whitelist was nonempty, issuer was not in whitelist: " + iss);
}
if (blacklist.contains(iss)) {
throw new AuthenticationServiceException("Issuer was in blacklist: " + iss);
}
return new IssuerServiceResponse(iss, request.getParameter("login_hint"), request.getParameter("target_link_uri"));
} else {
try {
// otherwise, need to forward to the account chooser
String redirectUri = request.getRequestURL().toString();
URIBuilder builder = new URIBuilder(accountChooserUrl);
builder.addParameter("redirect_uri", redirectUri);
return new IssuerServiceResponse(builder.build().toString());
} catch (URISyntaxException e) {
throw new AuthenticationServiceException("Account Chooser URL is not valid", e);
}
}
}
/**
* @return the accountChooserUrl
*/
public String getAccountChooserUrl() {
return accountChooserUrl;
}
/**
* @param accountChooserUrl the accountChooserUrl to set
*/
public void setAccountChooserUrl(String accountChooserUrl) {
this.accountChooserUrl = accountChooserUrl;
}
/**
* @return the whitelist
*/
public Set<String> getWhitelist() {
return whitelist;
}
/**
* @param whitelist the whitelist to set
*/
public void setWhitelist(Set<String> whitelist) {
this.whitelist = whitelist;
}
/**
* @return the blacklist
*/
public Set<String> getBlacklist() {
return blacklist;
}
/**
* @param blacklist the blacklist to set
*/
public void setBlacklist(Set<String> blacklist) {
this.blacklist = blacklist;
}
@PostConstruct
public void afterPropertiesSet() {
if (Strings.isNullOrEmpty(this.accountChooserUrl)) {
throw new IllegalArgumentException("Account Chooser URL cannot be null or empty");
}
}
}

View File

@ -1,305 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import javax.servlet.http.HttpServletRequest;
import org.apache.http.client.HttpClient;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.HttpClientBuilder;
import org.mitre.discovery.util.WebfingerURLNormalizer;
import org.mitre.openid.connect.client.model.IssuerServiceResponse;
import org.mitre.openid.connect.client.service.IssuerService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import com.google.common.base.Strings;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
/**
* Use Webfinger to discover the appropriate issuer for a user-given input string.
* @author jricher
*
*/
public class WebfingerIssuerService implements IssuerService {
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(WebfingerIssuerService.class);
// map of user input -> issuer, loaded dynamically from webfinger discover
private LoadingCache<String, LoadingResult> issuers;
// private data shuttle class to get back two bits of info from the cache loader
private class LoadingResult {
public String loginHint;
public String issuer;
public LoadingResult(String loginHint, String issuer) {
this.loginHint = loginHint;
this.issuer = issuer;
}
}
private Set<String> whitelist = new HashSet<>();
private Set<String> blacklist = new HashSet<>();
/**
* Name of the incoming parameter to check for discovery purposes.
*/
private String parameterName = "identifier";
/**
* URL of the page to forward to if no identifier is given.
*/
private String loginPageUrl;
/**
* Strict enfocement of "https"
*/
private boolean forceHttps = true;
public WebfingerIssuerService() {
this(HttpClientBuilder.create().useSystemProperties().build());
}
public WebfingerIssuerService(HttpClient httpClient) {
issuers = CacheBuilder.newBuilder().build(new WebfingerIssuerFetcher(httpClient));
}
/* (non-Javadoc)
* @see org.mitre.openid.connect.client.service.IssuerService#getIssuer(javax.servlet.http.HttpServletRequest)
*/
@Override
public IssuerServiceResponse getIssuer(HttpServletRequest request) {
String identifier = request.getParameter(parameterName);
if (!Strings.isNullOrEmpty(identifier)) {
try {
LoadingResult lr = issuers.get(identifier);
if (!whitelist.isEmpty() && !whitelist.contains(lr.issuer)) {
throw new AuthenticationServiceException("Whitelist was nonempty, issuer was not in whitelist: " + lr.issuer);
}
if (blacklist.contains(lr.issuer)) {
throw new AuthenticationServiceException("Issuer was in blacklist: " + lr.issuer);
}
return new IssuerServiceResponse(lr.issuer, lr.loginHint, request.getParameter("target_link_uri"));
} catch (UncheckedExecutionException | ExecutionException e) {
logger.warn("Issue fetching issuer for user input: " + identifier + ": " + e.getMessage());
return null;
}
} else {
logger.warn("No user input given, directing to login page: " + loginPageUrl);
return new IssuerServiceResponse(loginPageUrl);
}
}
/**
* @return the parameterName
*/
public String getParameterName() {
return parameterName;
}
/**
* @param parameterName the parameterName to set
*/
public void setParameterName(String parameterName) {
this.parameterName = parameterName;
}
/**
* @return the loginPageUrl
*/
public String getLoginPageUrl() {
return loginPageUrl;
}
/**
* @param loginPageUrl the loginPageUrl to set
*/
public void setLoginPageUrl(String loginPageUrl) {
this.loginPageUrl = loginPageUrl;
}
/**
* @return the whitelist
*/
public Set<String> getWhitelist() {
return whitelist;
}
/**
* @param whitelist the whitelist to set
*/
public void setWhitelist(Set<String> whitelist) {
this.whitelist = whitelist;
}
/**
* @return the blacklist
*/
public Set<String> getBlacklist() {
return blacklist;
}
/**
* @param blacklist the blacklist to set
*/
public void setBlacklist(Set<String> blacklist) {
this.blacklist = blacklist;
}
/**
* @return the forceHttps
*/
public boolean isForceHttps() {
return forceHttps;
}
/**
* @param forceHttps the forceHttps to set
*/
public void setForceHttps(boolean forceHttps) {
this.forceHttps = forceHttps;
}
/**
* @author jricher
*
*/
private class WebfingerIssuerFetcher extends CacheLoader<String, LoadingResult> {
private HttpComponentsClientHttpRequestFactory httpFactory;
private JsonParser parser = new JsonParser();
WebfingerIssuerFetcher(HttpClient httpClient) {
this.httpFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
}
@Override
public LoadingResult load(String identifier) throws Exception {
UriComponents key = WebfingerURLNormalizer.normalizeResource(identifier);
RestTemplate restTemplate = new RestTemplate(httpFactory);
// construct the URL to go to
String scheme = key.getScheme();
// preserving http scheme is strictly for demo system use only.
if (!Strings.isNullOrEmpty(scheme) &&scheme.equals("http")) {
if (forceHttps) {
throw new IllegalArgumentException("Scheme must not be 'http'");
} else {
logger.warn("Webfinger endpoint MUST use the https URI scheme, overriding by configuration");
scheme = "http://"; // add on colon and slashes.
}
} else {
// otherwise we don't know the scheme, assume HTTPS
scheme = "https://";
}
// do a webfinger lookup
URIBuilder builder = new URIBuilder(scheme
+ key.getHost()
+ (key.getPort() >= 0 ? ":" + key.getPort() : "")
+ Strings.nullToEmpty(key.getPath())
+ "/.well-known/webfinger"
+ (Strings.isNullOrEmpty(key.getQuery()) ? "" : "?" + key.getQuery())
);
builder.addParameter("resource", identifier);
builder.addParameter("rel", "http://openid.net/specs/connect/1.0/issuer");
try {
// do the fetch
logger.info("Loading: " + builder.toString());
String webfingerResponse = restTemplate.getForObject(builder.build(), String.class);
JsonElement json = parser.parse(webfingerResponse);
if (json != null && json.isJsonObject()) {
// find the issuer
JsonArray links = json.getAsJsonObject().get("links").getAsJsonArray();
for (JsonElement link : links) {
if (link.isJsonObject()) {
JsonObject linkObj = link.getAsJsonObject();
if (linkObj.has("href")
&& linkObj.has("rel")
&& linkObj.get("rel").getAsString().equals("http://openid.net/specs/connect/1.0/issuer")) {
// we found the issuer, return it
String href = linkObj.get("href").getAsString();
if (identifier.equals(href)
|| identifier.startsWith("http")) {
// try to avoid sending a URL as the login hint
return new LoadingResult(null, href);
} else {
// otherwise pass back whatever the user typed as a login hint
return new LoadingResult(identifier, href);
}
}
}
}
}
} catch (JsonParseException | RestClientException e) {
logger.warn("Failure in fetching webfinger input", e.getMessage());
}
// we couldn't find it!
if (key.getScheme().equals("http") || key.getScheme().equals("https")) {
// if it looks like HTTP then punt: return the input, hope for the best
logger.warn("Returning normalized input string as issuer, hoping for the best: " + identifier);
return new LoadingResult(null, identifier);
} else {
// if it's not HTTP, give up
logger.warn("Couldn't find issuer: " + identifier);
throw new IllegalArgumentException();
}
}
}
}

View File

@ -1,106 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT 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.oauth2.introspectingfilter;
import java.util.Collections;
import java.util.Date;
import java.util.Set;
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";
private static Set<String> scopes = ImmutableSet.of("bar", "foo");
private static String scopeString = "foo bar";
private static Date exp = new Date(123 * 1000L);
private static Long expVal = 123L;
@Test
public void testFullToken() {
JsonObject tokenObj = new JsonObject();
tokenObj.addProperty("active", true);
tokenObj.addProperty("scope", scopeString);
tokenObj.addProperty("exp", expVal);
tokenObj.addProperty("sub", "subject");
tokenObj.addProperty("client_id", "123-456-789");
OAuth2AccessTokenImpl tok = new OAuth2AccessTokenImpl(tokenObj, tokenString);
assertThat(tok.getScope(), is(equalTo(scopes)));
assertThat(tok.getExpiration(), is(equalTo(exp)));
}
@Test
public void testNullExp() {
JsonObject tokenObj = new JsonObject();
tokenObj.addProperty("active", true);
tokenObj.addProperty("scope", scopeString);
tokenObj.addProperty("sub", "subject");
tokenObj.addProperty("client_id", "123-456-789");
OAuth2AccessTokenImpl tok = new OAuth2AccessTokenImpl(tokenObj, tokenString);
assertThat(tok.getScope(), is(equalTo(scopes)));
assertThat(tok.getExpiration(), is(equalTo(null)));
}
@Test
public void testNullScopes() {
JsonObject tokenObj = new JsonObject();
tokenObj.addProperty("active", true);
tokenObj.addProperty("exp", expVal);
tokenObj.addProperty("sub", "subject");
tokenObj.addProperty("client_id", "123-456-789");
OAuth2AccessTokenImpl tok = new OAuth2AccessTokenImpl(tokenObj, tokenString);
assertThat(tok.getScope(), is(equalTo(Collections.EMPTY_SET)));
assertThat(tok.getExpiration(), is(equalTo(exp)));
}
@Test
public void testNullScopesNullExp() {
JsonObject tokenObj = new JsonObject();
tokenObj.addProperty("active", true);
tokenObj.addProperty("sub", "subject");
tokenObj.addProperty("client_id", "123-456-789");
OAuth2AccessTokenImpl tok = new OAuth2AccessTokenImpl(tokenObj, tokenString);
assertThat(tok.getScope(), is(equalTo(Collections.EMPTY_SET)));
assertThat(tok.getExpiration(), is(equalTo(null)));
}
}

View File

@ -1,84 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT 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.oauth2.introspectingfilter.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import com.google.gson.JsonObject;
import static org.junit.Assert.assertTrue;
/**
* @author jricher
*
*/
public class TestScopeBasedIntrospectionAuthoritiesGranter {
private JsonObject introspectionResponse;
private ScopeBasedIntrospectionAuthoritiesGranter granter = new ScopeBasedIntrospectionAuthoritiesGranter();
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
introspectionResponse = new JsonObject();
}
/**
* Test method for {@link org.mitre.oauth2.introspectingfilter.service.impl.ScopeBasedIntrospectionAuthoritiesGranter#getAuthorities(com.google.gson.JsonObject)}.
*/
@Test
public void testGetAuthoritiesJsonObject_withScopes() {
introspectionResponse.addProperty("scope", "foo bar baz batman");
List<GrantedAuthority> expected = new ArrayList<>();
expected.add(new SimpleGrantedAuthority("ROLE_API"));
expected.add(new SimpleGrantedAuthority("OAUTH_SCOPE_foo"));
expected.add(new SimpleGrantedAuthority("OAUTH_SCOPE_bar"));
expected.add(new SimpleGrantedAuthority("OAUTH_SCOPE_baz"));
expected.add(new SimpleGrantedAuthority("OAUTH_SCOPE_batman"));
List<GrantedAuthority> authorities = granter.getAuthorities(introspectionResponse);
assertTrue(authorities.containsAll(expected));
assertTrue(expected.containsAll(authorities));
}
/**
* Test method for {@link org.mitre.oauth2.introspectingfilter.service.impl.ScopeBasedIntrospectionAuthoritiesGranter#getAuthorities(com.google.gson.JsonObject)}.
*/
@Test
public void testGetAuthoritiesJsonObject_withoutScopes() {
List<GrantedAuthority> expected = new ArrayList<>();
expected.add(new SimpleGrantedAuthority("ROLE_API"));
List<GrantedAuthority> authorities = granter.getAuthorities(introspectionResponse);
assertTrue(authorities.containsAll(expected));
assertTrue(expected.containsAll(authorities));
}
}

View File

@ -1,61 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT 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.client;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.security.authentication.AuthenticationServiceException;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.mockito.Mockito.mock;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
public class TestOIDCAuthenticationFilter {
private OIDCAuthenticationFilter filter = new OIDCAuthenticationFilter();
@Test
public void attemptAuthentication_error() throws Exception {
HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
Mockito.when(request.getParameter("error")).thenReturn("Error");
Mockito.when(request.getParameter("error_description")).thenReturn("Description");
Mockito.when(request.getParameter("error_uri")).thenReturn("http://example.com");
try {
filter.attemptAuthentication(request, mock(HttpServletResponse.class));
fail("AuthorizationEndpointException expected.");
}
catch (AuthorizationEndpointException exception) {
assertThat(exception.getMessage(),
is("Error from Authorization Endpoint: Error Description http://example.com"));
assertThat(exception.getError(), is("Error"));
assertThat(exception.getErrorDescription(), is("Description"));
assertThat(exception.getErrorURI(), is("http://example.com"));
assertThat(exception, is(instanceOf(AuthenticationServiceException.class)));
}
}
}

View File

@ -1,117 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.config.ServerConfiguration;
import org.mockito.InjectMocks;
import org.mockito.Matchers;
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
*
*/
@RunWith(MockitoJUnitRunner.class)
public class TestHybridClientConfigurationService {
@Mock
private StaticClientConfigurationService mockStaticService;
@Mock
private DynamicRegistrationClientConfigurationService mockDynamicService;
@InjectMocks
private HybridClientConfigurationService hybridService;
// test fixture
@Mock
private RegisteredClient mockClient;
@Mock
private ServerConfiguration mockServerConfig;
private String issuer = "https://www.example.com/";
@Before
public void prepare() {
Mockito.reset(mockDynamicService, mockStaticService);
Mockito.when(mockServerConfig.getIssuer()).thenReturn(issuer);
}
@Test
public void getClientConfiguration_useStatic() {
Mockito.when(mockStaticService.getClientConfiguration(mockServerConfig)).thenReturn(mockClient);
RegisteredClient result = hybridService.getClientConfiguration(mockServerConfig);
Mockito.verify(mockStaticService).getClientConfiguration(mockServerConfig);
Mockito.verify(mockDynamicService, Mockito.never()).getClientConfiguration(Matchers.any(ServerConfiguration.class));
assertEquals(mockClient, result);
}
@Test
public void getClientConfiguration_useDynamic() {
Mockito.when(mockStaticService.getClientConfiguration(mockServerConfig)).thenReturn(null);
Mockito.when(mockDynamicService.getClientConfiguration(mockServerConfig)).thenReturn(mockClient);
RegisteredClient result = hybridService.getClientConfiguration(mockServerConfig);
Mockito.verify(mockStaticService).getClientConfiguration(mockServerConfig);
Mockito.verify(mockDynamicService).getClientConfiguration(mockServerConfig);
assertEquals(mockClient, result);
}
/**
* Checks the behavior when the issuer is not known.
*/
@Test
public void getClientConfiguration_noIssuer() {
// The mockServerConfig is known to both services
Mockito.when(mockStaticService.getClientConfiguration(mockServerConfig)).thenReturn(mockClient);
Mockito.when(mockDynamicService.getClientConfiguration(mockServerConfig)).thenReturn(mockClient);
// But oh noes! We're going to ask it to find us some other issuer
ServerConfiguration badIssuer = Mockito.mock(ServerConfiguration.class);
Mockito.when(badIssuer.getIssuer()).thenReturn("www.badexample.com");
RegisteredClient result = hybridService.getClientConfiguration(badIssuer);
Mockito.verify(mockStaticService).getClientConfiguration(badIssuer);
Mockito.verify(mockDynamicService).getClientConfiguration(badIssuer);
assertThat(result, is(nullValue()));
}
}

View File

@ -1,108 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mitre.openid.connect.config.ServerConfiguration;
import org.mockito.InjectMocks;
import org.mockito.Matchers;
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
*
*/
@RunWith(MockitoJUnitRunner.class)
public class TestHybridServerConfigurationService {
@Mock
private StaticServerConfigurationService mockStaticService;
@Mock
private DynamicServerConfigurationService mockDynamicService;
@InjectMocks
private HybridServerConfigurationService hybridService;
@Mock
private ServerConfiguration mockServerConfig;
private String issuer = "https://www.example.com/";
@Before
public void prepare() {
Mockito.reset(mockDynamicService, mockStaticService);
}
@Test
public void getServerConfiguration_useStatic() {
Mockito.when(mockStaticService.getServerConfiguration(issuer)).thenReturn(mockServerConfig);
ServerConfiguration result = hybridService.getServerConfiguration(issuer);
Mockito.verify(mockStaticService).getServerConfiguration(issuer);
Mockito.verify(mockDynamicService, Mockito.never()).getServerConfiguration(Matchers.anyString());
assertEquals(mockServerConfig, result);
}
@Test
public void getServerConfiguration_useDynamic() {
Mockito.when(mockStaticService.getServerConfiguration(issuer)).thenReturn(null);
Mockito.when(mockDynamicService.getServerConfiguration(issuer)).thenReturn(mockServerConfig);
ServerConfiguration result = hybridService.getServerConfiguration(issuer);
Mockito.verify(mockStaticService).getServerConfiguration(issuer);
Mockito.verify(mockDynamicService).getServerConfiguration(issuer);
assertEquals(mockServerConfig, result);
}
/**
* Checks the behavior when the issuer is not known.
*/
@Test
public void getServerConfiguration_noIssuer() {
Mockito.when(mockStaticService.getServerConfiguration(issuer)).thenReturn(mockServerConfig);
Mockito.when(mockDynamicService.getServerConfiguration(issuer)).thenReturn(mockServerConfig);
String badIssuer = "www.badexample.com";
ServerConfiguration result = hybridService.getServerConfiguration(badIssuer);
Mockito.verify(mockStaticService).getServerConfiguration(badIssuer);
Mockito.verify(mockDynamicService).getServerConfiguration(badIssuer);
assertThat(result, is(nullValue()));
}
}

View File

@ -1,108 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.config.ServerConfiguration;
import org.mockito.Mockito;
import org.springframework.security.authentication.AuthenticationServiceException;
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
*
*/
public class TestPlainAuthRequestUrlBuilder {
// Test fixture:
ServerConfiguration serverConfig;
RegisteredClient clientConfig;
private PlainAuthRequestUrlBuilder urlBuilder = new PlainAuthRequestUrlBuilder();
@Before
public void prepare() {
serverConfig = Mockito.mock(ServerConfiguration.class);
Mockito.when(serverConfig.getAuthorizationEndpointUri()).thenReturn("https://server.example.com/authorize");
clientConfig = Mockito.mock(RegisteredClient.class);
Mockito.when(clientConfig.getClientId()).thenReturn("s6BhdRkqt3");
Mockito.when(clientConfig.getScope()).thenReturn(Sets.newHashSet("openid", "profile"));
}
@Test
public void buildAuthRequestUrl() {
String expectedUrl = "https://server.example.com/authorize?" +
"response_type=code" +
"&client_id=s6BhdRkqt3" +
"&scope=openid+profile" + // plus sign used for space per application/x-www-form-encoded standard
"&redirect_uri=https%3A%2F%2Fclient.example.org%2F" +
"&nonce=34fasf3ds" +
"&state=af0ifjsldkj" +
"&foo=bar";
Map<String, String> options = ImmutableMap.of("foo", "bar");
String actualUrl = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "https://client.example.org/", "34fasf3ds", "af0ifjsldkj", options, null);
assertThat(actualUrl, equalTo(expectedUrl));
}
@Test
public void buildAuthRequestUrl_withLoginHint() {
String expectedUrl = "https://server.example.com/authorize?" +
"response_type=code" +
"&client_id=s6BhdRkqt3" +
"&scope=openid+profile" + // plus sign used for space per application/x-www-form-encoded standard
"&redirect_uri=https%3A%2F%2Fclient.example.org%2F" +
"&nonce=34fasf3ds" +
"&state=af0ifjsldkj" +
"&foo=bar" +
"&login_hint=bob";
Map<String, String> options = ImmutableMap.of("foo", "bar");
String actualUrl = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "https://client.example.org/", "34fasf3ds", "af0ifjsldkj", options, "bob");
assertThat(actualUrl, equalTo(expectedUrl));
}
@Test(expected = AuthenticationServiceException.class)
public void buildAuthRequestUrl_badUri() {
Mockito.when(serverConfig.getAuthorizationEndpointUri()).thenReturn("e=mc^2");
Map<String, String> options = ImmutableMap.of("foo", "bar");
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "", options, null);
}
}

View File

@ -1,204 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.text.ParseException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.mitre.jwt.signer.service.impl.DefaultJWTSigningAndValidationService;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.config.ServerConfiguration;
import org.mockito.Mockito;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.nimbusds.jose.Algorithm;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.jwt.JWTClaimsSet;
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
*
*/
public class TestSignedAuthRequestUrlBuilder {
// Test fixture:
private ServerConfiguration serverConfig;
private RegisteredClient clientConfig;
private String redirectUri = "https://client.example.org/";
private String nonce = "34fasf3ds";
private String state = "af0ifjsldkj";
private String responseType = "code";
private Map<String, String> options = ImmutableMap.of("foo", "bar");
// RSA key properties:
// {@link package com.nimbusds.jose.jwk#RSAKey}
private String n = "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zw" +
"u1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc" +
"5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8K" +
"JZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh" +
"6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw";
private String e = "AQAB";
private String d = "X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknc" +
"hnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5" +
"N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSa" +
"wm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk1" +
"9Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q";
private String alg = "RS256";
private String kid = "2011-04-29";
private String loginHint = "bob";
private DefaultJWTSigningAndValidationService signingAndValidationService;
private SignedAuthRequestUrlBuilder urlBuilder = new SignedAuthRequestUrlBuilder();
@Before
public void prepare() throws NoSuchAlgorithmException, InvalidKeySpecException {
RSAKey key = new RSAKey(new Base64URL(n), new Base64URL(e), new Base64URL(d), KeyUse.SIGNATURE, null, new Algorithm(alg), kid, null, null, null, null, null);
Map<String, JWK> keys = Maps.newHashMap();
keys.put("client", key);
signingAndValidationService = new DefaultJWTSigningAndValidationService(keys);
signingAndValidationService.setDefaultSignerKeyId("client");
signingAndValidationService.setDefaultSigningAlgorithmName(alg);
urlBuilder.setSigningAndValidationService(signingAndValidationService);
serverConfig = Mockito.mock(ServerConfiguration.class);
Mockito.when(serverConfig.getAuthorizationEndpointUri()).thenReturn("https://server.example.com/authorize");
clientConfig = Mockito.mock(RegisteredClient.class);
Mockito.when(clientConfig.getClientId()).thenReturn("s6BhdRkqt3");
Mockito.when(clientConfig.getScope()).thenReturn(Sets.newHashSet("openid", "profile"));
}
/**
* This test takes the URI from the result of building a signed request
* and checks that the JWS object parsed from the request URI matches up
* with the expected claim values.
*/
@Test
public void buildAuthRequestUrl() {
String requestUri = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options, null);
// parsing the result
UriComponentsBuilder builder = null;
try {
builder = UriComponentsBuilder.fromUri(new URI(requestUri));
} catch (URISyntaxException e1) {
fail("URISyntaxException was thrown.");
}
UriComponents components = builder.build();
String jwtString = components.getQueryParams().get("request").get(0);
JWTClaimsSet claims = null;
try {
SignedJWT jwt = SignedJWT.parse(jwtString);
claims = jwt.getJWTClaimsSet();
} catch (ParseException e) {
fail("ParseException was thrown.");
}
assertEquals(responseType, claims.getClaim("response_type"));
assertEquals(clientConfig.getClientId(), claims.getClaim("client_id"));
List<String> scopeList = Arrays.asList(((String) claims.getClaim("scope")).split(" "));
assertTrue(scopeList.containsAll(clientConfig.getScope()));
assertEquals(redirectUri, claims.getClaim("redirect_uri"));
assertEquals(nonce, claims.getClaim("nonce"));
assertEquals(state, claims.getClaim("state"));
for (String claim : options.keySet()) {
assertEquals(options.get(claim), claims.getClaim(claim));
}
}
@Test
public void buildAuthRequestUrl_withLoginHint() {
String requestUri = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options, loginHint);
// parsing the result
UriComponentsBuilder builder = null;
try {
builder = UriComponentsBuilder.fromUri(new URI(requestUri));
} catch (URISyntaxException e1) {
fail("URISyntaxException was thrown.");
}
UriComponents components = builder.build();
String jwtString = components.getQueryParams().get("request").get(0);
JWTClaimsSet claims = null;
try {
SignedJWT jwt = SignedJWT.parse(jwtString);
claims = jwt.getJWTClaimsSet();
} catch (ParseException e) {
fail("ParseException was thrown.");
}
assertEquals(responseType, claims.getClaim("response_type"));
assertEquals(clientConfig.getClientId(), claims.getClaim("client_id"));
List<String> scopeList = Arrays.asList(((String) claims.getClaim("scope")).split(" "));
assertTrue(scopeList.containsAll(clientConfig.getScope()));
assertEquals(redirectUri, claims.getClaim("redirect_uri"));
assertEquals(nonce, claims.getClaim("nonce"));
assertEquals(state, claims.getClaim("state"));
for (String claim : options.keySet()) {
assertEquals(options.get(claim), claims.getClaim(claim));
}
assertEquals(loginHint, claims.getClaim("login_hint"));
}
@Test(expected = AuthenticationServiceException.class)
public void buildAuthRequestUrl_badUri() {
Mockito.when(serverConfig.getAuthorizationEndpointUri()).thenReturn("e=mc^2");
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "", options, null);
}
}

View File

@ -1,90 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.config.ServerConfiguration;
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
*
*/
@RunWith(MockitoJUnitRunner.class)
public class TestStaticClientConfigurationService {
private StaticClientConfigurationService service;
private String issuer = "https://www.example.com/";
@Mock
private RegisteredClient mockClient;
@Mock
private ServerConfiguration mockServerConfig;
@Before
public void prepare() {
service = new StaticClientConfigurationService();
Map<String, RegisteredClient> clients = new HashMap<>();
clients.put(issuer, mockClient);
service.setClients(clients);
Mockito.when(mockServerConfig.getIssuer()).thenReturn(issuer);
}
@Test
public void getClientConfiguration_success() {
RegisteredClient result = service.getClientConfiguration(mockServerConfig);
assertThat(mockClient, is(notNullValue()));
assertEquals(mockClient, result);
}
/**
* Checks the behavior when the issuer is not known.
*/
@Test
public void getClientConfiguration_noIssuer() {
Mockito.when(mockServerConfig.getIssuer()).thenReturn("www.badexample.net");
RegisteredClient actualClient = service.getClientConfiguration(mockServerConfig);
assertThat(actualClient, is(nullValue()));
}
}

View File

@ -1,83 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import java.util.HashMap;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
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
*
*/
@RunWith(MockitoJUnitRunner.class)
public class TestStaticServerConfigurationService {
private StaticServerConfigurationService service;
private String issuer = "https://www.example.com/";
@Mock
private ServerConfiguration mockServerConfig;
@Before
public void prepare() {
service = new StaticServerConfigurationService();
Map<String, ServerConfiguration> servers = new HashMap<>();
servers.put(issuer, mockServerConfig);
service.setServers(servers);
}
@Test
public void getServerConfiguration_success() {
ServerConfiguration result = service.getServerConfiguration(issuer);
assertThat(mockServerConfig, is(notNullValue()));
assertEquals(mockServerConfig, result);
}
/**
* Checks the behavior when the issuer is not known.
*/
@Test
public void getClientConfiguration_noIssuer() {
ServerConfiguration result = service.getServerConfiguration("www.badexample.net");
assertThat(result, is(nullValue()));
}
}

View File

@ -1,130 +0,0 @@
/*******************************************************************************
* Copyright 2018 The MIT Internet Trust Consortium
*
* Portions copyright 2011-2013 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.client.service.impl;
import javax.servlet.http.HttpServletRequest;
import org.junit.Before;
import org.junit.Test;
import org.mitre.openid.connect.client.model.IssuerServiceResponse;
import org.mockito.Mockito;
import org.springframework.security.authentication.AuthenticationServiceException;
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
*
*/
public class TestThirdPartyIssuerService {
// Test fixture:
private HttpServletRequest request;
private String iss = "https://server.example.org";
private String login_hint = "I'm not telling you nothin!";
private String target_link_uri = "https://www.example.com";
private String redirect_uri = "https://www.example.com";
private String accountChooserUrl = "https://www.example.com/account";
private ThirdPartyIssuerService service = new ThirdPartyIssuerService();
@Before
public void prepare() {
service.setAccountChooserUrl(accountChooserUrl);
request = Mockito.mock(HttpServletRequest.class);
Mockito.when(request.getParameter("iss")).thenReturn(iss);
Mockito.when(request.getParameter("login_hint")).thenReturn(login_hint);
Mockito.when(request.getParameter("target_link_uri")).thenReturn(target_link_uri);
Mockito.when(request.getRequestURL()).thenReturn(new StringBuffer(redirect_uri));
}
@Test
public void getIssuer_hasIssuer() {
IssuerServiceResponse response = service.getIssuer(request);
assertThat(response.getIssuer(), equalTo(iss));
assertThat(response.getLoginHint(), equalTo(login_hint));
assertThat(response.getTargetLinkUri(), equalTo(target_link_uri));
assertThat(response.getRedirectUrl(), nullValue());
}
@Test
public void getIssuer_noIssuer() {
Mockito.when(request.getParameter("iss")).thenReturn(null);
IssuerServiceResponse response = service.getIssuer(request);
assertThat(response.getIssuer(), nullValue());
assertThat(response.getLoginHint(), nullValue());
assertThat(response.getTargetLinkUri(), nullValue());
String expectedRedirectUrl = accountChooserUrl + "?redirect_uri=" + "https%3A%2F%2Fwww.example.com"; // url-encoded string of the request url
assertThat(response.getRedirectUrl(), equalTo(expectedRedirectUrl));
}
@Test
public void getIssuer_isWhitelisted() {
service.setWhitelist(Sets.newHashSet(iss));
IssuerServiceResponse response = service.getIssuer(request);
assertThat(response.getIssuer(), equalTo(iss));
assertThat(response.getLoginHint(), equalTo(login_hint));
assertThat(response.getTargetLinkUri(), equalTo(target_link_uri));
assertThat(response.getRedirectUrl(), nullValue());
}
@Test(expected = AuthenticationServiceException.class)
public void getIssuer_notWhitelisted() {
service.setWhitelist(Sets.newHashSet("some.other.site"));
service.getIssuer(request);
}
@Test(expected = AuthenticationServiceException.class)
public void getIssuer_blacklisted() {
service.setBlacklist(Sets.newHashSet(iss));
service.getIssuer(request);
}
@Test(expected = AuthenticationServiceException.class)
public void getIssuer_badUri() {
Mockito.when(request.getParameter("iss")).thenReturn(null);
service.setAccountChooserUrl("e=mc^2");
service.getIssuer(request);
}
}

View File

@ -1,8 +0,0 @@
{"jwk":
[
{"alg":"RSA",
"mod": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"exp":"AQAB",
"kid":"2011-04-29"}
]
}

View File

@ -1,8 +0,0 @@
{"jwk":
[
{"alg":"RSA",
"mod": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
"exp":"AQAB",
"kid":"2011-04-29"}
]
}

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2018 The MIT Internet Trust Consortium
Portions copyright 2011-2013 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.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jwt-signer="http://www.mitre.org/schema/openid-connect/jwt-signer"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.mitre.org/schema/openid-connect/jwt-signer http://www.mitre.org/schema/openid-connect/jwt-signer/jwt-signer-1.0.xsd" >
<!-- Creates an in-memory database populated with test jdbc -->
<bean id="dataSource" class="org.mitre.jdbc.datasource.H2DataSourceFactory">
<property name="databaseName" value="connect"/>
<property name="scriptLocations" >
<list>
<!-- OpenID Connect Data model -->
<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>
</property>
<property name="dateConversionPatterns">
<map>
<entry key="yyyy/mm/dd hh24:mi:ss" value="yyy/MM/dd HH:mm:ss" />
<entry key="yyyy-mm-dd" value="yyyy-MM-dd" />
</map>
</property>
</bean>
</beans>

View File

@ -1,15 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICxDCCAi0CBECcV/wwDQYJKoZIhvcNAQEEBQAwgagxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIEwVU
ZXhhczEPMA0GA1UEBxMGQXVzdGluMSowKAYDVQQKEyFUaGUgVW5pdmVyc2l0eSBvZiBUZXhhcyBh
dCBBdXN0aW4xKDAmBgNVBAsTH0luZm9ybWF0aW9uIFRlY2hub2xvZ3kgU2VydmljZXMxIjAgBgNV
BAMTGXhtbGdhdGV3YXkuaXRzLnV0ZXhhcy5lZHUwHhcNMDQwNTA4MDM0NjA0WhcNMDQwODA2MDM0
NjA0WjCBqDELMAkGA1UEBhMCVVMxDjAMBgNVBAgTBVRleGFzMQ8wDQYDVQQHEwZBdXN0aW4xKjAo
BgNVBAoTIVRoZSBVbml2ZXJzaXR5IG9mIFRleGFzIGF0IEF1c3RpbjEoMCYGA1UECxMfSW5mb3Jt
YXRpb24gVGVjaG5vbG9neSBTZXJ2aWNlczEiMCAGA1UEAxMZeG1sZ2F0ZXdheS5pdHMudXRleGFz
LmVkdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsmc+6+NjLmanvh+FvBziYdBwTiz+d/DZ
Uy2jyvij6f8Xly6zkhHLSsuBzw08wPzr2K+F359bf9T3uiZMuao//FBGtDrTYpvQwkn4PFZwSeY2
Ynw4edxp1JEWT2zfOY+QJDfNgpsYQ9hrHDwqnpbMVVqjdBq5RgTKGhFBj9kxEq0CAwEAATANBgkq
hkiG9w0BAQQFAAOBgQCPYGXF6oRbnjti3CPtjfwORoO7ab1QzNS9Z2rLMuPnt6POlm1A3UPEwCS8
6flTlAqg19Sh47H7+Iq/LuzotKvUE5ugK52QRNMa4c0OSaO5UEM5EfVox1pT9tZV1Z3whYYMhThg
oC4y/On0NUVMN5xfF/GpSACga/bVjoNvd8HWEg==
-----END CERTIFICATE-----

View File

@ -1,15 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICxDCCAi0CBECcV/wwDQYJKoZIhvcNAQEEBQAwgagxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIEwVU
ZXhhczEPMA0GA1UEBxMGQXVzdGluMSowKAYDVQQKEyFUaGUgVW5pdmVyc2l0eSBvZiBUZXhhcyBh
dCBBdXN0aW4xKDAmBgNVBAsTH0luZm9ybWF0aW9uIFRlY2hub2xvZ3kgU2VydmljZXMxIjAgBgNV
BAMTGXhtbGdhdGV3YXkuaXRzLnV0ZXhhcy5lZHUwHhcNMDQwNTA4MDM0NjA0WhcNMDQwODA2MDM0
NjA0WjCBqDELMAkGA1UEBhMCVVMxDjAMBgNVBAgTBVRleGFzMQ8wDQYDVQQHEwZBdXN0aW4xKjAo
BgNVBAoTIVRoZSBVbml2ZXJzaXR5IG9mIFRleGFzIGF0IEF1c3RpbjEoMCYGA1UECxMfSW5mb3Jt
YXRpb24gVGVjaG5vbG9neSBTZXJ2aWNlczEiMCAGA1UEAxMZeG1sZ2F0ZXdheS5pdHMudXRleGFz
LmVkdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsmc+6+NjLmanvh+FvBziYdBwTiz+d/DZ
Uy2jyvij6f8Xly6zkhHLSsuBzw08wPzr2K+F359bf9T3uiZMuao//FBGtDrTYpvQwkn4PFZwSeY2
Ynw4edxp1JEWT2zfOY+QJDfNgpsYQ9hrHDwqnpbMVVqjdBq5RgTKGhFBj9kxEq0CAwEAATANBgkq
hkiG9w0BAQQFAAOBgQCPYGXF6oRbnjti3CPtjfwORoO7ab1QzNS9Z2rLMuPnt6POlm1A3UPEwCS8
6flTlAqg19Sh47H7+Iq/LuzotKvUE5ugK52QRNMa4c0OSaO5UEM5EfVox1pT9tZV1Z3whYYMhThg
oC4y/On0NUVMN5xfF/GpSACga/bVjoNvd8HWEg==
-----END CERTIFICATE-----

View File

@ -1,12 +0,0 @@
local-values.conf
target
*~
bin
*.idea
*.iml
*.eml
.project
.settings
.classpath
/target
.springBeans

View File

@ -1,132 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2018 The MIT Internet Trust Consortium
Portions copyright 2011-2013 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>openid-connect-parent</artifactId>
<groupId>org.mitre</groupId>
<version>1.3.4-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<artifactId>openid-connect-common</artifactId>
<description>OpenID Connect Common modules</description>
<name>OpenID Connect Common</name>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>javax.persistence</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</dependency>
</dependencies>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${java-version}</source>
<target>${java-version}</target>
</configuration>
</plugin>
<!-- BUILD SOURCE FILES -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- BUILD JavaDoc FILES -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,3 +0,0 @@
Manifest-Version: 1.0
Class-Path:

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