package com.janrain.backplane2.server; import com.janrain.backplane.common.BackplaneServerException; import com.janrain.backplane.common.model.Message; import com.janrain.backplane.dao.DaoException; import com.janrain.backplane.server2.dao.BP2DAOs; import com.janrain.backplane.server2.model.Backplane2MessageFields; import com.janrain.backplane.server2.model.ChannelFields; import com.janrain.backplane.server2.oauth2.model.Grant2; import com.janrain.backplane.server2.oauth2.model.GrantFields; import com.janrain.commons.supersimpledb.SimpleDBException; import com.janrain.oauth2.TokenException; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import scala.collection.JavaConversions; import java.util.*; /** * Grant logic utility class. * * @author Tom Raney */ public class GrantLogic { /** * Retrieve all active grants issued to the supplied clientId * that match any of the fields that require authorization in the supplied scope. * * If none of the fields in the supplied scope require authorization, or if the supplied scope is null, * returns all grants issued to clientId, keyed on a single map entry representing the full scope * that includes the filter-only, no-authorization-required supplied scope. * * @return map of authorized scopes backed-by grants * @throws */ public static @NotNull Map<Scope,Set<Grant2>> retrieveClientGrants(final String clientId, @Nullable Scope scope) throws BackplaneServerException, TokenException, DaoException { List<Grant2> clientActiveGrants = JavaConversions.seqAsJavaList(BP2DAOs.grantDao().getByClientId(clientId)); Map<Scope,Set<Grant2>> result = new LinkedHashMap<Scope, Set<Grant2>>(); if (scope == null || ! scope.isAuthorizationRequired()) { Set<Grant2> selectedGrants = new LinkedHashSet<Grant2>(); Map<Backplane2MessageFields.EnumVal,LinkedHashSet<String>> authorizedScopesMap = new LinkedHashMap<Backplane2MessageFields.EnumVal, LinkedHashSet<String>>(); for (Grant2 grant : clientActiveGrants) { if (Message.isExpired(grant.get(GrantFields.TIME_EXPIRE()))) continue; selectedGrants.add(grant); Scope.addScopes(authorizedScopesMap, grant.getAuthorizedScope().getScopeMap()); } if (scope != null) { Scope.addScopes(authorizedScopesMap, scope.getScopeMap()); // add request filter-only scopes } result.put(new Scope(authorizedScopesMap), selectedGrants); } else { for(Scope authReqScope : scope.getAuthReqScopes()) { final Scope testScope; if (authReqScope.getScopeMap().containsKey(Backplane2MessageFields.CHANNEL())) { com.janrain.backplane.server2.model.Channel channel = BP2DAOs.channelDao().get(authReqScope.getScopeMap().get(Backplane2MessageFields.CHANNEL()).iterator().next()).getOrElse(null); String boundBus = channel == null ? null : (String) channel.get(ChannelFields.BUS()).getOrElse(null); testScope = new Scope(Backplane2MessageFields.BUS(), boundBus); } else { testScope = authReqScope; } for(Grant2 grant : clientActiveGrants) { if (Message.isExpired(grant.get(GrantFields.TIME_EXPIRE()))) continue; if (grant.getAuthorizedScope().containsScope(testScope)) { Set<Grant2> backingGrants = result.get(authReqScope); if (backingGrants == null) { backingGrants = new LinkedHashSet<Grant2>(); result.put(authReqScope, backingGrants); } backingGrants.add(grant); } } } } return result; } /** * Activate authorization_code grant, mark code used, return updated grant. * * @return the updated grant, never null * * @throws com.janrain.oauth2.TokenException if: * 1) no grant was found for the supplied code, or * 2) the grant found was not an authorization_code grant, or * 3) the grant was not issued to the supplied authenticatedClientId, or * 4) the grant/grant code has expired, or * 5) the grant's code had already been used (in this case the grant is also invalidated/revoked), or * * @throws */ public static Grant2 getAndActivateCodeGrant(final String codeId, String authenticatedClientId) throws BackplaneServerException, TokenException, DaoException { Grant2 existing = BP2DAOs.grantDao().get(codeId).getOrElse(null); GrantState updatedState = GrantState.ACTIVE; if ( existing == null) { logger.warn("No grant found for code: " + codeId); throw new TokenException("Invalid code: " + codeId); } else if ( GrantType.AUTHORIZATION_CODE != existing.getType() || Message.isExpired(existing.get(GrantFields.TIME_EXPIRE())) || StringUtils.isBlank(authenticatedClientId) || ! authenticatedClientId.equals(existing.get(GrantFields.ISSUED_TO_CLIENT()).getOrElse(null)) || GrantState.INACTIVE != existing.getState()) { logger.error("Invalid grant for code: " + codeId); updatedState = GrantState.REVOKED; } Grant2 updated; // no expiration try { updated = new GrantBuilder(existing, updatedState).buildGrant(); } catch (SimpleDBException e) { throw new BackplaneServerException(e.getMessage()); } BP2DAOs.grantDao().update(updated); logger.info( "Grant status: " + updatedState.toString().toLowerCase() + " for code: " + codeId + ", client_id: " + authenticatedClientId); if (updatedState.isActive()) { return updated; } else { throw new TokenException("Invalid code: " + codeId); } } // - PRIVATE private static final Logger logger = Logger.getLogger(GrantLogic.class); private GrantLogic() {} }