Skip to content

Commit

Permalink
feat(jans-auth-server): added "authorization_challenge" scope enforce…
Browse files Browse the repository at this point in the history
…ment #5856 (#6216)

#5856

Signed-off-by: YuriyZ <yzabrovarniy@gmail.com>
  • Loading branch information
yuriyz authored Oct 10, 2023
1 parent 91c9d94 commit b3db5c8
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 0 deletions.
3 changes: 3 additions & 0 deletions docs/admin/auth-server/endpoints/authorization-challenge.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ challenge endpoint looks like below:
https://janssen.server.host/jans-auth/restv1/authorization_challenge
```

In order to call Authorization Challenge Endpoint client must have `authorization_challenge` scope.
If scope is not present AS rejects call with 401 (unauthorized) http status code.

More information about request and response of the authorization challenge endpoint can be found in the OpenAPI specification
of [jans-auth-server module](https://gluu.org/swagger-ui/?url=https://raw.githubusercontent.com/JanssenProject/jans/vreplace-janssen-version/jans-auth-server/docs/swagger.yaml#/Authorization_Challenge).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ public Response authorize(AuthzRequest authzRequest) throws IOException, TokenBi

final Client client = authorizeRestWebServiceValidator.validateClient(authzRequest, false);
authorizationChallengeValidator.validateGrantType(client, state);
authorizationChallengeValidator.validateAccess(client);
Set<String> scopes = scopeChecker.checkScopesPolicy(client, authzRequest.getScope());

final ExecutionContext executionContext = ExecutionContext.of(authzRequest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@
import io.jans.as.model.common.GrantType;
import io.jans.as.model.configuration.AppConfiguration;
import io.jans.as.model.error.ErrorResponseFactory;
import io.jans.as.server.model.config.Constants;
import io.jans.as.server.service.ScopeService;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Response;
import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;

import javax.inject.Named;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
Expand All @@ -31,6 +35,9 @@ public class AuthorizationChallengeValidator {
@Inject
private ErrorResponseFactory errorResponseFactory;

@Inject
private ScopeService scopeService;

public void validateGrantType(Client client, String state) {
if (client == null) {
final String msg = "Unable to find client.";
Expand Down Expand Up @@ -60,4 +67,23 @@ public void validateGrantType(Client client, String state) {
.build());
}
}

public void validateAccess(Client client) {
if (client == null || ArrayUtils.isEmpty(client.getScopes())) {
log.debug("Client is null or have no scopes defined. Rejected request.");
throw new WebApplicationException(
Response.status(Response.Status.UNAUTHORIZED.getStatusCode())
.entity(errorResponseFactory.getErrorAsJson(AuthorizeErrorResponseType.INVALID_REQUEST))
.build());
}

List<String> scopesAllowedIds = scopeService.getScopeIdsByDns(Arrays.asList(client.getScopes()));

if (!scopesAllowedIds.contains(Constants.AUTHORIZATION_CHALLENGE_SCOPE)) {
log.debug("Client does not have required 'authorization_challenge' scope.");
throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED.getStatusCode())
.entity(errorResponseFactory.getErrorAsJson(AuthorizeErrorResponseType.INVALID_REQUEST))
.build());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public final class Constants {

public static final String OX_AUTH_SCOPE_TYPE_OPENID = "openid";
public static final String REVOKE_SESSION_SCOPE = "revoke_session";
public static final String AUTHORIZATION_CHALLENGE_SCOPE = "authorization_challenge";

public static final String REMOTE_IP = "remote_ip";
public static final String AUTHENTICATED_USER = "auth_user";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package io.jans.as.server.authorize.ws.rs;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import io.jans.as.common.model.registration.Client;
import io.jans.as.model.common.GrantType;
import io.jans.as.model.configuration.AppConfiguration;
import io.jans.as.model.error.ErrorResponseFactory;
import io.jans.as.server.service.ScopeService;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Response;
import org.mockito.InjectMocks;
Expand Down Expand Up @@ -34,6 +36,36 @@ public class AuthorizationChallengeValidatorTest {
@Mock
private ErrorResponseFactory errorResponseFactory;

@Mock
private ScopeService scopeService;

@Test(expectedExceptions = WebApplicationException.class)
public void validateAccess_whenClientIsNull_shouldThrowError() {
when(errorResponseFactory.newErrorResponse(Response.Status.BAD_REQUEST)).thenCallRealMethod();

authorizationChallengeValidator.validateAccess(null);
}

@Test(expectedExceptions = WebApplicationException.class)
public void validateAccess_whenClientDoesNotHaveRequiredScopes_shouldThrowError() {
when(errorResponseFactory.newErrorResponse(Response.Status.BAD_REQUEST)).thenCallRealMethod();

Client client = new Client();
client.setScopes(new String[] {"id1"});

authorizationChallengeValidator.validateAccess(client);
}

@Test
public void validateAccess_whenClientHasAuthorizationChallengeScope_shouldPass() {
when(scopeService.getScopeIdsByDns(Lists.newArrayList("id1"))).thenReturn(Lists.newArrayList("authorization_challenge"));

Client client = new Client();
client.setScopes(new String[] {"id1"});

authorizationChallengeValidator.validateAccess(client);
}

@Test(expectedExceptions = WebApplicationException.class)
public void validateGrantType_whenClientIsNull_shouldThrowError() {
when(errorResponseFactory.newErrorResponse(Response.Status.BAD_REQUEST)).thenCallRealMethod();
Expand Down
11 changes: 11 additions & 0 deletions jans-linux-setup/jans_setup/templates/scopes.ldif
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ jansScopeTyp: openid
objectClass: top
objectClass: jansScope

dn: inum=6D92,ou=scopes,o=jans
description: Authorization Challenge
displayName: authorization_challenge
inum: 6D92
jansAttrs: {"spontaneousClientId":"","spontaneousClientScopes":[],"showInConfigurationEndpoint":true}
jansDefScope: false
jansId: authorization_challenge
jansScopeTyp: oauth
objectClass: top
objectClass: jansScope

dn: inum=7D90,ou=scopes,o=jans
description: revoke_session scope which is required to be able call /revoke_session endpoint
displayName: revoke_session
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@ changetype: modify
jansDefScope: true
replace: jansDefScope

dn: inum=6D92,ou=scopes,o=jans
changetype: modify
jansDefScope: true
replace: jansDefScope

dn: inum=341A,ou=scopes,o=jans
changetype: modify
add: jansClaim
Expand Down Expand Up @@ -164,6 +169,7 @@ jansScope: inum=764C,ou=scopes,o=jans
jansScope: inum=43F1,ou=scopes,o=jans
jansScope: inum=341A,ou=scopes,o=jans
jansScope: inum=6D99,ou=scopes,o=jans
jansScope: inum=6D92,ou=scopes,o=jans
jansTknEndpointAuthMethod: client_secret_basic
jansTrustedClnt: true
objectClass: top
Expand All @@ -185,6 +191,7 @@ jansRespTyp: code
jansRespTyp: id_token
jansScope: inum=6D99,ou=scopes,o=jans
jansScope: inum=7D90,ou=scopes,o=jans
jansScope: inum=6D92,ou=scopes,o=jans
jansTknEndpointAuthMethod: client_secret_basic
jansTrustedClnt: true
objectClass: top
Expand Down

0 comments on commit b3db5c8

Please sign in to comment.