Merge pull request #3372 from patriot1burke/master
onCreate for Components
This commit is contained in:
commit
cdf7dd3a6c
13 changed files with 142 additions and 17 deletions
|
@ -22,7 +22,6 @@ import org.keycloak.common.enums.SslRequired;
|
|||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.component.ComponentFactory;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.jose.jwk.JWKBuilder;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.AuthenticationFlowModel;
|
||||
import org.keycloak.models.AuthenticatorConfigModel;
|
||||
|
@ -66,10 +65,6 @@ import org.keycloak.models.utils.KeycloakModelUtils;
|
|||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
import java.security.Key;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
@ -2058,6 +2053,8 @@ public class RealmAdapter implements RealmModel, JpaModel<RealmEntity> {
|
|||
em.persist(c);
|
||||
setConfig(model, c);
|
||||
model.setId(c.getId());
|
||||
KeycloakModelUtils.notifyCreated(session, this, model);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
|
|
|
@ -1966,7 +1966,7 @@ public class RealmAdapter extends AbstractMongoAdapter<MongoRealmEntity> impleme
|
|||
model.setId(entity.getId());
|
||||
realm.getComponentEntities().add(entity);
|
||||
updateRealm();
|
||||
|
||||
KeycloakModelUtils.notifyCreated(session, this, model);
|
||||
return model;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.keycloak.component;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.provider.ConfiguredProvider;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
@ -35,4 +36,9 @@ public interface ComponentFactory<CreatedType, ProviderType extends Provider> ex
|
|||
|
||||
void validateConfiguration(KeycloakSession session, ComponentModel model) throws ComponentValidationException;
|
||||
|
||||
default
|
||||
void onCreate(KeycloakSession session, RealmModel realm, ComponentModel model) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.keycloak.common.util.CertificateUtils;
|
|||
import org.keycloak.common.util.KeyUtils;
|
||||
import org.keycloak.common.util.MultivaluedHashMap;
|
||||
import org.keycloak.common.util.PemUtils;
|
||||
import org.keycloak.component.ComponentFactory;
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.keys.KeyProvider;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
|
@ -48,6 +49,8 @@ import org.keycloak.models.UserFederationProvider;
|
|||
import org.keycloak.models.UserFederationProviderFactory;
|
||||
import org.keycloak.models.UserFederationProviderModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.representations.idm.CertificateRepresentation;
|
||||
import org.keycloak.transaction.JtaTransactionManagerLookup;
|
||||
|
||||
|
@ -680,4 +683,16 @@ public final class KeycloakModelUtils {
|
|||
}
|
||||
|
||||
|
||||
public static void notifyCreated(KeycloakSession session, RealmModel realm, ComponentModel model) {
|
||||
Class<? extends Provider> providerClass = null;
|
||||
try {
|
||||
providerClass = (Class<? extends Provider>)Class.forName(model.getProviderType());
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
ProviderFactory factory = session.getKeycloakSessionFactory().getProviderFactory(providerClass, model.getProviderId());
|
||||
if (factory instanceof ComponentFactory) {
|
||||
((ComponentFactory)factory).onCreate(session, realm, model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.keycloak.component.ComponentModel;
|
|||
import org.keycloak.component.ComponentValidationException;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
||||
import java.util.Collections;
|
||||
|
@ -82,4 +83,16 @@ public interface UserStorageProviderFactory<T extends UserStorageProvider> exten
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when UserStorageProviderModel is created. This allows you to do initialization of any additional configuration
|
||||
* you need to add. For example, you may be introspecting a database or ldap schema to automatically create mappings.
|
||||
*
|
||||
* @param session
|
||||
* @param realm
|
||||
* @param model
|
||||
*/
|
||||
@Override
|
||||
default void onCreate(KeycloakSession session, RealmModel realm, ComponentModel model) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -243,16 +243,19 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
|
|||
String preferredUsername = (String)idToken.getOtherClaims().get(IDToken.PREFERRED_USERNAME);
|
||||
String email = (String)idToken.getOtherClaims().get(IDToken.EMAIL);
|
||||
|
||||
if (getConfig().getUserInfoUrl() != null && (id == null || name == null || preferredUsername == null || email == null) ) {
|
||||
SimpleHttp request = JsonSimpleHttp.doGet(getConfig().getUserInfoUrl())
|
||||
.header("Authorization", "Bearer " + accessToken);
|
||||
JsonNode userInfo = JsonSimpleHttp.asJson(request);
|
||||
if (!getConfig().isDisableUserInfoService()) {
|
||||
String userInfoUrl = getUserInfoUrl();
|
||||
if (userInfoUrl != null && (id == null || name == null || preferredUsername == null || email == null)) {
|
||||
SimpleHttp request = JsonSimpleHttp.doGet(userInfoUrl)
|
||||
.header("Authorization", "Bearer " + accessToken);
|
||||
JsonNode userInfo = JsonSimpleHttp.asJson(request);
|
||||
|
||||
id = getJsonProperty(userInfo, "sub");
|
||||
name = getJsonProperty(userInfo, "name");
|
||||
preferredUsername = getJsonProperty(userInfo, "preferred_username");
|
||||
email = getJsonProperty(userInfo, "email");
|
||||
AbstractJsonUserAttributeMapper.storeUserProfileForMapper(identity, userInfo, getConfig().getAlias());
|
||||
id = getJsonProperty(userInfo, "sub");
|
||||
name = getJsonProperty(userInfo, "name");
|
||||
preferredUsername = getJsonProperty(userInfo, "preferred_username");
|
||||
email = getJsonProperty(userInfo, "email");
|
||||
AbstractJsonUserAttributeMapper.storeUserProfileForMapper(identity, userInfo, getConfig().getAlias());
|
||||
}
|
||||
}
|
||||
identity.getContextData().put(FEDERATED_ACCESS_TOKEN_RESPONSE, tokenResponse);
|
||||
identity.getContextData().put(VALIDATED_ID_TOKEN, idToken);
|
||||
|
@ -287,6 +290,11 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProvider<OIDCIde
|
|||
}
|
||||
}
|
||||
|
||||
protected String getUserInfoUrl() {
|
||||
return getConfig().getUserInfoUrl();
|
||||
}
|
||||
|
||||
|
||||
private String verifyAccessToken(AccessTokenResponse tokenResponse) {
|
||||
String accessToken = tokenResponse.getToken();
|
||||
|
||||
|
|
|
@ -93,6 +93,15 @@ public class OIDCIdentityProviderConfig extends OAuth2IdentityProviderConfig {
|
|||
getConfig().put("backchannelSupported", String.valueOf(backchannel));
|
||||
}
|
||||
|
||||
public boolean isDisableUserInfoService() {
|
||||
String disableUserInfo = getConfig().get("disableUserInfo");
|
||||
return disableUserInfo == null ? false : Boolean.valueOf(disableUserInfo);
|
||||
}
|
||||
|
||||
public void setDisableUserInfoService(boolean disable) {
|
||||
getConfig().put("disableUserInfo", String.valueOf(disable));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -16,9 +16,12 @@
|
|||
*/
|
||||
package org.keycloak.social.google;
|
||||
|
||||
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||
import org.keycloak.broker.oidc.OIDCIdentityProvider;
|
||||
import org.keycloak.broker.oidc.OIDCIdentityProviderConfig;
|
||||
import org.keycloak.broker.social.SocialIdentityProvider;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.common.util.KeycloakUriBuilder;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
|
@ -31,7 +34,7 @@ public class GoogleIdentityProvider extends OIDCIdentityProvider implements Soci
|
|||
public static final String PROFILE_URL = "https://www.googleapis.com/plus/v1/people/me/openIdConnect";
|
||||
public static final String DEFAULT_SCOPE = "openid profile email";
|
||||
|
||||
public GoogleIdentityProvider(KeycloakSession session, OIDCIdentityProviderConfig config) {
|
||||
public GoogleIdentityProvider(KeycloakSession session, GoogleIdentityProviderConfig config) {
|
||||
super(session, config);
|
||||
config.setAuthorizationUrl(AUTH_URL);
|
||||
config.setTokenUrl(TOKEN_URL);
|
||||
|
@ -42,4 +45,19 @@ public class GoogleIdentityProvider extends OIDCIdentityProvider implements Soci
|
|||
protected String getDefaultScopes() {
|
||||
return DEFAULT_SCOPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getUserInfoUrl() {
|
||||
String uri = super.getUserInfoUrl();
|
||||
if (((GoogleIdentityProviderConfig)getConfig()).isUserIp()) {
|
||||
ClientConnection connection = ResteasyProviderFactory.getContextData(ClientConnection.class);
|
||||
if (connection != null) {
|
||||
uri = KeycloakUriBuilder.fromUri(super.getUserInfoUrl()).queryParam("userIp", connection.getRemoteAddr()).build().toString();
|
||||
}
|
||||
|
||||
}
|
||||
logger.debugv("GOOGLE userInfoUrl: {0}", uri);
|
||||
return uri;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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.social.google;
|
||||
|
||||
import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig;
|
||||
import org.keycloak.broker.oidc.OIDCIdentityProviderConfig;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
|
||||
/**
|
||||
* @author Vlastimil Elias (velias at redhat dot com)
|
||||
*/
|
||||
public class GoogleIdentityProviderConfig extends OIDCIdentityProviderConfig {
|
||||
|
||||
public GoogleIdentityProviderConfig(IdentityProviderModel model) {
|
||||
super(model);
|
||||
}
|
||||
|
||||
public boolean isUserIp() {
|
||||
String userIp = getConfig().get("userIp");
|
||||
return userIp == null ? false : Boolean.valueOf(userIp);
|
||||
}
|
||||
|
||||
public void setUserIp(boolean ip) {
|
||||
getConfig().put("userIp", String.valueOf(ip));
|
||||
}
|
||||
|
||||
}
|
|
@ -36,7 +36,7 @@ public class GoogleIdentityProviderFactory extends AbstractIdentityProviderFacto
|
|||
|
||||
@Override
|
||||
public GoogleIdentityProvider create(KeycloakSession session, IdentityProviderModel model) {
|
||||
return new GoogleIdentityProvider(session, new OIDCIdentityProviderConfig(model));
|
||||
return new GoogleIdentityProvider(session, new GoogleIdentityProviderConfig(model));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -434,6 +434,10 @@ store-tokens=Store Tokens
|
|||
identity-provider.store-tokens.tooltip=Enable/disable if tokens must be stored after authenticating users.
|
||||
stored-tokens-readable=Stored Tokens Readable
|
||||
identity-provider.stored-tokens-readable.tooltip=Enable/disable if new users can read any stored tokens. This assigns the broker.read-token role.
|
||||
disableUserInfo=Disable User Info
|
||||
identity-provider.disableUserInfo.tooltip=Disable usage of User Info service to obtain additional user information? Default is to use this OIDC service.
|
||||
userIp=Use userIp Param
|
||||
identity-provider.google-userIp.tooltip=Set 'userIp' query parameter when invoking on Google's User Info service. This will use the user's ip address. Useful if Google is throttling access to the User Info service.
|
||||
update-profile-on-first-login=Update Profile on First Login
|
||||
on=On
|
||||
on-missing-info=On missing info
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="userIp">{{:: 'userIp' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="identityProvider.config.userIp" id="userIp" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'identity-provider.google-userIp.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
|
@ -64,6 +64,13 @@
|
|||
</div>
|
||||
<kc-tooltip>{{:: 'identity-provider.enabled.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="disableUserInfo">{{:: 'disableUserInfo' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
<input ng-model="identityProvider.config.disableUserInfo" id="disableUserInfo" onoffswitchvalue on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||
</div>
|
||||
<kc-tooltip>{{:: 'identity-provider.disableUserInfo.tooltip' | translate}}</kc-tooltip>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-md-2 control-label" for="trustEmail">{{:: 'trust-email' | translate}}</label>
|
||||
<div class="col-md-6">
|
||||
|
|
Loading…
Reference in a new issue