Add federated identity ProviderEvent(s)

Signed-off-by: Réda Housni Alaoui <reda-alaoui@hey.com>
This commit is contained in:
Réda Housni Alaoui 2024-01-10 11:51:41 +01:00 committed by Pedro Igor
parent 42f0488d76
commit 98230aa372
4 changed files with 213 additions and 2 deletions

View file

@ -575,6 +575,28 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
} else { } else {
getFederatedStorage().addFederatedIdentity(realm, user.getId(), socialLink); getFederatedStorage().addFederatedIdentity(realm, user.getId(), socialLink);
} }
session.getKeycloakSessionFactory().publish(new FederatedIdentityModel.FederatedIdentityCreatedEvent() {
@Override
public KeycloakSession getKeycloakSession() {
return session;
}
@Override
public RealmModel getRealm() {
return realm;
}
@Override
public UserModel getUser() {
return user;
}
@Override
public FederatedIdentityModel getFederatedIdentity() {
return socialLink;
}
});
} }
@Override @Override
@ -588,11 +610,44 @@ public class UserStorageManager extends AbstractStorageManager<UserStorageProvid
@Override @Override
public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) { public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
FederatedIdentityModel federatedIdentityModel;
if (StorageId.isLocalStorage(user)) { if (StorageId.isLocalStorage(user)) {
return localStorage().removeFederatedIdentity(realm, user, socialProvider); UserProvider localStorage = localStorage();
federatedIdentityModel = localStorage.getFederatedIdentity(realm, user, socialProvider);
localStorage.removeFederatedIdentity(realm, user, socialProvider);
} else { } else {
return getFederatedStorage().removeFederatedIdentity(realm, user.getId(), socialProvider); UserFederatedStorageProvider federatedStorage = getFederatedStorage();
federatedIdentityModel = federatedStorage.getFederatedIdentity(user.getId(), socialProvider, realm);
federatedStorage.removeFederatedIdentity(realm, user.getId(), socialProvider);
} }
if (federatedIdentityModel == null) {
return false;
}
session.getKeycloakSessionFactory().publish(new FederatedIdentityModel.FederatedIdentityRemovedEvent() {
@Override
public KeycloakSession getKeycloakSession() {
return session;
}
@Override
public RealmModel getRealm() {
return realm;
}
@Override
public UserModel getUser() {
return user;
}
@Override
public FederatedIdentityModel getFederatedIdentity() {
return federatedIdentityModel;
}
});
return true;
} }
@Override @Override

View file

@ -17,6 +17,8 @@
package org.keycloak.models; package org.keycloak.models;
import org.keycloak.provider.ProviderEvent;
/** /**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a> * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/ */
@ -85,4 +87,18 @@ public class FederatedIdentityModel {
result = 31 * result + (userName != null ? userName.hashCode() : 0); result = 31 * result + (userName != null ? userName.hashCode() : 0);
return result; return result;
} }
public interface FederatedIdentityCreatedEvent extends ProviderEvent {
KeycloakSession getKeycloakSession();
RealmModel getRealm();
UserModel getUser();
FederatedIdentityModel getFederatedIdentity();
}
public interface FederatedIdentityRemovedEvent extends ProviderEvent {
KeycloakSession getKeycloakSession();
RealmModel getRealm();
UserModel getUser();
FederatedIdentityModel getFederatedIdentity();
}
} }

View file

@ -0,0 +1,131 @@
/*
* Copyright 2024 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.model;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.broker.provider.IdentityProviderFactory;
import org.keycloak.models.Constants;
import org.keycloak.models.FederatedIdentityModel;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
import org.keycloak.provider.ProviderEventListener;
import org.keycloak.testsuite.broker.oidc.TestKeycloakOidcIdentityProviderFactory;
/**
* @author Réda Housni Alaoui
*/
@RequireProvider(value = IdentityProvider.class, only = TestKeycloakOidcIdentityProviderFactory.ID)
public class FederatedIdentityModelTest extends KeycloakModelTest {
private static final String IDENTITY_PROVIDER_ALIAS = "idp-test";
private static final String USERNAME = "jdoe";
private String realmId;
private String userId;
@Override
public void createEnvironment(KeycloakSession s) {
RealmModel realm = createRealm(s, "realm");
realm.setDefaultRole(s.roles().addRealmRole(realm, Constants.DEFAULT_ROLES_ROLE_PREFIX + "-" + realm.getName()));
this.realmId = realm.getId();
IdentityProviderFactory identityProviderFactory = (IdentityProviderFactory) s.getKeycloakSessionFactory()
.getProviderFactory(IdentityProvider.class, TestKeycloakOidcIdentityProviderFactory.ID);
IdentityProviderModel identityProviderModel = identityProviderFactory.createConfig();
identityProviderModel.setAlias(IDENTITY_PROVIDER_ALIAS);
realm.addIdentityProvider(identityProviderModel);
userId = s.users().addUser(realm, USERNAME).getId();
}
@Override
public void cleanEnvironment(KeycloakSession s) {
s.realms().removeRealm(realmId);
}
@Test
public void addFederatedIdentity() {
List<FederatedIdentityModel.FederatedIdentityCreatedEvent> recordedEvents = new ArrayList<>();
ProviderEventListener providerEventListener = event -> {
if (event instanceof FederatedIdentityModel.FederatedIdentityCreatedEvent) {
recordedEvents.add((FederatedIdentityModel.FederatedIdentityCreatedEvent) event);
}
};
getFactory().register(providerEventListener);
try {
withRealm(realmId, (session, realm) -> {
FederatedIdentityModel federatedIdentity = new FederatedIdentityModel(IDENTITY_PROVIDER_ALIAS, userId, USERNAME);
UserModel user = session.users().getUserById(realm, userId);
session.users().addFederatedIdentity(realm, user, federatedIdentity);
assertThat(recordedEvents, hasSize(1));
FederatedIdentityModel.FederatedIdentityCreatedEvent event = recordedEvents.get(0);
assertThat(event.getKeycloakSession(), equalTo(session));
assertThat(event.getRealm(), equalTo(realm));
assertThat(event.getUser(), equalTo(user));
assertThat(event.getFederatedIdentity(), equalTo(federatedIdentity));
return null;
});
} finally {
getFactory().unregister(providerEventListener);
}
}
@Test
public void removeFederatedIdentity() {
List<FederatedIdentityModel.FederatedIdentityRemovedEvent> recordedEvents = new ArrayList<>();
ProviderEventListener providerEventListener = event -> {
if (event instanceof FederatedIdentityModel.FederatedIdentityRemovedEvent) {
recordedEvents.add((FederatedIdentityModel.FederatedIdentityRemovedEvent) event);
}
};
getFactory().register(providerEventListener);
try {
withRealm(realmId, (session, realm) -> {
FederatedIdentityModel federatedIdentity = new FederatedIdentityModel(IDENTITY_PROVIDER_ALIAS, userId, USERNAME);
UserModel user = session.users().getUserById(realm, userId);
session.users().addFederatedIdentity(realm, user, federatedIdentity);
session.users().removeFederatedIdentity(realm, user, IDENTITY_PROVIDER_ALIAS);
assertThat(recordedEvents, hasSize(1));
FederatedIdentityModel.FederatedIdentityRemovedEvent event = recordedEvents.get(0);
assertThat(event.getKeycloakSession(), equalTo(session));
assertThat(event.getRealm(), equalTo(realm));
assertThat(event.getUser(), equalTo(user));
assertThat(event.getFederatedIdentity(), equalTo(federatedIdentity));
return null;
});
} finally {
getFactory().unregister(providerEventListener);
}
}
}

View file

@ -17,6 +17,9 @@
package org.keycloak.testsuite.model.parameters; package org.keycloak.testsuite.model.parameters;
import org.keycloak.authorization.jpa.store.JPAAuthorizationStoreFactory; import org.keycloak.authorization.jpa.store.JPAAuthorizationStoreFactory;
import org.keycloak.broker.provider.IdentityProvider;
import org.keycloak.broker.provider.IdentityProviderFactory;
import org.keycloak.broker.provider.IdentityProviderSpi;
import org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory; import org.keycloak.connections.jpa.DefaultJpaConnectionProviderFactory;
import org.keycloak.connections.jpa.JpaConnectionSpi; import org.keycloak.connections.jpa.JpaConnectionSpi;
import org.keycloak.connections.jpa.updater.JpaUpdaterProviderFactory; import org.keycloak.connections.jpa.updater.JpaUpdaterProviderFactory;
@ -68,6 +71,9 @@ public class LegacyJpa extends KeycloakModelParameters {
.add(DBLockSpi.class) .add(DBLockSpi.class)
//required for FederatedIdentityModel
.add(IdentityProviderSpi.class)
.build(); .build();
static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder() static final Set<Class<? extends ProviderFactory>> ALLOWED_FACTORIES = ImmutableSet.<Class<? extends ProviderFactory>>builder()
@ -92,6 +98,9 @@ public class LegacyJpa extends KeycloakModelParameters {
.add(MigrationProviderFactory.class) .add(MigrationProviderFactory.class)
.add(LoginProtocolFactory.class) .add(LoginProtocolFactory.class)
//required for FederatedIdentityModel
.add(IdentityProviderFactory.class)
.build(); .build();
public LegacyJpa() { public LegacyJpa() {