mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
Only set organization to client session when re-authenticating if user is member of the mapped organization
Closes #37169 Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
parent
9bd12dcacd
commit
44f18467d5
@ -163,7 +163,7 @@ public class OrganizationAuthenticator extends IdentityProviderAuthenticator {
|
||||
if (alias.isEmpty()) {
|
||||
OrganizationModel organization = Organizations.resolveOrganization(session, user, domain);
|
||||
|
||||
if (organization != null) {
|
||||
if (isSSOAuthentication(authSession) && organization != null) {
|
||||
// make sure the organization selected by the user is available from the client session when running mappers and issuing tokens
|
||||
authSession.setClientNote(OrganizationModel.ORGANIZATION_ATTRIBUTE, organization.getId());
|
||||
}
|
||||
|
||||
@ -36,6 +36,7 @@ import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.OrganizationModel;
|
||||
import org.keycloak.models.ProtocolMapperModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.models.UserSessionModel;
|
||||
import org.keycloak.models.utils.ModelToRepresentation;
|
||||
import org.keycloak.models.utils.RepresentationToModel;
|
||||
@ -122,8 +123,8 @@ public class OrganizationMembershipMapper extends AbstractOIDCProtocolMapper imp
|
||||
KeycloakContext context = session.getContext();
|
||||
RealmModel realm = context.getRealm();
|
||||
ProtocolMapperModel effectiveModel = getEffectiveModel(session, realm, model);
|
||||
|
||||
Object claim = resolveValue(effectiveModel, organizations.toList());
|
||||
UserModel user = userSession.getUser();
|
||||
Object claim = resolveValue(effectiveModel, user, organizations.toList());
|
||||
|
||||
if (claim == null) {
|
||||
return;
|
||||
@ -144,7 +145,7 @@ public class OrganizationMembershipMapper extends AbstractOIDCProtocolMapper imp
|
||||
|
||||
}
|
||||
|
||||
private Object resolveValue(ProtocolMapperModel model, List<OrganizationModel> organizations) {
|
||||
private Object resolveValue(ProtocolMapperModel model, UserModel user, List<OrganizationModel> organizations) {
|
||||
if (organizations.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@ -156,7 +157,7 @@ public class OrganizationMembershipMapper extends AbstractOIDCProtocolMapper imp
|
||||
Map<String, Map<String, Object>> value = new HashMap<>();
|
||||
|
||||
for (OrganizationModel o : organizations) {
|
||||
if (o == null || !o.isEnabled()) {
|
||||
if (o == null || !o.isEnabled() || user == null || !o.isMember(user)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -731,6 +731,10 @@ public class TokenManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (user != null && orgScope.resolveOrganizations(user, scopeParam, session).findAny().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return orgScope.toClientScope(name, user, session);
|
||||
}
|
||||
|
||||
|
||||
@ -861,6 +861,53 @@ public class OrganizationOIDCProtocolMapperTest extends AbstractOrganizationTest
|
||||
assertScopeAndClaims(scopeName, orgA);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClaimNotMappedIfUserNotMemberWhenDefaultClientScope() {
|
||||
OrganizationRepresentation orgARep = createOrganization("orga", true);
|
||||
OrganizationResource orgA = testRealm().organizations().get(orgARep.getId());
|
||||
MemberRepresentation member = addMember(orgA, "member@" + orgARep.getDomains().iterator().next().getName());
|
||||
orgA.members().member(member.getId()).delete().close();
|
||||
|
||||
ClientRepresentation clientRep = testRealm().clients().findByClientId("broker-app").get(0);
|
||||
ClientResource client = testRealm().clients().get(clientRep.getId());
|
||||
ClientScopeRepresentation orgScopeRep = client.getOptionalClientScopes().stream().filter(scope -> "organization".equals(scope.getName())).findAny().orElse(null);
|
||||
client.removeOptionalClientScope(orgScopeRep.getId());
|
||||
client.addDefaultClientScope(orgScopeRep.getId());
|
||||
getCleanup().addCleanup(() -> {
|
||||
client.removeDefaultClientScope(orgScopeRep.getId());
|
||||
client.addOptionalClientScope(orgScopeRep.getId());
|
||||
});
|
||||
// resolve organization based on the organization scope value
|
||||
oauth.clientId("broker-app");
|
||||
oauth.scope(null);
|
||||
loginPage.open(bc.consumerRealmName());
|
||||
loginPage.loginUsername(member.getEmail());
|
||||
loginPage.login(memberPassword);
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
AccessTokenResponse response = oauth.doAccessTokenRequest(code, KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET);
|
||||
assertThat(response.getScope(), containsString(orgScopeRep.getName()));
|
||||
AccessToken accessToken = oauth.verifyToken(response.getAccessToken());
|
||||
assertThat(accessToken.getScope(), containsString(orgScopeRep.getName()));
|
||||
assertThat(accessToken.getOtherClaims().keySet(), not(hasItem(OAuth2Constants.ORGANIZATION)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClaimNotMappedIfUserNotMemberWhenScopeOrgAliasRequested() {
|
||||
OrganizationRepresentation orgARep = createOrganization("orga", true);
|
||||
assertClaimNotMapped("organization:" + orgARep.getAlias(), orgARep, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClaimNotMappedIfUserNotMemberWhenScopeOrgAllRequested() {
|
||||
assertClaimNotMapped("organization:*", createOrganization("orga", true), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClaimNotMappedIfUserNotMemberWhenScopeOrgRequested() {
|
||||
assertClaimNotMapped("organization", createOrganization("orga", true), true);
|
||||
}
|
||||
|
||||
private AccessTokenResponse assertSuccessfulCodeGrant() {
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
AccessTokenResponse response = oauth.doAccessTokenRequest(code, KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET);
|
||||
@ -926,4 +973,24 @@ public class OrganizationOIDCProtocolMapperTest extends AbstractOrganizationTest
|
||||
|
||||
orgScopeResource.getProtocolMappers().update(orgMapper.getId(), orgMapper);
|
||||
}
|
||||
|
||||
private void assertClaimNotMapped(String orgScope, OrganizationRepresentation orgARep, boolean grantScope) {
|
||||
OrganizationResource orgA = testRealm().organizations().get(orgARep.getId());
|
||||
MemberRepresentation member = addMember(orgA, "member@" + orgARep.getDomains().iterator().next().getName());
|
||||
orgA.members().member(member.getId()).delete().close();
|
||||
driver.manage().timeouts().pageLoadTimeout(Duration.ofDays(1));
|
||||
// resolve organization based on the organization scope value
|
||||
oauth.clientId("broker-app");
|
||||
oauth.scope(orgScope);
|
||||
loginPage.open(bc.consumerRealmName());
|
||||
loginPage.loginUsername(member.getEmail());
|
||||
loginPage.login(memberPassword);
|
||||
|
||||
String code = oauth.getCurrentQuery().get(OAuth2Constants.CODE);
|
||||
AccessTokenResponse response = oauth.doAccessTokenRequest(code, KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET);
|
||||
assertThat(response.getScope(), grantScope ? containsString(orgScope) : not(containsString(orgScope)));
|
||||
AccessToken accessToken = oauth.verifyToken(response.getAccessToken());
|
||||
assertThat(accessToken.getScope(), grantScope ? containsString(orgScope) : not(containsString(orgScope)));
|
||||
assertThat(accessToken.getOtherClaims().keySet(), not(hasItem(OAuth2Constants.ORGANIZATION)));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user