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;
}
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);
}
}
}
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;
}
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);
}
}
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());
}
Aggregations