From 16954fc370c788a1c8493b58cad46915e9561ffb Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Thu, 10 Aug 2017 14:58:09 -0400 Subject: [PATCH] fix --- .../java/org/keycloak/OAuth2Constants.java | 2 + .../broker/provider/TokenExchangeTo.java | 42 +++++++++++++++++ .../oidc/endpoints/TokenEndpoint.java | 45 +++++++++++++++---- .../admin/permissions/GroupPermissions.java | 2 +- 4 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 server-spi-private/src/main/java/org/keycloak/broker/provider/TokenExchangeTo.java diff --git a/core/src/main/java/org/keycloak/OAuth2Constants.java b/core/src/main/java/org/keycloak/OAuth2Constants.java index 2e585c3278..bedef8d97d 100644 --- a/core/src/main/java/org/keycloak/OAuth2Constants.java +++ b/core/src/main/java/org/keycloak/OAuth2Constants.java @@ -97,6 +97,8 @@ public interface OAuth2Constants { String AUDIENCE="audience"; String SUBJECT_TOKEN="subject_token"; String SUBJECT_TOKEN_TYPE="subject_token_type"; + String REQUESTED_TOKEN_TYPE="requested_token_type"; + String REQUESTED_ISSUER="requested_issuer"; String ACCESS_TOKEN_TYPE="urn:ietf:params:oauth:token-type:access_token"; String REFRESH_TOKEN_TYPE="urn:ietf:params:oauth:token-type:refresh_token"; String JWT_TOKEN_TYPE="urn:ietf:params:oauth:token-type:jwt"; diff --git a/server-spi-private/src/main/java/org/keycloak/broker/provider/TokenExchangeTo.java b/server-spi-private/src/main/java/org/keycloak/broker/provider/TokenExchangeTo.java new file mode 100644 index 0000000000..36755d4588 --- /dev/null +++ b/server-spi-private/src/main/java/org/keycloak/broker/provider/TokenExchangeTo.java @@ -0,0 +1,42 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.keycloak.broker.provider; + +import org.keycloak.models.ClientModel; +import org.keycloak.models.UserModel; +import org.keycloak.models.UserSessionModel; +import org.keycloak.representations.AccessToken; + +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; + +/** + * @author Bill Burke + * @version $Revision: 1 $ + */ +public interface TokenExchangeTo { + /** + * + * @param authorizedClient client requesting exchange + * @param tokenUserSession UserSessionModel of token exchanging from + * @param tokenSubject UserModel of token exchanging from + * @param token access token representation of token exchanging from + * @param params form parameters received for requested exchange + * @return + */ + Response exchangeTo(ClientModel authorizedClient, UserSessionModel tokenUserSession, UserModel tokenSubject, AccessToken token, MultivaluedMap params); +} diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java index fef17c6ca0..b0b3e198ac 100644 --- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java +++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/TokenEndpoint.java @@ -564,19 +564,43 @@ public class TokenEndpoint { public Response buildTokenExchange() { event.detail(Details.AUTH_METHOD, "oauth_credentials"); - String scope = formParams.getFirst(OAuth2Constants.SCOPE); String subjectToken = formParams.getFirst(OAuth2Constants.SUBJECT_TOKEN); String subjectTokenType = formParams.getFirst(OAuth2Constants.SUBJECT_TOKEN_TYPE); + if (subjectTokenType != null && !subjectTokenType.equals(OAuth2Constants.ACCESS_TOKEN_TYPE)) { + event.error(Errors.INVALID_TOKEN); + throw new ErrorResponseException(OAuthErrorException.INVALID_TOKEN, "Invalid token type, must be access token", Response.Status.BAD_REQUEST); + + } + + AuthenticationManager.AuthResult authResult = AuthenticationManager.verifyIdentityToken(session, realm, uriInfo, clientConnection, true, true, false, subjectToken, headers); if (authResult == null) { event.error(Errors.INVALID_TOKEN); throw new ErrorResponseException(OAuthErrorException.INVALID_TOKEN, "Invalid token", Response.Status.BAD_REQUEST); } + String requestedIssuer = formParams.getFirst(OAuth2Constants.REQUESTED_ISSUER); + + if (requestedIssuer == null) { + + } + + return exchangeClientToClient(authResult); + } + + public Response exchangeClientToClient(AuthenticationManager.AuthResult subject) { + String requestedTokenType = formParams.getFirst(OAuth2Constants.REQUESTED_TOKEN_TYPE); + if (requestedTokenType == null) { + requestedTokenType = OAuth2Constants.REFRESH_TOKEN_TYPE; + } else if (!requestedTokenType.equals(OAuth2Constants.ACCESS_TOKEN_TYPE) && !requestedTokenType.equals(OAuth2Constants.REFRESH_TOKEN_TYPE)) { + event.error(Errors.INVALID_REQUEST); + throw new ErrorResponseException("unsupported_requested_token_type", "Unsupported requested token type", Response.Status.BAD_REQUEST); + + } String audience = formParams.getFirst(OAuth2Constants.AUDIENCE); if (audience == null) { event.error(Errors.INVALID_REQUEST); - throw new ErrorResponseException("invalid_audience", "No audience specified", Response.Status.BAD_REQUEST); + throw new ErrorResponseException("invalid_audience", "Audience parameter required", Response.Status.BAD_REQUEST); } ClientModel targetClient = null; @@ -594,7 +618,7 @@ public class TokenEndpoint { } boolean exchangeFromAllowed = false; - for (String aud : authResult.getToken().getAudience()) { + for (String aud : subject.getToken().getAudience()) { ClientModel audClient = realm.getClientByClientId(aud); if (audClient == null) continue; if (audClient.equals(client)) { @@ -617,13 +641,15 @@ public class TokenEndpoint { throw new ErrorResponseException(OAuthErrorException.ACCESS_DENIED, "Client not allowed to exchange", Response.Status.FORBIDDEN); } + String scope = formParams.getFirst(OAuth2Constants.SCOPE); + AuthenticationSessionModel authSession = new AuthenticationSessionManager(session).createAuthenticationSession(realm, targetClient, false); - authSession.setAuthenticatedUser(authResult.getUser()); + authSession.setAuthenticatedUser(subject.getUser()); authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL); authSession.setClientNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName())); authSession.setClientNote(OIDCLoginProtocol.SCOPE_PARAM, scope); - UserSessionModel userSession = authResult.getSession(); + UserSessionModel userSession = subject.getSession(); event.session(userSession); AuthenticationManager.setRolesAndMappersInSession(authSession); @@ -637,10 +663,13 @@ public class TokenEndpoint { updateUserSessionFromClientAuth(userSession); TokenManager.AccessTokenResponseBuilder responseBuilder = tokenManager.responseBuilder(realm, targetClient, event, session, userSession, clientSession) - .generateAccessToken() - .generateRefreshToken(); + .generateAccessToken(); responseBuilder.getAccessToken().issuedFor(client.getClientId()); - responseBuilder.getRefreshToken().issuedFor(client.getClientId()); + + if (requestedTokenType.equals(OAuth2Constants.REFRESH_TOKEN_TYPE)) { + responseBuilder.generateRefreshToken(); + responseBuilder.getRefreshToken().issuedFor(client.getClientId()); + } String scopeParam = clientSession.getNote(OAuth2Constants.SCOPE); if (TokenUtil.isOIDCRequest(scopeParam)) { diff --git a/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissions.java b/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissions.java index b20d4626df..46b15d024e 100644 --- a/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissions.java +++ b/services/src/main/java/org/keycloak/services/resources/admin/permissions/GroupPermissions.java @@ -185,7 +185,7 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag authz.getStoreFactory().getPolicyStore().delete(manageMembersPermission.getId()); } Policy viewMembersPermission = viewMembersPermission(group); - if (viewMembersPermission == null) { + if (viewMembersPermission != null) { authz.getStoreFactory().getPolicyStore().delete(viewMembersPermission.getId()); } Policy manageMembershipPermission = manageMembershipPermission(group);