mirror of
https://github.com/keycloak/keycloak.git
synced 2026-06-08 16:42:13 -04:00
feat: add ability to hide social broker logins in flow
Signed-off-by: Spliterash <me@spliterash.ru>
This commit is contained in:
parent
eac504cce5
commit
fe86d2d441
6 changed files with 275 additions and 2 deletions
|
|
@ -63,6 +63,8 @@ public abstract class AbstractUsernameFormAuthenticator extends AbstractFormAuth
|
|||
// Flag is true if user was already set in the authContext before this authenticator was triggered. In this case we skip clearing of the user after unsuccessful password authentication
|
||||
public static final String USER_SET_BEFORE_USERNAME_PASSWORD_AUTH = "USER_SET_BEFORE_USERNAME_PASSWORD_AUTH";
|
||||
|
||||
// What broker's should be hidden on login page
|
||||
public static final String HIDDEN_BROKERS = "HIDDEN_BROKERS";
|
||||
@Override
|
||||
public void action(AuthenticationFlowContext context) {
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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.authentication.authenticators.browser;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
import org.keycloak.authentication.AuthenticationFlowContext;
|
||||
import org.keycloak.authentication.Authenticator;
|
||||
import org.keycloak.authentication.authenticators.browser.util.HiddenBrokerContext;
|
||||
import org.keycloak.models.AuthenticatorConfigModel;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
||||
public class SetHiddenBrokerAuthenticator implements Authenticator {
|
||||
@Override
|
||||
public void authenticate(AuthenticationFlowContext context) {
|
||||
context.success();
|
||||
|
||||
AuthenticatorConfigModel config = context.getAuthenticatorConfig();
|
||||
if (config == null) return;
|
||||
|
||||
Map<String, String> map = config.getConfig();
|
||||
if (map == null) return;
|
||||
|
||||
String mapValue = map.get(SetHiddenBrokerAuthenticatorFactory.HIDDEN_BROKER_CONFIG);
|
||||
if (mapValue == null) return;
|
||||
|
||||
String[] values = Constants.CFG_DELIMITER_PATTERN.split(mapValue);
|
||||
if (values.length == 0) return;
|
||||
|
||||
HiddenBrokerContext hiddenBrokerContext = new HiddenBrokerContext();
|
||||
hiddenBrokerContext.setHiddenBrokers(Arrays.stream(values).toList());
|
||||
hiddenBrokerContext.saveToAuthenticationSession(context.getAuthenticationSession());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(AuthenticationFlowContext context) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresUser() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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.authentication.authenticators.browser;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.Authenticator;
|
||||
import org.keycloak.authentication.AuthenticatorFactory;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
||||
public class SetHiddenBrokerAuthenticatorFactory implements AuthenticatorFactory {
|
||||
private static final SetHiddenBrokerAuthenticator INSTANCE = new SetHiddenBrokerAuthenticator();
|
||||
public static final String PROVIDER_ID = "set-hidden-broker";
|
||||
public static final String HIDDEN_BROKER_CONFIG = "hidden";
|
||||
|
||||
static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
|
||||
AuthenticationExecutionModel.Requirement.REQUIRED,
|
||||
AuthenticationExecutionModel.Requirement.DISABLED};
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authenticator create(KeycloakSession session) {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Set hidden Broker";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfigurable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReferenceCategory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
|
||||
return REQUIREMENT_CHOICES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserSetupAllowed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Hide log in via social buttons on login page";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
ProviderConfigProperty hiddenBrokers = new ProviderConfigProperty(
|
||||
HIDDEN_BROKER_CONFIG,
|
||||
"Hidden brokers",
|
||||
"What social brokers should be hidden on login page. Use alias",
|
||||
ProviderConfigProperty.MULTIVALUED_STRING_TYPE,
|
||||
null,
|
||||
false,
|
||||
true
|
||||
);
|
||||
|
||||
return List.of(hiddenBrokers);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.authentication.authenticators.browser.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.keycloak.authentication.authenticators.browser.AbstractUsernameFormAuthenticator;
|
||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
|
||||
public class HiddenBrokerContext {
|
||||
|
||||
private Set<String> hiddenBrokers = new LinkedHashSet<>();
|
||||
|
||||
public Set<String> getHiddenBrokers() {
|
||||
return hiddenBrokers;
|
||||
}
|
||||
|
||||
public void setHiddenBrokers(Collection<String> hiddenBrokers) {
|
||||
this.hiddenBrokers.clear();
|
||||
this.hiddenBrokers.addAll(hiddenBrokers);
|
||||
}
|
||||
|
||||
public void addHiddenBroker(String brokerAliasId) {
|
||||
hiddenBrokers.add(brokerAliasId);
|
||||
}
|
||||
|
||||
// Save this context as note to authSession
|
||||
public void saveToAuthenticationSession(AuthenticationSessionModel authSession) {
|
||||
try {
|
||||
String asString = JsonSerialization.writeValueAsString(this);
|
||||
authSession.setAuthNote(AbstractUsernameFormAuthenticator.HIDDEN_BROKERS, asString);
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
|
||||
public static HiddenBrokerContext readFromAuthenticationSession(AuthenticationSessionModel authSession) {
|
||||
String asString = authSession.getAuthNote(AbstractUsernameFormAuthenticator.HIDDEN_BROKERS);
|
||||
if (asString == null) {
|
||||
return null;
|
||||
} else {
|
||||
try {
|
||||
return JsonSerialization.readValue(asString, HiddenBrokerContext.class);
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ import org.keycloak.authentication.AuthenticationFlowContext;
|
|||
import org.keycloak.authentication.AuthenticationProcessor;
|
||||
import org.keycloak.authentication.authenticators.broker.AbstractIdpAuthenticator;
|
||||
import org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext;
|
||||
import org.keycloak.authentication.authenticators.browser.util.HiddenBrokerContext;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
|
|
@ -73,15 +74,30 @@ public class IdentityProviderBean {
|
|||
if (this.providers == null) {
|
||||
String existingIDP = this.getExistingIDP(session, context);
|
||||
Set<String> federatedIdentities = this.getLinkedBrokerAliases(session, realm, context);
|
||||
List<IdentityProvider> defaultProviders;
|
||||
if (federatedIdentities != null) {
|
||||
this.providers = getFederatedIdentityProviders(federatedIdentities, existingIDP);
|
||||
defaultProviders = getFederatedIdentityProviders(federatedIdentities, existingIDP);
|
||||
} else {
|
||||
this.providers = searchForIdentityProviders(existingIDP);
|
||||
defaultProviders = searchForIdentityProviders(existingIDP);
|
||||
}
|
||||
this.providers = filterHiddenProviders(defaultProviders);
|
||||
}
|
||||
return this.providers;
|
||||
}
|
||||
|
||||
protected List<IdentityProvider> filterHiddenProviders(List<IdentityProvider> defaultProviders) {
|
||||
AuthenticationSessionModel authenticationSession = context.getAuthenticationSession();
|
||||
if (authenticationSession == null) return defaultProviders;
|
||||
|
||||
HiddenBrokerContext hiddenBrokerContext = HiddenBrokerContext.readFromAuthenticationSession(authenticationSession);
|
||||
if (hiddenBrokerContext == null) return defaultProviders;
|
||||
|
||||
return defaultProviders
|
||||
.stream()
|
||||
.filter(p -> !hiddenBrokerContext.getHiddenBrokers().contains(p.alias))
|
||||
.toList();
|
||||
}
|
||||
|
||||
public KeycloakSession getSession() {
|
||||
return this.session;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,3 +58,4 @@ org.keycloak.authentication.authenticators.sessionlimits.UserSessionLimitsAuthen
|
|||
org.keycloak.authentication.authenticators.browser.RecoveryAuthnCodesFormAuthenticatorFactory
|
||||
org.keycloak.organization.authentication.authenticators.browser.OrganizationAuthenticatorFactory
|
||||
org.keycloak.authentication.authenticators.browser.PasskeysConditionalUIAuthenticatorFactory
|
||||
org.keycloak.authentication.authenticators.browser.SetHiddenBrokerAuthenticatorFactory
|
||||
Loading…
Reference in a new issue