added login hint capability to client library
parent
f7a082d4b8
commit
c166cbe49c
|
@ -262,7 +262,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
|
|
||||||
Map<String, String> options = authOptions.getOptions(serverConfig, clientConfig, request);
|
Map<String, String> options = authOptions.getOptions(serverConfig, clientConfig, request);
|
||||||
|
|
||||||
String authRequest = authRequestBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options);
|
String authRequest = authRequestBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options, issResp.getLoginHint());
|
||||||
|
|
||||||
logger.debug("Auth Request: " + authRequest);
|
logger.debug("Auth Request: " + authRequest);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@ import org.mitre.oauth2.model.RegisteredClient;
|
||||||
import org.mitre.openid.connect.config.ServerConfiguration;
|
import org.mitre.openid.connect.config.ServerConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Builds a URL string to the IdP's authorization endpoint.
|
||||||
|
*
|
||||||
* @author jricher
|
* @author jricher
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -36,8 +38,9 @@ public interface AuthRequestUrlBuilder {
|
||||||
* @param redirectUri
|
* @param redirectUri
|
||||||
* @param nonce
|
* @param nonce
|
||||||
* @param state
|
* @param state
|
||||||
|
* @param loginHint
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options);
|
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options, String loginHint);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.mitre.openid.connect.config.ServerConfiguration;
|
||||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.nimbusds.jose.EncryptionMethod;
|
import com.nimbusds.jose.EncryptionMethod;
|
||||||
import com.nimbusds.jose.JWEAlgorithm;
|
import com.nimbusds.jose.JWEAlgorithm;
|
||||||
import com.nimbusds.jose.JWEHeader;
|
import com.nimbusds.jose.JWEHeader;
|
||||||
|
@ -54,7 +55,7 @@ public class EncryptedAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
||||||
* @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)
|
* @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
|
@Override
|
||||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options) {
|
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
|
// create our signed JWT for the request object
|
||||||
JWTClaimsSet claims = new JWTClaimsSet();
|
JWTClaimsSet claims = new JWTClaimsSet();
|
||||||
|
@ -78,6 +79,11 @@ public class EncryptedAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
||||||
claims.setClaim(option.getKey(), option.getValue());
|
claims.setClaim(option.getKey(), option.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if there's a login hint, send it
|
||||||
|
if (!Strings.isNullOrEmpty(loginHint)) {
|
||||||
|
claims.setClaim("login_hint", loginHint);
|
||||||
|
}
|
||||||
|
|
||||||
EncryptedJWT jwt = new EncryptedJWT(new JWEHeader(alg, enc), claims);
|
EncryptedJWT jwt = new EncryptedJWT(new JWEHeader(alg, enc), claims);
|
||||||
|
|
||||||
JWTEncryptionAndDecryptionService encryptor = encrypterService.getEncrypter(serverConfig.getJwksUri());
|
JWTEncryptionAndDecryptionService encryptor = encrypterService.getEncrypter(serverConfig.getJwksUri());
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.mitre.openid.connect.config.ServerConfiguration;
|
||||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -44,7 +45,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)
|
* @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
|
@Override
|
||||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options) {
|
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options, String loginHint) {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
|
URIBuilder uriBuilder = new URIBuilder(serverConfig.getAuthorizationEndpointUri());
|
||||||
|
@ -63,6 +64,11 @@ public class PlainAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
||||||
uriBuilder.addParameter(option.getKey(), option.getValue());
|
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();
|
return uriBuilder.build().toString();
|
||||||
|
|
||||||
} catch (URISyntaxException e) {
|
} catch (URISyntaxException e) {
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.mitre.openid.connect.config.ServerConfiguration;
|
||||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.nimbusds.jose.JWSAlgorithm;
|
import com.nimbusds.jose.JWSAlgorithm;
|
||||||
import com.nimbusds.jose.JWSHeader;
|
import com.nimbusds.jose.JWSHeader;
|
||||||
import com.nimbusds.jwt.JWTClaimsSet;
|
import com.nimbusds.jwt.JWTClaimsSet;
|
||||||
|
@ -48,7 +49,7 @@ 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)
|
* @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
|
@Override
|
||||||
public String buildAuthRequestUrl(ServerConfiguration serverConfig, RegisteredClient clientConfig, String redirectUri, String nonce, String state, Map<String, String> options) {
|
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
|
// create our signed JWT for the request object
|
||||||
JWTClaimsSet claims = new JWTClaimsSet();
|
JWTClaimsSet claims = new JWTClaimsSet();
|
||||||
|
@ -72,6 +73,11 @@ public class SignedAuthRequestUrlBuilder implements AuthRequestUrlBuilder {
|
||||||
claims.setClaim(option.getKey(), option.getValue());
|
claims.setClaim(option.getKey(), option.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if there's a login hint, send it
|
||||||
|
if (!Strings.isNullOrEmpty(loginHint)) {
|
||||||
|
claims.setClaim("login_hint", loginHint);
|
||||||
|
}
|
||||||
|
|
||||||
JWSAlgorithm alg = clientConfig.getRequestObjectSigningAlg();
|
JWSAlgorithm alg = clientConfig.getRequestObjectSigningAlg();
|
||||||
if (alg == null) {
|
if (alg == null) {
|
||||||
alg = signingAndValidationService.getDefaultSigningAlgorithm();
|
alg = signingAndValidationService.getDefaultSigningAlgorithm();
|
||||||
|
|
|
@ -98,7 +98,7 @@ public class WebfingerIssuerService implements IssuerService {
|
||||||
throw new AuthenticationServiceException("Issuer was in blacklist: " + issuer);
|
throw new AuthenticationServiceException("Issuer was in blacklist: " + issuer);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new IssuerServiceResponse(issuer, null, null);
|
return new IssuerServiceResponse(issuer, identifier, null);
|
||||||
} catch (UncheckedExecutionException ue) {
|
} catch (UncheckedExecutionException ue) {
|
||||||
logger.warn("Issue fetching issuer for user input: " + identifier, ue);
|
logger.warn("Issue fetching issuer for user input: " + identifier, ue);
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -69,7 +69,27 @@ public class TestPlainAuthRequestUrlBuilder {
|
||||||
|
|
||||||
Map<String, String> options = ImmutableMap.of("foo", "bar");
|
Map<String, String> options = ImmutableMap.of("foo", "bar");
|
||||||
|
|
||||||
String actualUrl = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "https://client.example.org/", "34fasf3ds", "af0ifjsldkj", options);
|
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));
|
assertThat(actualUrl, equalTo(expectedUrl));
|
||||||
}
|
}
|
||||||
|
@ -81,7 +101,7 @@ public class TestPlainAuthRequestUrlBuilder {
|
||||||
|
|
||||||
Map<String, String> options = ImmutableMap.of("foo", "bar");
|
Map<String, String> options = ImmutableMap.of("foo", "bar");
|
||||||
|
|
||||||
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "", options);
|
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "", options, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,7 @@ public class TestSignedAuthRequestUrlBuilder {
|
||||||
"9Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q";
|
"9Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q";
|
||||||
private String alg = "RS256";
|
private String alg = "RS256";
|
||||||
private String kid = "2011-04-29";
|
private String kid = "2011-04-29";
|
||||||
|
private String loginHint = "bob";
|
||||||
|
|
||||||
private DefaultJWTSigningAndValidationService signingAndValidationService;
|
private DefaultJWTSigningAndValidationService signingAndValidationService;
|
||||||
|
|
||||||
|
@ -116,7 +117,7 @@ public class TestSignedAuthRequestUrlBuilder {
|
||||||
@Test
|
@Test
|
||||||
public void buildAuthRequestUrl() {
|
public void buildAuthRequestUrl() {
|
||||||
|
|
||||||
String requestUri = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options);
|
String requestUri = urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, redirectUri, nonce, state, options, null);
|
||||||
|
|
||||||
// parsing the result
|
// parsing the result
|
||||||
UriComponentsBuilder builder = null;
|
UriComponentsBuilder builder = null;
|
||||||
|
@ -152,11 +153,51 @@ public class TestSignedAuthRequestUrlBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
ReadOnlyJWTClaimsSet 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)
|
@Test(expected = AuthenticationServiceException.class)
|
||||||
public void buildAuthRequestUrl_badUri() {
|
public void buildAuthRequestUrl_badUri() {
|
||||||
|
|
||||||
Mockito.when(serverConfig.getAuthorizationEndpointUri()).thenReturn("e=mc^2");
|
Mockito.when(serverConfig.getAuthorizationEndpointUri()).thenReturn("e=mc^2");
|
||||||
|
|
||||||
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "", options);
|
urlBuilder.buildAuthRequestUrl(serverConfig, clientConfig, "example.com", "", "", options, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue