This commit is contained in:
Bill Burke 2017-08-10 14:58:09 -04:00
parent 41cdd9db70
commit 16954fc370
4 changed files with 82 additions and 9 deletions

View file

@ -97,6 +97,8 @@ public interface OAuth2Constants {
String AUDIENCE="audience"; String AUDIENCE="audience";
String SUBJECT_TOKEN="subject_token"; String SUBJECT_TOKEN="subject_token";
String SUBJECT_TOKEN_TYPE="subject_token_type"; 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 ACCESS_TOKEN_TYPE="urn:ietf:params:oauth:token-type:access_token";
String REFRESH_TOKEN_TYPE="urn:ietf:params:oauth:token-type:refresh_token"; String REFRESH_TOKEN_TYPE="urn:ietf:params:oauth:token-type:refresh_token";
String JWT_TOKEN_TYPE="urn:ietf:params:oauth:token-type:jwt"; String JWT_TOKEN_TYPE="urn:ietf:params:oauth:token-type:jwt";

View file

@ -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 <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @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<String, String> params);
}

View file

@ -564,19 +564,43 @@ public class TokenEndpoint {
public Response buildTokenExchange() { public Response buildTokenExchange() {
event.detail(Details.AUTH_METHOD, "oauth_credentials"); event.detail(Details.AUTH_METHOD, "oauth_credentials");
String scope = formParams.getFirst(OAuth2Constants.SCOPE);
String subjectToken = formParams.getFirst(OAuth2Constants.SUBJECT_TOKEN); String subjectToken = formParams.getFirst(OAuth2Constants.SUBJECT_TOKEN);
String subjectTokenType = formParams.getFirst(OAuth2Constants.SUBJECT_TOKEN_TYPE); 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); AuthenticationManager.AuthResult authResult = AuthenticationManager.verifyIdentityToken(session, realm, uriInfo, clientConnection, true, true, false, subjectToken, headers);
if (authResult == null) { if (authResult == null) {
event.error(Errors.INVALID_TOKEN); event.error(Errors.INVALID_TOKEN);
throw new ErrorResponseException(OAuthErrorException.INVALID_TOKEN, "Invalid token", Response.Status.BAD_REQUEST); 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); String audience = formParams.getFirst(OAuth2Constants.AUDIENCE);
if (audience == null) { if (audience == null) {
event.error(Errors.INVALID_REQUEST); 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; ClientModel targetClient = null;
@ -594,7 +618,7 @@ public class TokenEndpoint {
} }
boolean exchangeFromAllowed = false; boolean exchangeFromAllowed = false;
for (String aud : authResult.getToken().getAudience()) { for (String aud : subject.getToken().getAudience()) {
ClientModel audClient = realm.getClientByClientId(aud); ClientModel audClient = realm.getClientByClientId(aud);
if (audClient == null) continue; if (audClient == null) continue;
if (audClient.equals(client)) { 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); 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); AuthenticationSessionModel authSession = new AuthenticationSessionManager(session).createAuthenticationSession(realm, targetClient, false);
authSession.setAuthenticatedUser(authResult.getUser()); authSession.setAuthenticatedUser(subject.getUser());
authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL); authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
authSession.setClientNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName())); authSession.setClientNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(uriInfo.getBaseUri(), realm.getName()));
authSession.setClientNote(OIDCLoginProtocol.SCOPE_PARAM, scope); authSession.setClientNote(OIDCLoginProtocol.SCOPE_PARAM, scope);
UserSessionModel userSession = authResult.getSession(); UserSessionModel userSession = subject.getSession();
event.session(userSession); event.session(userSession);
AuthenticationManager.setRolesAndMappersInSession(authSession); AuthenticationManager.setRolesAndMappersInSession(authSession);
@ -637,10 +663,13 @@ public class TokenEndpoint {
updateUserSessionFromClientAuth(userSession); updateUserSessionFromClientAuth(userSession);
TokenManager.AccessTokenResponseBuilder responseBuilder = tokenManager.responseBuilder(realm, targetClient, event, session, userSession, clientSession) TokenManager.AccessTokenResponseBuilder responseBuilder = tokenManager.responseBuilder(realm, targetClient, event, session, userSession, clientSession)
.generateAccessToken() .generateAccessToken();
.generateRefreshToken();
responseBuilder.getAccessToken().issuedFor(client.getClientId()); 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); String scopeParam = clientSession.getNote(OAuth2Constants.SCOPE);
if (TokenUtil.isOIDCRequest(scopeParam)) { if (TokenUtil.isOIDCRequest(scopeParam)) {

View file

@ -185,7 +185,7 @@ class GroupPermissions implements GroupPermissionEvaluator, GroupPermissionManag
authz.getStoreFactory().getPolicyStore().delete(manageMembersPermission.getId()); authz.getStoreFactory().getPolicyStore().delete(manageMembersPermission.getId());
} }
Policy viewMembersPermission = viewMembersPermission(group); Policy viewMembersPermission = viewMembersPermission(group);
if (viewMembersPermission == null) { if (viewMembersPermission != null) {
authz.getStoreFactory().getPolicyStore().delete(viewMembersPermission.getId()); authz.getStoreFactory().getPolicyStore().delete(viewMembersPermission.getId());
} }
Policy manageMembershipPermission = manageMembershipPermission(group); Policy manageMembershipPermission = manageMembershipPermission(group);