org.cloudfoundry.identity.uaa.oauth.UserManagedAuthzApprovalHandler Maven / Gradle / Ivy
/*******************************************************************************
* Cloud Foundry
* Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved.
*
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
* You may not use this product except in compliance with the License.
*
* This product includes a number of subcomponents with
* separate copyright notices and license terms. Your use of these
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
*******************************************************************************/
package org.cloudfoundry.identity.uaa.oauth;
import static org.cloudfoundry.identity.uaa.approval.Approval.ApprovalStatus.APPROVED;
import static org.cloudfoundry.identity.uaa.approval.Approval.ApprovalStatus.DENIED;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudfoundry.identity.uaa.authentication.Origin;
import org.cloudfoundry.identity.uaa.approval.Approval;
import org.cloudfoundry.identity.uaa.approval.ApprovalStore;
import org.cloudfoundry.identity.uaa.resources.QueryableResourceManager;
import org.cloudfoundry.identity.uaa.util.UaaTokenUtils;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
public class UserManagedAuthzApprovalHandler implements UserApprovalHandler {
private static final String SCOPE_PREFIX = "scope.";
private static Log logger = LogFactory.getLog(UserManagedAuthzApprovalHandler.class);
private final String approvalParameter = OAuth2Utils.USER_OAUTH_APPROVAL;
private ApprovalStore approvalStore;
private QueryableResourceManager clientDetailsService;
private int approvalExpiryInMillis = -1;
/**
* @param clientDetailsService the clientDetailsService to set
*/
public void setClientDetailsService(QueryableResourceManager clientDetailsService) {
this.clientDetailsService = clientDetailsService;
}
public void setApprovalStore(ApprovalStore approvalStore) {
this.approvalStore = approvalStore;
}
@Override
public boolean isApproved(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
String flag = authorizationRequest.getApprovalParameters().get(approvalParameter);
boolean userApproval = flag != null && flag.toLowerCase().equals("true");
if (logger.isDebugEnabled()) {
StringBuilder builder = new StringBuilder("Looking up user approved authorizations for ");
builder.append("client_id=").append(authorizationRequest.getClientId());
builder.append(" and username=").append(userAuthentication.getName());
logger.debug(builder.toString());
}
Collection requestedScopes = authorizationRequest.getScope();
// Factor in auto approved scopes
Set autoApprovedScopes = new HashSet<>();
BaseClientDetails client = (BaseClientDetails) clientDetailsService.retrieve(authorizationRequest.getClientId(), IdentityZoneHolder.get().getId());
if (client != null && requestedScopes != null) {
autoApprovedScopes.addAll(client.getAutoApproveScopes());
autoApprovedScopes = UaaTokenUtils.retainAutoApprovedScopes(requestedScopes, autoApprovedScopes);
}
//translate scope to user scopes - including wild cards
if (userApproval) {
// Store the scopes that have been approved / denied
Date expiry = computeExpiry();
// Get the approved scopes, calculate the denied scope
Map approvalParameters = authorizationRequest.getApprovalParameters();
Set approvedScopes = new HashSet<>();
approvedScopes.addAll(autoApprovedScopes);
boolean foundUserApprovalParameter = false;
for (String approvalParameter : approvalParameters.keySet()) {
if (approvalParameter.startsWith(SCOPE_PREFIX)) {
approvedScopes.add(approvalParameters.get(approvalParameter).substring(SCOPE_PREFIX.length()));
foundUserApprovalParameter = true;
}
}
if (foundUserApprovalParameter) {
authorizationRequest.setScope(approvedScopes);
for (String requestedScope : requestedScopes) {
if (approvedScopes.contains(requestedScope)) {
Approval approval = new Approval()
.setUserId(getUserId(userAuthentication))
.setClientId(authorizationRequest.getClientId())
.setScope(requestedScope)
.setExpiresAt(expiry)
.setStatus(APPROVED);
approvalStore.addApproval(approval, IdentityZoneHolder.get().getId());
}
else {
Approval approval = new Approval()
.setUserId(getUserId(userAuthentication))
.setClientId(authorizationRequest.getClientId())
.setScope(requestedScope)
.setExpiresAt(expiry)
.setStatus(DENIED);
approvalStore.addApproval(approval, IdentityZoneHolder.get().getId());
}
}
}
else { // Deny all except auto approved scopes
authorizationRequest.setScope(autoApprovedScopes);
for (String requestedScope : requestedScopes) {
if (!autoApprovedScopes.contains(requestedScope)) {
Approval approval = new Approval()
.setUserId(getUserId(userAuthentication))
.setClientId(authorizationRequest.getClientId())
.setScope(requestedScope)
.setExpiresAt(expiry)
.setStatus(DENIED);
approvalStore.addApproval(approval, IdentityZoneHolder.get().getId());
}
}
}
if (userAuthentication.isAuthenticated()) {
return true;
}
} else {
// Find the stored approvals for that user and client
List userApprovals = approvalStore.getApprovals(getUserId(userAuthentication), authorizationRequest.getClientId(), IdentityZoneHolder.get().getId());
// Look at the scopes and see if they have expired
Set validUserApprovedScopes = new HashSet<>();
Set approvedScopes = new HashSet<>();
approvedScopes.addAll(autoApprovedScopes);
validUserApprovedScopes.addAll(autoApprovedScopes);
Date today = new Date();
for (Approval approval : userApprovals) {
if (approval.getExpiresAt().after(today)) {
validUserApprovedScopes.add(approval.getScope());
if (approval.getStatus() == APPROVED) {
approvedScopes.add(approval.getScope());
}
}
}
if (logger.isDebugEnabled()) {
logger.debug("Valid user approved/denied scopes are " + validUserApprovedScopes);
}
// If the requested scopes have already been acted upon by the user,
// this request is approved
if (validUserApprovedScopes.containsAll(requestedScopes) && userAuthentication.isAuthenticated()) {
approvedScopes = UaaTokenUtils.retainAutoApprovedScopes(requestedScopes, approvedScopes);
// Set only the scopes that have been approved by the user
authorizationRequest.setScope(approvedScopes);
return true;
}
}
return false;
}
protected String getUserId(Authentication authentication) {
return Origin.getUserId(authentication);
}
private Date computeExpiry() {
Calendar expiresAt = Calendar.getInstance();
if (approvalExpiryInMillis == -1) { // use default of 1 month
expiresAt.add(Calendar.MONTH, 1);
}
else {
expiresAt.add(Calendar.MILLISECOND, approvalExpiryInMillis);
}
return expiresAt.getTime();
}
public void setApprovalExpiryInSeconds(int approvalExpirySeconds) {
this.approvalExpiryInMillis = approvalExpirySeconds * 1000;
}
@Override
public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
return authorizationRequest;
}
@Override
public AuthorizationRequest updateAfterApproval(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
return authorizationRequest;
}
@Override
public Map getUserApprovalRequest(AuthorizationRequest authorizationRequest, Authentication userAuthentication) {
Map model = new HashMap();
model.putAll(authorizationRequest.getRequestParameters());
return model;
}
}