[keycloak-dev] Putting a value into a custom Protocol mapper
Chris Smith
chris.smith at cmfirstgroup.com
Wed Jun 19 12:12:22 EDT 2019
OK, I have an ugly hack. I hope someone might have a suggestion more aligned with Keycloak architecture
My hack is to use a ThreadLocal to hold the serialized Kerberos ticket in the LDAPStorageProvider
public static final String KERBEROS_NOT_SET = "*NOT_SET";
public static final ThreadLocal<String> SERILIZED_KERBEROS_TICKET = new ThreadLocal<String>() {
@Override
protected String initialValue() {
return KERBEROS_NOT_SET;
}
};
public boolean validPassword(RealmModel realm, UserModel user, String password) {
if (kerberosConfig.isAllowKerberosAuthentication() && kerberosConfig.isUseKerberosForPasswordAuthentication()) {
// Use Kerberos JAAS (Krb5LoginModule)
KerberosUsernamePasswordAuthenticator authenticator = factory.createKerberosUsernamePasswordAuthenticator(kerberosConfig);
boolean isValid = authenticator.validUser(user.getUsername(), password);
if (isValid) {
SERILIZED_KERBEROS_TICKET.set(authenticator.getSerializedKerberosTicket());
}
return isValid;
} else {
// Use Naming LDAP API
...
And in the UsernamePasswordForm
1: override the validate password method
2: write the serialized ticket as a user session note to the AuthenticationFlowContext.
@Override
public boolean validatePassword(AuthenticationFlowContext context, UserModel user,
MultivaluedMap<String, String> inputData) {
boolean isValid = super.validatePassword(context, user, inputData);
if (isValid) {
saveKerbTicketClaim(context);
}
return isValid;
}
private void saveKerbTicketClaim(AuthenticationFlowContext context) {
String kerbTicket = LDAPStorageProvider.SERILIZED_KERBEROS_TICKET.get();
if (!kerbTicket.equals(LDAPStorageProvider.KERBEROS_NOT_SET)) {
context.getAuthenticationSession()
.setUserSessionNote(KerberosConstants.GSS_DELEGATION_CREDENTIAL, kerbTicket);
}
LDAPStorageProvider.SERILIZED_KERBEROS_TICKET.remove();
return;
}
This is bad, but it works for now until someone can point out to me what I missed.
-----Original Message-----
From: keycloak-dev-bounces at lists.jboss.org <keycloak-dev-bounces at lists.jboss.org> On Behalf Of Chris Smith
Sent: Monday, June 17, 2019 5:38 PM
To: keycloak-dev at lists.jboss.org; Marek Posolda <mposolda at redhat.com>
Subject: Re: [keycloak-dev] Putting a value into a custom Protocol mapper
correction
From: Chris Smith
Sent: Monday, June 17, 2019 5:15 PM
To: keycloak-dev at lists.jboss.org; Marek Posolda <mposolda at redhat.com>
Subject: RE: Putting a value into a custom Protocol mapper
I really need some help here
I can not find out how to add a Claim after a successful Kerberos User/Password login
This is as far as I know what is going on.
This is in the LDAPStorageProvider class. The KerberosUsernamePasswordAuthenticator has been updated to hold the serialized Kerberos ticket. I now need to put this somewhere/somehow so that my custom Protocol mapper will put it into the Access Token
public boolean validPassword(RealmModel realm, UserModel user, String password) {
if (kerberosConfig.isAllowKerberosAuthentication() && kerberosConfig.isUseKerberosForPasswordAuthentication()) {
// Use Kerberos JAAS (Krb5LoginModule)
Map<String, String> state = new HashMap<>();
KerberosUsernamePasswordAuthenticator authenticator = factory.createKerberosUsernamePasswordAuthenticator(kerberosConfig);
boolean isValidUser = authenticator.validUser(user.getUsername(), password);
if (isValidUser) {
String delegationCredential = authenticator.getSerializedKerberosTicket();
if (delegationCredential != null) {
state.put("odic-fms-sso-kerberos-ticket-mapper", delegationCredential);
}
<< WHAT GOES HERE?? >>
return isValidUser;
This is from my servlet
KeycloakPrincipal<KeycloakSecurityContext> kcp = (KeycloakPrincipal<KeycloakSecurityContext>)request.getUserPrincipal();
AccessToken at = kcp.getKeycloakSecurityContext().getToken();
Map<String, Object> otherClaims = at.getOtherClaims();
String otherClaim = (String)otherClaims.get("odic-fms-sso-kerberos-ticket-mapper");
GSSCredential gssCredential = KerberosSerializationUtils.deserializeCredential(otherClaim);
From: Chris Smith
Sent: Friday, June 14, 2019 4:24 PM
To: keycloak-dev at lists.jboss.org<mailto:keycloak-dev at lists.jboss.org>
Subject: Putting a value into a custom Protocol mapper
I'm trying to have a custom protocol mapper provide a serialized Kerberos ticket as a claim
I have updated the KerberosUsernamePasswordAuthenticator so that it gets the ticket
public Subject authenticateSubject(String username, String password) throws LoginException {
String principal = getKerberosPrincipal(username);
logger.debug("Validating password of principal: " + principal);
loginContext = new LoginContext("does-not-matter", null,
createJaasCallbackHandler(principal, password),
createJaasConfiguration());
loginContext.login();
serializedKerberosTicket = serializeTicket();
logger.debug("Principal " + principal + " authenticated succesfully");
return loginContext.getSubject();
}
private String serializeTicket() {
KerberosTicket kerberosTicket = loginContext.getSubject()
.getPrivateCredentials(KerberosTicket.class)
.stream().findFirst().get();
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)){
oos.writeObject(kerberosTicket);
return Base64.getEncoder().encodeToString(bos.toByteArray());
} catch (IOException e) {
logger.error("Kerberos ticket serialization failed", e);
return null;
}
}
I reviewed the SPNEGOAuthenticator and traced it's execution to see how it adds the Kerberos ticket and I do not see that as a workable approach as it is so different from the Kerberos User/Password authenticator.
Where can my custom KerberosUsernamePasswordAuthenticator put the serialized ticket so that my custom protocol mapper will get it and add it as a claim on my Access token?
I have looked and googled with no luck.
_______________________________________________
keycloak-dev mailing list
keycloak-dev at lists.jboss.org
https://lists.jboss.org/mailman/listinfo/keycloak-dev
More information about the keycloak-dev
mailing list