Adds Openshift Identity Provider as part of social brokers

This commit is contained in:
Bartosz Majsak 2017-03-02 15:04:33 +01:00
parent b8767d13d5
commit 1a6bb2fedb
8 changed files with 155 additions and 0 deletions

View file

@ -0,0 +1,20 @@
package org.keycloak.social.openshift;
import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig;
import org.keycloak.models.IdentityProviderModel;
public class OpenshifV3IdentityProviderConfig extends OAuth2IdentityProviderConfig {
private static final String BASE_URL = "baseUrl";
public OpenshifV3IdentityProviderConfig(IdentityProviderModel identityProviderModel) {
super(identityProviderModel);
}
public String getBaseUrl() {
return getConfig().get(BASE_URL);
}
public void setBaseUrl(String baseUrl) {
getConfig().put(BASE_URL, baseUrl);
}
}

View file

@ -0,0 +1,66 @@
package org.keycloak.social.openshift;
import com.fasterxml.jackson.databind.JsonNode;
import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider;
import org.keycloak.broker.oidc.mappers.AbstractJsonUserAttributeMapper;
import org.keycloak.broker.oidc.util.JsonSimpleHttp;
import org.keycloak.broker.provider.BrokeredIdentityContext;
import org.keycloak.broker.provider.IdentityBrokerException;
import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.broker.social.SocialIdentityProvider;
import org.keycloak.models.KeycloakSession;
import java.io.IOException;
import java.util.Optional;
/**
* Identity provider for Openshift V3. Check <a href="https://docs.openshift.com/enterprise/3.0/architecture/additional_concepts/authentication.html">official documentation</a> for more details.
*/
public class OpenshiftV3IdentityProvider extends AbstractOAuth2IdentityProvider<OpenshifV3IdentityProviderConfig> implements SocialIdentityProvider<OpenshifV3IdentityProviderConfig> {
public static final String BASE_URL = "https://api.preview.openshift.com";
private static final String AUTH_RESOURCE = "/oauth/authorize";
private static final String TOKEN_RESOURCE = "/oauth/token";
private static final String PROFILE_RESOURCE = "/oapi/v1/users/~";
private static final String DEFAULT_SCOPE = "user:info";
public OpenshiftV3IdentityProvider(KeycloakSession session, OpenshifV3IdentityProviderConfig config) {
super(session, config);
final String baseUrl = Optional.ofNullable(config.getBaseUrl()).orElse(BASE_URL);
config.setAuthorizationUrl(baseUrl + AUTH_RESOURCE);
config.setTokenUrl(baseUrl + TOKEN_RESOURCE);
config.setUserInfoUrl(baseUrl + PROFILE_RESOURCE);
}
@Override
protected String getDefaultScopes() {
return DEFAULT_SCOPE;
}
@Override
protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) {
try {
final JsonNode profile = fetchProfile(accessToken);
final BrokeredIdentityContext user = extractUserContext(profile.get("metadata"));
AbstractJsonUserAttributeMapper.storeUserProfileForMapper(user, profile, getConfig().getAlias());
return user;
} catch (Exception e) {
throw new IdentityBrokerException("Could not obtain user profile from Openshift.", e);
}
}
private BrokeredIdentityContext extractUserContext(JsonNode metadata) {
final BrokeredIdentityContext user = new BrokeredIdentityContext(getJsonProperty(metadata, "uid"));
user.setUsername(getJsonProperty(metadata, "name"));
user.setName(getJsonProperty(metadata, "fullName"));
user.setIdpConfig(getConfig());
user.setIdp(this);
return user;
}
private JsonNode fetchProfile(String accessToken) throws IOException {
return JsonSimpleHttp.asJson(SimpleHttp.doGet(getConfig().getUserInfoUrl())
.header("Authorization", "Bearer " + accessToken));
}
}

View file

@ -0,0 +1,27 @@
package org.keycloak.social.openshift;
import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
import org.keycloak.broker.social.SocialIdentityProviderFactory;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.KeycloakSession;
public class OpenshiftV3IdentityProviderFactory extends AbstractIdentityProviderFactory<OpenshiftV3IdentityProvider> implements SocialIdentityProviderFactory<OpenshiftV3IdentityProvider> {
public static final String PROVIDER_ID = "openshift-v3";
@Override
public String getName() {
return "Openshift v3";
}
@Override
public OpenshiftV3IdentityProvider create(KeycloakSession keycloakSession, IdentityProviderModel identityProviderModel) {
return new OpenshiftV3IdentityProvider(keycloakSession, new OpenshifV3IdentityProviderConfig(identityProviderModel));
}
@Override
public String getId() {
return PROVIDER_ID;
}
}

View file

@ -22,3 +22,4 @@ org.keycloak.social.linkedin.LinkedInIdentityProviderFactory
org.keycloak.social.stackoverflow.StackoverflowIdentityProviderFactory
org.keycloak.social.twitter.TwitterIdentityProviderFactory
org.keycloak.social.microsoft.MicrosoftIdentityProviderFactory
org.keycloak.social.openshift.OpenshiftV3IdentityProviderFactory

View file

@ -37,6 +37,9 @@ import org.keycloak.social.google.GoogleIdentityProvider;
import org.keycloak.social.google.GoogleIdentityProviderFactory;
import org.keycloak.social.linkedin.LinkedInIdentityProvider;
import org.keycloak.social.linkedin.LinkedInIdentityProviderFactory;
import org.keycloak.social.openshift.OpenshifV3IdentityProviderConfig;
import org.keycloak.social.openshift.OpenshiftV3IdentityProvider;
import org.keycloak.social.openshift.OpenshiftV3IdentityProviderFactory;
import org.keycloak.social.stackoverflow.StackOverflowIdentityProviderConfig;
import org.keycloak.social.stackoverflow.StackoverflowIdentityProvider;
import org.keycloak.social.stackoverflow.StackoverflowIdentityProviderFactory;
@ -146,6 +149,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertLinkedInIdentityProviderConfig(identityProvider);
} else if (StackoverflowIdentityProviderFactory.PROVIDER_ID.equals(providerId)) {
assertStackoverflowIdentityProviderConfig(identityProvider);
} else if (OpenshiftV3IdentityProviderFactory.PROVIDER_ID.equals(providerId)) {
assertOpenshiftIdentityProviderConfig(identityProvider);
} else {
continue;
}
@ -283,6 +288,21 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
assertEquals(StackoverflowIdentityProvider.PROFILE_URL, config.getUserInfoUrl());
}
private void assertOpenshiftIdentityProviderConfig(IdentityProviderModel identityProvider) {
OpenshiftV3IdentityProvider osoIdentityProvider = new OpenshiftV3IdentityProviderFactory().create(session, identityProvider);
OpenshifV3IdentityProviderConfig config = osoIdentityProvider.getConfig();
assertEquals("model-openshift-v3", config.getAlias());
assertEquals(OpenshiftV3IdentityProviderFactory.PROVIDER_ID, config.getProviderId());
assertEquals(true, config.isEnabled());
assertEquals(false, config.isTrustEmail());
assertEquals(false, config.isAuthenticateByDefault());
assertEquals(true, config.isStoreToken());
assertEquals(OpenshiftV3IdentityProvider.BASE_URL, config.getBaseUrl());
assertEquals("clientId", config.getClientId());
assertEquals("clientSecret", config.getClientSecret());
}
private void assertTwitterIdentityProviderConfig(IdentityProviderModel identityProvider) {
TwitterIdentityProvider twitterIdentityProvider = new TwitterIdentityProviderFactory().create(session, identityProvider);
OAuth2IdentityProviderConfig config = twitterIdentityProvider.getConfig();

View file

@ -91,6 +91,20 @@
"clientSecret": "clientSecret"
}
},
{
"alias" : "model-openshift-v3",
"providerId" : "openshift-v3",
"enabled": true,
"storeToken": true,
"config": {
"baseUrl": "https://api.preview.openshift.com",
"authorizationUrl": "authorizationUrl",
"tokenUrl": "tokenUrl",
"userInfoUrl": "userInfoUrl",
"clientId": "clientId",
"clientSecret": "clientSecret"
}
},
{
"alias" : "model-saml-signed-idp",
"providerId" : "saml",

View file

@ -0,0 +1,6 @@
<div class="form-group clearfix">
<label class="col-md-2 control-label" for="baseUrl"><span class="required">*</span> {{:: 'Base URL' | translate}}</label>
<div class="col-md-6">
<input class="form-control" id="baseUrl" type="text" ng-model="identityProvider.config.baseUrl" required>
</div>
</div>

View file

@ -0,0 +1 @@
<div data-ng-include data-src="resourceUrl + '/partials/realm-identity-provider-social.html'"></div>