keycloak-aplcache
Changes
broker/kerberos/pom.xml 34(+34 -0)
broker/kerberos/src/main/java/org/keycloak/broker/kerberos/impl/KerberosServerSubjectAuthenticator.java 66(+66 -0)
broker/kerberos/src/main/java/org/keycloak/broker/kerberos/impl/SPNEGOAuthenticator.java 138(+138 -0)
broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosIdentityProvider.java 127(+127 -0)
broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosIdentityProviderConfig.java 26(+26 -0)
broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosIdentityProviderFactory.java 28(+28 -0)
broker/kerberos/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderFactory 1(+1 -0)
broker/pom.xml 1(+1 -0)
dependencies/server-all/pom.xml 5(+5 -0)
Details
broker/kerberos/pom.xml 34(+34 -0)
diff --git a/broker/kerberos/pom.xml b/broker/kerberos/pom.xml
new file mode 100644
index 0000000..0c69371
--- /dev/null
+++ b/broker/kerberos/pom.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-broker-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.2.0.Beta1-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-broker-kerberos</artifactId>
+ <name>Keycloak Broker Kerberos</name>
+ <description/>
+ <packaging>jar</packaging>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-broker-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>net.iharder</groupId>
+ <artifactId>base64</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/impl/KerberosServerSubjectAuthenticator.java b/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/impl/KerberosServerSubjectAuthenticator.java
new file mode 100644
index 0000000..3384a43
--- /dev/null
+++ b/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/impl/KerberosServerSubjectAuthenticator.java
@@ -0,0 +1,66 @@
+package org.keycloak.broker.kerberos.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.jboss.logging.Logger;
+import org.keycloak.broker.kerberos.KerberosIdentityProviderConfig;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class KerberosServerSubjectAuthenticator {
+
+ private static final Logger logger = Logger.getLogger(KerberosServerSubjectAuthenticator.class);
+
+ private final KerberosIdentityProviderConfig config;
+ private LoginContext loginContext;
+
+ public KerberosServerSubjectAuthenticator(KerberosIdentityProviderConfig config) {
+ this.config = config;
+ }
+
+ public Subject authenticateServerSubject() throws LoginException {
+ Configuration config = createJaasConfiguration();
+ loginContext = new LoginContext("does-not-matter", null, null, config);
+ loginContext.login();
+ return loginContext.getSubject();
+ }
+
+ public void logoutServerSubject() {
+ if (loginContext != null) {
+ try {
+ loginContext.logout();
+ } catch (LoginException le) {
+ logger.error("Failed to logout kerberos server subject: " + config.getServerPrincipal(), le);
+ }
+ }
+ }
+
+ protected Configuration createJaasConfiguration() {
+ return new Configuration() {
+
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+ Map<String, Object> options = new HashMap<String, Object>();
+ options.put("storeKey", "true");
+ options.put("doNotPrompt", "true");
+ options.put("isInitiator", "false");
+ options.put("useKeyTab", "true");
+
+ options.put("keyTab", config.getKeyTab());
+ options.put("principal", config.getServerPrincipal());
+ options.put("debug", String.valueOf(config.getDebug()));
+ AppConfigurationEntry kerberosLMConfiguration = new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, options);
+ return new AppConfigurationEntry[] { kerberosLMConfiguration };
+ }
+ };
+ }
+
+}
diff --git a/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/impl/SPNEGOAuthenticator.java b/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/impl/SPNEGOAuthenticator.java
new file mode 100644
index 0000000..cbac036
--- /dev/null
+++ b/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/impl/SPNEGOAuthenticator.java
@@ -0,0 +1,138 @@
+package org.keycloak.broker.kerberos.impl;
+
+import java.io.IOException;
+import java.security.PrivilegedExceptionAction;
+
+import javax.security.auth.Subject;
+
+import net.iharder.Base64;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSCredential;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.Oid;
+import org.jboss.logging.Logger;
+import org.keycloak.broker.kerberos.KerberosConstants;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class SPNEGOAuthenticator {
+
+ private static final Logger logger = Logger.getLogger(SPNEGOAuthenticator.class);
+
+ private static final GSSManager GSS_MANAGER = GSSManager.getInstance();
+
+ private final KerberosServerSubjectAuthenticator kerberosSubjectAuthenticator;
+ private final String spnegoToken;
+
+ private boolean authenticated = false;
+ private String principal = null;
+ private GSSCredential delegationCredential;
+ private String responseToken = null;
+
+ public SPNEGOAuthenticator(KerberosServerSubjectAuthenticator kerberosSubjectAuthenticator, String spnegoToken) {
+ this.kerberosSubjectAuthenticator = kerberosSubjectAuthenticator;
+ this.spnegoToken = spnegoToken;
+ }
+
+ public void authenticate() {
+ // TODO: debug
+ logger.info("SPNEGO Login with token: " + spnegoToken);
+
+ try {
+ Subject serverSubject = kerberosSubjectAuthenticator.authenticateServerSubject();
+ authenticated = Subject.doAs(serverSubject, new AcceptSecContext());
+ } catch (Exception e) {
+ logger.warn("SPNEGO login failed: " + e.getMessage());
+
+ // TODO: debug and check if it is shown in the log
+ if (logger.isInfoEnabled()) {
+ logger.info("SPNEGO login failed: " + e.getMessage(), e);
+ }
+ } finally {
+ kerberosSubjectAuthenticator.logoutServerSubject();
+ }
+ }
+
+ public boolean isAuthenticated() {
+ return authenticated;
+ }
+
+ public String getPrincipal() {
+ return principal;
+ }
+
+ public String getResponseToken() {
+ return responseToken;
+ }
+
+ public GSSCredential getDelegationCredential() {
+ return delegationCredential;
+ }
+
+ private class AcceptSecContext implements PrivilegedExceptionAction<Boolean> {
+
+ @Override
+ public Boolean run() throws Exception {
+ GSSContext gssContext = null;
+ try {
+ // TODO: debug
+ logger.info("Going to establish security context");
+ gssContext = establishContext();
+ logAuthDetails(gssContext);
+
+ // What should be done with delegation credential? Figure out if there are use-cases for storing it as claims in FederatedIdentity
+ if (gssContext.getCredDelegState()) {
+ delegationCredential = gssContext.getDelegCred();
+ }
+
+ if (gssContext.isEstablished()) {
+ principal = gssContext.getSrcName().toString();
+ return true;
+ } else {
+ return false;
+ }
+ } finally {
+ if (gssContext != null) {
+ gssContext.dispose();
+ }
+ }
+ }
+
+ }
+
+ protected GSSContext establishContext() throws GSSException, IOException {
+ Oid spnegoOid = new Oid(KerberosConstants.SPNEGO_OID);
+ GSSCredential credential = GSS_MANAGER.createCredential(null,
+ GSSCredential.DEFAULT_LIFETIME,
+ spnegoOid,
+ GSSCredential.ACCEPT_ONLY);
+ GSSContext gssContext = GSS_MANAGER.createContext(credential);
+
+ byte[] inputToken = Base64.decode(spnegoToken);
+ byte[] respToken = gssContext.acceptSecContext(inputToken, 0, inputToken.length);
+ responseToken = Base64.encodeBytes(respToken);
+
+ return gssContext;
+ }
+
+ protected void logAuthDetails(GSSContext gssContext) throws GSSException {
+
+ // TODO: debug
+ if (logger.isInfoEnabled()) {
+ String message = new StringBuilder("SPNEGO Security context accepted with token: " + responseToken)
+ .append(", established: " + gssContext.isEstablished())
+ .append(", credDelegState: " + gssContext.getCredDelegState())
+ .append(", mutualAuthState: " + gssContext.getMutualAuthState())
+ .append(", lifetime: " + gssContext.getLifetime())
+ .append(", confState: " + gssContext.getConfState())
+ .append(", integState: " + gssContext.getIntegState())
+ .append(", srcName: " + gssContext.getSrcName())
+ .append(", targName: " + gssContext.getTargName())
+ .toString();
+ logger.info(message);
+ }
+ }
+
+}
diff --git a/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosConstants.java b/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosConstants.java
new file mode 100644
index 0000000..f84cb90
--- /dev/null
+++ b/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosConstants.java
@@ -0,0 +1,25 @@
+package org.keycloak.broker.kerberos;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class KerberosConstants {
+
+ /**
+ * Value of HTTP Headers "WWW-Authenticate" or "Authorization" used for SPNEGO/Kerberos
+ **/
+ public static final String NEGOTIATE = "Negotiate";
+
+
+ /**
+ * Helper parameter for relay state
+ */
+ public static final String RELAY_STATE_PARAM = "RelayState";
+
+
+ /**
+ * OID of SPNEGO mechanism. See http://www.oid-info.com/get/1.3.6.1.5.5.2
+ */
+ public static final String SPNEGO_OID = "1.3.6.1.5.5.2";
+
+}
diff --git a/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosIdentityProvider.java b/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosIdentityProvider.java
new file mode 100644
index 0000000..e2ae6be
--- /dev/null
+++ b/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosIdentityProvider.java
@@ -0,0 +1,127 @@
+package org.keycloak.broker.kerberos;
+
+import java.net.URI;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+
+import org.jboss.logging.Logger;
+import org.keycloak.broker.kerberos.impl.KerberosServerSubjectAuthenticator;
+import org.keycloak.broker.kerberos.impl.SPNEGOAuthenticator;
+import org.keycloak.broker.provider.AbstractIdentityProvider;
+import org.keycloak.broker.provider.AuthenticationRequest;
+import org.keycloak.broker.provider.AuthenticationResponse;
+import org.keycloak.broker.provider.FederatedIdentity;
+import org.keycloak.models.FederatedIdentityModel;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class KerberosIdentityProvider extends AbstractIdentityProvider<KerberosIdentityProviderConfig> {
+
+ private static final Logger logger = Logger.getLogger(KerberosIdentityProvider.class);
+
+ public KerberosIdentityProvider(KerberosIdentityProviderConfig config) {
+ super(config);
+ }
+
+
+ @Override
+ public AuthenticationResponse handleRequest(AuthenticationRequest request) {
+ // TODO: trace
+ logger.info("handleRequest");
+
+ // Just redirect to handleResponse for now
+ URI redirectUri = UriBuilder.fromUri(request.getRedirectUri()).queryParam(KerberosConstants.RELAY_STATE_PARAM, request.getState()).build();
+ Response response = Response.status(302)
+ .location(redirectUri)
+ .build();
+
+ return AuthenticationResponse.fromResponse(response);
+ }
+
+
+ @Override
+ public String getRelayState(AuthenticationRequest request) {
+ UriInfo uriInfo = request.getUriInfo();
+ return uriInfo.getQueryParameters().getFirst(KerberosConstants.RELAY_STATE_PARAM);
+ }
+
+
+ @Override
+ public AuthenticationResponse handleResponse(AuthenticationRequest request) {
+ String authHeader = request.getHttpRequest().getHttpHeaders().getRequestHeaders().getFirst(HttpHeaders.AUTHORIZATION);
+
+ // Case when we don't yet have any Negotiate header
+ if (authHeader == null) {
+ return sendNegotiateResponse(null);
+ }
+
+ String[] tokens = authHeader.split(" ");
+ if (tokens.length != 2) {
+ logger.warn("Invalid length of tokens: " + tokens.length);
+ return sendNegotiateResponse(null);
+ } else if (!KerberosConstants.NEGOTIATE.equalsIgnoreCase(tokens[0])) {
+ logger.warn("Unknown scheme " + tokens[0]);
+ return sendNegotiateResponse(null);
+ } else {
+ String spnegoToken = tokens[1];
+ SPNEGOAuthenticator spnegoAuthenticator = createSPNEGOAuthenticator(spnegoToken);
+ spnegoAuthenticator.authenticate();
+
+ if (spnegoAuthenticator.isAuthenticated()) {
+ FederatedIdentity federatedIdentity = getFederatedIdentity(spnegoAuthenticator);
+ return AuthenticationResponse.end(federatedIdentity);
+ } else {
+ return sendNegotiateResponse(spnegoAuthenticator.getResponseToken());
+ }
+ }
+ }
+
+ protected SPNEGOAuthenticator createSPNEGOAuthenticator(String spnegoToken) {
+ KerberosServerSubjectAuthenticator kerberosAuth = createKerberosSubjectAuthenticator();
+ return new SPNEGOAuthenticator(kerberosAuth, spnegoToken);
+ }
+
+ protected KerberosServerSubjectAuthenticator createKerberosSubjectAuthenticator() {
+ return new KerberosServerSubjectAuthenticator(getConfig());
+ }
+
+
+ /**
+ * Send response with header "WWW-Authenticate: Negotiate {negotiateToken}"
+ *
+ * @param negotiateToken token to be send back in response or null if just "WWW-Authenticate: Negotiate" should be sent
+ * @return AuthenticationResponse
+ */
+ protected AuthenticationResponse sendNegotiateResponse(String negotiateToken) {
+ String negotiateHeader = negotiateToken == null ? KerberosConstants.NEGOTIATE : KerberosConstants.NEGOTIATE + " " + negotiateToken;
+
+ Response response = Response.status(Response.Status.UNAUTHORIZED)
+ .header(HttpHeaders.WWW_AUTHENTICATE, negotiateHeader)
+ .build();
+ return AuthenticationResponse.fromResponse(response);
+ }
+
+
+ protected FederatedIdentity getFederatedIdentity(SPNEGOAuthenticator spnegoAuthenticator) {
+ String kerberosUsername = spnegoAuthenticator.getPrincipal();
+ FederatedIdentity user = new FederatedIdentity(kerberosUsername);
+ user.setUsername(kerberosUsername);
+
+ // Just guessing email, but likely can't do anything better...
+ String[] tokens = kerberosUsername.split("@");
+ String email = tokens[0] + "@" + tokens[1].toLowerCase();
+ user.setEmail(email);
+ return user;
+ }
+
+
+ @Override
+ public Response retrieveToken(FederatedIdentityModel identity) {
+ logger.warn("retrieveToken unsupported for Kerberos right now");
+ return null;
+ }
+}
diff --git a/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosIdentityProviderConfig.java b/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosIdentityProviderConfig.java
new file mode 100644
index 0000000..50dd85a
--- /dev/null
+++ b/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosIdentityProviderConfig.java
@@ -0,0 +1,26 @@
+package org.keycloak.broker.kerberos;
+
+import org.keycloak.models.IdentityProviderModel;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class KerberosIdentityProviderConfig extends IdentityProviderModel {
+
+ public KerberosIdentityProviderConfig(IdentityProviderModel identityProviderModel) {
+ super(identityProviderModel);
+ }
+
+ public String getServerPrincipal() {
+ return getConfig().get("serverPrincipal");
+ }
+
+ public String getKeyTab() {
+ return getConfig().get("keyTab");
+ }
+
+ public boolean getDebug() {
+ return Boolean.valueOf(getConfig().get("debug"));
+ }
+
+}
diff --git a/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosIdentityProviderFactory.java b/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosIdentityProviderFactory.java
new file mode 100644
index 0000000..e99f7d5
--- /dev/null
+++ b/broker/kerberos/src/main/java/org/keycloak/broker/kerberos/KerberosIdentityProviderFactory.java
@@ -0,0 +1,28 @@
+package org.keycloak.broker.kerberos;
+
+import org.keycloak.broker.kerberos.KerberosIdentityProvider;
+import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
+import org.keycloak.models.IdentityProviderModel;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class KerberosIdentityProviderFactory extends AbstractIdentityProviderFactory<KerberosIdentityProvider> {
+
+ public static final String PROVIDER_ID = "kerberos";
+
+ @Override
+ public String getId() {
+ return PROVIDER_ID;
+ }
+
+ @Override
+ public String getName() {
+ return "Kerberos";
+ }
+
+ @Override
+ public KerberosIdentityProvider create(IdentityProviderModel model) {
+ return new KerberosIdentityProvider(new KerberosIdentityProviderConfig(model));
+ }
+}
diff --git a/broker/kerberos/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderFactory b/broker/kerberos/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderFactory
new file mode 100644
index 0000000..4c72cb8
--- /dev/null
+++ b/broker/kerberos/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderFactory
@@ -0,0 +1 @@
+org.keycloak.broker.kerberos.KerberosIdentityProviderFactory
\ No newline at end of file
broker/pom.xml 1(+1 -0)
diff --git a/broker/pom.xml b/broker/pom.xml
index 7121b2b..e2ae6ff 100755
--- a/broker/pom.xml
+++ b/broker/pom.xml
@@ -18,6 +18,7 @@
<module>core</module>
<module>oidc</module>
<module>saml</module>
+ <module>kerberos</module>
</modules>
</project>
dependencies/server-all/pom.xml 5(+5 -0)
diff --git a/dependencies/server-all/pom.xml b/dependencies/server-all/pom.xml
index 5d5576b..c2546e8 100755
--- a/dependencies/server-all/pom.xml
+++ b/dependencies/server-all/pom.xml
@@ -95,6 +95,11 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
+ <artifactId>keycloak-broker-kerberos</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
<artifactId>keycloak-social-github</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
index 98a6e6b..4971ee1 100755
--- a/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/js/controllers/realm.js
@@ -785,6 +785,14 @@ module.controller('RealmIdentityProviderCtrl', function($scope, $filter, $upload
$scope.identityProvider.config.postBindingResponse = true;
}
}
+
+ $scope.initKerberosProvider = function() {
+ if (instance && instance.id) {
+ $scope.identityProvider.config.debug = $scope.getBoolean($scope.identityProvider.config.debug);
+ } else {
+ $scope.identityProvider.config.debug = false;
+ }
+ }
});
module.controller('RealmTokenDetailCtrl', function($scope, Realm, realm, $http, $location, $route, Dialog, Notifications, TimeUnit) {
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-kerberos.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-kerberos.html
new file mode 100644
index 0000000..489628a
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-kerberos.html
@@ -0,0 +1,71 @@
+<div class="bs-sidebar col-sm-3 " data-ng-include data-src="'partials/realm-menu.html'"></div>
+<div id="content-area" class="col-sm-9" role="main" data-ng-init="initKerberosProvider()">
+ <data-kc-navigation data-kc-current="social" data-kc-realm="realm.realm" data-kc-social="realm.social"></data-kc-navigation>
+ <h2></h2>
+ <div id="content">
+ <ol class="breadcrumb">
+ <li><a href="#/realms/{{realm.realm}}/identity-provider-settings">Identity Providers</a></li>
+ <li class="active">{{identityProvider.name}} Provider Settings</li>
+ </ol>
+ <h2 class="pull-left">{{identityProvider.name}} Provider Settings</h2>
+ <p class="subtitle"><span class="required">*</span> Required fields</p>
+ <form class="form-horizontal" name="realmForm" novalidate>
+ <fieldset>
+ <div class="form-group clearfix">
+ <label class="col-sm-2 control-label" for="identifier">Alias <span class="required">*</span></label>
+ <div class="col-sm-4">
+ <input class="form-control" id="identifier" type="text" ng-model="identityProvider.id" required>
+ </div>
+ <span tooltip-placement="right" tooltip="The alias unique identifies an identity provider and it is also used to build the redirect uri." class="fa fa-info-circle"></span>
+ </div>
+ <div class="form-group clearfix">
+ <label class="col-sm-2 control-label" for="name">Name <span class="required">*</span></label>
+ <div class="col-sm-4">
+ <input class="form-control" id="name" type="text" ng-model="identityProvider.name" required>
+ </div>
+ <span tooltip-placement="right" tooltip="The friendly name for this identity provider." class="fa fa-info-circle"></span>
+ </div>
+ <div class="form-group clearfix">
+ <label class="col-sm-2 control-label" for="serverPrincipal">Server principal <span class="required">*</span></label>
+ <div class="col-sm-4">
+ <input class="form-control" id="serverPrincipal" type="text" ng-model="identityProvider.config.serverPrincipal" required>
+ </div>
+ <span tooltip-placement="right" tooltip="Full name of server principal for HTTP service including server and domain name. For example HTTP/host.foo.org@FOO.ORG" class="fa fa-info-circle"></span>
+ </div>
+ <div class="form-group clearfix">
+ <label class="col-sm-2 control-label" for="keyTab">KeyTab <span class="required">*</span></label>
+ <div class="col-sm-4">
+ <input class="form-control" id="keyTab" type="text" ng-model="identityProvider.config.keyTab" required>
+ </div>
+ <span tooltip-placement="right" tooltip="Location of Kerberos KeyTab file containing the credentials of server principal. For example /etc/krb5.keytab" class="fa fa-info-circle"></span>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="debug">Debug </label>
+ <div class="col-sm-4">
+ <input ng-model="identityProvider.config.debug" id="debug" onoffswitch />
+ </div>
+ <span tooltip-placement="right" tooltip="Enable/disable debug logging to standard output for Krb5LoginModule." class="fa fa-info-circle"></span>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="enabled">Enabled</label>
+ <div class="col-sm-4">
+ <input ng-model="identityProvider.enabled" id="enabled" onoffswitch />
+ </div>
+ <span tooltip-placement="right" tooltip="Enable/disable this identity provider." class="fa fa-info-circle"></span>
+ </div>
+ <div class="form-group">
+ <label class="col-sm-2 control-label" for="updateProfileFirstLogin">Update Profile on First Login</label>
+ <div class="col-sm-4">
+ <input ng-model="identityProvider.updateProfileFirstLogin" name="identityProvider.updateProfileFirstLogin" id="updateProfileFirstLogin" onoffswitch />
+ </div>
+ <span tooltip-placement="right" tooltip="Indicates if user must update his profile right after the first login." class="fa fa-info-circle"></span>
+ </div>
+ </fieldset>
+
+ <div class="pull-right form-actions">
+ <button kc-save>Save</button>
+ <button kc-delete data-ng-click="remove()" data-ng-show="!newIdentityProvider">Delete</button>
+ </div>
+ </form>
+ </div>
+</div>
diff --git a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
index 9cfcead..f6e428f 100755
--- a/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
+++ b/model/api/src/main/java/org/keycloak/models/entities/ClientEntity.java
@@ -27,7 +27,7 @@ public class ClientEntity extends AbstractIdentifiableEntity {
private List<String> webOrigins = new ArrayList<String>();
private List<String> redirectUris = new ArrayList<String>();
private List<String> scopeIds = new ArrayList<String>();
- private List<String> allowedIdentityProviders;
+ private List<String> allowedIdentityProviders = new ArrayList<String>();
public String getName() {
return name;
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index 00b45ba..70b3ebb 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -679,11 +679,10 @@ public class AccountService {
try {
ClientSessionModel clientSession = auth.getClientSession();
- clientSession.setAction(ClientSessionModel.Action.AUTHENTICATE);
+ ClientSessionCode clientSessionCode = new ClientSessionCode(realm, clientSession);
+ clientSessionCode.setAction(ClientSessionModel.Action.AUTHENTICATE);
clientSession.setRedirectUri(redirectUri);
clientSession.setNote(OpenIDConnect.STATE_PARAM, UUID.randomUUID().toString());
- clientSession.setNote(ClientSessionCode.ACTION_KEY, KeycloakModelUtils.generateCodeSecret());
- ClientSessionCode clientSessionCode = new ClientSessionCode(realm, clientSession);
URI url = UriBuilder.fromUri(this.uriInfo.getBaseUri())
.path(AuthenticationBrokerResource.class)