Merge pull request #1032 from patriot1burke/master
mapper fixes and tests
This commit is contained in:
commit
bf27c22dd5
25 changed files with 585 additions and 230 deletions
|
@ -9,7 +9,7 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.protocol.AbstractLoginProtocolFactory;
|
||||
import org.keycloak.protocol.LoginProtocol;
|
||||
import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
|
||||
import org.keycloak.protocol.saml.mappers.SAMLBasicRoleListMapper;
|
||||
import org.keycloak.protocol.saml.mappers.RoleListMapper;
|
||||
import org.keycloak.protocol.saml.mappers.UserPropertyAttributeStatementMapper;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
import org.picketlink.common.constants.JBossSAMLURIConstants;
|
||||
|
@ -77,7 +77,7 @@ public class SamlProtocolFactory extends AbstractLoginProtocolFactory {
|
|||
X500SAMLProfileConstants.SURNAME.getFriendlyName(),
|
||||
true, "family name");
|
||||
builtins.add(model);
|
||||
model = SAMLBasicRoleListMapper.create("role list", "Role", AttributeStatementHelper.BASIC, null, false);
|
||||
model = RoleListMapper.create("role list", "Role", AttributeStatementHelper.BASIC, null, false);
|
||||
builtins.add(model);
|
||||
defaultBuiltins.add(model);
|
||||
|
||||
|
|
|
@ -73,14 +73,14 @@ public class AttributeStatementHelper {
|
|||
|
||||
}
|
||||
public static ProtocolMapperModel createAttributeMapper(String name, String userAttribute, String samlAttributeName, String nameFormat, String friendlyName, boolean consentRequired, String consentText, String mapperId) {
|
||||
ProtocolMapperModel mapper = mapper = new ProtocolMapperModel();
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(mapperId);
|
||||
mapper.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
|
||||
mapper.setConsentRequired(consentRequired);
|
||||
mapper.setConsentText(consentText);
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
config.put(ProtocolMapperUtils.USER_ATTRIBUTE, userAttribute);
|
||||
if (userAttribute != null) config.put(ProtocolMapperUtils.USER_ATTRIBUTE, userAttribute);
|
||||
config.put(SAML_ATTRIBUTE_NAME, samlAttributeName);
|
||||
if (friendlyName != null) {
|
||||
config.put(FRIENDLY_NAME, friendlyName);
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
package org.keycloak.protocol.saml.mappers;
|
||||
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||
import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Mappings UserModel property (the property name of a getter method) to an AttributeStatement.
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class HardcodedAttributeMapper extends AbstractSAMLProtocolMapper implements SAMLAttributeStatementMapper {
|
||||
public static final String PROVIDER_ID = "saml-hardcode-attribute-mapper";
|
||||
public static final String ATTRIBUTE_VALUE = "attribute.value";
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
|
||||
static {
|
||||
ConfigProperty property;
|
||||
property = new ConfigProperty();
|
||||
property.setName(ProtocolMapperUtils.USER_ATTRIBUTE);
|
||||
property.setLabel(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_LABEL);
|
||||
property.setHelpText(ProtocolMapperUtils.USER_MODEL_ATTRIBUTE_HELP_TEXT);
|
||||
configProperties.add(property);
|
||||
AttributeStatementHelper.setConfigProperties(configProperties);
|
||||
property = new ConfigProperty();
|
||||
property.setName(ATTRIBUTE_VALUE);
|
||||
property.setLabel("Attribute value");
|
||||
property.setType(ConfigProperty.STRING_TYPE);
|
||||
property.setHelpText("Value of the attribute you want to hard code.");
|
||||
configProperties.add(property);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<ConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Hardcoded attribute";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayCategory() {
|
||||
return AttributeStatementHelper.ATTRIBUTE_STATEMENT_CATEGORY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Hardcode an attribute into the SAML Assertion.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transformAttributeStatement(AttributeStatementType attributeStatement, ProtocolMapperModel mappingModel, KeycloakSession session, UserSessionModel userSession, ClientSessionModel clientSession) {
|
||||
String attributeValue = mappingModel.getConfig().get(ATTRIBUTE_VALUE);
|
||||
AttributeStatementHelper.addAttribute(attributeStatement, mappingModel, attributeValue);
|
||||
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel create(String name,
|
||||
String samlAttributeName, String nameFormat, String friendlyName, String value,
|
||||
boolean consentRequired, String consentText) {
|
||||
String mapperId = PROVIDER_ID;
|
||||
ProtocolMapperModel model = AttributeStatementHelper.createAttributeMapper(name, null, samlAttributeName, nameFormat, friendlyName,
|
||||
consentRequired, consentText, mapperId);
|
||||
model.getConfig().put(ATTRIBUTE_VALUE, value);
|
||||
return model;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package org.keycloak.protocol.saml.mappers;
|
||||
|
||||
import org.keycloak.models.ClientSessionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||
import org.keycloak.protocol.saml.SamlProtocol;
|
||||
import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Mappings UserModel property (the property name of a getter method) to an AttributeStatement.
|
||||
*
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class HardcodedRole extends AbstractSAMLProtocolMapper {
|
||||
public static final String PROVIDER_ID = "saml-hardcode-role-mapper";
|
||||
public static final String ATTRIBUTE_VALUE = "attribute.value";
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
|
||||
static {
|
||||
ConfigProperty property;
|
||||
property = new ConfigProperty();
|
||||
property.setName("role");
|
||||
property.setLabel("Role");
|
||||
property.setHelpText("Role name you want to hardcode.");
|
||||
property.setType(ConfigProperty.STRING_TYPE);
|
||||
configProperties.add(property);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public List<ConfigProperty> getConfigProperties() {
|
||||
return configProperties;
|
||||
}
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Hardcoded role";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayCategory() {
|
||||
return AttributeStatementHelper.ATTRIBUTE_STATEMENT_CATEGORY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Hardcode role into SAML Assertion.";
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel create(String name,
|
||||
String role) {
|
||||
String mapperId = PROVIDER_ID;
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(mapperId);
|
||||
mapper.setProtocol(SamlProtocol.LOGIN_PROTOCOL);
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
config.put("role", role);
|
||||
mapper.setConfig(config);
|
||||
return mapper;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -14,6 +14,7 @@ import org.picketlink.identity.federation.saml.v2.assertion.AttributeType;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -21,7 +22,7 @@ import java.util.Map;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SAMLBasicRoleListMapper extends AbstractSAMLProtocolMapper implements SAMLRoleListMapper {
|
||||
public class RoleListMapper extends AbstractSAMLProtocolMapper implements SAMLRoleListMapper {
|
||||
public static final String PROVIDER_ID = "saml-role-list-mapper";
|
||||
public static final String SINGLE_ROLE_ATTRIBUTE = "single";
|
||||
|
||||
|
@ -92,17 +93,33 @@ public class SAMLBasicRoleListMapper extends AbstractSAMLProtocolMapper implemen
|
|||
String single = mappingModel.getConfig().get(SINGLE_ROLE_ATTRIBUTE);
|
||||
boolean singleAttribute = Boolean.parseBoolean(single);
|
||||
|
||||
Map<ProtocolMapperModel, SAMLRoleNameMapper> roleNameMappers = new HashMap<>();
|
||||
List<SamlProtocol.ProtocolMapperProcessor<SAMLRoleNameMapper>> roleNameMappers = new LinkedList<>();
|
||||
KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
|
||||
AttributeType singleAttributeType = null;
|
||||
for (ProtocolMapperModel mapping : clientSession.getClient().getProtocolMappers()) {
|
||||
if (!mapping.getProtocol().equals(SamlProtocol.LOGIN_PROTOCOL)) continue;
|
||||
|
||||
ProtocolMapper mapper = (ProtocolMapper)sessionFactory.getProviderFactory(ProtocolMapper.class, mapping.getProtocolMapper());
|
||||
if (mapper == null || !(mapper instanceof SAMLRoleNameMapper)) continue;
|
||||
roleNameMappers.put(mapping, (SAMLRoleNameMapper)mapper);
|
||||
if (mapper == null) continue;
|
||||
if (mapper instanceof SAMLRoleNameMapper) {
|
||||
roleNameMappers.add(new SamlProtocol.ProtocolMapperProcessor<>((SAMLRoleNameMapper) mapper,mapping));
|
||||
}
|
||||
if (mapper instanceof HardcodedRole) {
|
||||
AttributeType attributeType = null;
|
||||
if (singleAttribute) {
|
||||
if (singleAttributeType == null) {
|
||||
singleAttributeType = AttributeStatementHelper.createAttributeType(mappingModel);
|
||||
roleAttributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(singleAttributeType));
|
||||
}
|
||||
attributeType = singleAttributeType;
|
||||
} else {
|
||||
attributeType = AttributeStatementHelper.createAttributeType(mappingModel);
|
||||
roleAttributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attributeType));
|
||||
}
|
||||
attributeType.addAttributeValue(mapping.getConfig().get("role"));
|
||||
}
|
||||
}
|
||||
|
||||
AttributeType singleAttributeType = null;
|
||||
for (String roleId : clientSession.getRoles()) {
|
||||
// todo need a role mapping
|
||||
RoleModel roleModel = clientSession.getRealm().getRoleById(roleId);
|
||||
|
@ -118,8 +135,8 @@ public class SAMLBasicRoleListMapper extends AbstractSAMLProtocolMapper implemen
|
|||
roleAttributeStatement.addAttribute(new AttributeStatementType.ASTChoiceType(attributeType));
|
||||
}
|
||||
String roleName = roleModel.getName();
|
||||
for (Map.Entry<ProtocolMapperModel, SAMLRoleNameMapper> entry : roleNameMappers.entrySet()) {
|
||||
String newName = entry.getValue().mapName(entry.getKey(), roleModel);
|
||||
for (SamlProtocol.ProtocolMapperProcessor<SAMLRoleNameMapper> entry : roleNameMappers) {
|
||||
String newName = entry.mapper.mapName(entry.model, roleModel);
|
||||
if (newName != null) {
|
||||
roleName = newName;
|
||||
break;
|
|
@ -5,9 +5,12 @@ import org.keycloak.models.ProtocolMapperModel;
|
|||
import org.keycloak.models.RoleContainerModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper;
|
||||
import org.keycloak.protocol.saml.SamlProtocol;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Map an assigned role to a different position and name in the token
|
||||
|
@ -15,7 +18,7 @@ import java.util.List;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SAMLBasicRoleNameMapper extends AbstractOIDCProtocolMapper implements SAMLRoleNameMapper {
|
||||
public class RoleNameMapper extends AbstractOIDCProtocolMapper implements SAMLRoleNameMapper {
|
||||
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
|
||||
|
@ -88,4 +91,21 @@ public class SAMLBasicRoleNameMapper extends AbstractOIDCProtocolMapper implemen
|
|||
if (roleModel.getName().equals(role)) return newName;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel create(String name,
|
||||
String role,
|
||||
String newName) {
|
||||
String mapperId = PROVIDER_ID;
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(mapperId);
|
||||
mapper.setProtocol(SamlProtocol.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;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
org.keycloak.protocol.saml.mappers.SAMLBasicRoleListMapper
|
||||
org.keycloak.protocol.saml.mappers.SAMLBasicRoleNameMapper
|
||||
org.keycloak.protocol.saml.mappers.RoleListMapper
|
||||
org.keycloak.protocol.saml.mappers.RoleNameMapper
|
||||
org.keycloak.protocol.saml.mappers.HardcodedRole
|
||||
org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper
|
||||
org.keycloak.protocol.saml.mappers.UserAttributeStatementMapper
|
||||
org.keycloak.protocol.saml.mappers.UserPropertyAttributeStatementMapper
|
||||
|
||||
|
|
|
@ -8,11 +8,11 @@ import org.keycloak.models.ProtocolMapperModel;
|
|||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.protocol.AbstractLoginProtocolFactory;
|
||||
import org.keycloak.protocol.LoginProtocol;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCAddressMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.AddressMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.FullNameMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCFullNameMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCUserModelMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCUserSessionNoteMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.UserPropertyMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
|
||||
import org.keycloak.services.managers.AuthenticationManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -41,35 +41,35 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
|
|||
static {
|
||||
|
||||
ProtocolMapperModel model;
|
||||
model = OIDCUserModelMapper.createClaimMapper("username",
|
||||
model = UserPropertyMapper.createClaimMapper("username",
|
||||
"username",
|
||||
"preferred_username", "String",
|
||||
true, "username",
|
||||
true, true);
|
||||
builtins.add(model);
|
||||
defaultBuiltins.add(model);
|
||||
model = OIDCUserModelMapper.createClaimMapper("email",
|
||||
model = UserPropertyMapper.createClaimMapper("email",
|
||||
"email",
|
||||
"email", "String",
|
||||
true, "email",
|
||||
true, true);
|
||||
builtins.add(model);
|
||||
defaultBuiltins.add(model);
|
||||
model = OIDCUserModelMapper.createClaimMapper("given name",
|
||||
model = UserPropertyMapper.createClaimMapper("given name",
|
||||
"firstName",
|
||||
"given_name", "String",
|
||||
true, "given name",
|
||||
true, true);
|
||||
builtins.add(model);
|
||||
defaultBuiltins.add(model);
|
||||
model = OIDCUserModelMapper.createClaimMapper("family name",
|
||||
model = UserPropertyMapper.createClaimMapper("family name",
|
||||
"lastName",
|
||||
"family_name", "String",
|
||||
true, "family name",
|
||||
true, true);
|
||||
builtins.add(model);
|
||||
defaultBuiltins.add(model);
|
||||
model = OIDCUserModelMapper.createClaimMapper("email verified",
|
||||
model = UserPropertyMapper.createClaimMapper("email verified",
|
||||
"emailVerified",
|
||||
"email_verified", "boolean",
|
||||
false, null,
|
||||
|
@ -78,7 +78,7 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
|
|||
|
||||
ProtocolMapperModel fullName = new ProtocolMapperModel();
|
||||
fullName.setName("full name");
|
||||
fullName.setProtocolMapper(OIDCFullNameMapper.PROVIDER_ID);
|
||||
fullName.setProtocolMapper(FullNameMapper.PROVIDER_ID);
|
||||
fullName.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
fullName.setConsentRequired(true);
|
||||
fullName.setConsentText("full name");
|
||||
|
@ -89,10 +89,10 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
|
|||
builtins.add(fullName);
|
||||
defaultBuiltins.add(fullName);
|
||||
|
||||
ProtocolMapperModel address = OIDCAddressMapper.createAddressMapper();
|
||||
ProtocolMapperModel address = AddressMapper.createAddressMapper();
|
||||
builtins.add(address);
|
||||
|
||||
model = OIDCUserSessionNoteMapper.createClaimMapper(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
|
||||
model = UserSessionNoteMapper.createClaimMapper(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
|
||||
KerberosConstants.GSS_DELEGATION_CREDENTIAL,
|
||||
KerberosConstants.GSS_DELEGATION_CREDENTIAL, "String",
|
||||
true, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.OAuthClientModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.RequiredCredentialModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.UserSessionProvider;
|
||||
|
@ -372,85 +373,22 @@ public class OIDCLoginProtocolService {
|
|||
Map<String, String> err = new HashMap<String, String>();
|
||||
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_GRANT);
|
||||
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Token invalid");
|
||||
logger.error("Invalid token. Token verification failed.");
|
||||
event.error(Errors.INVALID_TOKEN);
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
|
||||
.build();
|
||||
}
|
||||
event.user(token.getSubject()).session(token.getSessionState()).detail(Details.VALIDATE_ACCESS_TOKEN, token.getId());
|
||||
|
||||
if (token.isExpired()
|
||||
|| token.getIssuedAt() < realm.getNotBefore()
|
||||
) {
|
||||
Map<String, String> err = new HashMap<String, String>();
|
||||
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_GRANT);
|
||||
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Token expired");
|
||||
event.error(Errors.INVALID_TOKEN);
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
UserModel user = session.users().getUserById(token.getSubject(), realm);
|
||||
if (user == null) {
|
||||
Map<String, String> err = new HashMap<String, String>();
|
||||
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_GRANT);
|
||||
err.put(OAuth2Constants.ERROR_DESCRIPTION, "User does not exist");
|
||||
event.error(Errors.USER_NOT_FOUND);
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
|
||||
.build();
|
||||
}
|
||||
|
||||
if (!user.isEnabled()) {
|
||||
Map<String, String> err = new HashMap<String, String>();
|
||||
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_GRANT);
|
||||
err.put(OAuth2Constants.ERROR_DESCRIPTION, "User disabled");
|
||||
event.error(Errors.USER_DISABLED);
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
|
||||
.build();
|
||||
}
|
||||
|
||||
UserSessionModel userSession = session.sessions().getUserSession(realm, token.getSessionState());
|
||||
if (!AuthenticationManager.isSessionValid(realm, userSession)) {
|
||||
Map<String, String> err = new HashMap<String, String>();
|
||||
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_GRANT);
|
||||
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Expired session");
|
||||
event.error(Errors.USER_SESSION_NOT_FOUND);
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
|
||||
.build();
|
||||
}
|
||||
|
||||
ClientModel client = realm.findClient(token.getIssuedFor());
|
||||
if (client == null) {
|
||||
Map<String, String> err = new HashMap<String, String>();
|
||||
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_CLIENT);
|
||||
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Issued for client no longer exists");
|
||||
event.error(Errors.CLIENT_NOT_FOUND);
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
|
||||
.build();
|
||||
|
||||
}
|
||||
|
||||
if (token.getIssuedAt() < client.getNotBefore()) {
|
||||
Map<String, String> err = new HashMap<String, String>();
|
||||
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_CLIENT);
|
||||
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Issued for client no longer exists");
|
||||
event.error(Errors.INVALID_TOKEN);
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
|
||||
.build();
|
||||
}
|
||||
|
||||
try {
|
||||
tokenManager.verifyAccess(token, realm, client, user);
|
||||
tokenManager.validateToken(session, uriInfo, clientConnection, realm, token);
|
||||
} catch (OAuthErrorException e) {
|
||||
Map<String, String> err = new HashMap<String, String>();
|
||||
err.put(OAuth2Constants.ERROR, OAuthErrorException.INVALID_SCOPE);
|
||||
err.put(OAuth2Constants.ERROR_DESCRIPTION, "Role mappings have changed");
|
||||
Map<String, String> error = new HashMap<String, String>();
|
||||
error.put(OAuth2Constants.ERROR, e.getError());
|
||||
if (e.getDescription() != null) error.put(OAuth2Constants.ERROR_DESCRIPTION, e.getDescription());
|
||||
event.error(Errors.INVALID_TOKEN);
|
||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(err)
|
||||
.build();
|
||||
|
||||
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
|
||||
}
|
||||
|
||||
event.success();
|
||||
|
||||
return Response.ok(token, MediaType.APPLICATION_JSON_TYPE).build();
|
||||
|
@ -666,16 +604,6 @@ public class OIDCLoginProtocolService {
|
|||
|
||||
AccessToken token = tokenManager.createClientAccessToken(session, accessCode.getRequestedRoles(), realm, client, user, userSession, clientSession);
|
||||
|
||||
try {
|
||||
tokenManager.verifyAccess(token, realm, client, user);
|
||||
} catch (OAuthErrorException e) {
|
||||
Map<String, String> error = new HashMap<String, String>();
|
||||
error.put(OAuth2Constants.ERROR, e.getError());
|
||||
if (e.getDescription() != null) error.put(OAuth2Constants.ERROR_DESCRIPTION, e.getDescription());
|
||||
event.error(Errors.INVALID_CODE);
|
||||
return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
|
||||
}
|
||||
|
||||
AccessTokenResponse res = tokenManager.responseBuilder(realm, client, event, session, userSession, clientSession)
|
||||
.accessToken(token)
|
||||
.generateIDToken()
|
||||
|
|
|
@ -59,12 +59,22 @@ public class TokenManager {
|
|||
}
|
||||
}
|
||||
|
||||
public AccessTokenResponse refreshAccessToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, ClientModel client, String encodedRefreshToken, EventBuilder event) throws OAuthErrorException {
|
||||
RefreshToken refreshToken = verifyRefreshToken(realm, encodedRefreshToken);
|
||||
public static class TokenValidation {
|
||||
public final UserModel user;
|
||||
public final UserSessionModel userSession;
|
||||
public final ClientSessionModel clientSession;
|
||||
public final AccessToken newToken;
|
||||
|
||||
event.user(refreshToken.getSubject()).session(refreshToken.getSessionState()).detail(Details.REFRESH_TOKEN_ID, refreshToken.getId());
|
||||
public TokenValidation(UserModel user, UserSessionModel userSession, ClientSessionModel clientSession, AccessToken newToken) {
|
||||
this.user = user;
|
||||
this.userSession = userSession;
|
||||
this.clientSession = clientSession;
|
||||
this.newToken = newToken;
|
||||
}
|
||||
}
|
||||
|
||||
UserModel user = session.users().getUserById(refreshToken.getSubject(), realm);
|
||||
public TokenValidation validateToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, AccessToken oldToken) throws OAuthErrorException {
|
||||
UserModel user = session.users().getUserById(oldToken.getSubject(), realm);
|
||||
if (user == null) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", "Unknown user");
|
||||
}
|
||||
|
@ -73,24 +83,14 @@ public class TokenManager {
|
|||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "User disabled", "User disabled");
|
||||
}
|
||||
|
||||
UserSessionModel userSession = session.sessions().getUserSession(realm, refreshToken.getSessionState());
|
||||
int currentTime = Time.currentTime();
|
||||
UserSessionModel userSession = session.sessions().getUserSession(realm, oldToken.getSessionState());
|
||||
if (!AuthenticationManager.isSessionValid(realm, userSession)) {
|
||||
AuthenticationManager.logout(session, realm, userSession, uriInfo, connection);
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Session not active", "Session not active");
|
||||
}
|
||||
|
||||
if (!client.getClientId().equals(refreshToken.getIssuedFor())) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Unmatching clients", "Unmatching clients");
|
||||
}
|
||||
|
||||
if (refreshToken.getIssuedAt() < client.getNotBefore()) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale refresh token");
|
||||
}
|
||||
|
||||
ClientSessionModel clientSession = null;
|
||||
for (ClientSessionModel clientSessionModel : userSession.getClientSessions()) {
|
||||
if (clientSessionModel.getId().equals(refreshToken.getClientSession())) {
|
||||
if (clientSessionModel.getId().equals(oldToken.getClientSession())) {
|
||||
clientSession = clientSessionModel;
|
||||
break;
|
||||
}
|
||||
|
@ -98,20 +98,48 @@ public class TokenManager {
|
|||
|
||||
if (clientSession == null) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Client session not active", "Client session not active");
|
||||
}
|
||||
|
||||
ClientModel client = clientSession.getClient();
|
||||
|
||||
if (!client.getClientId().equals(oldToken.getIssuedFor())) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Unmatching clients", "Unmatching clients");
|
||||
}
|
||||
|
||||
if (oldToken.getIssuedAt() < client.getNotBefore()) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale token");
|
||||
}
|
||||
if (oldToken.getIssuedAt() < realm.getNotBefore()) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Stale token");
|
||||
}
|
||||
|
||||
|
||||
// recreate token.
|
||||
Set<RoleModel> requestedRoles = TokenManager.getAccess(null, clientSession.getClient(), user);
|
||||
AccessToken newToken = createClientAccessToken(session, requestedRoles, realm, client, user, userSession, clientSession);
|
||||
verifyAccess(oldToken, newToken);
|
||||
|
||||
return new TokenValidation(user, userSession, clientSession, newToken);
|
||||
|
||||
|
||||
}
|
||||
|
||||
verifyAccess(refreshToken, realm, client, user);
|
||||
public AccessTokenResponse refreshAccessToken(KeycloakSession session, UriInfo uriInfo, ClientConnection connection, RealmModel realm, ClientModel authorizedClient, String encodedRefreshToken, EventBuilder event) throws OAuthErrorException {
|
||||
RefreshToken refreshToken = verifyRefreshToken(realm, encodedRefreshToken);
|
||||
|
||||
AccessToken accessToken = initToken(realm, client, user, userSession, clientSession);
|
||||
accessToken.setRealmAccess(refreshToken.getRealmAccess());
|
||||
accessToken.setResourceAccess(refreshToken.getResourceAccess());
|
||||
accessToken = transformAccessToken(session, accessToken, realm, client, user, userSession, clientSession);
|
||||
event.user(refreshToken.getSubject()).session(refreshToken.getSessionState()).detail(Details.REFRESH_TOKEN_ID, refreshToken.getId());
|
||||
|
||||
userSession.setLastSessionRefresh(currentTime);
|
||||
TokenValidation validation = validateToken(session, uriInfo, connection, realm, refreshToken);
|
||||
// validate authorizedClient is same as validated client
|
||||
if (!validation.clientSession.getClient().getId().equals(authorizedClient.getId())) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token. Token client and authorized client don't match");
|
||||
}
|
||||
|
||||
AccessTokenResponse res = responseBuilder(realm, client, event, session, userSession, clientSession)
|
||||
.accessToken(accessToken)
|
||||
int currentTime = Time.currentTime();
|
||||
validation.userSession.setLastSessionRefresh(currentTime);
|
||||
|
||||
AccessTokenResponse res = responseBuilder(realm, authorizedClient, event, session, validation.userSession, validation.clientSession)
|
||||
.accessToken(validation.newToken)
|
||||
.generateIDToken()
|
||||
.generateRefreshToken().build();
|
||||
return res;
|
||||
|
@ -198,41 +226,27 @@ public class TokenManager {
|
|||
return requestedRoles;
|
||||
}
|
||||
|
||||
public void verifyAccess(AccessToken token, RealmModel realm, ClientModel client, UserModel user) throws OAuthErrorException {
|
||||
ApplicationModel clientApp = (client instanceof ApplicationModel) ? (ApplicationModel)client : null;
|
||||
|
||||
|
||||
public void verifyAccess(AccessToken token, AccessToken newToken) throws OAuthErrorException {
|
||||
if (token.getRealmAccess() != null) {
|
||||
if (newToken.getRealmAccess() == null) throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "User no long has permission for realm roles");
|
||||
|
||||
for (String roleName : token.getRealmAccess().getRoles()) {
|
||||
RoleModel role = realm.getRole(roleName);
|
||||
if (role == null) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid realm role " + roleName);
|
||||
}
|
||||
if (!user.hasRole(role)) {
|
||||
if (!newToken.getRealmAccess().getRoles().contains(roleName)) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "User no long has permission for realm role: " + roleName);
|
||||
}
|
||||
if (!client.hasScope(role)) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Client no longer has realm scope: " + roleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (token.getResourceAccess() != null) {
|
||||
for (Map.Entry<String, AccessToken.Access> entry : token.getResourceAccess().entrySet()) {
|
||||
ApplicationModel app = realm.getApplicationByName(entry.getKey());
|
||||
if (app == null) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Application no longer exists", "Application no longer exists: " + entry.getKey());
|
||||
AccessToken.Access appAccess = newToken.getResourceAccess(entry.getKey());
|
||||
if (appAccess == null && !entry.getValue().getRoles().isEmpty()) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "User or application no longer has role permissions for application key: " + entry.getKey());
|
||||
|
||||
}
|
||||
for (String roleName : entry.getValue().getRoles()) {
|
||||
RoleModel role = app.getRole(roleName);
|
||||
if (role == null) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_GRANT, "Invalid refresh token", "Unknown application role: " + roleName);
|
||||
}
|
||||
if (!user.hasRole(role)) {
|
||||
if (!appAccess.getRoles().contains(roleName)) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "User no long has permission for application role " + roleName);
|
||||
}
|
||||
if (clientApp != null && !clientApp.equals(app) && !client.hasScope(role)) {
|
||||
throw new OAuthErrorException(OAuthErrorException.INVALID_SCOPE, "Client no longer has application scope" + roleName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import java.util.Map;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCAddressMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
public class AddressMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
|
|
@ -5,11 +5,15 @@ import org.keycloak.models.KeycloakSession;
|
|||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.IDToken;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Set the 'name' claim to be first + last name.
|
||||
|
@ -17,7 +21,7 @@ import java.util.List;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCFullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
public class FullNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
|
||||
|
@ -88,4 +92,21 @@ public class OIDCFullNameMapper extends AbstractOIDCProtocolMapper implements OI
|
|||
setClaim(token, userSession);
|
||||
return token;
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel create(String name,
|
||||
boolean consentRequired, String consentText,
|
||||
boolean accessToken, boolean idToken) {
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(PROVIDER_ID);
|
||||
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
mapper.setConsentRequired(consentRequired);
|
||||
mapper.setConsentText(consentText);
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
if (accessToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||
if (idToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
|
||||
mapper.setConfig(config);
|
||||
return mapper;
|
||||
}
|
||||
|
||||
}
|
|
@ -6,11 +6,14 @@ import org.keycloak.models.ProtocolMapperModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.IDToken;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -18,7 +21,7 @@ import java.util.List;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCAddClaimMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
public class HardcodedClaim extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
|
||||
|
@ -62,7 +65,7 @@ public class OIDCAddClaimMapper extends AbstractOIDCProtocolMapper implements OI
|
|||
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-add-claim-mapper";
|
||||
public static final String PROVIDER_ID = "oidc-hardcoded-claim-mapper";
|
||||
|
||||
|
||||
public List<ConfigProperty> getConfigProperties() {
|
||||
|
@ -111,16 +114,25 @@ public class OIDCAddClaimMapper extends AbstractOIDCProtocolMapper implements OI
|
|||
return token;
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel createClaimMapper(String name,
|
||||
String userAttribute,
|
||||
String tokenClaimName, String claimType,
|
||||
public static ProtocolMapperModel create(String name,
|
||||
String hardcodedName,
|
||||
String hardcodedValue, String claimType,
|
||||
boolean consentRequired, String consentText,
|
||||
boolean accessToken, boolean idToken) {
|
||||
return OIDCAttributeMapperHelper.createClaimMapper(name, userAttribute,
|
||||
tokenClaimName, claimType,
|
||||
consentRequired, consentText,
|
||||
accessToken, idToken,
|
||||
PROVIDER_ID);
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(PROVIDER_ID);
|
||||
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
mapper.setConsentRequired(consentRequired);
|
||||
mapper.setConsentText(consentText);
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
config.put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, hardcodedName);
|
||||
config.put(CLAIM_VALUE, hardcodedValue);
|
||||
config.put(OIDCAttributeMapperHelper.JSON_TYPE, claimType);
|
||||
if (accessToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||
if (idToken) config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
|
||||
mapper.setConfig(config);
|
||||
return mapper;
|
||||
}
|
||||
|
||||
|
|
@ -4,10 +4,13 @@ import org.keycloak.models.ClientSessionModel;
|
|||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Add a role to a token
|
||||
|
@ -15,7 +18,7 @@ import java.util.List;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCAddRoleMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
||||
public class HardcodedRole extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
||||
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
|
||||
|
@ -31,7 +34,7 @@ public class OIDCAddRoleMapper extends AbstractOIDCProtocolMapper implements OID
|
|||
configProperties.add(property);
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-role-mapper";
|
||||
public static final String PROVIDER_ID = "oidc-hardcoded-role-mapper";
|
||||
|
||||
|
||||
public List<ConfigProperty> getConfigProperties() {
|
||||
|
@ -78,4 +81,19 @@ public class OIDCAddRoleMapper extends AbstractOIDCProtocolMapper implements OID
|
|||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel create(String name,
|
||||
String role) {
|
||||
String mapperId = PROVIDER_ID;
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
mapper.setName(name);
|
||||
mapper.setProtocolMapper(mapperId);
|
||||
mapper.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||
Map<String, String> config = new HashMap<String, String>();
|
||||
config.put(ROLE_CONFIG, role);
|
||||
mapper.setConfig(config);
|
||||
return mapper;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -6,11 +6,14 @@ import org.keycloak.models.ProtocolMapperModel;
|
|||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.IDToken;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Map an assigned role to a different position and name in the token
|
||||
|
@ -18,7 +21,7 @@ import java.util.List;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCRoleMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
||||
public class RoleNameMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper {
|
||||
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
|
||||
|
@ -41,7 +44,7 @@ public class OIDCRoleMapper extends AbstractOIDCProtocolMapper implements OIDCAc
|
|||
configProperties.add(property);
|
||||
}
|
||||
|
||||
public static final String PROVIDER_ID = "oidc-role-mapper";
|
||||
public static final String PROVIDER_ID = "oidc-role-name-mapper";
|
||||
|
||||
|
||||
public List<ConfigProperty> getConfigProperties() {
|
||||
|
@ -98,4 +101,21 @@ public class OIDCRoleMapper extends AbstractOIDCProtocolMapper implements OIDCAc
|
|||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
public static ProtocolMapperModel create(String name,
|
||||
String role,
|
||||
String newName) {
|
||||
String mapperId = PROVIDER_ID;
|
||||
ProtocolMapperModel mapper = new ProtocolMapperModel();
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -21,7 +21,7 @@ import java.util.List;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCUserAttributeMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
public class UserAttributeMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
|
|
@ -21,7 +21,7 @@ import java.util.List;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OIDCUserModelMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
public class UserPropertyMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
|
||||
static {
|
|
@ -19,7 +19,7 @@ import org.keycloak.representations.IDToken;
|
|||
*
|
||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||
*/
|
||||
public class OIDCUserSessionNoteMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
public class UserSessionNoteMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper {
|
||||
|
||||
private static final List<ConfigProperty> configProperties = new ArrayList<ConfigProperty>();
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
org.keycloak.protocol.oidc.mappers.OIDCUserAttributeMapper
|
||||
org.keycloak.protocol.oidc.mappers.OIDCFullNameMapper
|
||||
org.keycloak.protocol.oidc.mappers.OIDCUserModelMapper
|
||||
org.keycloak.protocol.oidc.mappers.OIDCAddressMapper
|
||||
org.keycloak.protocol.oidc.mappers.OIDCAddClaimMapper
|
||||
org.keycloak.protocol.oidc.mappers.OIDCAddRoleMapper
|
||||
org.keycloak.protocol.oidc.mappers.OIDCRoleMapper
|
||||
org.keycloak.protocol.oidc.mappers.OIDCUserSessionNoteMapper
|
||||
org.keycloak.protocol.oidc.mappers.UserAttributeMapper
|
||||
org.keycloak.protocol.oidc.mappers.FullNameMapper
|
||||
org.keycloak.protocol.oidc.mappers.UserPropertyMapper
|
||||
org.keycloak.protocol.oidc.mappers.AddressMapper
|
||||
org.keycloak.protocol.oidc.mappers.HardcodedClaim
|
||||
org.keycloak.protocol.oidc.mappers.HardcodedRole
|
||||
org.keycloak.protocol.oidc.mappers.RoleNameMapper
|
||||
org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper
|
||||
|
||||
|
||||
|
|
|
@ -276,8 +276,8 @@ public class AccountTest {
|
|||
|
||||
events.expectLogin().client("account").detail(Details.REDIRECT_URI, ACCOUNT_REDIRECT).assertEvent();
|
||||
|
||||
Assert.assertEquals("", profilePage.getFirstName());
|
||||
Assert.assertEquals("", profilePage.getLastName());
|
||||
Assert.assertEquals("Tom", profilePage.getFirstName());
|
||||
Assert.assertEquals("Brady", profilePage.getLastName());
|
||||
Assert.assertEquals("test-user@localhost", profilePage.getEmail());
|
||||
|
||||
// All fields are required, so there should be an error when something is missing.
|
||||
|
@ -310,8 +310,8 @@ public class AccountTest {
|
|||
|
||||
profilePage.clickCancel();
|
||||
|
||||
Assert.assertEquals("", profilePage.getFirstName());
|
||||
Assert.assertEquals("", profilePage.getLastName());
|
||||
Assert.assertEquals("Tom", profilePage.getFirstName());
|
||||
Assert.assertEquals("Brady", profilePage.getLastName());
|
||||
Assert.assertEquals("test-user@localhost", profilePage.getEmail());
|
||||
|
||||
events.assertEmpty();
|
||||
|
|
9
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/AbstractKerberosTest.java
Normal file → Executable file
9
testsuite/integration/src/test/java/org/keycloak/testsuite/federation/AbstractKerberosTest.java
Normal file → Executable file
|
@ -17,7 +17,6 @@ import org.junit.After;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.adapters.HttpClientBuilder;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.federation.kerberos.CommonKerberosConfig;
|
||||
|
@ -31,15 +30,11 @@ import org.keycloak.models.UserFederationProvider;
|
|||
import org.keycloak.models.UserFederationProviderModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocolFactory;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCUserSessionNoteMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.OAuthClient;
|
||||
import org.keycloak.testsuite.adapter.AdapterTest;
|
||||
import org.keycloak.testsuite.adapter.AdapterTestStrategy;
|
||||
import org.keycloak.testsuite.pages.AccountPasswordPage;
|
||||
import org.keycloak.testsuite.pages.AppPage;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
import org.keycloak.testsuite.rule.WebResource;
|
||||
|
@ -182,7 +177,7 @@ public abstract class AbstractKerberosTest {
|
|||
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
ProtocolMapperModel protocolMapper = OIDCUserSessionNoteMapper.createClaimMapper(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
|
||||
ProtocolMapperModel protocolMapper = UserSessionNoteMapper.createClaimMapper(KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
|
||||
KerberosConstants.GSS_DELEGATION_CREDENTIAL,
|
||||
KerberosConstants.GSS_DELEGATION_CREDENTIAL, "String",
|
||||
true, KerberosConstants.GSS_DELEGATION_CREDENTIAL_DISPLAY_NAME,
|
||||
|
|
|
@ -40,8 +40,12 @@ import org.keycloak.models.RealmModel;
|
|||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCAddressMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.OIDCUserAttributeMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.AddressMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.FullNameMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.HardcodedClaim;
|
||||
import org.keycloak.protocol.oidc.mappers.HardcodedRole;
|
||||
import org.keycloak.protocol.oidc.mappers.RoleNameMapper;
|
||||
import org.keycloak.protocol.oidc.mappers.UserAttributeMapper;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.IDToken;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
|
@ -67,6 +71,7 @@ import javax.ws.rs.core.UriBuilder;
|
|||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
@ -594,9 +599,14 @@ public class AccessTokenTest {
|
|||
user.setAttribute("country", "USA");
|
||||
user.setAttribute("phone", "617-777-6666");
|
||||
ApplicationModel app = realm.getApplicationByName("test-app");
|
||||
ProtocolMapperModel mapper = OIDCAddressMapper.createAddressMapper(true, true);
|
||||
ProtocolMapperModel mapper = AddressMapper.createAddressMapper(true, true);
|
||||
app.addProtocolMapper(mapper);
|
||||
app.addProtocolMapper(OIDCUserAttributeMapper.createClaimMapper("custom phone", "phone", "home_phone", "String", true, "", true, true));
|
||||
app.addProtocolMapper(HardcodedClaim.create("hard", "hard", "coded", "String", false, null, true, true));
|
||||
app.addProtocolMapper(HardcodedClaim.create("hard-nested", "nested.hard", "coded-nested", "String", false, null, true, true));
|
||||
app.addProtocolMapper(UserAttributeMapper.createClaimMapper("custom phone", "phone", "home_phone", "String", true, "", true, true));
|
||||
app.addProtocolMapper(UserAttributeMapper.createClaimMapper("nested phone", "phone", "home.phone", "String", true, "", true, true));
|
||||
app.addProtocolMapper(HardcodedRole.create("hard-realm", "hardcoded"));
|
||||
app.addProtocolMapper(HardcodedRole.create("hard-app", "app.hardcoded"));
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
|
@ -607,15 +617,22 @@ public class AccessTokenTest {
|
|||
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
|
||||
IDToken idToken = getIdToken(tokenResponse);
|
||||
Assert.assertNotNull(idToken.getAddress());
|
||||
Assert.assertEquals(idToken.getName(), "Tom Brady");
|
||||
Assert.assertEquals(idToken.getAddress().getStreetAddress(), "5 Yawkey Way");
|
||||
Assert.assertEquals(idToken.getAddress().getLocality(), "Boston");
|
||||
Assert.assertEquals(idToken.getAddress().getRegion(), "MA");
|
||||
Assert.assertEquals(idToken.getAddress().getPostalCode(), "02115");
|
||||
Assert.assertEquals(idToken.getAddress().getCountry(), "USA");
|
||||
Assert.assertNotNull(idToken.getOtherClaims().get("home_phone"));
|
||||
//Assert.assertEquals("617-777-6666", idToken.getOtherClaims().get("home_phone"));
|
||||
Assert.assertEquals("617-777-6666", idToken.getOtherClaims().get("home_phone"));
|
||||
Assert.assertEquals("coded", idToken.getOtherClaims().get("hard"));
|
||||
Map nested = (Map)idToken.getOtherClaims().get("nested");
|
||||
Assert.assertEquals("coded-nested", nested.get("hard"));
|
||||
nested = (Map)idToken.getOtherClaims().get("home");
|
||||
Assert.assertEquals("617-777-6666", nested.get("phone"));
|
||||
|
||||
AccessToken accessToken = getAccessToken(tokenResponse);
|
||||
Assert.assertEquals(accessToken.getName(), "Tom Brady");
|
||||
Assert.assertNotNull(accessToken.getAddress());
|
||||
Assert.assertEquals(accessToken.getAddress().getStreetAddress(), "5 Yawkey Way");
|
||||
Assert.assertEquals(accessToken.getAddress().getLocality(), "Boston");
|
||||
|
@ -624,11 +641,41 @@ public class AccessTokenTest {
|
|||
Assert.assertEquals(accessToken.getAddress().getCountry(), "USA");
|
||||
Assert.assertNotNull(accessToken.getOtherClaims().get("home_phone"));
|
||||
Assert.assertEquals("617-777-6666", accessToken.getOtherClaims().get("home_phone"));
|
||||
Assert.assertEquals("coded", accessToken.getOtherClaims().get("hard"));
|
||||
nested = (Map)accessToken.getOtherClaims().get("nested");
|
||||
Assert.assertEquals("coded-nested", nested.get("hard"));
|
||||
nested = (Map)accessToken.getOtherClaims().get("home");
|
||||
Assert.assertEquals("617-777-6666", nested.get("phone"));
|
||||
Assert.assertTrue(accessToken.getRealmAccess().getRoles().contains("hardcoded"));
|
||||
Assert.assertTrue(accessToken.getResourceAccess("app").getRoles().contains("hardcoded"));
|
||||
|
||||
|
||||
response.close();
|
||||
}
|
||||
client.close();
|
||||
|
||||
// undo mappers
|
||||
{
|
||||
KeycloakSession session = keycloakRule.startSession();
|
||||
RealmModel realm = session.realms().getRealmByName("test");
|
||||
ApplicationModel app = realm.getApplicationByName("test-app");
|
||||
for (ProtocolMapperModel model : app.getProtocolMappers()) {
|
||||
if (model.getName().equals("address")
|
||||
|| model.getName().equals("hard")
|
||||
|| model.getName().equals("hard-nested")
|
||||
|| model.getName().equals("custom phone")
|
||||
|| model.getName().equals("nested phone")
|
||||
|| model.getName().equals("hard-realm")
|
||||
|| model.getName().equals("hard-app")
|
||||
) {
|
||||
app.removeProtocolMapper(model);
|
||||
}
|
||||
}
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
}
|
||||
|
||||
|
||||
events.clear();
|
||||
|
||||
}
|
||||
|
@ -645,7 +692,7 @@ public class AccessTokenTest {
|
|||
}
|
||||
|
||||
private AccessToken getAccessToken(org.keycloak.representations.AccessTokenResponse tokenResponse) throws VerificationException {
|
||||
JWSInput input = new JWSInput(tokenResponse.getIdToken());
|
||||
JWSInput input = new JWSInput(tokenResponse.getToken());
|
||||
AccessToken idToken = null;
|
||||
try {
|
||||
idToken = input.readJsonContent(AccessToken.class);
|
||||
|
|
|
@ -3,21 +3,27 @@ package org.keycloak.testsuite.saml;
|
|||
import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput;
|
||||
import org.junit.Assert;
|
||||
import org.junit.ClassRule;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.ApplicationModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.protocol.oidc.TokenManager;
|
||||
import org.keycloak.protocol.saml.mappers.AttributeStatementHelper;
|
||||
import org.keycloak.protocol.saml.mappers.HardcodedAttributeMapper;
|
||||
import org.keycloak.protocol.saml.mappers.HardcodedRole;
|
||||
import org.keycloak.protocol.saml.mappers.RoleListMapper;
|
||||
import org.keycloak.protocol.saml.mappers.RoleNameMapper;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.services.managers.RealmManager;
|
||||
import org.keycloak.services.resources.admin.AdminRoot;
|
||||
import org.keycloak.testsuite.pages.LoginPage;
|
||||
import org.keycloak.testsuite.rule.KeycloakRule;
|
||||
import org.keycloak.testsuite.rule.WebResource;
|
||||
import org.keycloak.testsuite.rule.WebRule;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
@ -101,10 +107,12 @@ public class SamlBindingTest {
|
|||
private void handler(HttpServletRequest req, HttpServletResponse resp) {
|
||||
System.out.println("********* HERE ******");
|
||||
if (req.getParameterMap().isEmpty()) {
|
||||
System.out.println("redirecting");
|
||||
resp.setStatus(302);
|
||||
resp.setHeader("Location", "http://localhost:8081/auth/realms/demo/protocol/saml?SAMLRequest=jVJbT8IwFP4rS99HuwluNIwEIUYSLwugD76Y2h2kSdfOng7l31uGRn0ATfrQ9HznfJfTEYpaN3zS%2Bo1ZwGsL6KP3WhvkXaEgrTPcClTIjagBuZd8Obm55mmP8cZZb6XV5NByGiwQwXllDYkmX9epNdjW4JbgtkrC%2FeK6IBvvG06ptlLojUXPc5YnFOpG2x0AJdEsaFRG7PuPoUWwQx0IXSOtoLb0SynduyLRpXUSOs8FWQuNQKL5rCDz2VO%2FymEgIY2zlJ3H%2FSx9jkU%2BzOK0ys8yNmSSsUEAYxnsqC18tyO2MDfohfEFSVkyiNlZzM5XacrDSbJePug%2Fkqj8FHKhTKXMy%2BnIng8g5FerVRmXd8sViR7AYec8AMh4tPfDO3L3Y2%2F%2F3cT4j7BH9Mf8A1nDb8PA%2Bay0WsldNNHavk1D1D5k4V0LXbi18MclJL2ke1FVvO6gvDXYgFRrBRWh4wPp7z85%2FgA%3D");
|
||||
return;
|
||||
}
|
||||
System.out.println("received response");
|
||||
samlResponse = req.getParameter("SAMLResponse");
|
||||
}
|
||||
}
|
||||
|
@ -199,6 +207,8 @@ public class SamlBindingTest {
|
|||
// this test has a hardcoded SAMLRequest and we hack a SP face servlet to get the SAMLResponse so we can look
|
||||
// at the assertions sent. This is because Picketlink, AFAICT, does not give you any way to get access to
|
||||
// the assertion.
|
||||
|
||||
{
|
||||
SamlSPFacade.samlResponse = null;
|
||||
driver.navigate().to("http://localhost:8081/employee/");
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith("http://localhost:8081/auth/realms/demo/protocol/saml"));
|
||||
|
@ -212,10 +222,12 @@ public class SamlBindingTest {
|
|||
Assert.assertTrue(rt.getAssertions().size() == 1);
|
||||
AssertionType assertion = rt.getAssertions().get(0).getAssertion();
|
||||
|
||||
// test attributes
|
||||
// test attributes and roles
|
||||
|
||||
boolean email = false;
|
||||
boolean phone = false;
|
||||
boolean userRole = false;
|
||||
boolean managerRole = false;
|
||||
for (AttributeStatementType statement : assertion.getAttributeStatements()) {
|
||||
for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
|
||||
AttributeType attr = choice.getAttribute();
|
||||
|
@ -228,6 +240,9 @@ public class SamlBindingTest {
|
|||
Assert.assertEquals(JBossSAMLURIConstants.ATTRIBUTE_FORMAT_BASIC.get(), attr.getNameFormat());
|
||||
Assert.assertEquals(attr.getAttributeValue().get(0), "617");
|
||||
phone = true;
|
||||
} else if (attr.getName().equals("Role")) {
|
||||
if (attr.getAttributeValue().get(0).equals("manager")) managerRole = true;
|
||||
if (attr.getAttributeValue().get(0).equals("user")) userRole = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,7 +250,79 @@ public class SamlBindingTest {
|
|||
|
||||
Assert.assertTrue(email);
|
||||
Assert.assertTrue(phone);
|
||||
Assert.assertTrue(userRole);
|
||||
Assert.assertTrue(managerRole);
|
||||
}
|
||||
|
||||
keycloakRule.update(new KeycloakRule.KeycloakSetup() {
|
||||
@Override
|
||||
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
|
||||
ApplicationModel app = appRealm.getApplicationByName("http://localhost:8081/employee/");
|
||||
for (ProtocolMapperModel mapper : app.getProtocolMappers()) {
|
||||
if (mapper.getName().equals("role-list")) {
|
||||
app.removeProtocolMapper(mapper);
|
||||
mapper.setId(null);
|
||||
mapper.getConfig().put(RoleListMapper.SINGLE_ROLE_ATTRIBUTE, "true");
|
||||
mapper.getConfig().put(AttributeStatementHelper.SAML_ATTRIBUTE_NAME, "memberOf");
|
||||
app.addProtocolMapper(mapper);
|
||||
}
|
||||
}
|
||||
app.addProtocolMapper(HardcodedAttributeMapper.create("hardcoded-attribute", "hardcoded-attribute", "Basic", null, "hard", false, null));
|
||||
app.addProtocolMapper(HardcodedRole.create("hardcoded-role", "hardcoded-role"));
|
||||
app.addProtocolMapper(RoleNameMapper.create("renamed-role", "manager", "el-jefe"));
|
||||
app.addProtocolMapper(RoleNameMapper.create("renamed-employee-role", "http://localhost:8081/employee/.employee", "pee-on"));
|
||||
}
|
||||
}, "demo");
|
||||
|
||||
System.out.println(">>>>>>>>>> single role attribute <<<<<<<<");
|
||||
|
||||
{
|
||||
SamlSPFacade.samlResponse = null;
|
||||
driver.navigate().to("http://localhost:8081/employee/");
|
||||
System.out.println(driver.getCurrentUrl());
|
||||
Assert.assertEquals(driver.getCurrentUrl(), "http://localhost:8081/employee/");
|
||||
Assert.assertNotNull(SamlSPFacade.samlResponse);
|
||||
SAML2Response saml2Response = new SAML2Response();
|
||||
byte[] samlResponse = PostBindingUtil.base64Decode(SamlSPFacade.samlResponse);
|
||||
ResponseType rt = saml2Response.getResponseType(new ByteArrayInputStream(samlResponse));
|
||||
Assert.assertTrue(rt.getAssertions().size() == 1);
|
||||
AssertionType assertion = rt.getAssertions().get(0).getAssertion();
|
||||
|
||||
// test attributes and roles
|
||||
|
||||
boolean userRole = false;
|
||||
boolean managerRole = false;
|
||||
boolean single = false;
|
||||
boolean hardcodedRole = false;
|
||||
boolean hardcodedAttribute = false;
|
||||
boolean peeOn = false;
|
||||
for (AttributeStatementType statement : assertion.getAttributeStatements()) {
|
||||
for (AttributeStatementType.ASTChoiceType choice : statement.getAttributes()) {
|
||||
AttributeType attr = choice.getAttribute();
|
||||
if (attr.getName().equals("memberOf")) {
|
||||
if (single) Assert.fail("too many role attributes");
|
||||
single = true;
|
||||
for (Object value : attr.getAttributeValue()) {
|
||||
if (value.equals("el-jefe")) managerRole = true;
|
||||
if (value.equals("user")) userRole = true;
|
||||
if (value.equals("hardcoded-role")) hardcodedRole = true;
|
||||
if (value.equals("pee-on")) peeOn = true;
|
||||
}
|
||||
} else if (attr.getName().equals("hardcoded-attribute")) {
|
||||
hardcodedAttribute = true;
|
||||
Assert.assertEquals(attr.getAttributeValue().get(0), "hard");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Assert.assertTrue(single);
|
||||
Assert.assertTrue(hardcodedAttribute);
|
||||
Assert.assertTrue(hardcodedRole);
|
||||
Assert.assertTrue(peeOn);
|
||||
Assert.assertTrue(userRole);
|
||||
Assert.assertTrue(managerRole);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -27,7 +27,10 @@
|
|||
"attributes" : {
|
||||
"phone": "617"
|
||||
},
|
||||
"realmRoles": ["manager", "user"]
|
||||
"realmRoles": ["manager", "user"],
|
||||
"applicationRoles": {
|
||||
"http://localhost:8081/employee/": [ "employee" ]
|
||||
}
|
||||
}
|
||||
],
|
||||
"applications": [
|
||||
|
@ -304,6 +307,14 @@
|
|||
"name": "user",
|
||||
"description": "Have User privileges"
|
||||
}
|
||||
],
|
||||
"application" : {
|
||||
"http://localhost:8081/employee/" : [
|
||||
{
|
||||
"name": "employee",
|
||||
"description": "Have Employee privileges"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
"username" : "test-user@localhost",
|
||||
"enabled": true,
|
||||
"email" : "test-user@localhost",
|
||||
"firstName": "Tom",
|
||||
"lastName": "Brady",
|
||||
"credentials" : [
|
||||
{ "type" : "password",
|
||||
"value" : "password" }
|
||||
|
|
Loading…
Reference in a new issue