added configurable support for clients to send extra parameters like display and prompt, addresses #426

pull/485/head
Justin Richer 2013-08-22 13:52:07 -04:00
parent 3360117b7b
commit 6a9650d2a7
8 changed files with 142 additions and 18 deletions

View File

@ -22,6 +22,7 @@ import java.net.URI;
import java.security.SecureRandom;
import java.text.ParseException;
import java.util.Date;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ -33,10 +34,12 @@ import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
import org.mitre.jwt.signer.service.impl.JWKSetSigningAndValidationServiceCacheService;
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.OIDCAuthenticationToken;
import org.springframework.beans.factory.annotation.Autowired;
@ -88,8 +91,9 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
private ServerConfigurationService servers;
private ClientConfigurationService clients;
private IssuerService issuerService;
private AuthRequestOptionsService authOptions = new StaticAuthRequestOptionsService(); // initialize with an empty set of options
private AuthRequestUrlBuilder authRequestBuilder;
protected int httpSocketTimeout = HTTP_SOCKET_TIMEOUT;
/**
@ -201,7 +205,9 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
// this value comes back in the auth code response
String state = createState(session);
String authRequest = authRequestBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state);
Map<String, String> options = authOptions.getOptions(serverConfig, clientConfig, request);
String authRequest = authRequestBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options);
logger.debug("Auth Request: " + authRequest);
@ -603,4 +609,18 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
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;
}
}

View File

@ -0,0 +1,25 @@
/**
*
*/
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.
* These options may depend on the server configuration, client configuration, or HTTP request.
*
* @author jricher
*
*/
public interface AuthRequestOptionsService {
public Map<String, String> getOptions(ServerConfiguration server, RegisteredClient client, HttpServletRequest request);
}

View File

@ -19,6 +19,8 @@
*/
package org.mitre.openid.connect.client.service;
import java.util.Map;
import org.mitre.oauth2.model.RegisteredClient;
import org.mitre.openid.connect.config.ServerConfiguration;
@ -36,6 +38,6 @@ public interface AuthRequestUrlBuilder {
* @param state
* @return
*/
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state);
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options);
}

View File

@ -20,6 +20,8 @@
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;
@ -42,7 +44,7 @@ public class PlainAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
* @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) {
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options) {
try {
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
@ -57,8 +59,9 @@ public class PlainAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
uriBuilder.addParameter("state", state);
// Optional parameters:
// TODO: display, prompt
for (Entry<String, String> option : options.entrySet()) {
uriBuilder.addParameter(option.getKey(), option.getValue());
}
return uriBuilder.build().toString();

View File

@ -20,6 +20,8 @@
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;
@ -45,24 +47,31 @@ public class SignedAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
* @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) {
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options) {
// create our signed JWT for the request object
JWTClaimsSet claims = new JWTClaimsSet();
//set parameters to JwtClaims
claims.setCustomClaim("response_type", "code");
claims.setCustomClaim("client_id", clientConfig.getClientId());
claims.setCustomClaim("scope", Joiner.on(" ").join(clientConfig.getScope()));
claims.setClaim("response_type", "code");
claims.setClaim("client_id", clientConfig.getClientId());
claims.setClaim("scope", Joiner.on(" ").join(clientConfig.getScope()));
// build our redirect URI
claims.setCustomClaim("redirect_uri", redirectUri);
claims.setClaim("redirect_uri", redirectUri);
// this comes back in the id token
claims.setCustomClaim("nonce", nonce);
claims.setClaim("nonce", nonce);
// this comes back in the auth request return
claims.setCustomClaim("state", state);
claims.setClaim("state", state);
// Optional parameters
for (Entry<String, String> option : options.entrySet()) {
claims.setClaim(option.getKey(), option.getValue());
}
SignedJWT jwt = new SignedJWT(new JWSHeader(signingAndValidationService.getDefaultSigningAlgorithm()), claims);

View File

@ -0,0 +1,50 @@
/**
*
*/
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<String, String>();
/* (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;
}
/**
* @return the options
*/
public Map<String, String> getOptions() {
return options;
}
/**
* @param options the options to set
*/
public void setOptions(Map<String, String> options) {
this.options = options;
}
}

View File

@ -16,6 +16,9 @@
******************************************************************************/
package org.mitre.openid.connect.client.service.impl;
import java.util.Collections;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.mitre.oauth2.model.RegisteredClient;
@ -23,6 +26,7 @@ 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;
@ -60,9 +64,12 @@ public class TestPlainAuthRequestUrlBuilder {
"&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";
"&state=af0ifjsldkj" +
"&foo=bar";
Map<String, String> options = ImmutableMap.of("foo", "bar");
String actualUrl = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "https://client.example.org/", "34fasf3ds", "af0ifjsldkj");
String actualUrl = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "https://client.example.org/", "34fasf3ds", "af0ifjsldkj", options);
assertThat(actualUrl, equalTo(expectedUrl));
}
@ -72,7 +79,9 @@ public class TestPlainAuthRequestUrlBuilder {
Mockito.when(serverConfig.getAuthorizationEndpointUri()).thenReturn("e=mc^2");
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "");
Map<String, String> options = ImmutableMap.of("foo", "bar");
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "", options);
}
}

View File

@ -35,6 +35,7 @@ import org.springframework.security.authentication.AuthenticationServiceExceptio
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;
@ -63,6 +64,8 @@ public class TestSignedAuthRequestUrlBuilder {
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}
@ -113,7 +116,7 @@ public class TestSignedAuthRequestUrlBuilder {
@Test
public void buildAuthRequestUrl() {
String requestUri = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state);
String requestUri = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options);
// parsing the result
UriComponentsBuilder builder = null;
@ -144,6 +147,9 @@ public class TestSignedAuthRequestUrlBuilder {
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(expected = AuthenticationServiceException.class)
@ -151,6 +157,6 @@ public class TestSignedAuthRequestUrlBuilder {
Mockito.when(serverConfig.getAuthorizationEndpointUri()).thenReturn("e=mc^2");
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "");
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "", options);
}
}