-
-
Save abstractj/8d3f1ca74a0dfb4f58f7810c519c6272 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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.testsuite.oauth; | |
import org.junit.Assert; | |
import org.junit.Before; | |
import org.junit.Test; | |
import org.keycloak.OAuth2Constants; | |
import org.keycloak.admin.client.resource.ClientResource; | |
import org.keycloak.admin.client.resource.RealmResource; | |
import org.keycloak.admin.client.resource.UserResource; | |
import org.keycloak.common.enums.SslRequired; | |
import org.keycloak.jose.jws.JWSInput; | |
import org.keycloak.jose.jws.JWSInputException; | |
import org.keycloak.models.UserModel; | |
import org.keycloak.models.utils.KeycloakModelUtils; | |
import org.keycloak.protocol.oidc.OIDCLoginProtocol; | |
import org.keycloak.protocol.oidc.OIDCLoginProtocolService; | |
import org.keycloak.representations.AccessToken; | |
import org.keycloak.representations.IDToken; | |
import org.keycloak.representations.idm.ClientRepresentation; | |
import org.keycloak.representations.idm.ProtocolMapperRepresentation; | |
import org.keycloak.representations.idm.RealmRepresentation; | |
import org.keycloak.representations.idm.UserRepresentation; | |
import org.keycloak.testsuite.AbstractKeycloakTest; | |
import org.keycloak.testsuite.AssertEvents; | |
import org.keycloak.testsuite.admin.ApiUtil; | |
import org.keycloak.util.BasicAuthHelper; | |
import javax.ws.rs.client.Client; | |
import javax.ws.rs.client.ClientBuilder; | |
import javax.ws.rs.client.Entity; | |
import javax.ws.rs.client.WebTarget; | |
import javax.ws.rs.core.Form; | |
import javax.ws.rs.core.HttpHeaders; | |
import javax.ws.rs.core.Response; | |
import javax.ws.rs.core.UriBuilder; | |
import java.net.URI; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import static org.keycloak.protocol.oidc.mappers.RoleNameMapper.NEW_ROLE_NAME; | |
import static org.keycloak.protocol.oidc.mappers.RoleNameMapper.PROVIDER_ID; | |
import static org.keycloak.protocol.oidc.mappers.RoleNameMapper.ROLE_CONFIG; | |
import static org.keycloak.testsuite.util.IOUtil.loadRealm; | |
/** | |
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a> | |
*/ | |
public class AccessTokenTest2 extends AbstractKeycloakTest { | |
AssertEvents events; | |
@Before | |
public void initAssertEvents() throws Exception { | |
events = new AssertEvents(this); | |
} | |
@Override | |
public void addTestRealms(List<RealmRepresentation> testRealms) { | |
RealmRepresentation testRealmRep = loadTestRealm(testRealms); | |
testRealmRep.setEventsEnabled(true); | |
} | |
@Before | |
public void setUp(){ | |
ClientResource clientResource = getClientById("test-app"); | |
ClientRepresentation clientRepresentation = new ClientRepresentation(); | |
clientRepresentation.setDirectAccessGrantsEnabled(true); | |
clientResource.update(clientRepresentation); | |
for (ProtocolMapperRepresentation protocolRep : clientResource.getProtocolMappers().getMappers()) { | |
clientResource.getProtocolMappers().delete(protocolRep.getId()); | |
} | |
UserRepresentation userRepresentation = new UserRepresentation(); | |
userRepresentation.setEnabled(true); | |
userRepresentation.setId(KeycloakModelUtils.generateId()); | |
userRepresentation.setUsername("no-permissions"); | |
ApiUtil.createUserAndResetPasswordWithAdminClient(adminClient.realm("test"), userRepresentation, "password"); | |
} | |
RealmRepresentation loadTestRealm(List<RealmRepresentation> testRealms) { | |
RealmRepresentation result = loadRealm("/testrealm.json"); | |
testRealms.add(result); | |
return result; | |
} | |
@Test | |
public void testKeycloak2221() throws Exception { | |
Client client = ClientBuilder.newClient(); | |
UriBuilder builder = UriBuilder.fromUri(Constants.AUTH_SERVER_ROOT); | |
URI grantUri = OIDCLoginProtocolService.tokenUrl(builder).build("test"); | |
WebTarget grantTarget = client.target(grantUri); | |
ClientResource clientResource; | |
{ | |
clientResource = getClientById("test-app"); | |
clientResource.getProtocolMappers().createMapper(createRoleNameMapper("rename-role", "user", "realm-user")); | |
clientResource.getProtocolMappers().createMapper(createRoleNameMapper("rename-role2", "admin", "the-admin")); | |
} | |
{ | |
Response response = executeGrantRequest(grantTarget, "no-permissions", "password"); | |
Assert.assertEquals(200, response.getStatus()); | |
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class); | |
AccessToken accessToken = getAccessToken(tokenResponse, clientResource.getProtocolMappers().getMappers().get(0)); | |
Assert.assertEquals(accessToken.getRealmAccess().getRoles().size(), 1); | |
Assert.assertTrue(accessToken.getRealmAccess().getRoles().contains("realm-user")); | |
response.close(); | |
} | |
// undo mappers | |
{ | |
ClientResource app = getClientById("test-app"); | |
ClientRepresentation clientRepresentation = app.toRepresentation(); | |
for (ProtocolMapperRepresentation protocolRep : clientRepresentation.getProtocolMappers()) { | |
if (protocolRep.getName().startsWith("rename-role")) { | |
clientResource.getProtocolMappers().delete(protocolRep.getId()); | |
} | |
} | |
} | |
events.clear(); | |
} | |
private IDToken getIdToken(org.keycloak.representations.AccessTokenResponse tokenResponse) throws JWSInputException { | |
JWSInput input = new JWSInput(tokenResponse.getIdToken()); | |
return input.readJsonContent(IDToken.class); | |
} | |
private AccessToken getAccessToken(org.keycloak.representations.AccessTokenResponse tokenResponse) throws JWSInputException { | |
JWSInput input = new JWSInput(tokenResponse.getToken()); | |
return input.readJsonContent(AccessToken.class); | |
} | |
//@TODO new method | |
private AccessToken getAccessToken(org.keycloak.representations.AccessTokenResponse tokenResponse, | |
ProtocolMapperRepresentation protocolRep) throws JWSInputException { | |
AccessToken accessToken = getAccessToken(tokenResponse); | |
return transformAccessToken(accessToken, protocolRep); | |
} | |
protected Response executeGrantAccessTokenRequest(WebTarget grantTarget) { | |
String username = "test-user@localhost"; | |
String password = "password"; | |
return executeGrantRequest(grantTarget, username, password); | |
} | |
protected Response executeGrantRequest(WebTarget grantTarget, String username, String password) { | |
String header = BasicAuthHelper.createHeader("test-app", "password"); | |
Form form = new Form(); | |
form.param(OAuth2Constants.GRANT_TYPE, OAuth2Constants.PASSWORD) | |
.param("username", username) | |
.param("password", password); | |
return grantTarget.request() | |
.header(HttpHeaders.AUTHORIZATION, header) | |
.post(Entity.form(form)); | |
} | |
public ClientResource getClientById(String clientId) { | |
String appId = adminClient.realm("test").clients().findByClientId(clientId).get(0).getId(); | |
return adminClient.realm("test").clients().get(appId); | |
} | |
public UserResource getUserByUsername(String username) { | |
String userId = adminClient.realm("test").users().search(username, null, null, null, 0, 1).get(0).getId(); | |
return adminClient.realm("test").users().get(userId); | |
} | |
public static ProtocolMapperRepresentation createRoleNameMapper(String name, | |
String role, | |
String newName) { | |
String mapperId = PROVIDER_ID; | |
ProtocolMapperRepresentation mapper = new ProtocolMapperRepresentation(); | |
mapper.setName(name); | |
mapper.setProtocolMapper(mapperId); | |
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL); | |
Map<String, String> config = new HashMap<String, String>(); | |
config.put(ROLE_CONFIG, role); | |
config.put(NEW_ROLE_NAME, newName); | |
mapper.setConfig(config); | |
return mapper; | |
} | |
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperRepresentation mapperRepresentation) { | |
String role = mapperRepresentation.getConfig().get(ROLE_CONFIG); | |
String newName = mapperRepresentation.getConfig().get(NEW_ROLE_NAME); | |
String[] scopedRole = KeycloakModelUtils.parseRole(role); | |
String[] newScopedRole = KeycloakModelUtils.parseRole(newName); | |
String appName = scopedRole[0]; | |
String roleName = scopedRole[1]; | |
if (appName != null) { | |
AccessToken.Access access = token.getResourceAccess(appName); | |
if (access == null) return token; | |
if (!access.getRoles().contains(roleName)) return token; | |
access.getRoles().remove(roleName); | |
} else { | |
AccessToken.Access access = token.getRealmAccess(); | |
if (access == null || !access.getRoles().contains(roleName)) return token; | |
access.getRoles().remove(roleName); | |
} | |
String newAppName = newScopedRole[0]; | |
String newRoleName = newScopedRole[1]; | |
AccessToken.Access access = null; | |
if (newAppName == null) { | |
access = token.getRealmAccess(); | |
if (access == null) { | |
access = new AccessToken.Access(); | |
token.setRealmAccess(access); | |
} | |
} else { | |
access = token.addAccess(newAppName); | |
} | |
access.addRole(newRoleName); | |
return token; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment