fix other claims in IDToken

This commit is contained in:
Bill Burke 2015-03-04 20:27:06 -05:00
parent 453ef808cc
commit 98831ec05a
15 changed files with 692 additions and 403 deletions

View file

@ -0,0 +1,76 @@
package org.keycloak.representations;
import org.codehaus.jackson.annotate.JsonProperty;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
public class AddressClaimSet {
@JsonProperty("formatted")
protected String formattedAddress;
@JsonProperty("street_address")
protected String streetAddress;
@JsonProperty("locality")
protected String locality;
@JsonProperty("region")
protected String region;
@JsonProperty("postal_code")
protected String postalCode;
@JsonProperty("country")
protected String country;
public String getFormattedAddress() {
return this.formattedAddress;
}
public void setFormattedAddress(String formattedAddress) {
this.formattedAddress = formattedAddress;
}
public String getStreetAddress() {
return this.streetAddress;
}
public void setStreetAddress(String streetAddress) {
this.streetAddress = streetAddress;
}
public String getLocality() {
return this.locality;
}
public void setLocality(String locality) {
this.locality = locality;
}
public String getRegion() {
return this.region;
}
public void setRegion(String region) {
this.region = region;
}
public String getPostalCode() {
return this.postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public String getCountry() {
return this.country;
}
public void setCountry(String country) {
this.country = country;
}
}

View file

@ -13,15 +13,73 @@ import java.util.Map;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class IDToken extends JsonWebToken { public class IDToken extends JsonWebToken {
// NOTE!!! WE used to use @JsonUnwrapped on a UserClaimSet object. This screws up otherClaims and the won't work
// anymore. So don't have any @JsonUnwrapped!
@JsonProperty("nonce") @JsonProperty("nonce")
protected String nonce; protected String nonce;
@JsonProperty("session_state") @JsonProperty("session_state")
protected String sessionState; protected String sessionState;
@JsonUnwrapped @JsonProperty("name")
protected UserClaimSet userClaimSet = new UserClaimSet(); protected String name;
@JsonProperty("given_name")
protected String givenName;
@JsonProperty("family_name")
protected String familyName;
@JsonProperty("middle_name")
protected String middleName;
@JsonProperty("nickname")
protected String nickName;
@JsonProperty("preferred_username")
protected String preferredUsername;
@JsonProperty("profile")
protected String profile;
@JsonProperty("picture")
protected String picture;
@JsonProperty("website")
protected String website;
@JsonProperty("email")
protected String email;
@JsonProperty("email_verified")
protected Boolean emailVerified;
@JsonProperty("gender")
protected String gender;
@JsonProperty("birthdate")
protected String birthdate;
@JsonProperty("zoneinfo")
protected String zoneinfo;
@JsonProperty("locale")
protected String locale;
@JsonProperty("phone_number")
protected String phoneNumber;
@JsonProperty("phone_number_verified")
protected Boolean phoneNumberVerified;
@JsonProperty("address")
protected AddressClaimSet address;
@JsonProperty("updated_at")
protected Long updatedAt;
@JsonProperty("claims_locales")
protected String claimsLocales;
protected Map<String, Object> otherClaims = new HashMap<String, Object>(); protected Map<String, Object> otherClaims = new HashMap<String, Object>();
@ -41,17 +99,166 @@ public class IDToken extends JsonWebToken {
this.sessionState = sessionState; this.sessionState = sessionState;
} }
/**
* Standardized OpenID Connect claims
* public String getName() {
* @return return this.name;
*/
public UserClaimSet getUserClaimSet() {
return this.userClaimSet;
} }
public void setUserClaimSet(UserClaimSet userClaimSet) { public void setName(String name) {
this.userClaimSet = userClaimSet; this.name = name;
}
public String getGivenName() {
return this.givenName;
}
public void setGivenName(String givenName) {
this.givenName = givenName;
}
public String getFamilyName() {
return this.familyName;
}
public void setFamilyName(String familyName) {
this.familyName = familyName;
}
public String getMiddleName() {
return this.middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public String getNickName() {
return this.nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getPreferredUsername() {
return this.preferredUsername;
}
public void setPreferredUsername(String preferredUsername) {
this.preferredUsername = preferredUsername;
}
public String getProfile() {
return this.profile;
}
public void setProfile(String profile) {
this.profile = profile;
}
public String getPicture() {
return this.picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public String getWebsite() {
return this.website;
}
public void setWebsite(String website) {
this.website = website;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public Boolean getEmailVerified() {
return this.emailVerified;
}
public void setEmailVerified(Boolean emailVerified) {
this.emailVerified = emailVerified;
}
public String getGender() {
return this.gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getBirthdate() {
return this.birthdate;
}
public void setBirthdate(String birthdate) {
this.birthdate = birthdate;
}
public String getZoneinfo() {
return this.zoneinfo;
}
public void setZoneinfo(String zoneinfo) {
this.zoneinfo = zoneinfo;
}
public String getLocale() {
return this.locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public String getPhoneNumber() {
return this.phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public Boolean getPhoneNumberVerified() {
return this.phoneNumberVerified;
}
public void setPhoneNumberVerified(Boolean phoneNumberVerified) {
this.phoneNumberVerified = phoneNumberVerified;
}
public AddressClaimSet getAddress() {
return address;
}
public void setAddress(AddressClaimSet address) {
this.address = address;
}
public Long getUpdatedAt() {
return this.updatedAt;
}
public void setUpdatedAt(Long updatedAt) {
this.updatedAt = updatedAt;
}
public String getClaimsLocales() {
return this.claimsLocales;
}
public void setClaimsLocales(String claimsLocales) {
this.claimsLocales = claimsLocales;
} }
/** /**
@ -65,7 +272,7 @@ public class IDToken extends JsonWebToken {
} }
@JsonAnySetter @JsonAnySetter
public void setOtherClaims(Map<String, Object> otherClaims) { public void setOtherClaims(String name, Object value) {
this.otherClaims = otherClaims; otherClaims.put(name, value);
} }
} }

View file

@ -1,334 +0,0 @@
/*
* JBoss, Home of Professional Open Source
*
* Copyright 2013 Red Hat, Inc. and/or its affiliates.
*
* 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.representations;
import org.codehaus.jackson.annotate.JsonProperty;
/**
* @author pedroigor
*/
public class UserClaimSet {
public static class AddressClaimSet {
@JsonProperty("formatted")
protected String formattedAddress;
@JsonProperty("street_address")
protected String streetAddress;
@JsonProperty("locality")
protected String locality;
@JsonProperty("region")
protected String region;
@JsonProperty("postal_code")
protected String postalCode;
@JsonProperty("country")
protected String country;
public String getFormattedAddress() {
return this.formattedAddress;
}
public void setFormattedAddress(String formattedAddress) {
this.formattedAddress = formattedAddress;
}
public String getStreetAddress() {
return this.streetAddress;
}
public void setStreetAddress(String streetAddress) {
this.streetAddress = streetAddress;
}
public String getLocality() {
return this.locality;
}
public void setLocality(String locality) {
this.locality = locality;
}
public String getRegion() {
return this.region;
}
public void setRegion(String region) {
this.region = region;
}
public String getPostalCode() {
return this.postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public String getCountry() {
return this.country;
}
public void setCountry(String country) {
this.country = country;
}
}
@JsonProperty("sub")
protected String sub;
@JsonProperty("name")
protected String name;
@JsonProperty("given_name")
protected String givenName;
@JsonProperty("family_name")
protected String familyName;
@JsonProperty("middle_name")
protected String middleName;
@JsonProperty("nickname")
protected String nickName;
@JsonProperty("preferred_username")
protected String preferredUsername;
@JsonProperty("profile")
protected String profile;
@JsonProperty("picture")
protected String picture;
@JsonProperty("website")
protected String website;
@JsonProperty("email")
protected String email;
@JsonProperty("email_verified")
protected Boolean emailVerified;
@JsonProperty("gender")
protected String gender;
@JsonProperty("birthdate")
protected String birthdate;
@JsonProperty("zoneinfo")
protected String zoneinfo;
@JsonProperty("locale")
protected String locale;
@JsonProperty("phone_number")
protected String phoneNumber;
@JsonProperty("phone_number_verified")
protected Boolean phoneNumberVerified;
@JsonProperty("address")
protected AddressClaimSet address;
@JsonProperty("updated_at")
protected Long updatedAt;
@JsonProperty("claims_locales")
protected String claimsLocales;
public String getSubject() {
return this.sub;
}
public void setSubject(String subject) {
this.sub = subject;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getGivenName() {
return this.givenName;
}
public void setGivenName(String givenName) {
this.givenName = givenName;
}
public String getFamilyName() {
return this.familyName;
}
public void setFamilyName(String familyName) {
this.familyName = familyName;
}
public String getMiddleName() {
return this.middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public String getNickName() {
return this.nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getPreferredUsername() {
return this.preferredUsername;
}
public void setPreferredUsername(String preferredUsername) {
this.preferredUsername = preferredUsername;
}
public String getProfile() {
return this.profile;
}
public void setProfile(String profile) {
this.profile = profile;
}
public String getPicture() {
return this.picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public String getWebsite() {
return this.website;
}
public void setWebsite(String website) {
this.website = website;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public Boolean getEmailVerified() {
return this.emailVerified;
}
public void setEmailVerified(Boolean emailVerified) {
this.emailVerified = emailVerified;
}
public String getGender() {
return this.gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getBirthdate() {
return this.birthdate;
}
public void setBirthdate(String birthdate) {
this.birthdate = birthdate;
}
public String getZoneinfo() {
return this.zoneinfo;
}
public void setZoneinfo(String zoneinfo) {
this.zoneinfo = zoneinfo;
}
public String getLocale() {
return this.locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public String getPhoneNumber() {
return this.phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public Boolean getPhoneNumberVerified() {
return this.phoneNumberVerified;
}
public void setPhoneNumberVerified(Boolean phoneNumberVerified) {
this.phoneNumberVerified = phoneNumberVerified;
}
public AddressClaimSet getAddress() {
return address;
}
public void setAddress(AddressClaimSet address) {
this.address = address;
}
public Long getUpdatedAt() {
return this.updatedAt;
}
public void setUpdatedAt(Long updatedAt) {
this.updatedAt = updatedAt;
}
public String getSub() {
return this.sub;
}
public void setSub(String sub) {
this.sub = sub;
}
public String getClaimsLocales() {
return this.claimsLocales;
}
public void setClaimsLocales(String claimsLocales) {
this.claimsLocales = claimsLocales;
}
}

View file

@ -17,9 +17,248 @@
*/ */
package org.keycloak.representations; package org.keycloak.representations;
import org.codehaus.jackson.annotate.JsonProperty;
/** /**
* @author pedroigor * @author pedroigor
*/ */
public class UserInfo extends UserClaimSet { public class UserInfo {
@JsonProperty("sub")
protected String sub;
@JsonProperty("name")
protected String name;
@JsonProperty("given_name")
protected String givenName;
@JsonProperty("family_name")
protected String familyName;
@JsonProperty("middle_name")
protected String middleName;
@JsonProperty("nickname")
protected String nickName;
@JsonProperty("preferred_username")
protected String preferredUsername;
@JsonProperty("profile")
protected String profile;
@JsonProperty("picture")
protected String picture;
@JsonProperty("website")
protected String website;
@JsonProperty("email")
protected String email;
@JsonProperty("email_verified")
protected Boolean emailVerified;
@JsonProperty("gender")
protected String gender;
@JsonProperty("birthdate")
protected String birthdate;
@JsonProperty("zoneinfo")
protected String zoneinfo;
@JsonProperty("locale")
protected String locale;
@JsonProperty("phone_number")
protected String phoneNumber;
@JsonProperty("phone_number_verified")
protected Boolean phoneNumberVerified;
@JsonProperty("address")
protected AddressClaimSet address;
@JsonProperty("updated_at")
protected Long updatedAt;
@JsonProperty("claims_locales")
protected String claimsLocales;
public String getSubject() {
return this.sub;
}
public void setSubject(String subject) {
this.sub = subject;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getGivenName() {
return this.givenName;
}
public void setGivenName(String givenName) {
this.givenName = givenName;
}
public String getFamilyName() {
return this.familyName;
}
public void setFamilyName(String familyName) {
this.familyName = familyName;
}
public String getMiddleName() {
return this.middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public String getNickName() {
return this.nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getPreferredUsername() {
return this.preferredUsername;
}
public void setPreferredUsername(String preferredUsername) {
this.preferredUsername = preferredUsername;
}
public String getProfile() {
return this.profile;
}
public void setProfile(String profile) {
this.profile = profile;
}
public String getPicture() {
return this.picture;
}
public void setPicture(String picture) {
this.picture = picture;
}
public String getWebsite() {
return this.website;
}
public void setWebsite(String website) {
this.website = website;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public Boolean getEmailVerified() {
return this.emailVerified;
}
public void setEmailVerified(Boolean emailVerified) {
this.emailVerified = emailVerified;
}
public String getGender() {
return this.gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getBirthdate() {
return this.birthdate;
}
public void setBirthdate(String birthdate) {
this.birthdate = birthdate;
}
public String getZoneinfo() {
return this.zoneinfo;
}
public void setZoneinfo(String zoneinfo) {
this.zoneinfo = zoneinfo;
}
public String getLocale() {
return this.locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public String getPhoneNumber() {
return this.phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public Boolean getPhoneNumberVerified() {
return this.phoneNumberVerified;
}
public void setPhoneNumberVerified(Boolean phoneNumberVerified) {
this.phoneNumberVerified = phoneNumberVerified;
}
public AddressClaimSet getAddress() {
return address;
}
public void setAddress(AddressClaimSet address) {
this.address = address;
}
public Long getUpdatedAt() {
return this.updatedAt;
}
public void setUpdatedAt(Long updatedAt) {
this.updatedAt = updatedAt;
}
public String getSub() {
return this.sub;
}
public void setSub(String sub) {
this.sub = sub;
}
public String getClaimsLocales() {
return this.claimsLocales;
}
public void setClaimsLocales(String claimsLocales) {
this.claimsLocales = claimsLocales;
}
} }

View file

@ -26,6 +26,7 @@ public class JsonParserTest {
IDToken test = new IDToken(); IDToken test = new IDToken();
test.getOtherClaims().put("phone_number", "978-666-0000"); test.getOtherClaims().put("phone_number", "978-666-0000");
test.getOtherClaims().put("email_verified", "true"); test.getOtherClaims().put("email_verified", "true");
test.getOtherClaims().put("yo", "true");
Map<String, String> nested = new HashMap<String, String>(); Map<String, String> nested = new HashMap<String, String>();
nested.put("foo", "bar"); nested.put("foo", "bar");
test.getOtherClaims().put("nested", nested); test.getOtherClaims().put("nested", nested);
@ -33,11 +34,15 @@ public class JsonParserTest {
System.out.println(json); System.out.println(json);
test = JsonSerialization.readValue(json, IDToken.class); test = JsonSerialization.readValue(json, IDToken.class);
System.out.println("email_verified property: " + test.getUserClaimSet().getEmailVerified()); System.out.println("email_verified property: " + test.getEmailVerified());
System.out.println("property: " + test.getUserClaimSet().getPhoneNumber()); System.out.println("property: " + test.getPhoneNumber());
System.out.println("map: " + test.getOtherClaims().get("phone_number")); System.out.println("map: " + test.getOtherClaims().get("phone_number"));
Assert.assertNotNull(test.getUserClaimSet().getPhoneNumber()); Assert.assertNotNull(test.getPhoneNumber());
Assert.assertNotNull(test.getOtherClaims().get("yo"));
Assert.assertNull(test.getOtherClaims().get("phone_number")); Assert.assertNull(test.getOtherClaims().get("phone_number"));
nested = (Map<String, String>)test.getOtherClaims().get("nested");
Assert.assertNotNull(nested);
Assert.assertNotNull(nested.get("foo"));
} }
@Test @Test

View file

@ -6,7 +6,6 @@ import org.keycloak.jose.jws.JWSBuilder;
import org.keycloak.jose.jws.JWSInput; import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.crypto.RSAProvider; import org.keycloak.jose.jws.crypto.RSAProvider;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import org.keycloak.representations.UserClaimSet;
import org.keycloak.representations.IDToken; import org.keycloak.representations.IDToken;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
@ -59,9 +58,8 @@ public class SkeletonKeyTokenTest {
public void testSerialization() throws Exception { public void testSerialization() throws Exception {
AccessToken token = createSimpleToken(); AccessToken token = createSimpleToken();
IDToken idToken = new IDToken(); IDToken idToken = new IDToken();
UserClaimSet claimSet = idToken.getUserClaimSet();
claimSet.setEmail("joe@email.cz"); idToken.setEmail("joe@email.cz");
KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
@ -98,7 +96,7 @@ public class SkeletonKeyTokenTest {
Assert.assertEquals("111", token.getId()); Assert.assertEquals("111", token.getId());
Assert.assertTrue(token.getResourceAccess("foo").isUserInRole("admin")); Assert.assertTrue(token.getResourceAccess("foo").isUserInRole("admin"));
Assert.assertTrue(token.getResourceAccess("bar").isUserInRole("user")); Assert.assertTrue(token.getResourceAccess("bar").isUserInRole("user"));
Assert.assertEquals("joe@email.cz", claimSet.getEmail()); Assert.assertEquals("joe@email.cz", idToken.getEmail());
Assert.assertEquals("acme", ctx.getRealm()); Assert.assertEquals("acme", ctx.getRealm());
ois.close(); ois.close();
} }

View file

@ -3,7 +3,6 @@
<%@ page import="org.keycloak.constants.ServiceUrlConstants" %> <%@ page import="org.keycloak.constants.ServiceUrlConstants" %>
<%@ page import="org.keycloak.example.CustomerDatabaseClient" %> <%@ page import="org.keycloak.example.CustomerDatabaseClient" %>
<%@ page import="org.keycloak.representations.IDToken" %> <%@ page import="org.keycloak.representations.IDToken" %>
<%@ page import="org.keycloak.representations.UserClaimSet" %>
<%@ page import="org.keycloak.util.KeycloakUriBuilder" %> <%@ page import="org.keycloak.util.KeycloakUriBuilder" %>
<%@ page session="false" %> <%@ page session="false" %>
<html> <html>
@ -17,18 +16,17 @@
String acctUri = KeycloakUriBuilder.fromUri("/auth").path(ServiceUrlConstants.ACCOUNT_SERVICE_PATH) String acctUri = KeycloakUriBuilder.fromUri("/auth").path(ServiceUrlConstants.ACCOUNT_SERVICE_PATH)
.queryParam("referrer", "customer-portal").build("demo").toString(); .queryParam("referrer", "customer-portal").build("demo").toString();
IDToken idToken = CustomerDatabaseClient.getIDToken(request); IDToken idToken = CustomerDatabaseClient.getIDToken(request);
UserClaimSet claims = idToken.getUserClaimSet();
%> %>
<p>Goto: <a href="/product-portal">products</a> | <a href="<%=logoutUri%>">logout</a> | <a <p>Goto: <a href="/product-portal">products</a> | <a href="<%=logoutUri%>">logout</a> | <a
href="<%=acctUri%>">manage acct</a></p> href="<%=acctUri%>">manage acct</a></p>
Servlet User Principal <b><%=request.getUserPrincipal().getName()%> Servlet User Principal <b><%=request.getUserPrincipal().getName()%>
</b> made this request. </b> made this request.
<p><b>Caller IDToken values</b> (<i>You can specify what is returned in IDToken in the customer-portal claims page in the admin console</i>:</p> <p><b>Caller IDToken values</b> (<i>You can specify what is returned in IDToken in the customer-portal claims page in the admin console</i>:</p>
<p>Username: <%=claims.getPreferredUsername()%></p> <p>Username: <%=idToken.getPreferredUsername()%></p>
<p>Email: <%=claims.getEmail()%></p> <p>Email: <%=idToken.getEmail()%></p>
<p>Full Name: <%=claims.getName()%></p> <p>Full Name: <%=idToken.getName()%></p>
<p>First: <%=claims.getGivenName()%></p> <p>First: <%=idToken.getGivenName()%></p>
<p>Last: <%=claims.getFamilyName()%></p> <p>Last: <%=idToken.getFamilyName()%></p>
<h2>Customer Listing</h2> <h2>Customer Listing</h2>
<% <%
java.util.List<String> list = null; java.util.List<String> list = null;

View file

@ -2,7 +2,6 @@
<%@ page import="org.keycloak.representations.AccessTokenResponse" %> <%@ page import="org.keycloak.representations.AccessTokenResponse" %>
<%@ page import="org.keycloak.representations.IDToken" %> <%@ page import="org.keycloak.representations.IDToken" %>
<%@ page import="org.keycloak.servlet.ServletOAuthClient" %> <%@ page import="org.keycloak.servlet.ServletOAuthClient" %>
<%@ page import="org.keycloak.representations.UserClaimSet" %>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%> pageEncoding="ISO-8859-1"%>
<%@ page session="false" %> <%@ page session="false" %>
@ -17,16 +16,15 @@
AccessTokenResponse tokenResponse = ProductDatabaseClient.getTokenResponse(request); AccessTokenResponse tokenResponse = ProductDatabaseClient.getTokenResponse(request);
if (tokenResponse.getIdToken() != null) { if (tokenResponse.getIdToken() != null) {
IDToken idToken = ServletOAuthClient.extractIdToken(tokenResponse.getIdToken()); IDToken idToken = ServletOAuthClient.extractIdToken(tokenResponse.getIdToken());
UserClaimSet claimSet = idToken.getUserClaimSet();
out.println("<p><i>Change client claims in admin console to view personal info of user</i></p>"); out.println("<p><i>Change client claims in admin console to view personal info of user</i></p>");
if (claimSet.getPreferredUsername() != null) { if (idToken.getPreferredUsername() != null) {
out.println("<p>Username: " + claimSet.getPreferredUsername() + "</p>"); out.println("<p>Username: " + idToken.getPreferredUsername() + "</p>");
} }
if (claimSet.getName() != null) { if (idToken.getName() != null) {
out.println("<p>Full Name: " + claimSet.getName() + "</p>"); out.println("<p>Full Name: " + idToken.getName() + "</p>");
} }
if (claimSet.getEmail() != null) { if (idToken.getEmail() != null) {
out.println("<p>Email: " + claimSet.getEmail() + "</p>"); out.println("<p>Email: " + idToken.getEmail() + "</p>");
} }
} }
list = ProductDatabaseClient.getProducts(request, tokenResponse.getToken()); list = ProductDatabaseClient.getProducts(request, tokenResponse.getToken());

View file

@ -55,7 +55,7 @@ public class ProtectedServlet extends HttpServlet {
writer.write(principal.getKeycloakSecurityContext().getIdToken().getIssuer()); writer.write(principal.getKeycloakSecurityContext().getIdToken().getIssuer());
writer.write("<br/>User: "); writer.write("<br/>User: ");
writer.write(principal.getKeycloakSecurityContext().getIdToken().getUserClaimSet().getPreferredUsername()); writer.write(principal.getKeycloakSecurityContext().getIdToken().getPreferredUsername());
writer.write(String.format("<br/><a href=\"/multitenant/%s/logout\">Logout</a>", realm)); writer.write(String.format("<br/><a href=\"/multitenant/%s/logout\">Logout</a>", realm));
} }

View file

@ -4,7 +4,6 @@ import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal; import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext; import org.keycloak.KeycloakSecurityContext;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import org.keycloak.representations.UserClaimSet;
import org.keycloak.util.UriUtils; import org.keycloak.util.UriUtils;
import java.util.Collections; import java.util.Collections;
@ -78,22 +77,21 @@ public class AdapterUtils {
String attr = "sub"; String attr = "sub";
if (deployment.getPrincipalAttribute() != null) attr = deployment.getPrincipalAttribute(); if (deployment.getPrincipalAttribute() != null) attr = deployment.getPrincipalAttribute();
String name = null; String name = null;
UserClaimSet claimSet = token.getUserClaimSet();
if ("sub".equals(attr)) { if ("sub".equals(attr)) {
name = token.getSubject(); name = token.getSubject();
} else if ("email".equals(attr)) { } else if ("email".equals(attr)) {
name = claimSet.getEmail(); name = token.getEmail();
} else if ("preferred_username".equals(attr)) { } else if ("preferred_username".equals(attr)) {
name = claimSet.getPreferredUsername(); name = token.getPreferredUsername();
} else if ("name".equals(attr)) { } else if ("name".equals(attr)) {
name = claimSet.getName(); name = token.getName();
} else if ("given_name".equals(attr)) { } else if ("given_name".equals(attr)) {
name = claimSet.getGivenName(); name = token.getGivenName();
} else if ("family_name".equals(attr)) { } else if ("family_name".equals(attr)) {
name = claimSet.getFamilyName(); name = token.getFamilyName();
} else if ("nickname".equals(attr)) { } else if ("nickname".equals(attr)) {
name = claimSet.getNickName(); name = token.getNickName();
} }
if (name == null) name = token.getSubject(); if (name == null) name = token.getSubject();
return name; return name;

View file

@ -4,7 +4,6 @@ import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange; import io.undertow.server.HttpServerExchange;
import io.undertow.util.HttpString; import io.undertow.util.HttpString;
import org.keycloak.adapters.undertow.KeycloakUndertowAccount; import org.keycloak.adapters.undertow.KeycloakUndertowAccount;
import org.keycloak.representations.UserClaimSet;
import org.keycloak.representations.IDToken; import org.keycloak.representations.IDToken;
/** /**
@ -65,16 +64,14 @@ public class ConstraintAuthorizationHandler implements HttpHandler {
exchange.getRequestHeaders().put(KEYCLOAK_SUBJECT, idToken.getSubject()); exchange.getRequestHeaders().put(KEYCLOAK_SUBJECT, idToken.getSubject());
} }
UserClaimSet claimSet = idToken.getUserClaimSet(); if (idToken.getPreferredUsername() != null) {
exchange.getRequestHeaders().put(KEYCLOAK_USERNAME, idToken.getPreferredUsername());
if (claimSet.getPreferredUsername() != null) {
exchange.getRequestHeaders().put(KEYCLOAK_USERNAME, claimSet.getPreferredUsername());
} }
if (claimSet.getEmail() != null) { if (idToken.getEmail() != null) {
exchange.getRequestHeaders().put(KEYCLOAK_EMAIL, claimSet.getEmail()); exchange.getRequestHeaders().put(KEYCLOAK_EMAIL, idToken.getEmail());
} }
if (claimSet.getName() != null) { if (idToken.getName() != null) {
exchange.getRequestHeaders().put(KEYCLOAK_NAME, claimSet.getName()); exchange.getRequestHeaders().put(KEYCLOAK_NAME, idToken.getName());
} }
if (sendAccessToken) { if (sendAccessToken) {
exchange.getRequestHeaders().put(KEYCLOAK_ACCESS_TOKEN, account.getKeycloakSecurityContext().getTokenString()); exchange.getRequestHeaders().put(KEYCLOAK_ACCESS_TOKEN, account.getKeycloakSecurityContext().getTokenString());

View file

@ -7,7 +7,6 @@ import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.protocol.AbstractLoginProtocolFactory; import org.keycloak.protocol.AbstractLoginProtocolFactory;
import org.keycloak.protocol.LoginProtocol; import org.keycloak.protocol.LoginProtocol;
import org.keycloak.protocol.ProtocolMapperUtils;
import org.keycloak.protocol.oidc.mappers.OIDCAddressMapper; import org.keycloak.protocol.oidc.mappers.OIDCAddressMapper;
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper; import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
import org.keycloak.protocol.oidc.mappers.OIDCFullNameMapper; import org.keycloak.protocol.oidc.mappers.OIDCFullNameMapper;
@ -88,16 +87,7 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
builtins.add(fullName); builtins.add(fullName);
defaultBuiltins.add(fullName); defaultBuiltins.add(fullName);
ProtocolMapperModel address = new ProtocolMapperModel(); ProtocolMapperModel address = OIDCAddressMapper.createAddressMapper();
address.setName("address");
address.setProtocolMapper(OIDCAddressMapper.PROVIDER_ID);
address.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
address.setConsentRequired(true);
address.setConsentText("address");
config = new HashMap<String, String>();
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
address.setConfig(config);
builtins.add(address); builtins.add(address);
} }

View file

@ -5,12 +5,15 @@ import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel; import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.models.UserSessionModel; import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import org.keycloak.representations.AddressClaimSet;
import org.keycloak.representations.IDToken; import org.keycloak.representations.IDToken;
import org.keycloak.representations.UserClaimSet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Set the 'name' claim to be first + last name. * Set the 'name' claim to be first + last name.
@ -42,6 +45,35 @@ public class OIDCAddressMapper extends AbstractOIDCProtocolMapper implements OID
public static final String PROVIDER_ID = "oidc-address-mapper"; public static final String PROVIDER_ID = "oidc-address-mapper";
public static ProtocolMapperModel createAddressMapper() {
Map<String, String> config;
ProtocolMapperModel address = new ProtocolMapperModel();
address.setName("address");
address.setProtocolMapper(PROVIDER_ID);
address.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
address.setConsentRequired(true);
address.setConsentText("address");
config = new HashMap<String, String>();
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
address.setConfig(config);
return address;
}
public static ProtocolMapperModel createAddressMapper(boolean idToken, boolean accessToken) {
Map<String, String> config;
ProtocolMapperModel address = new ProtocolMapperModel();
address.setName("address");
address.setProtocolMapper(PROVIDER_ID);
address.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
address.setConsentRequired(true);
address.setConsentText("address");
config = new HashMap<String, String>();
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, Boolean.toString(idToken));
config.put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, Boolean.toString(accessToken));
address.setConfig(config);
return address;
}
public List<ConfigProperty> getConfigProperties() { public List<ConfigProperty> getConfigProperties() {
return configProperties; return configProperties;
@ -84,7 +116,7 @@ public class OIDCAddressMapper extends AbstractOIDCProtocolMapper implements OID
protected void setClaim(IDToken token, UserSessionModel userSession) { protected void setClaim(IDToken token, UserSessionModel userSession) {
UserModel user = userSession.getUser(); UserModel user = userSession.getUser();
UserClaimSet.AddressClaimSet addressSet = new UserClaimSet.AddressClaimSet(); AddressClaimSet addressSet = new AddressClaimSet();
addressSet.setStreetAddress(user.getAttribute("street")); addressSet.setStreetAddress(user.getAttribute("street"));
addressSet.setLocality(user.getAttribute("locality")); addressSet.setLocality(user.getAttribute("locality"));
addressSet.setRegion(user.getAttribute("region")); addressSet.setRegion(user.getAttribute("region"));

View file

@ -38,7 +38,7 @@ public class MultiTenantServlet extends HttpServlet {
KeycloakSecurityContext context = (KeycloakSecurityContext)req.getAttribute(KeycloakSecurityContext.class.getName()); KeycloakSecurityContext context = (KeycloakSecurityContext)req.getAttribute(KeycloakSecurityContext.class.getName());
pw.print("Username: "); pw.print("Username: ");
pw.println(context.getIdToken().getUserClaimSet().getPreferredUsername()); pw.println(context.getIdToken().getPreferredUsername());
pw.print("<br/>Realm: "); pw.print("<br/>Realm: ");
pw.println(context.getRealm()); pw.println(context.getRealm());

View file

@ -26,18 +26,24 @@ import org.junit.ClassRule;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.keycloak.OAuth2Constants; import org.keycloak.OAuth2Constants;
import org.keycloak.VerificationException;
import org.keycloak.enums.SslRequired; import org.keycloak.enums.SslRequired;
import org.keycloak.events.Details; import org.keycloak.events.Details;
import org.keycloak.events.Errors; import org.keycloak.events.Errors;
import org.keycloak.events.Event; import org.keycloak.events.Event;
import org.keycloak.jose.jws.JWSInput;
import org.keycloak.models.ApplicationModel; import org.keycloak.models.ApplicationModel;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService; import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.protocol.oidc.mappers.OIDCAddressMapper;
import org.keycloak.protocol.oidc.mappers.OIDCUserAttributeMapper;
import org.keycloak.representations.AccessToken; import org.keycloak.representations.AccessToken;
import org.keycloak.representations.IDToken;
import org.keycloak.services.managers.RealmManager; import org.keycloak.services.managers.RealmManager;
import org.keycloak.testsuite.AssertEvents; import org.keycloak.testsuite.AssertEvents;
import org.keycloak.testsuite.OAuthClient; import org.keycloak.testsuite.OAuthClient;
@ -58,6 +64,7 @@ import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
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 java.io.IOException;
import java.net.URI; import java.net.URI;
import java.util.HashMap; import java.util.HashMap;
@ -570,6 +577,84 @@ public class AccessTokenTest {
} }
@Test
public void testTokenMapping() throws Exception {
Client client = ClientBuilder.newClient();
UriBuilder builder = UriBuilder.fromUri(org.keycloak.testsuite.Constants.AUTH_SERVER_ROOT);
URI grantUri = OIDCLoginProtocolService.grantAccessTokenUrl(builder).build("test");
WebTarget grantTarget = client.target(grantUri);
{
KeycloakSession session = keycloakRule.startSession();
RealmModel realm = session.realms().getRealmByName("test");
UserModel user = session.users().getUserByUsername("test-user@localhost", realm);
user.setAttribute("street", "5 Yawkey Way");
user.setAttribute("locality", "Boston");
user.setAttribute("region", "MA");
user.setAttribute("postal_code", "02115");
user.setAttribute("country", "USA");
user.setAttribute("phone", "617-777-6666");
ApplicationModel app = realm.getApplicationByName("test-app");
ProtocolMapperModel mapper = OIDCAddressMapper.createAddressMapper(true, true);
app.addProtocolMapper(mapper);
app.addProtocolMapper(OIDCUserAttributeMapper.createClaimMapper("custom phone", "phone", "home_phone", "String", true, "", true, true));
session.getTransaction().commit();
session.close();
}
{
Response response = executeGrantAccessTokenRequest(grantTarget);
Assert.assertEquals(200, response.getStatus());
org.keycloak.representations.AccessTokenResponse tokenResponse = response.readEntity(org.keycloak.representations.AccessTokenResponse.class);
IDToken idToken = getIdToken(tokenResponse);
Assert.assertNotNull(idToken.getAddress());
Assert.assertEquals(idToken.getAddress().getStreetAddress(), "5 Yawkey Way");
Assert.assertEquals(idToken.getAddress().getLocality(), "Boston");
Assert.assertEquals(idToken.getAddress().getRegion(), "MA");
Assert.assertEquals(idToken.getAddress().getPostalCode(), "02115");
Assert.assertEquals(idToken.getAddress().getCountry(), "USA");
Assert.assertNotNull(idToken.getOtherClaims().get("home_phone"));
//Assert.assertEquals("617-777-6666", idToken.getOtherClaims().get("home_phone"));
AccessToken accessToken = getAccessToken(tokenResponse);
Assert.assertNotNull(accessToken.getAddress());
Assert.assertEquals(accessToken.getAddress().getStreetAddress(), "5 Yawkey Way");
Assert.assertEquals(accessToken.getAddress().getLocality(), "Boston");
Assert.assertEquals(accessToken.getAddress().getRegion(), "MA");
Assert.assertEquals(accessToken.getAddress().getPostalCode(), "02115");
Assert.assertEquals(accessToken.getAddress().getCountry(), "USA");
Assert.assertNotNull(accessToken.getOtherClaims().get("home_phone"));
Assert.assertEquals("617-777-6666", accessToken.getOtherClaims().get("home_phone"));
response.close();
}
client.close();
events.clear();
}
private IDToken getIdToken(org.keycloak.representations.AccessTokenResponse tokenResponse) throws VerificationException {
JWSInput input = new JWSInput(tokenResponse.getIdToken());
IDToken idToken = null;
try {
idToken = input.readJsonContent(IDToken.class);
} catch (IOException e) {
throw new VerificationException();
}
return idToken;
}
private AccessToken getAccessToken(org.keycloak.representations.AccessTokenResponse tokenResponse) throws VerificationException {
JWSInput input = new JWSInput(tokenResponse.getIdToken());
AccessToken idToken = null;
try {
idToken = input.readJsonContent(AccessToken.class);
} catch (IOException e) {
throw new VerificationException();
}
return idToken;
}
protected Response executeGrantAccessTokenRequest(WebTarget grantTarget) { protected Response executeGrantAccessTokenRequest(WebTarget grantTarget) {
String header = BasicAuthHelper.createHeader("test-app", "password"); String header = BasicAuthHelper.createHeader("test-app", "password");
Form form = new Form(); Form form = new Form();