Skip to content

Commit

Permalink
feat(jans-auth-server): split validation logic to TokenRestWebService…
Browse files Browse the repository at this point in the history
…Validator #1591

docs: no docs required
  • Loading branch information
yuriyz committed Jul 18, 2022
1 parent 929048e commit f9f6f49
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -151,41 +151,26 @@ public Response requestAccessToken(String grantType, String code,
return umaTokenService.requestRpt(grantType, ticket, claimToken, claimTokenFormat, pctCode, rptCode, scope, request, response);
}

OAuth2AuditLog oAuth2AuditLog = new OAuth2AuditLog(ServerUtil.getIpAddress(request), Action.TOKEN_REQUEST);
oAuth2AuditLog.setClientId(clientId);
oAuth2AuditLog.setUsername(username);
oAuth2AuditLog.setScope(scope);
OAuth2AuditLog auditLog = new OAuth2AuditLog(ServerUtil.getIpAddress(request), Action.TOKEN_REQUEST);
auditLog.setClientId(clientId);
auditLog.setUsername(username);
auditLog.setScope(scope);

String tokenBindingHeader = request.getHeader("Sec-Token-Binding");

scope = ServerUtil.urlDecode(scope); // it may be encoded in uma case
ResponseBuilder builder = Response.ok();

String dpopStr = runDPoP(request, oAuth2AuditLog);
String dpopStr = runDPoP(request, auditLog);

try {
tokenRestWebServiceValidator.validateParams(grantType, code, redirectUri, refreshToken, oAuth2AuditLog);
tokenRestWebServiceValidator.validateParams(grantType, code, redirectUri, refreshToken, auditLog);

GrantType gt = GrantType.fromString(grantType);
log.debug("Grant type: '{}'", gt);

SessionClient sessionClient = identity.getSessionClient();
Client client = null;
if (sessionClient != null) {
client = sessionClient.getClient();
log.debug("Get sessionClient: '{}'", sessionClient);
}

if (client == null) {
return response(error(401, TokenErrorResponseType.INVALID_GRANT, "Unable to find client."), oAuth2AuditLog);
}

log.debug("Get client from session: '{}'", client.getClientId());
if (client.isDisabled()) {
return response(error(Response.Status.FORBIDDEN.getStatusCode(), TokenErrorResponseType.DISABLED_CLIENT, "Client is disabled."), oAuth2AuditLog);
}

tokenRestWebServiceValidator.validateGrantType(gt, client.getGrantTypes(), oAuth2AuditLog);
Client client = tokenRestWebServiceValidator.validateClient(getClient(), auditLog);
tokenRestWebServiceValidator.validateGrantType(gt, client, auditLog);

final Function<JsonWebResponse, Void> idTokenTokingBindingPreprocessing = TokenBindingMessage.createIdTokenTokingBindingPreprocessing(
tokenBindingHeader, client.getIdTokenTokenBindingCnf()); // for all except authorization code grant
Expand All @@ -209,17 +194,17 @@ public Response requestAccessToken(String grantType, String code,
log.debug("AuthorizationCodeGrant is empty by clientId: '{}', code: '{}'", client.getClientId(), code);
// if authorization code is not found then code was already used or wrong client provided = remove all grants with this auth code
grantService.removeAllByAuthorizationCode(code);
return response(error(400, TokenErrorResponseType.INVALID_GRANT, "Unable to find grant object for given code."), oAuth2AuditLog);
return response(error(400, TokenErrorResponseType.INVALID_GRANT, "Unable to find grant object for given code."), auditLog);
}

if (!client.getClientId().equals(authorizationCodeGrant.getClientId())) {
log.debug("AuthorizationCodeGrant is found but belongs to another client. Grant's clientId: '{}', code: '{}'", authorizationCodeGrant.getClientId(), code);
// if authorization code is not found then code was already used or wrong client provided = remove all grants with this auth code
grantService.removeAllByAuthorizationCode(code);
return response(error(400, TokenErrorResponseType.INVALID_GRANT, "Client mismatch."), oAuth2AuditLog);
return response(error(400, TokenErrorResponseType.INVALID_GRANT, "Client mismatch."), auditLog);
}

validatePKCE(authorizationCodeGrant, codeVerifier, oAuth2AuditLog);
validatePKCE(authorizationCodeGrant, codeVerifier, auditLog);

authorizationCodeGrant.setIsCachedWithNoPersistence(false);
authorizationCodeGrant.save();
Expand Down Expand Up @@ -254,26 +239,26 @@ public Response requestAccessToken(String grantType, String code,
nonce, authorizationCodeGrant.getAuthorizationCode(), accToken, null, null, executionContext);
}

oAuth2AuditLog.updateOAuth2AuditLog(authorizationCodeGrant, true);
auditLog.updateOAuth2AuditLog(authorizationCodeGrant, true);

grantService.removeAuthorizationCode(authorizationCodeGrant.getAuthorizationCode().getCode());

final String entity = getJSonResponse(accToken, accToken.getTokenType(), accToken.getExpiresIn(), reToken, scope, idToken);
return response(Response.ok().entity(entity), oAuth2AuditLog);
return response(Response.ok().entity(entity), auditLog);
}

if (gt == GrantType.REFRESH_TOKEN) {
AuthorizationGrant authorizationGrant = authorizationGrantList.getAuthorizationGrantByRefreshToken(client.getClientId(), refreshToken);

if (authorizationGrant == null) {
log.trace("Grant object is not found by refresh token.");
return response(error(400, TokenErrorResponseType.INVALID_GRANT, "Unable to find grant object by refresh token or otherwise token type or client does not match."), oAuth2AuditLog);
return response(error(400, TokenErrorResponseType.INVALID_GRANT, "Unable to find grant object by refresh token or otherwise token type or client does not match."), auditLog);
}

final RefreshToken refreshTokenObject = authorizationGrant.getRefreshToken(refreshToken);
if (refreshTokenObject == null || !refreshTokenObject.isValid()) {
log.trace("Invalid refresh token.");
return response(error(400, TokenErrorResponseType.INVALID_GRANT, "Unable to find refresh token or otherwise token type or client does not match."), oAuth2AuditLog);
return response(error(400, TokenErrorResponseType.INVALID_GRANT, "Unable to find refresh token or otherwise token type or client does not match."), auditLog);
}

executionContext.setGrant(authorizationGrant);
Expand Down Expand Up @@ -321,7 +306,7 @@ public Response requestAccessToken(String grantType, String code,
reToken,
scope,
idToken));
oAuth2AuditLog.updateOAuth2AuditLog(authorizationGrant, true);
auditLog.updateOAuth2AuditLog(authorizationGrant, true);
} else if (gt == GrantType.CLIENT_CREDENTIALS) {
ClientCredentialsGrant clientCredentialsGrant = authorizationGrantList.createClientCredentialsGrant(new User(), client);

Expand All @@ -345,7 +330,7 @@ public Response requestAccessToken(String grantType, String code,
null, null, null, null, null, executionContext);
}

oAuth2AuditLog.updateOAuth2AuditLog(clientCredentialsGrant, true);
auditLog.updateOAuth2AuditLog(clientCredentialsGrant, true);
builder.entity(getJSonResponse(accessToken,
accessToken.getTokenType(),
accessToken.getExpiresIn(),
Expand Down Expand Up @@ -407,7 +392,7 @@ public Response requestAccessToken(String grantType, String code,
null, null, null, null, null, executionContext);
}

oAuth2AuditLog.updateOAuth2AuditLog(resourceOwnerPasswordCredentialsGrant, true);
auditLog.updateOAuth2AuditLog(resourceOwnerPasswordCredentialsGrant, true);
builder.entity(getJSonResponse(accessToken,
accessToken.getTokenType(),
accessToken.getExpiresIn(),
Expand All @@ -430,7 +415,7 @@ public Response requestAccessToken(String grantType, String code,
if (cibaGrant != null) {
if (!cibaGrant.getClientId().equals(client.getClientId())) {
builder = error(400, TokenErrorResponseType.INVALID_GRANT, REASON_CLIENT_NOT_AUTHORIZED);
return response(builder, oAuth2AuditLog);
return response(builder, auditLog);
}
if (cibaGrant.getClient().getBackchannelTokenDeliveryMode() == BackchannelTokenDeliveryMode.PING ||
cibaGrant.getClient().getBackchannelTokenDeliveryMode() == BackchannelTokenDeliveryMode.POLL) {
Expand Down Expand Up @@ -465,7 +450,7 @@ public Response requestAccessToken(String grantType, String code,
scope,
idToken));

oAuth2AuditLog.updateOAuth2AuditLog(cibaGrant, true);
auditLog.updateOAuth2AuditLog(cibaGrant, true);
} else {
builder = error(400, TokenErrorResponseType.INVALID_GRANT, "AuthReqId is no longer available.");
}
Expand All @@ -479,7 +464,7 @@ public Response requestAccessToken(String grantType, String code,
if (cibaRequest != null) {
if (!cibaRequest.getClient().getClientId().equals(client.getClientId())) {
builder = error(400, TokenErrorResponseType.INVALID_GRANT, REASON_CLIENT_NOT_AUTHORIZED);
return response(builder, oAuth2AuditLog);
return response(builder, auditLog);
}
long currentTime = new Date().getTime();
Long lastAccess = cibaRequest.getLastAccessControl();
Expand Down Expand Up @@ -513,7 +498,7 @@ public Response requestAccessToken(String grantType, String code,
}
}
} else if (gt == GrantType.DEVICE_CODE) {
return processDeviceCodeGrantType(gt, client, deviceCode, scope, request, response, oAuth2AuditLog);
return processDeviceCodeGrantType(client, deviceCode, scope, request, response, auditLog);
}
} catch (WebApplicationException e) {
throw e;
Expand All @@ -522,7 +507,18 @@ public Response requestAccessToken(String grantType, String code,
log.error(e.getMessage(), e);
}

return response(builder, oAuth2AuditLog);
return response(builder, auditLog);
}

@Nullable
private Client getClient() {
SessionClient sessionClient = identity.getSessionClient();
Client client = null;
if (sessionClient != null) {
client = sessionClient.getClient();
log.debug("Get sessionClient: '{}'", sessionClient);
}
return client;
}

private User authenticateUser(String username, String password, ExecutionContext executionContext, User user) {
Expand Down Expand Up @@ -585,25 +581,24 @@ private RefreshToken createRefreshToken(@NotNull HttpServletRequest request, @No
/**
* Processes token request for device code grant type.
*
* @param grantType Grant type used, should be device code.
* @param client Client in process.
* @param deviceCode Device code generated in device authn request.
* @param scope Scope registered in device authn request.
* @param request HttpServletRequest
* @param response HttpServletResponse
* @param oAuth2AuditLog OAuth2AuditLog
* @param auditLog OAuth2AuditLog
*/
private Response processDeviceCodeGrantType(final GrantType grantType, final Client client, final String deviceCode,
private Response processDeviceCodeGrantType(final Client client, final String deviceCode,
String scope, final HttpServletRequest request,
final HttpServletResponse response, final OAuth2AuditLog oAuth2AuditLog) {
final HttpServletResponse response, final OAuth2AuditLog auditLog) {
log.debug("Attempting to find authorizationGrant by deviceCode: '{}'", deviceCode);
final DeviceCodeGrant deviceCodeGrant = authorizationGrantList.getDeviceCodeGrant(deviceCode);

log.trace("DeviceCodeGrant : '{}'", deviceCodeGrant);

if (deviceCodeGrant != null) {
if (!deviceCodeGrant.getClientId().equals(client.getClientId())) {
throw new WebApplicationException(response(error(400, TokenErrorResponseType.INVALID_GRANT, REASON_CLIENT_NOT_AUTHORIZED), oAuth2AuditLog));
throw new WebApplicationException(response(error(400, TokenErrorResponseType.INVALID_GRANT, REASON_CLIENT_NOT_AUTHORIZED), auditLog));
}
RefreshToken refToken = createRefreshToken(request, client, scope, deviceCodeGrant, null);

Expand Down Expand Up @@ -631,7 +626,7 @@ private Response processDeviceCodeGrantType(final GrantType grantType, final Cli

log.info("Device authorization in token endpoint processed and return to the client, device_code: {}", deviceCodeGrant.getDeviceCode());

oAuth2AuditLog.updateOAuth2AuditLog(deviceCodeGrant, true);
auditLog.updateOAuth2AuditLog(deviceCodeGrant, true);

grantService.removeByCode(deviceCodeGrant.getDeviceCode());

Expand All @@ -640,13 +635,8 @@ private Response processDeviceCodeGrantType(final GrantType grantType, final Cli
} else {
final DeviceAuthorizationCacheControl cacheData = deviceAuthorizationService.getDeviceAuthzByDeviceCode(deviceCode);
log.trace("DeviceAuthorizationCacheControl data : '{}'", cacheData);
if (cacheData == null) {
log.debug("The authentication request has expired for deviceCode: '{}'", deviceCode);
throw new WebApplicationException(response(error(400, TokenErrorResponseType.EXPIRED_TOKEN, "The authentication request has expired."), oAuth2AuditLog));
}
if (!cacheData.getClient().getClientId().equals(client.getClientId())) {
throw new WebApplicationException(response(error(400, TokenErrorResponseType.INVALID_GRANT, REASON_CLIENT_NOT_AUTHORIZED), oAuth2AuditLog));
}
tokenRestWebServiceValidator.validateDeviceAuthorization(client, deviceCode, cacheData, auditLog);

long currentTime = new Date().getTime();
Long lastAccess = cacheData.getLastAccessControl();
if (lastAccess == null) {
Expand All @@ -661,18 +651,18 @@ private Response processDeviceCodeGrantType(final GrantType grantType, final Cli

if (timeFromLastAccess > intervalSeconds * 1000) {
log.debug("Access hasn't been granted yet for deviceCode: '{}'", deviceCode);
throw new WebApplicationException(response(error(400, TokenErrorResponseType.AUTHORIZATION_PENDING, "User hasn't answered yet"), oAuth2AuditLog));
throw new WebApplicationException(response(error(400, TokenErrorResponseType.AUTHORIZATION_PENDING, "User hasn't answered yet"), auditLog));
} else {
log.debug("Slow down protection deviceCode: '{}'", deviceCode);
throw new WebApplicationException(response(error(400, TokenErrorResponseType.SLOW_DOWN, "Client is asking too fast the token."), oAuth2AuditLog));
throw new WebApplicationException(response(error(400, TokenErrorResponseType.SLOW_DOWN, "Client is asking too fast the token."), auditLog));
}
}
if (cacheData.getStatus() == DeviceAuthorizationStatus.DENIED) {
log.debug("The end-user denied the authorization request for deviceCode: '{}'", deviceCode);
throw new WebApplicationException(response(error(400, TokenErrorResponseType.ACCESS_DENIED, "The end-user denied the authorization request."), oAuth2AuditLog));
throw new WebApplicationException(response(error(400, TokenErrorResponseType.ACCESS_DENIED, "The end-user denied the authorization request."), auditLog));
}
log.debug("The authentication request has expired for deviceCode: '{}'", deviceCode);
throw new WebApplicationException(response(error(400, TokenErrorResponseType.EXPIRED_TOKEN, "The authentication request has expired"), oAuth2AuditLog));
throw new WebApplicationException(response(error(400, TokenErrorResponseType.EXPIRED_TOKEN, "The authentication request has expired"), auditLog));
}
}

Expand Down
Loading

0 comments on commit f9f6f49

Please sign in to comment.