Search in sources :

Example 1 with Metadata

use of org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata in project keycloak by keycloak.

the class HttpMethodAuthenticator method uma.

public HttpMethod<R> uma(AuthorizationRequest request) {
    String ticket = request.getTicket();
    PermissionTicketToken permissions = request.getPermissions();
    if (ticket == null && permissions == null) {
        throw new IllegalArgumentException("You must either provide a permission ticket or the permissions you want to request.");
    }
    uma();
    method.param("ticket", ticket);
    method.param("claim_token", request.getClaimToken());
    method.param("claim_token_format", request.getClaimTokenFormat());
    method.param("pct", request.getPct());
    method.param("rpt", request.getRptToken());
    method.param("scope", request.getScope());
    method.param("audience", request.getAudience());
    method.param("subject_token", request.getSubjectToken());
    if (permissions != null) {
        for (Permission permission : permissions.getPermissions()) {
            String resourceId = permission.getResourceId();
            Set<String> scopes = permission.getScopes();
            StringBuilder value = new StringBuilder();
            if (resourceId != null) {
                value.append(resourceId);
            }
            if (scopes != null && !scopes.isEmpty()) {
                value.append("#");
                for (String scope : scopes) {
                    if (!value.toString().endsWith("#")) {
                        value.append(",");
                    }
                    value.append(scope);
                }
            }
            method.params("permission", value.toString());
        }
    }
    Metadata metadata = request.getMetadata();
    if (metadata != null) {
        if (metadata.getIncludeResourceName() != null) {
            method.param("response_include_resource_name", metadata.getIncludeResourceName().toString());
        }
        if (metadata.getLimit() != null) {
            method.param("response_permissions_limit", metadata.getLimit().toString());
        }
    }
    return method;
}
Also used : PermissionTicketToken(org.keycloak.representations.idm.authorization.PermissionTicketToken) Permission(org.keycloak.representations.idm.authorization.Permission) Metadata(org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata)

Example 2 with Metadata

use of org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata in project keycloak by keycloak.

the class Permissions method all.

/**
 * Returns a list of permissions for all resources and scopes that belong to the given <code>resourceServer</code> and
 * <code>identity</code>.
 *
 * TODO: review once we support caches
 *
 * @param resourceServer
 * @param identity
 * @param authorization
 * @return
 */
public static void all(ResourceServer resourceServer, Identity identity, AuthorizationProvider authorization, AuthorizationRequest request, Consumer<ResourcePermission> evaluator) {
    StoreFactory storeFactory = authorization.getStoreFactory();
    ResourceStore resourceStore = storeFactory.getResourceStore();
    Metadata metadata = request.getMetadata();
    final AtomicLong limit;
    if (metadata != null && metadata.getLimit() != null) {
        limit = new AtomicLong(metadata.getLimit());
    } else {
        limit = new AtomicLong(Long.MAX_VALUE);
    }
    // obtain all resources where owner is the resource server
    resourceStore.findByOwner(resourceServer.getId(), resourceServer.getId(), resource -> {
        if (limit.decrementAndGet() >= 0) {
            evaluator.accept(createResourcePermissions(resource, resourceServer, resource.getScopes(), authorization, request));
        }
    });
    // resource server isn't current user
    if (resourceServer.getId() != identity.getId()) {
        // obtain all resources where owner is the current user
        resourceStore.findByOwner(identity.getId(), resourceServer.getId(), resource -> {
            if (limit.decrementAndGet() >= 0) {
                evaluator.accept(createResourcePermissions(resource, resourceServer, resource.getScopes(), authorization, request));
            }
        });
    }
    // obtain all resources granted to the user via permission tickets (uma)
    List<PermissionTicket> tickets = storeFactory.getPermissionTicketStore().findGranted(identity.getId(), resourceServer.getId());
    if (!tickets.isEmpty()) {
        Map<String, ResourcePermission> userManagedPermissions = new HashMap<>();
        for (PermissionTicket ticket : tickets) {
            if (limit.get() < 0) {
                break;
            }
            ResourcePermission permission = userManagedPermissions.computeIfAbsent(ticket.getResource().getId(), s -> {
                limit.decrementAndGet();
                ResourcePermission resourcePermission = new ResourcePermission(ticket.getResource(), new ArrayList<>(), resourceServer, request.getClaims());
                resourcePermission.setGranted(true);
                return resourcePermission;
            });
            permission.addScope(ticket.getScope());
        }
        for (ResourcePermission permission : userManagedPermissions.values()) {
            evaluator.accept(permission);
        }
    }
}
Also used : AtomicLong(java.util.concurrent.atomic.AtomicLong) PermissionTicket(org.keycloak.authorization.model.PermissionTicket) HashMap(java.util.HashMap) Metadata(org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata) ResourceStore(org.keycloak.authorization.store.ResourceStore) StoreFactory(org.keycloak.authorization.store.StoreFactory)

Example 3 with Metadata

use of org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata in project keycloak by keycloak.

the class TokenEndpoint method permissionGrant.

public Response permissionGrant() {
    event.detail(Details.AUTH_METHOD, "oauth_credentials");
    String accessTokenString = null;
    String authorizationHeader = headers.getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION);
    if (authorizationHeader != null && authorizationHeader.toLowerCase().startsWith("bearer")) {
        accessTokenString = new AppAuthManager().extractAuthorizationHeaderToken(headers);
    }
    // public clients don't have secret and should be able to obtain a RPT by providing an access token previously issued by the server
    if (accessTokenString != null) {
        AccessToken accessToken = Tokens.getAccessToken(session);
        if (accessToken == null) {
            try {
                // In case the access token is invalid because it's expired or the user is disabled, identify the client
                // from the access token anyway in order to set correct CORS headers.
                AccessToken invalidToken = new JWSInput(accessTokenString).readJsonContent(AccessToken.class);
                ClientModel client = realm.getClientByClientId(invalidToken.getIssuedFor());
                cors.allowedOrigins(session, client);
                event.client(client);
            } catch (JWSInputException ignore) {
            }
            event.error(Errors.INVALID_TOKEN);
            throw new CorsErrorResponseException(cors, OAuthErrorException.INVALID_GRANT, "Invalid bearer token", Status.UNAUTHORIZED);
        }
        ClientModel client = realm.getClientByClientId(accessToken.getIssuedFor());
        session.getContext().setClient(client);
        cors.allowedOrigins(session, client);
        event.client(client);
    }
    String claimToken = null;
    // claim_token is optional, if provided we just grab it from the request
    if (formParams.containsKey("claim_token")) {
        claimToken = formParams.get("claim_token").get(0);
    }
    String claimTokenFormat = formParams.getFirst("claim_token_format");
    if (claimToken != null && claimTokenFormat == null) {
        claimTokenFormat = AuthorizationTokenService.CLAIM_TOKEN_FORMAT_ID_TOKEN;
    }
    String subjectToken = formParams.getFirst("subject_token");
    if (accessTokenString == null) {
        // in case no bearer token is provided, we force client authentication
        checkClient();
        // if a claim token is provided, we check if the format is a OpenID Connect IDToken and assume the token represents the identity asking for permissions
        if (AuthorizationTokenService.CLAIM_TOKEN_FORMAT_ID_TOKEN.equalsIgnoreCase(claimTokenFormat)) {
            accessTokenString = claimToken;
        } else if (subjectToken != null) {
            accessTokenString = subjectToken;
        } else {
            // Clients need to authenticate in order to obtain a RPT from the server.
            // In order to support cases where the client is obtaining permissions on its on behalf, we issue a temporary access token
            accessTokenString = AccessTokenResponse.class.cast(clientCredentialsGrant().getEntity()).getToken();
        }
    }
    AuthorizationTokenService.KeycloakAuthorizationRequest authorizationRequest = new AuthorizationTokenService.KeycloakAuthorizationRequest(session.getProvider(AuthorizationProvider.class), tokenManager, event, this.request, cors, clientConnection);
    authorizationRequest.setTicket(formParams.getFirst("ticket"));
    authorizationRequest.setClaimToken(claimToken);
    authorizationRequest.setClaimTokenFormat(claimTokenFormat);
    authorizationRequest.setPct(formParams.getFirst("pct"));
    String rpt = formParams.getFirst("rpt");
    if (rpt != null) {
        AccessToken accessToken = session.tokens().decode(rpt, AccessToken.class);
        if (accessToken == null) {
            event.error(Errors.INVALID_REQUEST);
            throw new CorsErrorResponseException(cors, "invalid_rpt", "RPT signature is invalid", Status.FORBIDDEN);
        }
        authorizationRequest.setRpt(accessToken);
    }
    authorizationRequest.setScope(formParams.getFirst("scope"));
    String audienceParam = formParams.getFirst("audience");
    authorizationRequest.setAudience(audienceParam);
    authorizationRequest.setSubjectToken(accessTokenString);
    event.detail(Details.AUDIENCE, audienceParam);
    String submitRequest = formParams.getFirst("submit_request");
    authorizationRequest.setSubmitRequest(submitRequest == null ? true : Boolean.valueOf(submitRequest));
    // permissions have a format like RESOURCE#SCOPE1,SCOPE2
    List<String> permissions = formParams.get("permission");
    if (permissions != null) {
        event.detail(Details.PERMISSION, String.join("|", permissions));
        for (String permission : permissions) {
            String[] parts = permission.split("#");
            String resource = parts[0];
            if (parts.length == 1) {
                authorizationRequest.addPermission(resource);
            } else {
                String[] scopes = parts[1].split(",");
                authorizationRequest.addPermission(parts[0], scopes);
            }
        }
    }
    Metadata metadata = new Metadata();
    String responseIncludeResourceName = formParams.getFirst("response_include_resource_name");
    if (responseIncludeResourceName != null) {
        metadata.setIncludeResourceName(Boolean.parseBoolean(responseIncludeResourceName));
    }
    String responsePermissionsLimit = formParams.getFirst("response_permissions_limit");
    if (responsePermissionsLimit != null) {
        metadata.setLimit(Integer.parseInt(responsePermissionsLimit));
    }
    metadata.setResponseMode(formParams.getFirst("response_mode"));
    authorizationRequest.setMetadata(metadata);
    Response authorizationResponse = AuthorizationTokenService.instance().authorize(authorizationRequest);
    event.success();
    return authorizationResponse;
}
Also used : AuthorizationProvider(org.keycloak.authorization.AuthorizationProvider) Metadata(org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata) JWSInputException(org.keycloak.jose.jws.JWSInputException) JWSInput(org.keycloak.jose.jws.JWSInput) AccessTokenResponse(org.keycloak.representations.AccessTokenResponse) Response(javax.ws.rs.core.Response) HttpResponse(org.jboss.resteasy.spi.HttpResponse) ClientModel(org.keycloak.models.ClientModel) AuthorizationTokenService(org.keycloak.authorization.authorization.AuthorizationTokenService) AccessToken(org.keycloak.representations.AccessToken) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) AccessTokenResponse(org.keycloak.representations.AccessTokenResponse) AppAuthManager(org.keycloak.services.managers.AppAuthManager)

Example 4 with Metadata

use of org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata in project keycloak by keycloak.

the class AuthorizationTokenService method authorize.

public Response authorize(KeycloakAuthorizationRequest request) {
    EventBuilder event = request.getEvent();
    // it is not secure to allow public clients to push arbitrary claims because message can be tampered
    if (isPublicClientRequestingEntitlementWithClaims(request)) {
        CorsErrorResponseException forbiddenClientException = new CorsErrorResponseException(request.getCors(), OAuthErrorException.INVALID_GRANT, "Public clients are not allowed to send claims", Status.FORBIDDEN);
        fireErrorEvent(event, Errors.INVALID_REQUEST, forbiddenClientException);
        throw forbiddenClientException;
    }
    try {
        PermissionTicketToken ticket = getPermissionTicket(request);
        request.setClaims(ticket.getClaims());
        EvaluationContext evaluationContext = createEvaluationContext(request);
        KeycloakIdentity identity = KeycloakIdentity.class.cast(evaluationContext.getIdentity());
        if (identity != null) {
            event.user(identity.getId());
        }
        ResourceServer resourceServer = getResourceServer(ticket, request);
        Collection<Permission> permissions;
        if (request.getTicket() != null) {
            permissions = evaluateUserManagedPermissions(request, ticket, resourceServer, evaluationContext);
        } else if (ticket.getPermissions().isEmpty() && request.getRpt() == null) {
            permissions = evaluateAllPermissions(request, resourceServer, evaluationContext);
        } else {
            permissions = evaluatePermissions(request, ticket, resourceServer, evaluationContext, identity);
        }
        if (isGranted(ticket, request, permissions)) {
            AuthorizationProvider authorization = request.getAuthorization();
            ClientModel targetClient = authorization.getRealm().getClientById(resourceServer.getId());
            Metadata metadata = request.getMetadata();
            String responseMode = metadata != null ? metadata.getResponseMode() : null;
            if (responseMode != null) {
                if (RESPONSE_MODE_DECISION.equals(metadata.getResponseMode())) {
                    Map<String, Object> responseClaims = new HashMap<>();
                    responseClaims.put(RESPONSE_MODE_DECISION_RESULT, true);
                    return createSuccessfulResponse(responseClaims, request);
                } else if (RESPONSE_MODE_PERMISSIONS.equals(metadata.getResponseMode())) {
                    return createSuccessfulResponse(permissions, request);
                } else {
                    CorsErrorResponseException invalidResponseModeException = new CorsErrorResponseException(request.getCors(), OAuthErrorException.INVALID_REQUEST, "Invalid response_mode", Status.BAD_REQUEST);
                    fireErrorEvent(event, Errors.INVALID_REQUEST, invalidResponseModeException);
                    throw invalidResponseModeException;
                }
            } else {
                return createSuccessfulResponse(createAuthorizationResponse(identity, permissions, request, targetClient), request);
            }
        }
        if (request.isSubmitRequest()) {
            CorsErrorResponseException submittedRequestException = new CorsErrorResponseException(request.getCors(), OAuthErrorException.ACCESS_DENIED, "request_submitted", Status.FORBIDDEN);
            fireErrorEvent(event, Errors.ACCESS_DENIED, submittedRequestException);
            throw submittedRequestException;
        } else {
            CorsErrorResponseException notAuthorizedException = new CorsErrorResponseException(request.getCors(), OAuthErrorException.ACCESS_DENIED, "not_authorized", Status.FORBIDDEN);
            fireErrorEvent(event, Errors.ACCESS_DENIED, notAuthorizedException);
            throw notAuthorizedException;
        }
    } catch (ErrorResponseException | CorsErrorResponseException cause) {
        if (logger.isDebugEnabled()) {
            logger.debug("Error while evaluating permissions", cause);
        }
        throw cause;
    } catch (Exception cause) {
        logger.error("Unexpected error while evaluating permissions", cause);
        throw new CorsErrorResponseException(request.getCors(), OAuthErrorException.SERVER_ERROR, "Unexpected error while evaluating permissions", Status.INTERNAL_SERVER_ERROR);
    }
}
Also used : PermissionTicketToken(org.keycloak.representations.idm.authorization.PermissionTicketToken) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) AuthorizationProvider(org.keycloak.authorization.AuthorizationProvider) Metadata(org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata) OAuthErrorException(org.keycloak.OAuthErrorException) ErrorResponseException(org.keycloak.services.ErrorResponseException) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) ClientModel(org.keycloak.models.ClientModel) EventBuilder(org.keycloak.events.EventBuilder) KeycloakIdentity(org.keycloak.authorization.common.KeycloakIdentity) ResourcePermission(org.keycloak.authorization.permission.ResourcePermission) Permission(org.keycloak.representations.idm.authorization.Permission) ErrorResponseException(org.keycloak.services.ErrorResponseException) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) CorsErrorResponseException(org.keycloak.services.CorsErrorResponseException) DefaultEvaluationContext(org.keycloak.authorization.common.DefaultEvaluationContext) EvaluationContext(org.keycloak.authorization.policy.evaluation.EvaluationContext) ResourceServer(org.keycloak.authorization.model.ResourceServer)

Example 5 with Metadata

use of org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata in project keycloak by keycloak.

the class EntitlementAPITest method testObtainAllEntitlementsWithLimit.

@Test
public void testObtainAllEntitlementsWithLimit() throws Exception {
    org.keycloak.authorization.client.resource.AuthorizationResource authorizationResource = getAuthzClient(AUTHZ_CLIENT_CONFIG).authorization("marta", "password");
    AuthorizationResponse response = authorizationResource.authorize();
    AccessToken accessToken = toAccessToken(response.getToken());
    Authorization authorization = accessToken.getAuthorization();
    assertTrue(authorization.getPermissions().size() >= 20);
    AuthorizationRequest request = new AuthorizationRequest();
    Metadata metadata = new Metadata();
    metadata.setLimit(10);
    request.setMetadata(metadata);
    response = authorizationResource.authorize(request);
    accessToken = toAccessToken(response.getToken());
    authorization = accessToken.getAuthorization();
    assertEquals(10, authorization.getPermissions().size());
    metadata.setLimit(1);
    request.setMetadata(metadata);
    response = authorizationResource.authorize(request);
    accessToken = toAccessToken(response.getToken());
    authorization = accessToken.getAuthorization();
    assertEquals(1, authorization.getPermissions().size());
}
Also used : Authorization(org.keycloak.representations.AccessToken.Authorization) AuthorizationRequest(org.keycloak.representations.idm.authorization.AuthorizationRequest) AccessToken(org.keycloak.representations.AccessToken) Metadata(org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata) AuthorizationResponse(org.keycloak.representations.idm.authorization.AuthorizationResponse) Test(org.junit.Test)

Aggregations

Metadata (org.keycloak.representations.idm.authorization.AuthorizationRequest.Metadata)11 AuthorizationRequest (org.keycloak.representations.idm.authorization.AuthorizationRequest)6 Permission (org.keycloak.representations.idm.authorization.Permission)4 HashMap (java.util.HashMap)3 Test (org.junit.Test)3 AccessToken (org.keycloak.representations.AccessToken)3 LinkedHashMap (java.util.LinkedHashMap)2 AuthorizationProvider (org.keycloak.authorization.AuthorizationProvider)2 KeycloakIdentity (org.keycloak.authorization.common.KeycloakIdentity)2 ResourcePermission (org.keycloak.authorization.permission.ResourcePermission)2 ResourceStore (org.keycloak.authorization.store.ResourceStore)2 StoreFactory (org.keycloak.authorization.store.StoreFactory)2 ClientModel (org.keycloak.models.ClientModel)2 AuthorizationResponse (org.keycloak.representations.idm.authorization.AuthorizationResponse)2 PermissionTicketToken (org.keycloak.representations.idm.authorization.PermissionTicketToken)2 CorsErrorResponseException (org.keycloak.services.CorsErrorResponseException)2 ArrayList (java.util.ArrayList)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 AtomicLong (java.util.concurrent.atomic.AtomicLong)1 Response (javax.ws.rs.core.Response)1