added software statement to client model, added processor to dynamic registration parser
parent
17be89fe98
commit
fa63993896
|
@ -0,0 +1,30 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright 2016 The MITRE Corporation
|
||||||
|
* and 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.jwt.assertion;
|
||||||
|
|
||||||
|
import com.nimbusds.jwt.JWT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jricher
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface AssertionValidator {
|
||||||
|
|
||||||
|
public boolean isValid(JWT assertion);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright 2016 The MITRE Corporation
|
||||||
|
* and 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.jwt.assertion.impl;
|
||||||
|
|
||||||
|
import org.mitre.jwt.assertion.AssertionValidator;
|
||||||
|
|
||||||
|
import com.nimbusds.jwt.JWT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jricher
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class NullAssertionValidator implements AssertionValidator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid(JWT assertion) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -51,6 +51,7 @@ import org.mitre.oauth2.model.convert.JWEAlgorithmStringConverter;
|
||||||
import org.mitre.oauth2.model.convert.JWEEncryptionMethodStringConverter;
|
import org.mitre.oauth2.model.convert.JWEEncryptionMethodStringConverter;
|
||||||
import org.mitre.oauth2.model.convert.JWKSetStringConverter;
|
import org.mitre.oauth2.model.convert.JWKSetStringConverter;
|
||||||
import org.mitre.oauth2.model.convert.JWSAlgorithmStringConverter;
|
import org.mitre.oauth2.model.convert.JWSAlgorithmStringConverter;
|
||||||
|
import org.mitre.oauth2.model.convert.JWTStringConverter;
|
||||||
import org.mitre.oauth2.model.convert.SimpleGrantedAuthorityStringConverter;
|
import org.mitre.oauth2.model.convert.SimpleGrantedAuthorityStringConverter;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.oauth2.provider.ClientDetails;
|
import org.springframework.security.oauth2.provider.ClientDetails;
|
||||||
|
@ -59,6 +60,7 @@ import com.nimbusds.jose.EncryptionMethod;
|
||||||
import com.nimbusds.jose.JWEAlgorithm;
|
import com.nimbusds.jose.JWEAlgorithm;
|
||||||
import com.nimbusds.jose.JWSAlgorithm;
|
import com.nimbusds.jose.JWSAlgorithm;
|
||||||
import com.nimbusds.jose.jwk.JWKSet;
|
import com.nimbusds.jose.jwk.JWKSet;
|
||||||
|
import com.nimbusds.jwt.JWT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author jricher
|
* @author jricher
|
||||||
|
@ -144,6 +146,9 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
|
|
||||||
/** fields for UMA */
|
/** fields for UMA */
|
||||||
private Set<String> claimsRedirectUris;
|
private Set<String> claimsRedirectUris;
|
||||||
|
|
||||||
|
/** Software statement **/
|
||||||
|
private JWT softwareStatement;
|
||||||
|
|
||||||
public enum AuthMethod {
|
public enum AuthMethod {
|
||||||
SECRET_POST("client_secret_post"),
|
SECRET_POST("client_secret_post"),
|
||||||
|
@ -988,4 +993,21 @@ public class ClientDetailsEntity implements ClientDetails {
|
||||||
this.claimsRedirectUris = claimsRedirectUris;
|
this.claimsRedirectUris = claimsRedirectUris;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the softwareStatement
|
||||||
|
*/
|
||||||
|
@Basic
|
||||||
|
@Column(name = "software_statement")
|
||||||
|
@Convert(converter = JWTStringConverter.class)
|
||||||
|
public JWT getSoftwareStatement() {
|
||||||
|
return softwareStatement;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param softwareStatement the softwareStatement to set
|
||||||
|
*/
|
||||||
|
public void setSoftwareStatement(JWT softwareStatement) {
|
||||||
|
this.softwareStatement = softwareStatement;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.mitre.oauth2.model;
|
package org.mitre.oauth2.model;
|
||||||
|
|
||||||
public interface RegisteredClientFields {
|
public interface RegisteredClientFields {
|
||||||
|
public String SOFTWARE_STATEMENT = "software_statement";
|
||||||
public String CLAIMS_REDIRECT_URIS = "claims_redirect_uris";
|
public String CLAIMS_REDIRECT_URIS = "claims_redirect_uris";
|
||||||
public String CLIENT_SECRET_EXPIRES_AT = "client_secret_expires_at";
|
public String CLIENT_SECRET_EXPIRES_AT = "client_secret_expires_at";
|
||||||
public String CLIENT_ID_ISSUED_AT = "client_id_issued_at";
|
public String CLIENT_ID_ISSUED_AT = "client_id_issued_at";
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.mitre.openid.connect;
|
||||||
|
|
||||||
|
|
||||||
import static org.mitre.oauth2.model.RegisteredClientFields.APPLICATION_TYPE;
|
import static org.mitre.oauth2.model.RegisteredClientFields.APPLICATION_TYPE;
|
||||||
|
import static org.mitre.oauth2.model.RegisteredClientFields.CLAIMS_REDIRECT_URIS;
|
||||||
import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_ID;
|
import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_ID;
|
||||||
import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_ID_ISSUED_AT;
|
import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_ID_ISSUED_AT;
|
||||||
import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_NAME;
|
import static org.mitre.oauth2.model.RegisteredClientFields.CLIENT_NAME;
|
||||||
|
@ -47,9 +48,10 @@ import static org.mitre.oauth2.model.RegisteredClientFields.REQUEST_OBJECT_SIGNI
|
||||||
import static org.mitre.oauth2.model.RegisteredClientFields.REQUEST_URIS;
|
import static org.mitre.oauth2.model.RegisteredClientFields.REQUEST_URIS;
|
||||||
import static org.mitre.oauth2.model.RegisteredClientFields.REQUIRE_AUTH_TIME;
|
import static org.mitre.oauth2.model.RegisteredClientFields.REQUIRE_AUTH_TIME;
|
||||||
import static org.mitre.oauth2.model.RegisteredClientFields.RESPONSE_TYPES;
|
import static org.mitre.oauth2.model.RegisteredClientFields.RESPONSE_TYPES;
|
||||||
import static org.mitre.oauth2.model.RegisteredClientFields.*;
|
import static org.mitre.oauth2.model.RegisteredClientFields.SCOPE;
|
||||||
import static org.mitre.oauth2.model.RegisteredClientFields.SCOPE_SEPARATOR;
|
import static org.mitre.oauth2.model.RegisteredClientFields.SCOPE_SEPARATOR;
|
||||||
import static org.mitre.oauth2.model.RegisteredClientFields.SECTOR_IDENTIFIER_URI;
|
import static org.mitre.oauth2.model.RegisteredClientFields.SECTOR_IDENTIFIER_URI;
|
||||||
|
import static org.mitre.oauth2.model.RegisteredClientFields.SOFTWARE_STATEMENT;
|
||||||
import static org.mitre.oauth2.model.RegisteredClientFields.SUBJECT_TYPE;
|
import static org.mitre.oauth2.model.RegisteredClientFields.SUBJECT_TYPE;
|
||||||
import static org.mitre.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_METHOD;
|
import static org.mitre.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_METHOD;
|
||||||
import static org.mitre.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_SIGNING_ALG;
|
import static org.mitre.oauth2.model.RegisteredClientFields.TOKEN_ENDPOINT_AUTH_SIGNING_ALG;
|
||||||
|
@ -67,6 +69,7 @@ import static org.mitre.util.JsonUtils.getAsStringSet;
|
||||||
|
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
|
|
||||||
|
import org.mitre.jwt.assertion.AssertionValidator;
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity.AppType;
|
import org.mitre.oauth2.model.ClientDetailsEntity.AppType;
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
|
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
|
||||||
|
@ -74,6 +77,8 @@ import org.mitre.oauth2.model.ClientDetailsEntity.SubjectType;
|
||||||
import org.mitre.oauth2.model.RegisteredClient;
|
import org.mitre.oauth2.model.RegisteredClient;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
|
@ -82,6 +87,8 @@ import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import com.nimbusds.jose.jwk.JWKSet;
|
import com.nimbusds.jose.jwk.JWKSet;
|
||||||
|
import com.nimbusds.jwt.JWT;
|
||||||
|
import com.nimbusds.jwt.JWTParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class to handle the parsing and serialization of ClientDetails objects.
|
* Utility class to handle the parsing and serialization of ClientDetails objects.
|
||||||
|
@ -94,7 +101,7 @@ public class ClientDetailsEntityJsonProcessor {
|
||||||
private static Logger logger = LoggerFactory.getLogger(ClientDetailsEntityJsonProcessor.class);
|
private static Logger logger = LoggerFactory.getLogger(ClientDetailsEntityJsonProcessor.class);
|
||||||
|
|
||||||
private static JsonParser parser = new JsonParser();
|
private static JsonParser parser = new JsonParser();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* Create an unbound ClientDetailsEntity from the given JSON string.
|
* Create an unbound ClientDetailsEntity from the given JSON string.
|
||||||
|
@ -148,6 +155,7 @@ public class ClientDetailsEntityJsonProcessor {
|
||||||
c.setJwks(jwks);
|
c.setJwks(jwks);
|
||||||
} catch (ParseException e) {
|
} catch (ParseException e) {
|
||||||
logger.error("Unable to parse JWK Set for client", e);
|
logger.error("Unable to parse JWK Set for client", e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,6 +203,16 @@ public class ClientDetailsEntityJsonProcessor {
|
||||||
|
|
||||||
c.setClaimsRedirectUris(getAsStringSet(o, CLAIMS_REDIRECT_URIS));
|
c.setClaimsRedirectUris(getAsStringSet(o, CLAIMS_REDIRECT_URIS));
|
||||||
|
|
||||||
|
String softwareStatement = getAsString(o, SOFTWARE_STATEMENT);
|
||||||
|
try {
|
||||||
|
JWT softwareStatementJwt = JWTParser.parse(softwareStatement);
|
||||||
|
c.setSoftwareStatement(softwareStatementJwt);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
logger.warn("Error parsing software statement", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -169,6 +169,8 @@ CREATE TABLE IF NOT EXISTS client_details (
|
||||||
initiate_login_uri VARCHAR(2048),
|
initiate_login_uri VARCHAR(2048),
|
||||||
clear_access_tokens_on_refresh BOOLEAN DEFAULT true NOT NULL,
|
clear_access_tokens_on_refresh BOOLEAN DEFAULT true NOT NULL,
|
||||||
|
|
||||||
|
software_statement VARCHAR(4096),
|
||||||
|
|
||||||
UNIQUE (client_id)
|
UNIQUE (client_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.mitre.openid.connect.web;
|
package org.mitre.openid.connect.web;
|
||||||
|
|
||||||
|
import static org.mitre.oauth2.model.RegisteredClientFields.*;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -23,9 +25,12 @@ import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.mitre.jwt.assertion.AssertionValidator;
|
||||||
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
|
import org.mitre.jwt.signer.service.JWTSigningAndValidationService;
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||||
|
import org.mitre.oauth2.model.ClientDetailsEntity.AppType;
|
||||||
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
|
import org.mitre.oauth2.model.ClientDetailsEntity.AuthMethod;
|
||||||
|
import org.mitre.oauth2.model.ClientDetailsEntity.SubjectType;
|
||||||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
|
||||||
import org.mitre.oauth2.model.RegisteredClient;
|
import org.mitre.oauth2.model.RegisteredClient;
|
||||||
import org.mitre.oauth2.model.SystemScope;
|
import org.mitre.oauth2.model.SystemScope;
|
||||||
|
@ -43,9 +48,11 @@ import org.mitre.openid.connect.view.JsonErrorView;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
|
import org.springframework.security.oauth2.common.util.OAuth2Utils;
|
||||||
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
import org.springframework.security.oauth2.provider.OAuth2Authentication;
|
||||||
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
|
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
@ -60,6 +67,11 @@ import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.gson.JsonSyntaxException;
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
import com.nimbusds.jose.EncryptionMethod;
|
||||||
|
import com.nimbusds.jose.JWEAlgorithm;
|
||||||
|
import com.nimbusds.jose.JWSAlgorithm;
|
||||||
|
import com.nimbusds.jose.jwk.JWKSet;
|
||||||
|
import com.nimbusds.jwt.JWTClaimsSet;
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping(value = DynamicClientRegistrationEndpoint.URL)
|
@RequestMapping(value = DynamicClientRegistrationEndpoint.URL)
|
||||||
|
@ -88,6 +100,10 @@ public class DynamicClientRegistrationEndpoint {
|
||||||
@Autowired
|
@Autowired
|
||||||
private OIDCTokenService connectTokenService;
|
private OIDCTokenService connectTokenService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("clientAssertionValidator")
|
||||||
|
private static AssertionValidator assertionValidator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logger for this class
|
* Logger for this class
|
||||||
*/
|
*/
|
||||||
|
@ -132,6 +148,7 @@ public class DynamicClientRegistrationEndpoint {
|
||||||
newClient = validateGrantTypes(newClient);
|
newClient = validateGrantTypes(newClient);
|
||||||
newClient = validateRedirectUris(newClient);
|
newClient = validateRedirectUris(newClient);
|
||||||
newClient = validateAuth(newClient);
|
newClient = validateAuth(newClient);
|
||||||
|
newClient = validateSoftwareStatement(newClient);
|
||||||
} catch (ValidationException ve) {
|
} catch (ValidationException ve) {
|
||||||
// validation failed, return an error
|
// validation failed, return an error
|
||||||
m.addAttribute(JsonErrorView.ERROR, ve.getError());
|
m.addAttribute(JsonErrorView.ERROR, ve.getError());
|
||||||
|
@ -234,7 +251,7 @@ public class DynamicClientRegistrationEndpoint {
|
||||||
if (client != null && client.getClientId().equals(auth.getOAuth2Request().getClientId())) {
|
if (client != null && client.getClientId().equals(auth.getOAuth2Request().getClientId())) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
OAuth2AccessTokenEntity token = fetchValidRegistrationToken(auth, client);
|
OAuth2AccessTokenEntity token = rotateRegistrationTokenIfNecessary(auth, client);
|
||||||
RegisteredClient registered = new RegisteredClient(client, token.getValue(), config.getIssuer() + "register/" + UriUtils.encodePathSegment(client.getClientId(), "UTF-8"));
|
RegisteredClient registered = new RegisteredClient(client, token.getValue(), config.getIssuer() + "register/" + UriUtils.encodePathSegment(client.getClientId(), "UTF-8"));
|
||||||
|
|
||||||
// send it all out to the view
|
// send it all out to the view
|
||||||
|
@ -321,7 +338,7 @@ public class DynamicClientRegistrationEndpoint {
|
||||||
// save the client
|
// save the client
|
||||||
ClientDetailsEntity savedClient = clientService.updateClient(oldClient, newClient);
|
ClientDetailsEntity savedClient = clientService.updateClient(oldClient, newClient);
|
||||||
|
|
||||||
OAuth2AccessTokenEntity token = fetchValidRegistrationToken(auth, savedClient);
|
OAuth2AccessTokenEntity token = rotateRegistrationTokenIfNecessary(auth, savedClient);
|
||||||
|
|
||||||
RegisteredClient registered = new RegisteredClient(savedClient, token.getValue(), config.getIssuer() + "register/" + UriUtils.encodePathSegment(savedClient.getClientId(), "UTF-8"));
|
RegisteredClient registered = new RegisteredClient(savedClient, token.getValue(), config.getIssuer() + "register/" + UriUtils.encodePathSegment(savedClient.getClientId(), "UTF-8"));
|
||||||
|
|
||||||
|
@ -553,7 +570,155 @@ public class DynamicClientRegistrationEndpoint {
|
||||||
return newClient;
|
return newClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
private OAuth2AccessTokenEntity fetchValidRegistrationToken(OAuth2Authentication auth, ClientDetailsEntity client) {
|
|
||||||
|
/**
|
||||||
|
* @param newClient
|
||||||
|
* @return
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
private ClientDetailsEntity validateSoftwareStatement(ClientDetailsEntity newClient) throws ValidationException {
|
||||||
|
if (newClient.getSoftwareStatement() != null) {
|
||||||
|
if (assertionValidator.isValid(newClient.getSoftwareStatement())) {
|
||||||
|
// we have a software statement and its envelope passed all the checks from our validator
|
||||||
|
|
||||||
|
// swap out all of the client's fields for the associated parts of the software statement
|
||||||
|
try {
|
||||||
|
JWTClaimsSet claimSet = newClient.getSoftwareStatement().getJWTClaimsSet();
|
||||||
|
for (String claim : claimSet.getClaims().keySet()) {
|
||||||
|
switch (claim) {
|
||||||
|
case SOFTWARE_STATEMENT:
|
||||||
|
throw new ValidationException("invalid_client_metadata", "Software statement can't include another software statement", HttpStatus.BAD_REQUEST);
|
||||||
|
case CLAIMS_REDIRECT_URIS:
|
||||||
|
newClient.setClaimsRedirectUris(Sets.newHashSet(claimSet.getStringListClaim(claim)));
|
||||||
|
break;
|
||||||
|
case CLIENT_SECRET_EXPIRES_AT:
|
||||||
|
throw new ValidationException("invalid_client_metadata", "Software statement can't include a client secret expiration time", HttpStatus.BAD_REQUEST);
|
||||||
|
case CLIENT_ID_ISSUED_AT:
|
||||||
|
throw new ValidationException("invalid_client_metadata", "Software statement can't include a client ID issuance time", HttpStatus.BAD_REQUEST);
|
||||||
|
case REGISTRATION_CLIENT_URI:
|
||||||
|
throw new ValidationException("invalid_client_metadata", "Software statement can't include a client configuration endpoint", HttpStatus.BAD_REQUEST);
|
||||||
|
case REGISTRATION_ACCESS_TOKEN:
|
||||||
|
throw new ValidationException("invalid_client_metadata", "Software statement can't include a client registration access token", HttpStatus.BAD_REQUEST);
|
||||||
|
case REQUEST_URIS:
|
||||||
|
newClient.setRequestUris(Sets.newHashSet(claimSet.getStringListClaim(claim)));
|
||||||
|
break;
|
||||||
|
case POST_LOGOUT_REDIRECT_URIS:
|
||||||
|
newClient.setPostLogoutRedirectUris(Sets.newHashSet(claimSet.getStringListClaim(claim)));
|
||||||
|
break;
|
||||||
|
case INITIATE_LOGIN_URI:
|
||||||
|
newClient.setInitiateLoginUri(claimSet.getStringClaim(claim));
|
||||||
|
break;
|
||||||
|
case DEFAULT_ACR_VALUES:
|
||||||
|
newClient.setDefaultACRvalues(Sets.newHashSet(claimSet.getStringListClaim(claim)));
|
||||||
|
break;
|
||||||
|
case REQUIRE_AUTH_TIME:
|
||||||
|
newClient.setRequireAuthTime(claimSet.getBooleanClaim(claim));
|
||||||
|
break;
|
||||||
|
case DEFAULT_MAX_AGE:
|
||||||
|
newClient.setDefaultMaxAge(claimSet.getIntegerClaim(claim));
|
||||||
|
break;
|
||||||
|
case TOKEN_ENDPOINT_AUTH_SIGNING_ALG:
|
||||||
|
newClient.setTokenEndpointAuthSigningAlg(JWSAlgorithm.parse(claimSet.getStringClaim(claim)));
|
||||||
|
break;
|
||||||
|
case ID_TOKEN_ENCRYPTED_RESPONSE_ENC:
|
||||||
|
newClient.setIdTokenEncryptedResponseEnc(EncryptionMethod.parse(claimSet.getStringClaim(claim)));
|
||||||
|
break;
|
||||||
|
case ID_TOKEN_ENCRYPTED_RESPONSE_ALG:
|
||||||
|
newClient.setIdTokenEncryptedResponseAlg(JWEAlgorithm.parse(claimSet.getStringClaim(claim)));
|
||||||
|
break;
|
||||||
|
case ID_TOKEN_SIGNED_RESPONSE_ALG:
|
||||||
|
newClient.setIdTokenSignedResponseAlg(JWSAlgorithm.parse(claimSet.getStringClaim(claim)));
|
||||||
|
break;
|
||||||
|
case USERINFO_ENCRYPTED_RESPONSE_ENC:
|
||||||
|
newClient.setUserInfoEncryptedResponseEnc(EncryptionMethod.parse(claimSet.getStringClaim(claim)));
|
||||||
|
break;
|
||||||
|
case USERINFO_ENCRYPTED_RESPONSE_ALG:
|
||||||
|
newClient.setUserInfoEncryptedResponseAlg(JWEAlgorithm.parse(claimSet.getStringClaim(claim)));
|
||||||
|
break;
|
||||||
|
case USERINFO_SIGNED_RESPONSE_ALG:
|
||||||
|
newClient.setUserInfoSignedResponseAlg(JWSAlgorithm.parse(claimSet.getStringClaim(claim)));
|
||||||
|
break;
|
||||||
|
case REQUEST_OBJECT_SIGNING_ALG:
|
||||||
|
newClient.setRequestObjectSigningAlg(JWSAlgorithm.parse(claimSet.getStringClaim(claim)));
|
||||||
|
break;
|
||||||
|
case SUBJECT_TYPE:
|
||||||
|
newClient.setSubjectType(SubjectType.getByValue(claimSet.getStringClaim(claim)));
|
||||||
|
break;
|
||||||
|
case SECTOR_IDENTIFIER_URI:
|
||||||
|
newClient.setSectorIdentifierUri(claimSet.getStringClaim(claim));
|
||||||
|
break;
|
||||||
|
case APPLICATION_TYPE:
|
||||||
|
newClient.setApplicationType(AppType.getByValue(claimSet.getStringClaim(claim)));
|
||||||
|
break;
|
||||||
|
case JWKS_URI:
|
||||||
|
newClient.setJwksUri(claimSet.getStringClaim(claim));
|
||||||
|
break;
|
||||||
|
case JWKS:
|
||||||
|
newClient.setJwks(JWKSet.parse(claimSet.getStringClaim(claim)));
|
||||||
|
break;
|
||||||
|
case POLICY_URI:
|
||||||
|
newClient.setPolicyUri(claimSet.getStringClaim(claim));
|
||||||
|
break;
|
||||||
|
case RESPONSE_TYPES:
|
||||||
|
newClient.setResponseTypes(Sets.newHashSet(claimSet.getStringListClaim(claim)));
|
||||||
|
break;
|
||||||
|
case GRANT_TYPES:
|
||||||
|
newClient.setGrantTypes(Sets.newHashSet(claimSet.getStringListClaim(claim)));
|
||||||
|
break;
|
||||||
|
case SCOPE:
|
||||||
|
newClient.setScope(OAuth2Utils.parseParameterList(claimSet.getStringClaim(claim)));
|
||||||
|
break;
|
||||||
|
case TOKEN_ENDPOINT_AUTH_METHOD:
|
||||||
|
newClient.setTokenEndpointAuthMethod(AuthMethod.getByValue(claimSet.getStringClaim(claim)));
|
||||||
|
break;
|
||||||
|
case TOS_URI:
|
||||||
|
newClient.setTosUri(claimSet.getStringClaim(claim));
|
||||||
|
break;
|
||||||
|
case CONTACTS:
|
||||||
|
newClient.setContacts(Sets.newHashSet(claimSet.getStringListClaim(claim)));
|
||||||
|
break;
|
||||||
|
case LOGO_URI:
|
||||||
|
newClient.setLogoUri(claimSet.getStringClaim(claim));
|
||||||
|
break;
|
||||||
|
case CLIENT_URI:
|
||||||
|
newClient.setClientUri(claimSet.getStringClaim(claim));
|
||||||
|
break;
|
||||||
|
case CLIENT_NAME:
|
||||||
|
newClient.setClientName(claimSet.getStringClaim(claim));
|
||||||
|
break;
|
||||||
|
case REDIRECT_URIS:
|
||||||
|
newClient.setRedirectUris(Sets.newHashSet(claimSet.getStringListClaim(claim)));
|
||||||
|
break;
|
||||||
|
case CLIENT_SECRET:
|
||||||
|
throw new ValidationException("invalid_client_metadata", "Software statement can't contain client secret", HttpStatus.BAD_REQUEST);
|
||||||
|
case CLIENT_ID:
|
||||||
|
throw new ValidationException("invalid_client_metadata", "Software statement can't contain client ID", HttpStatus.BAD_REQUEST);
|
||||||
|
|
||||||
|
default:
|
||||||
|
logger.warn("Software statement contained unknown field: " + claim + " with value " + claimSet.getClaim(claim));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newClient;
|
||||||
|
} catch (ParseException e) {
|
||||||
|
throw new ValidationException("invalid_client_metadata", "Software statement claims didn't parse", HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ValidationException("invalid_client_metadata", "Software statement rejected by validator", HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// nothing to see here, carry on
|
||||||
|
return newClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rotates the registration token if it's expired, otherwise returns it
|
||||||
|
*/
|
||||||
|
private OAuth2AccessTokenEntity rotateRegistrationTokenIfNecessary(OAuth2Authentication auth, ClientDetailsEntity client) {
|
||||||
|
|
||||||
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) auth.getDetails();
|
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) auth.getDetails();
|
||||||
OAuth2AccessTokenEntity token = tokenService.readAccessToken(details.getTokenValue());
|
OAuth2AccessTokenEntity token = tokenService.readAccessToken(details.getTokenValue());
|
||||||
|
|
Loading…
Reference in New Issue