Display error page if kerberos token is unavailable
This commit is contained in:
parent
07bda93b81
commit
4b637036ac
9 changed files with 48 additions and 20 deletions
|
@ -2,10 +2,10 @@
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<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">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-broker-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.2.0.Beta1-SNAPSHOT</version>
|
<version>1.2.0.Beta1-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.broker.provider;
|
||||||
|
|
||||||
import org.jboss.resteasy.spi.HttpRequest;
|
import org.jboss.resteasy.spi.HttpRequest;
|
||||||
import org.keycloak.models.ClientSessionModel;
|
import org.keycloak.models.ClientSessionModel;
|
||||||
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
@ -28,6 +29,7 @@ import javax.ws.rs.core.UriInfo;
|
||||||
*/
|
*/
|
||||||
public class AuthenticationRequest {
|
public class AuthenticationRequest {
|
||||||
|
|
||||||
|
private final KeycloakSession session;
|
||||||
private final UriInfo uriInfo;
|
private final UriInfo uriInfo;
|
||||||
private final String state;
|
private final String state;
|
||||||
private final HttpRequest httpRequest;
|
private final HttpRequest httpRequest;
|
||||||
|
@ -35,7 +37,8 @@ public class AuthenticationRequest {
|
||||||
private final String redirectUri;
|
private final String redirectUri;
|
||||||
private final ClientSessionModel clientSession;
|
private final ClientSessionModel clientSession;
|
||||||
|
|
||||||
public AuthenticationRequest(RealmModel realm, ClientSessionModel clientSession, HttpRequest httpRequest, UriInfo uriInfo, String state, String redirectUri) {
|
public AuthenticationRequest(KeycloakSession session, RealmModel realm, ClientSessionModel clientSession, HttpRequest httpRequest, UriInfo uriInfo, String state, String redirectUri) {
|
||||||
|
this.session = session;
|
||||||
this.realm = realm;
|
this.realm = realm;
|
||||||
this.httpRequest = httpRequest;
|
this.httpRequest = httpRequest;
|
||||||
this.uriInfo = uriInfo;
|
this.uriInfo = uriInfo;
|
||||||
|
@ -44,6 +47,10 @@ public class AuthenticationRequest {
|
||||||
this.clientSession = clientSession;
|
this.clientSession = clientSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public KeycloakSession getSession() {
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
public UriInfo getUriInfo() {
|
public UriInfo getUriInfo() {
|
||||||
return this.uriInfo;
|
return this.uriInfo;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<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">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-broker-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.2.0.Beta1-SNAPSHOT</version>
|
<version>1.2.0.Beta1-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
@ -20,6 +20,11 @@
|
||||||
<artifactId>keycloak-broker-core</artifactId>
|
<artifactId>keycloak-broker-core</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-login-api</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jboss.logging</groupId>
|
<groupId>org.jboss.logging</groupId>
|
||||||
<artifactId>jboss-logging</artifactId>
|
<artifactId>jboss-logging</artifactId>
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.keycloak.broker.kerberos;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
import javax.ws.rs.core.HttpHeaders;
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
@ -14,6 +15,7 @@ import org.keycloak.broker.provider.AbstractIdentityProvider;
|
||||||
import org.keycloak.broker.provider.AuthenticationRequest;
|
import org.keycloak.broker.provider.AuthenticationRequest;
|
||||||
import org.keycloak.broker.provider.AuthenticationResponse;
|
import org.keycloak.broker.provider.AuthenticationResponse;
|
||||||
import org.keycloak.broker.provider.FederatedIdentity;
|
import org.keycloak.broker.provider.FederatedIdentity;
|
||||||
|
import org.keycloak.login.LoginFormsProvider;
|
||||||
import org.keycloak.models.FederatedIdentityModel;
|
import org.keycloak.models.FederatedIdentityModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,16 +56,16 @@ public class KerberosIdentityProvider extends AbstractIdentityProvider<KerberosI
|
||||||
|
|
||||||
// Case when we don't yet have any Negotiate header
|
// Case when we don't yet have any Negotiate header
|
||||||
if (authHeader == null) {
|
if (authHeader == null) {
|
||||||
return sendNegotiateResponse(null);
|
return sendNegotiateResponse(request, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] tokens = authHeader.split(" ");
|
String[] tokens = authHeader.split(" ");
|
||||||
if (tokens.length != 2) {
|
if (tokens.length != 2) {
|
||||||
logger.warn("Invalid length of tokens: " + tokens.length);
|
logger.warn("Invalid length of tokens: " + tokens.length);
|
||||||
return sendNegotiateResponse(null);
|
return sendNegotiateResponse(request, null);
|
||||||
} else if (!KerberosConstants.NEGOTIATE.equalsIgnoreCase(tokens[0])) {
|
} else if (!KerberosConstants.NEGOTIATE.equalsIgnoreCase(tokens[0])) {
|
||||||
logger.warn("Unknown scheme " + tokens[0]);
|
logger.warn("Unknown scheme " + tokens[0]);
|
||||||
return sendNegotiateResponse(null);
|
return sendNegotiateResponse(request, null);
|
||||||
} else {
|
} else {
|
||||||
String spnegoToken = tokens[1];
|
String spnegoToken = tokens[1];
|
||||||
SPNEGOAuthenticator spnegoAuthenticator = createSPNEGOAuthenticator(spnegoToken);
|
SPNEGOAuthenticator spnegoAuthenticator = createSPNEGOAuthenticator(spnegoToken);
|
||||||
|
@ -73,7 +75,7 @@ public class KerberosIdentityProvider extends AbstractIdentityProvider<KerberosI
|
||||||
FederatedIdentity federatedIdentity = getFederatedIdentity(spnegoAuthenticator);
|
FederatedIdentity federatedIdentity = getFederatedIdentity(spnegoAuthenticator);
|
||||||
return AuthenticationResponse.end(federatedIdentity);
|
return AuthenticationResponse.end(federatedIdentity);
|
||||||
} else {
|
} else {
|
||||||
return sendNegotiateResponse(spnegoAuthenticator.getResponseToken());
|
return sendNegotiateResponse(request, spnegoAuthenticator.getResponseToken());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,16 +96,22 @@ public class KerberosIdentityProvider extends AbstractIdentityProvider<KerberosI
|
||||||
* @param negotiateToken token to be send back in response or null if just "WWW-Authenticate: Negotiate" should be sent
|
* @param negotiateToken token to be send back in response or null if just "WWW-Authenticate: Negotiate" should be sent
|
||||||
* @return AuthenticationResponse
|
* @return AuthenticationResponse
|
||||||
*/
|
*/
|
||||||
protected AuthenticationResponse sendNegotiateResponse(String negotiateToken) {
|
protected AuthenticationResponse sendNegotiateResponse(AuthenticationRequest request, String negotiateToken) {
|
||||||
String negotiateHeader = negotiateToken == null ? KerberosConstants.NEGOTIATE : KerberosConstants.NEGOTIATE + " " + negotiateToken;
|
String negotiateHeader = negotiateToken == null ? KerberosConstants.NEGOTIATE : KerberosConstants.NEGOTIATE + " " + negotiateToken;
|
||||||
|
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("Sending back " + HttpHeaders.WWW_AUTHENTICATE + ": " + negotiateHeader);
|
logger.trace("Sending back " + HttpHeaders.WWW_AUTHENTICATE + ": " + negotiateHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
Response response = Response.status(Response.Status.UNAUTHORIZED)
|
// Error page is rendered just if browser is unable to send Authorization header with SPNEGO token
|
||||||
.header(HttpHeaders.WWW_AUTHENTICATE, negotiateHeader)
|
Response response = request.getSession().getProvider(LoginFormsProvider.class)
|
||||||
.build();
|
.setRealm(request.getRealm())
|
||||||
|
.setUriInfo(request.getUriInfo())
|
||||||
|
.setError("errorKerberosLogin")
|
||||||
|
.setStatus(Response.Status.UNAUTHORIZED)
|
||||||
|
.createErrorPage();
|
||||||
|
|
||||||
|
response.getMetadata().putSingle(HttpHeaders.WWW_AUTHENTICATE, negotiateHeader);
|
||||||
return AuthenticationResponse.fromResponse(response);
|
return AuthenticationResponse.fromResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<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">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-broker-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.2.0.Beta1-SNAPSHOT</version>
|
<version>1.2.0.Beta1-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<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">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>keycloak-broker-parent</artifactId>
|
<artifactId>keycloak-parent</artifactId>
|
||||||
<groupId>org.keycloak</groupId>
|
<groupId>org.keycloak</groupId>
|
||||||
<version>1.2.0.Beta1-SNAPSHOT</version>
|
<version>1.2.0.Beta1-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,8 @@ actionPasswordWarning=You need to change your password to activate your account.
|
||||||
actionEmailWarning=You need to verify your email address to activate your account.
|
actionEmailWarning=You need to verify your email address to activate your account.
|
||||||
actionFollow=Please fill in the fields below.
|
actionFollow=Please fill in the fields below.
|
||||||
|
|
||||||
|
errorKerberosLogin=Unable to login with Kerberos
|
||||||
|
|
||||||
successHeader=Success!
|
successHeader=Success!
|
||||||
errorHeader=Error!
|
errorHeader=Error!
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
||||||
|
|
||||||
private String message;
|
private String message;
|
||||||
private String accessCode;
|
private String accessCode;
|
||||||
private Response.Status status = Response.Status.OK;
|
private Response.Status status;
|
||||||
private List<RoleModel> realmRolesRequested;
|
private List<RoleModel> realmRolesRequested;
|
||||||
private MultivaluedMap<String, RoleModel> resourceRolesRequested;
|
private MultivaluedMap<String, RoleModel> resourceRolesRequested;
|
||||||
private MultivaluedMap<String, String> queryParams;
|
private MultivaluedMap<String, String> queryParams;
|
||||||
|
@ -218,6 +218,10 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status == null) {
|
||||||
|
status = Response.Status.OK;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String result = freeMarker.processTemplate(attributes, Templates.getTemplate(page), theme);
|
String result = freeMarker.processTemplate(attributes, Templates.getTemplate(page), theme);
|
||||||
Response.ResponseBuilder builder = Response.status(status).type(MediaType.TEXT_HTML).entity(result);
|
Response.ResponseBuilder builder = Response.status(status).type(MediaType.TEXT_HTML).entity(result);
|
||||||
|
@ -246,7 +250,9 @@ public class FreeMarkerLoginFormsProvider implements LoginFormsProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response createErrorPage() {
|
public Response createErrorPage() {
|
||||||
setStatus(Response.Status.INTERNAL_SERVER_ERROR);
|
if (status == null) {
|
||||||
|
status = Response.Status.INTERNAL_SERVER_ERROR;
|
||||||
|
}
|
||||||
return createResponse(LoginFormsPages.ERROR);
|
return createResponse(LoginFormsPages.ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -422,7 +422,7 @@ public class AuthenticationBrokerResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
private AuthenticationRequest createAuthenticationRequest(String providerId, String code, RealmModel realm, ClientSessionModel clientSession) {
|
private AuthenticationRequest createAuthenticationRequest(String providerId, String code, RealmModel realm, ClientSessionModel clientSession) {
|
||||||
return new AuthenticationRequest(realm, clientSession, this.request, this.uriInfo, code, getRedirectUri(providerId, realm));
|
return new AuthenticationRequest(this.session, realm, clientSession, this.request, this.uriInfo, code, getRedirectUri(providerId, realm));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getRedirectUri(String providerId, RealmModel realm) {
|
private String getRedirectUri(String providerId, RealmModel realm) {
|
||||||
|
|
Loading…
Reference in a new issue