/* Dave had previously re-shared VIEW scope to ED, but that was made invalid when he lost that scope himself. He has been re-granted that scope so the VIEW scope should move the active policy and the empty inactive policy should be deleted. */ @Test public void shouldUpdateInvalidRightsTree() throws Exception { // Given List<Resource> policies = excludePolicies(DAVE, ED); policies.add(makePolicy(DAVE, ED, true, DELETE)); policies.add(makePolicy(DAVE, ED, false, VIEW)); PolicyGraph graph = makePolicyGraph(policies); graph.computeGraph(); given(delegate.updatePolicies(isNull(ServerContext.class), anySet())) .willReturn( Promises.<List<Resource>, ResourceException>newResultPromise( Collections.<Resource>emptyList())); given(delegate.deletePolicies(isNull(ServerContext.class), anySet())) .willReturn( Promises.<List<Resource>, ResourceException>newResultPromise( Collections.<Resource>emptyList())); // When Promise<List<List<Resource>>, ResourceException> promise = graph.update(null, delegate); // Then AssertJPromiseAssert.assertThat(promise).succeeded(); assertThat(UmaPolicyUtils.getPolicyScopes(policyUpdated())).containsOnly(VIEW, DELETE); assertThat(policyDeleted()).isEqualTo("Dave-Ed-false"); verifyNoMoreInteractions(delegate); }
/* Alice has removed Dave's rights to EDIT, so EDIT needs removing from the active Dave -> Ed policy, and adding to an inactive policy. */ @Test public void shouldRemoveLostRights() throws Exception { // Given List<Resource> policies = excludePolicies(DAVE, ED); policies.add(makePolicy(DAVE, ED, true, VIEW, DELETE, EDIT)); PolicyGraph graph = makePolicyGraph(policies); graph.computeGraph(); given(resourceSetStore.read(anyString())) .willReturn(new ResourceSetDescription(RESOURCE_SET_ID, "RESOURCE_SERVER_ID", ALICE, null)); given(delegate.updatePolicies(isNull(ServerContext.class), anySet())) .willReturn( Promises.<List<Resource>, ResourceException>newResultPromise( Collections.<Resource>emptyList())); given(delegate.createPolicies(isNull(ServerContext.class), anySet())) .willReturn( Promises.<List<Resource>, ResourceException>newResultPromise( Collections.<Resource>emptyList())); // When Promise<List<List<Resource>>, ResourceException> promise = graph.update(null, delegate); // Then AssertJPromiseAssert.assertThat(promise).succeeded(); JsonValue created = policyCreated(); assertThat(UmaPolicyUtils.getPolicyScopes(created)).containsOnly(EDIT); assertThat(created.get("active").asBoolean()).isFalse(); assertThat(UmaPolicyUtils.getPolicyScopes(policyUpdated())).containsOnly(VIEW, DELETE); verifyNoMoreInteractions(delegate); }
/** * Creates the underlying backend policies. * * <p>NOTE: if the creation of the underlying policies fails, any successfully created underlying * policies will be attempted to be deleted but if the deletion fails, then the underlying * policies may be in an inconsistent state. * * @param context The request context. * @param policies The underlying policies to create. * @return A promise containing the list of created underlying policies or a {@code * ResourceException} if the creation fails. */ public Promise<List<Resource>, ResourceException> createPolicies( ServerContext context, Set<JsonValue> policies) { final List<String> policyIds = new ArrayList<String>(); List<Promise<Resource, ResourceException>> promises = new ArrayList<Promise<Resource, ResourceException>>(); for (JsonValue policy : policies) { promises.add( policyResource .handleCreate(context, Requests.newCreateRequest("", policy)) .thenOnResult( new ResultHandler<Resource>() { @Override public void handleResult(Resource result) { // Save ids of created policies, in case a latter policy fails to be created, // so we can roll back. policyIds.add(result.getId()); } })); } return Promises.when(promises) .thenAsync( new AsyncFunction<List<Resource>, List<Resource>, ResourceException>() { @Override public Promise<List<Resource>, ResourceException> apply(List<Resource> value) { return Promises.newResultPromise(value); } }, new UmaPolicyCreateFailureHandler(context, policyIds)); }
@Test public void shouldReadResourceSet() throws Exception { // Given ServerContext context = mock(ServerContext.class); ReadRequest request = mock(ReadRequest.class); given(request.getFields()).willReturn(Arrays.asList(new JsonPointer("/fred"))); ResultHandler<Resource> handler = mock(ResultHandler.class); ResourceSetDescription resourceSet = new ResourceSetDescription(); resourceSet.setDescription(json(object())); Promise<ResourceSetDescription, ResourceException> resourceSetPromise = Promises.newSuccessfulPromise(resourceSet); given(contextHelper.getRealm(context)).willReturn("REALM"); given(contextHelper.getUserId(context)).willReturn("RESOURCE_OWNER_ID"); given( resourceSetService.getResourceSet( context, "REALM", "RESOURCE_SET_ID", "RESOURCE_OWNER_ID", false)) .willReturn(resourceSetPromise); // When resource.readInstance(context, "RESOURCE_SET_ID", request, handler); // Then verify(handler).handleResult(Matchers.<Resource>anyObject()); }
@Test public void crestActionBlowupIsAllowed() throws SSOException, DelegationException { // Given... final Set<String> actions = new HashSet<>(Arrays.asList("MODIFY")); final DelegationPermission permission = new DelegationPermission( "/abc", "rest", "1.0", "policies", "destroy", actions, EXTENSIONS, DUMB_FUNC); given(factory.newInstance("/abc", "rest", "1.0", "policies", "destroy", actions, EXTENSIONS)) .willReturn(permission); given(subjectContext.getCallerSSOToken()).willReturn(token); given(evaluator.isAllowed(eq(token), eq(permission), eq(ENVIRONMENT))).willReturn(true); JsonValue jsonValue = json(object(field("someKey", "someValue"))); Promise<ActionResponse, ResourceException> promise = Promises.newResultPromise(Responses.newActionResponse(jsonValue)); given(provider.actionCollection(isA(Context.class), isA(ActionRequest.class))) .willReturn(promise); // When... final FilterChain chain = AuthorizationFilters.createAuthorizationFilter(provider, module); final Router router = new Router(); router.addRoute(RoutingMode.STARTS_WITH, Router.uriTemplate("/policies"), chain); final RealmContext context = new RealmContext(subjectContext); context.setSubRealm("abc", "abc"); final ActionRequest request = Requests.newActionRequest("/policies", "blowup"); Promise<ActionResponse, ResourceException> result = router.handleAction(context, request); // Then... assertThat(result).succeeded().withContent().stringAt("someKey").isEqualTo("someValue"); }
// 1st time called: Mock a 401 (Unauthorized status) response @Override public Promise<Response, NeverThrowsException> answer(InvocationOnMock invocation) throws Throwable { Response response = new Response(); response.setStatus(Status.UNAUTHORIZED); response.getHeaders().putSingle(AUTHENTICATE_HEADER, "Basic realm=\"Login\""); return Promises.newResultPromise(response); }
/** * Deletes the underlying backend policies. * * <p>NOTE: if the deletion of the underlying policies fails, the underlying policies may be in an * inconsistent state. * * @param context The request context. * @param policyIds The list of ids of the underlying backend policies to delete. * @return A promise containing the list of underlying policies that were deleted or a {@code * ResourceException} if the policies were failed to be deleted. */ public Promise<List<Resource>, ResourceException> deletePolicies( ServerContext context, Collection<String> policyIds) { List<Promise<Resource, ResourceException>> promises = new ArrayList<Promise<Resource, ResourceException>>(); for (String policyId : policyIds) { promises.add(policyResource.handleDelete(context, Requests.newDeleteRequest(policyId))); } return Promises.when(promises); }
/** * Calls each {@code AsyncServerAuthContext} in parallel to clean the client subject and only * return a successful promise if all complete successfully otherwise returns the first exception * in a failed promise. * * @param context {@inheritDoc} * @param clientSubject {@inheritDoc} * @return {@inheritDoc} */ @Override public Promise<Void, AuthenticationException> cleanSubject( MessageContext context, Subject clientSubject) { List<Promise<Void, AuthenticationException>> promises = new ArrayList<>(); for (AsyncServerAuthModule serverAuthModule : authModules) { promises.add(serverAuthModule.cleanSubject(context, clientSubject)); } return Promises.when(promises).thenAsync(ON_SUCCESS_RETURN_VOID); }
@Override public Promise<Response, NeverThrowsException> handle(Context context, Request request) { try { latch2.countDown(); latch1.await(); return null; } catch (InterruptedException e) { return Promises.newResultPromise(new Response(Status.INTERNAL_SERVER_ERROR)); } }
/** * Updates the underlying backend policies. * * <p>NOTE: if the update of the underlying policies fails, the underlying policies may be in an * inconsistent state. * * @param context The request context. * @param policies The updated underlying policies to update. * @return A promise containing the list of updated underlying policies or a {@code * ResourceException} if the update failed. */ public Promise<List<Resource>, ResourceException> updatePolicies( ServerContext context, Set<JsonValue> policies) { List<Promise<Resource, ResourceException>> promises = new ArrayList<Promise<Resource, ResourceException>>(); for (JsonValue policy : policies) { String policyName = policy.get("name").asString(); promises.add( policyResource.handleUpdate(context, Requests.newUpdateRequest(policyName, policy))); } return Promises.when(promises); }
@Override public Promise<Response, NeverThrowsException> answer(InvocationOnMock invocation) throws Throwable { Request request = (Request) invocation.getArguments()[1]; // Verify the authorization header: base64(user:pass) assertThat(request.getHeaders().getFirst(AUTHORIZATION_HEADER)) .isEqualTo("Basic " + credentials); // Produce a valid response, no special headers are required Response response = new Response(); response.setStatus(Status.OK); return Promises.newResultPromise(response); }
/** {@inheritDoc} */ @Override public Promise<AuthorizationResult, ResourceException> authorizeCreate( Context context, CreateRequest request) { try { if (!getUserId(context).equalsIgnoreCase(getUserIdFromUri(context))) { return Promises.newResultPromise( AuthorizationResult.accessDenied( "Only resource owner of resource set can create UMA " + "policies for it.")); } else { return authorize(context); } } catch (ResourceException e) { return e.asPromise(); } }
@Test public void nameQueryShouldBeSupported() throws Exception { // Given ServerContext context = mock(ServerContext.class); QueryRequest request = mock(QueryRequest.class); given(request.getFields()).willReturn(Arrays.asList(new JsonPointer("/fred"))); QueryResultHandler handler = mock(QueryResultHandler.class); ResourceSetDescription resourceSet = mock(ResourceSetDescription.class); QueryFilter queryFilter = QueryFilter.and( QueryFilter.equalTo("/name", "NAME"), QueryFilter.equalTo("/resourceServer", "myclient"), QueryFilter.equalTo("/policy/permissions/subject", "SUBJECT")); Promise<Collection<ResourceSetDescription>, ResourceException> resourceSetsPromise = Promises.newSuccessfulPromise((Collection<ResourceSetDescription>) asSet(resourceSet)); given(contextHelper.getRealm(context)).willReturn("REALM"); given(contextHelper.getUserId(context)).willReturn("RESOURCE_OWNER_ID"); given(request.getQueryFilter()).willReturn(queryFilter); given( resourceSetService.getResourceSets( eq(context), eq("REALM"), Matchers.<ResourceSetWithPolicyQuery>anyObject(), eq("RESOURCE_OWNER_ID"), eq(false))) .willReturn(resourceSetsPromise); // When resource.queryCollection(context, request, handler); // Then ArgumentCaptor<ResourceSetWithPolicyQuery> queryCaptor = ArgumentCaptor.forClass(ResourceSetWithPolicyQuery.class); verify(resourceSetService) .getResourceSets( eq(context), eq("REALM"), queryCaptor.capture(), eq("RESOURCE_OWNER_ID"), eq(false)); assertThat(queryCaptor.getValue().getOperator()).isEqualTo(AggregateQuery.Operator.AND); assertThat(queryCaptor.getValue().getPolicyQuery()) .isEqualTo(QueryFilter.equalTo("/permissions/subject", "SUBJECT")); assertThat(queryCaptor.getValue().getResourceSetQuery()) .isEqualTo( org.forgerock.util.query.QueryFilter.and( org.forgerock.util.query.QueryFilter.equalTo("name", "NAME"), org.forgerock.util.query.QueryFilter.equalTo("clientId", "myclient"))); verify(handler).handleResult(any(QueryResult.class)); }
/** * Secures the response message using the same {@code AsyncServerAuthModule} that authenticated * the incoming request message. * * <p>If no {@code AsyncServerAuthModule} authenticated the incoming request message, then this * method should not have been called and a failed promise will be return with an {@code * AuthenticationException}. * * @param context {@inheritDoc} * @param serviceSubject {@inheritDoc} * @return {@inheritDoc} */ @Override public Promise<AuthStatus, AuthenticationException> secureResponse( MessageContext context, Subject serviceSubject) { FallbackAuthContextState state = context.getState(this); if (state.getAuthenticatedAuthModuleIndex() < 0) { return Promises.newExceptionPromise( new AuthenticationException( "No auth module authenticated the incoming request message. " + "Cannot secure response message.")); } AsyncServerAuthModule authModule = authModules.get(state.getAuthenticatedAuthModuleIndex()); logger.debug( "Using authenticating auth module from private context map, {}, to secure the response", authModule.getModuleId()); return authModule.secureResponse(context, serviceSubject); }
@Test public void revokeAllUserPoliciesActionShouldHandleResourceException() { // Given ServerContext context = mock(ServerContext.class); ActionRequest request = mock(ActionRequest.class); ResultHandler<JsonValue> handler = mock(ResultHandler.class); given(contextHelper.getRealm(context)).willReturn("REALM"); given(contextHelper.getUserId(context)).willReturn("RESOURCE_OWNER_ID"); given(request.getAction()).willReturn("revokeAll"); given(resourceSetService.revokeAllPolicies(context, "REALM", "RESOURCE_OWNER_ID")) .willReturn(Promises.<Void, ResourceException>newFailedPromise(new NotFoundException())); // When resource.actionCollection(context, request, handler); // Then verify(handler).handleError(Matchers.<ResourceException>anyObject()); verify(handler, never()).handleResult(Matchers.<JsonValue>anyObject()); }
private Promise<AuthStatus, AuthenticationException> validateRequest( final MessageInfoContext messageInfo, final Subject clientSubject, final Subject serviceSubject) { if (position < authModules.size()) { final AsyncServerAuthModule authModule = authModules.get(position); return authModule .validateRequest(messageInfo, clientSubject, serviceSubject) .thenOnResult( new ResultHandler<AuthStatus>() { @Override public void handleResult(AuthStatus authStatus) { if (isSuccess(authStatus)) { /* * Save the index of the authenticating module so that it can * be retrieved when securing the response */ logger.trace( "Adding authenticating auth module to private context map, {}", authModule.getClass().getSimpleName()); state.setAuthenticatedAuthModuleIndex(position); } } }) .thenAsync( new AsyncFunction<AuthStatus, AuthStatus, AuthenticationException>() { @Override public Promise<AuthStatus, AuthenticationException> apply(AuthStatus authStatus) { if (isSendFailure(authStatus)) { return next().validateRequest(messageInfo, clientSubject, serviceSubject); } else { return Promises.newResultPromise(authStatus); } } }); } else { return Promises.newResultPromise(AuthStatus.SEND_FAILURE); } }
/* Dave had removed Ed's ability to DELETE, so Ed's resharing policy to Bob had been made inactive. Dave has re-granted Ed's DELETE, so the inactive policy can be made active again. */ @Test public void shouldSwitchAllScopesInvalid() throws Exception { // Given List<Resource> policies = excludePolicies(ED, BOB); policies.add(makePolicy(ED, BOB, false, DELETE)); PolicyGraph graph = makePolicyGraph(policies); graph.computeGraph(); given(delegate.updatePolicies(isNull(ServerContext.class), anySet())) .willReturn( Promises.<List<Resource>, ResourceException>newResultPromise( Collections.<Resource>emptyList())); // When Promise<List<List<Resource>>, ResourceException> promise = graph.update(null, delegate); // Then AssertJPromiseAssert.assertThat(promise).succeeded(); assertThat(policyUpdated().get("active").asBoolean()).isTrue(); verifyNoMoreInteractions(delegate); }
/** {@inheritDoc} */ @Override public Promise<List<Resource>, ResourceException> apply(final ResourceException error) { List<Promise<Resource, ResourceException>> promises = new ArrayList<Promise<Resource, ResourceException>>(); PromiseImpl<Resource, ResourceException> kicker = PromiseImpl.create(); promises.add(kicker); for (String id : policyIds) { promises.add(policyResource.handleDelete(context, Requests.newDeleteRequest(id))); } Promise<List<Resource>, ResourceException> promise = Promises.when(promises) .thenAsync( new AsyncFunction<List<Resource>, List<Resource>, ResourceException>() { @Override public Promise<List<Resource>, ResourceException> apply(List<Resource> value) { // If we succeed in deleting then return the original error return Promises.newExceptionPromise(error); } }); kicker.handleResult(null); return promise; }
/** * Allows users to query OAuth2 applications that they have given their consent access to and that * have active access and/or refresh tokens. * * <p>Applications consist of an id, a name (the client id), a set of scopes and an expiry time. * The scopes field is the union of the scopes of the individual access/refresh tokens. The expiry * time is the time when the last access/refresh token will expire, or null if the server is * configured to allow tokens to be refreshed indefinitely. * * @param context The request context. * @param queryHandler The query handler. * @param request Unused but necessary for used of the {@link @Query} annotation. * @return A promise of a query response. */ @Query public Promise<QueryResponse, ResourceException> query( Context context, QueryResourceHandler queryHandler, QueryRequest request) { String userId = contextHelper.getUserId(context); String realm = contextHelper.getRealm(context); try { QueryFilter<CoreTokenField> queryFilter = getQueryFilter(userId, realm); JsonValue tokens = tokenStore.query(queryFilter); Map<String, Set<JsonValue>> applicationTokensMap = new HashMap<>(); for (JsonValue token : tokens) { String clientId = getAttributeValue(token, CLIENT_ID.getOAuthField()); Set<JsonValue> applicationTokens = applicationTokensMap.get(clientId); if (applicationTokens == null) { applicationTokens = new HashSet<>(); applicationTokensMap.put(clientId, applicationTokens); } applicationTokens.add(token); } for (Map.Entry<String, Set<JsonValue>> applicationTokens : applicationTokensMap.entrySet()) { ResourceResponse resource = getResourceResponse(context, applicationTokens.getKey(), applicationTokens.getValue()); queryHandler.handleResource(resource); } return Promises.newResultPromise(Responses.newQueryResponse()); } catch (CoreTokenException | ServerException | InvalidClientException | NotFoundException e) { debug.message("Failed to query OAuth2 clients for user {}", userId, e); return new InternalServerErrorException(e).asPromise(); } catch (InternalServerErrorException e) { debug.message("Failed to query OAuth2 clients for user {}", userId, e); return e.asPromise(); } }
@Test public void shouldRevokeAllUserPolicies() { // Given ServerContext context = mock(ServerContext.class); ActionRequest request = mock(ActionRequest.class); ResultHandler<JsonValue> handler = mock(ResultHandler.class); given(contextHelper.getRealm(context)).willReturn("REALM"); given(contextHelper.getUserId(context)).willReturn("RESOURCE_OWNER_ID"); given(request.getAction()).willReturn("revokeAll"); given(resourceSetService.revokeAllPolicies(context, "REALM", "RESOURCE_OWNER_ID")) .willReturn(Promises.<Void, ResourceException>newSuccessfulPromise(null)); // When resource.actionCollection(context, request, handler); // Then ArgumentCaptor<JsonValue> jsonCaptor = ArgumentCaptor.forClass(JsonValue.class); verify(handler).handleResult(jsonCaptor.capture()); verify(handler, never()).handleError(Matchers.<ResourceException>anyObject()); assertThat(jsonCaptor.getValue().asMap()).isEmpty(); }
@Test public void crestQueryIsAllowed() throws SSOException, DelegationException, ResourceException { // Given... final Set<String> actions = new HashSet<>(Arrays.asList("READ")); final DelegationPermission permission = new DelegationPermission( "/abc", "rest", "1.0", "policies", "read", actions, EXTENSIONS, DUMB_FUNC); given(factory.newInstance("/abc", "rest", "1.0", "policies", "read", actions, EXTENSIONS)) .willReturn(permission); given(subjectContext.getCallerSSOToken()).willReturn(token); given(evaluator.isAllowed(eq(token), eq(permission), eq(ENVIRONMENT))).willReturn(true); QueryResourceHandler handler = mock(QueryResourceHandler.class); Promise<QueryResponse, ResourceException> promise = Promises.newResultPromise(Responses.newQueryResponse("abc-def")); given( provider.queryCollection( isA(Context.class), isA(QueryRequest.class), isA(QueryResourceHandler.class))) .willReturn(promise); // When... final FilterChain chain = AuthorizationFilters.createAuthorizationFilter(provider, module); final Router router = new Router(); router.addRoute(RoutingMode.STARTS_WITH, Router.uriTemplate("/policies"), chain); final RealmContext context = new RealmContext(subjectContext); context.setSubRealm("abc", "abc"); final QueryRequest request = Requests.newQueryRequest("/policies"); Promise<QueryResponse, ResourceException> result = router.handleQuery(context, request, handler); // Then... QueryResponse response = result.getOrThrowUninterruptibly(); assertThat(response.getPagedResultsCookie()).isEqualTo("abc-def"); }
@Override public Promise<Response, NeverThrowsException> handle( final Context context, final Request request) { return Promises.newResultPromise(response); }