use of uk.gov.di.authentication.oidc.entity.AuthRequestError in project di-authentication-api by alphagov.
the class RequestObjectService method validateRequestObject.
public Optional<AuthRequestError> validateRequestObject(AuthenticationRequest authRequest) {
var clientId = authRequest.getClientID().toString();
attachLogFieldToLogs(CLIENT_ID, clientId);
var client = dynamoClientService.getClient(clientId).orElse(null);
try {
if (Objects.isNull(client)) {
var errorMsg = "No Client found with given ClientID";
LOG.warn(errorMsg);
throw new RuntimeException(errorMsg);
}
var signedJWT = (SignedJWT) authRequest.getRequestObject();
var signatureValid = isSignatureValid(signedJWT, client.getPublicKey());
if (!signatureValid) {
LOG.error("Invalid Signature on request JWT");
throw new RuntimeException();
}
var jwtClaimsSet = signedJWT.getJWTClaimsSet();
if (client.getRedirectUrls().stream().filter(Objects::nonNull).noneMatch(s -> s.equals(jwtClaimsSet.getClaim("redirect_uri")))) {
throw new RuntimeException("Invalid Redirect URI in request JWT");
}
var redirectURI = URI.create((String) jwtClaimsSet.getClaim("redirect_uri"));
if (Boolean.FALSE.equals(client.getClientType().equals(ClientType.APP.getValue()))) {
LOG.warn("ClientType of client is not 'app'");
return Optional.of(new AuthRequestError(OAuth2Error.UNAUTHORIZED_CLIENT, redirectURI));
}
if (!authRequest.getResponseType().toString().equals(ResponseType.CODE.toString())) {
LOG.warn("Unsupported responseType included in request. Expected responseType of code");
return Optional.of(new AuthRequestError(OAuth2Error.UNSUPPORTED_RESPONSE_TYPE, redirectURI));
}
if (requestContainsInvalidScopes(authRequest.getScope().toStringList(), client, false)) {
LOG.warn("Invalid scopes in authRequest. Scopes in request: {}", authRequest.getScope().toStringList());
return Optional.of(new AuthRequestError(OAuth2Error.INVALID_SCOPE, redirectURI));
}
if (Objects.isNull(jwtClaimsSet.getClaim("client_id")) || !jwtClaimsSet.getClaim("client_id").toString().equals(authRequest.getClientID().getValue())) {
return Optional.of(new AuthRequestError(OAuth2Error.UNAUTHORIZED_CLIENT, redirectURI));
}
if (Objects.nonNull(jwtClaimsSet.getClaim("request")) || Objects.nonNull(jwtClaimsSet.getClaim("request_uri"))) {
LOG.warn("request or request_uri claim should not be incldued in request JWT");
return Optional.of(new AuthRequestError(OAuth2Error.INVALID_REQUEST, redirectURI));
}
if (Objects.isNull(jwtClaimsSet.getAudience()) || !jwtClaimsSet.getAudience().contains(buildURI(configurationService.getOidcApiBaseURL().orElseThrow(), "/authorize").toString())) {
LOG.warn("Invalid or missing audience");
return Optional.of(new AuthRequestError(OAuth2Error.ACCESS_DENIED, redirectURI));
}
if (Objects.isNull(jwtClaimsSet.getIssuer()) || !jwtClaimsSet.getIssuer().equals(client.getClientID())) {
LOG.warn("Invalid or missing issuer");
return Optional.of(new AuthRequestError(OAuth2Error.UNAUTHORIZED_CLIENT, redirectURI));
}
if (!ResponseType.CODE.toString().equals(jwtClaimsSet.getClaim("response_type"))) {
LOG.warn("Unsupported responseType included in request JWT. Expected responseType of code");
return Optional.of(new AuthRequestError(OAuth2Error.UNSUPPORTED_RESPONSE_TYPE, redirectURI));
}
if (Objects.isNull(jwtClaimsSet.getClaim("scope")) || requestContainsInvalidScopes(Scope.parse(jwtClaimsSet.getClaim("scope").toString()).toStringList(), client, true)) {
LOG.warn("Invalid scopes in request JWT");
return Optional.of(new AuthRequestError(OAuth2Error.INVALID_SCOPE, redirectURI));
}
if (Objects.isNull(jwtClaimsSet.getClaim("state"))) {
LOG.warn("State is missing from authRequest");
return Optional.of(new AuthRequestError(new ErrorObject(OAuth2Error.INVALID_REQUEST_CODE, "Request is missing state parameter"), redirectURI));
}
} catch (ParseException e) {
throw new RuntimeException(e);
}
LOG.info("RequestObject has passed initial validation");
return Optional.empty();
}
use of uk.gov.di.authentication.oidc.entity.AuthRequestError in project di-authentication-api by alphagov.
the class AuthorisationHandlerTest method shouldReturn400WhenAuthorisationRequestContainsInvalidScope.
@Test
void shouldReturn400WhenAuthorisationRequestContainsInvalidScope() {
when(authorizationService.validateAuthRequest(any(AuthenticationRequest.class))).thenReturn(Optional.of(new AuthRequestError(OAuth2Error.INVALID_SCOPE, URI.create("http://localhost:8080"))));
APIGatewayProxyRequestEvent event = new APIGatewayProxyRequestEvent();
event.setQueryStringParameters(Map.of("client_id", "test-id", "redirect_uri", "http://localhost:8080", "scope", "email,openid,profile,non-existent-scope", "response_type", "code"));
event.setRequestContext(new ProxyRequestContext().withIdentity(new RequestIdentity().withSourceIp("123.123.123.123")));
APIGatewayProxyResponseEvent response = makeHandlerRequest(event);
assertThat(response, hasStatus(302));
assertEquals("http://localhost:8080?error=invalid_scope&error_description=Invalid%2C+unknown+or+malformed+scope", response.getHeaders().get(ResponseHeaders.LOCATION));
verify(auditService).submitAuditEvent(AUTHORISATION_REQUEST_ERROR, AWS_REQUEST_ID, "", "", "", "", "123.123.123.123", "", PERSISTENT_SESSION_ID, pair("description", OAuth2Error.INVALID_SCOPE.getDescription()));
}
use of uk.gov.di.authentication.oidc.entity.AuthRequestError in project di-authentication-api by alphagov.
the class AuthorisationHandlerTest method shouldReturnErrorWhenRequestObjectIsInvalid.
@ParameterizedTest
@MethodSource("expectedErrorObjects")
void shouldReturnErrorWhenRequestObjectIsInvalid(ErrorObject errorObject) {
when(configService.isDocAppApiEnabled()).thenReturn(true);
when(requestObjectService.validateRequestObject(any(AuthenticationRequest.class))).thenReturn(Optional.of(new AuthRequestError(errorObject, URI.create("http://localhost:8080"))));
var event = new APIGatewayProxyRequestEvent();
event.setQueryStringParameters(Map.of("client_id", "test-id", "redirect_uri", "http://localhost:8080", "scope", "openid", "response_type", "code", "request", new PlainJWT(new JWTClaimsSet.Builder().build()).serialize()));
event.setRequestContext(new ProxyRequestContext().withIdentity(new RequestIdentity().withSourceIp("123.123.123.123")));
var response = makeHandlerRequest(event);
var expectedURI = new AuthenticationErrorResponse(URI.create("http://localhost:8080"), errorObject, null, null).toURI().toString();
assertThat(response, hasStatus(302));
assertEquals(expectedURI, response.getHeaders().get(ResponseHeaders.LOCATION));
verify(auditService).submitAuditEvent(AUTHORISATION_REQUEST_ERROR, AWS_REQUEST_ID, "", "", "", "", "123.123.123.123", "", PERSISTENT_SESSION_ID, pair("description", errorObject.getDescription()));
}
use of uk.gov.di.authentication.oidc.entity.AuthRequestError in project di-authentication-api by alphagov.
the class AuthorizationService method validateAuthRequest.
public Optional<AuthRequestError> validateAuthRequest(AuthenticationRequest authRequest) {
var clientId = authRequest.getClientID().toString();
attachLogFieldToLogs(CLIENT_ID, clientId);
Optional<ClientRegistry> client = dynamoClientService.getClient(clientId);
if (client.isEmpty()) {
var errorMsg = "No Client found with given ClientID";
LOG.warn(errorMsg);
throw new RuntimeException(errorMsg);
}
if (!client.get().getRedirectUrls().contains(authRequest.getRedirectionURI().toString())) {
LOG.warn("Invalid Redirect URI in request {}", authRequest.getRedirectionURI());
throw new RuntimeException(format("Invalid Redirect in request %s", authRequest.getRedirectionURI().toString()));
}
var redirectURI = authRequest.getRedirectionURI();
if (authRequest.getRequestURI() != null) {
return Optional.of(new AuthRequestError(OAuth2Error.REQUEST_URI_NOT_SUPPORTED, redirectURI));
}
if (authRequest.getRequestObject() != null) {
return Optional.of(new AuthRequestError(OAuth2Error.REQUEST_NOT_SUPPORTED, redirectURI));
}
if (!authRequest.getResponseType().toString().equals(ResponseType.CODE.toString())) {
LOG.warn("Unsupported responseType included in request. Expected responseType of code");
return Optional.of(new AuthRequestError(OAuth2Error.UNSUPPORTED_RESPONSE_TYPE, redirectURI));
}
if (!areScopesValid(authRequest.getScope().toStringList(), client.get())) {
LOG.warn("Invalid scopes in authRequest. Scopes in request: {}", authRequest.getScope().toStringList());
return Optional.of(new AuthRequestError(OAuth2Error.INVALID_SCOPE, redirectURI));
}
if (!areClaimsValid(authRequest.getOIDCClaims(), client.get())) {
LOG.warn("Invalid claims in authRequest. Claims in request: {}", authRequest.getOIDCClaims().toJSONString());
return Optional.of(new AuthRequestError(new ErrorObject(OAuth2Error.INVALID_REQUEST_CODE, "Request contains invalid claims"), redirectURI));
}
if (authRequest.getNonce() == null) {
LOG.warn("Nonce is missing from authRequest");
return Optional.of(new AuthRequestError(new ErrorObject(OAuth2Error.INVALID_REQUEST_CODE, "Request is missing nonce parameter"), redirectURI));
}
if (authRequest.getState() == null) {
LOG.warn("State is missing from authRequest");
return Optional.of(new AuthRequestError(new ErrorObject(OAuth2Error.INVALID_REQUEST_CODE, "Request is missing state parameter"), redirectURI));
}
List<String> authRequestVtr = authRequest.getCustomParameter(VTR_PARAM);
try {
var vectorOfTrust = VectorOfTrust.parseFromAuthRequestAttribute(authRequestVtr);
if (vectorOfTrust.containsLevelOfConfidence() && !ipvCapacityService.isIPVCapacityAvailable()) {
return Optional.of(new AuthRequestError(OAuth2Error.TEMPORARILY_UNAVAILABLE, redirectURI));
}
} catch (IllegalArgumentException e) {
LOG.warn("vtr in AuthRequest is not valid. vtr in request: {}. IllegalArgumentException: {}", authRequestVtr, e);
return Optional.of(new AuthRequestError(new ErrorObject(OAuth2Error.INVALID_REQUEST_CODE, "Request vtr not valid"), redirectURI));
}
return Optional.empty();
}
use of uk.gov.di.authentication.oidc.entity.AuthRequestError in project di-authentication-api by alphagov.
the class AuthorisationHandler method authoriseRequestHandler.
public APIGatewayProxyResponseEvent authoriseRequestHandler(APIGatewayProxyRequestEvent input, Context context) {
return isWarming(input).orElseGet(() -> {
var persistentSessionId = authorizationService.getExistingOrCreateNewPersistentSessionId(input.getHeaders());
var ipAddress = IpAddressHelper.extractIpAddress(input);
auditService.submitAuditEvent(OidcAuditableEvent.AUTHORISATION_REQUEST_RECEIVED, context.getAwsRequestId(), AuditService.UNKNOWN, AuditService.UNKNOWN, AuditService.UNKNOWN, AuditService.UNKNOWN, ipAddress, AuditService.UNKNOWN, persistentSessionId);
attachLogFieldToLogs(PERSISTENT_SESSION_ID, persistentSessionId);
attachLogFieldToLogs(AWS_REQUEST_ID, context.getAwsRequestId());
LOG.info("Received authentication request");
Map<String, List<String>> queryStringParameters;
AuthenticationRequest authRequest;
try {
queryStringParameters = input.getQueryStringParameters().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> List.of(entry.getValue())));
authRequest = AuthenticationRequest.parse(queryStringParameters);
} catch (ParseException e) {
if (e.getRedirectionURI() == null) {
LOG.warn("Authentication request could not be parsed: redirect URI or Client ID is missing from auth request");
throw new RuntimeException("Redirect URI or ClientID is missing from auth request", e);
}
LOG.warn("Authentication request could not be parsed", e);
return generateErrorResponse(e.getRedirectionURI(), e.getState(), e.getResponseMode(), e.getErrorObject(), context, ipAddress, persistentSessionId);
} catch (NullPointerException e) {
LOG.warn("No query string parameters are present in the Authentication request", e);
throw new RuntimeException("No query string parameters are present in the Authentication request", e);
}
Optional<AuthRequestError> authRequestError;
if (authRequest.getRequestObject() != null && configurationService.isDocAppApiEnabled()) {
LOG.info("RequestObject auth request received");
authRequestError = requestObjectService.validateRequestObject(authRequest);
} else {
authRequestError = authorizationService.validateAuthRequest(authRequest);
}
return authRequestError.map(e -> generateErrorResponse(e.getRedirectURI(), authRequest.getState(), authRequest.getResponseMode(), e.getErrorObject(), context, ipAddress, persistentSessionId)).orElseGet(() -> getOrCreateSessionAndRedirect(queryStringParameters, sessionService.getSessionFromSessionCookie(input.getHeaders()), authRequest, context, ipAddress, persistentSessionId));
});
}
Aggregations