Completed implementation in ClaimAccessor's

Fixes gh-4449
This commit is contained in:
Joe Grandja 2017-07-25 16:26:14 -04:00
parent e8c6a1acc8
commit c204cc2c31
6 changed files with 128 additions and 14 deletions

View File

@ -19,6 +19,7 @@ import org.springframework.security.oauth2.core.ClaimAccessor;
import java.net.URL;
import java.time.Instant;
import java.util.List;
/**
* A {@link ClaimAccessor} for the "Registered Claim Names"
@ -41,9 +42,8 @@ public interface JwtClaimAccessor extends ClaimAccessor {
return this.getClaimAsString(JwtClaim.SUB);
}
default String[] getAudience() {
// TODO Impl JwtClaim.AUD
return null;
default List<String> getAudience() {
return this.getClaimAsStringList(JwtClaim.AUD);
}
default Instant getExpiresAt() {

View File

@ -20,6 +20,9 @@ import org.springframework.util.Assert;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
@ -66,4 +69,22 @@ public interface ClaimAccessor {
throw new IllegalArgumentException("Unable to convert claim '" + claim + "' to URL: " + ex.getMessage(), ex);
}
}
default Map<String, Object> getClaimAsMap(String claim) {
if (!this.containsClaim(claim) || !Map.class.isAssignableFrom(this.getClaims().get(claim).getClass())) {
return null;
}
Map<String, Object> claimFields = new HashMap<>();
((Map<?, ?>)this.getClaims().get(claim)).forEach((k, v) -> claimFields.put(k.toString(), v));
return claimFields;
}
default List<String> getClaimAsStringList(String claim) {
if (!this.containsClaim(claim) || !List.class.isAssignableFrom(this.getClaims().get(claim).getClass())) {
return null;
}
List<String> claimValues = new ArrayList<>();
((List<?>)this.getClaims().get(claim)).forEach(e -> claimValues.add(e.toString()));
return claimValues;
}
}

View File

@ -15,6 +15,8 @@
*/
package org.springframework.security.oauth2.oidc.core;
import java.util.Map;
/**
* The Address Claim represents a physical mailing address defined by the <i>OpenID Connect Core 1.0</i> specification
* that can be returned either in the <i>UserInfo Response</i> or the <i>ID Token</i>.
@ -39,4 +41,94 @@ public interface Address {
String getCountry();
class Builder implements Address {
private static final String FORMATTED_FIELD_NAME = "formatted";
private static final String STREET_ADDRESS_FIELD_NAME = "street_address";
private static final String LOCALITY_FIELD_NAME = "locality";
private static final String REGION_FIELD_NAME = "region";
private static final String POSTAL_CODE_FIELD_NAME = "postal_code";
private static final String COUNTRY_FIELD_NAME = "country";
private String formatted;
private String streetAddress;
private String locality;
private String region;
private String postalCode;
private String country;
public Builder() {
}
public Builder(Map<String, Object> addressFields) {
this.formatted((String)addressFields.get(FORMATTED_FIELD_NAME));
this.streetAddress((String)addressFields.get(STREET_ADDRESS_FIELD_NAME));
this.locality((String)addressFields.get(LOCALITY_FIELD_NAME));
this.region((String)addressFields.get(REGION_FIELD_NAME));
this.postalCode((String)addressFields.get(POSTAL_CODE_FIELD_NAME));
this.country((String)addressFields.get(COUNTRY_FIELD_NAME));
}
public Builder formatted(String formatted) {
this.formatted = formatted;
return this;
}
public Builder streetAddress(String streetAddress) {
this.streetAddress = streetAddress;
return this;
}
public Builder locality(String locality) {
this.locality = locality;
return this;
}
public Builder region(String region) {
this.region = region;
return this;
}
public Builder postalCode(String postalCode) {
this.postalCode = postalCode;
return this;
}
public Builder country(String country) {
this.country = country;
return this;
}
public Address build() {
return this;
}
@Override
public String getFormatted() {
return this.formatted;
}
@Override
public String getStreetAddress() {
return this.streetAddress;
}
@Override
public String getLocality() {
return this.locality;
}
@Override
public String getRegion() {
return this.region;
}
@Override
public String getPostalCode() {
return this.postalCode;
}
@Override
public String getCountry() {
return this.country;
}
}
}

View File

@ -19,6 +19,7 @@ import org.springframework.security.oauth2.core.ClaimAccessor;
import java.net.URL;
import java.time.Instant;
import java.util.List;
/**
* A {@link ClaimAccessor} for the &quot;Claims&quot; that can be returned in the <i>ID Token</i>
@ -44,9 +45,8 @@ public interface IdTokenClaimAccessor extends StandardClaimAccessor {
return this.getClaimAsString(IdTokenClaim.SUB);
}
default String[] getAudience() {
// TODO Impl IdTokenClaim.AUD
return null;
default List<String> getAudience() {
return this.getClaimAsStringList(IdTokenClaim.AUD);
}
default Instant getExpiresAt() {
@ -69,9 +69,8 @@ public interface IdTokenClaimAccessor extends StandardClaimAccessor {
return this.getClaimAsString(IdTokenClaim.ACR);
}
default String[] getAuthenticationMethods() {
// TODO Impl IdTokenClaim.AMR
return null;
default List<String> getAuthenticationMethods() {
return this.getClaimAsStringList(IdTokenClaim.AMR);
}
default String getAuthorizedParty() {

View File

@ -18,6 +18,7 @@ package org.springframework.security.oauth2.oidc.core;
import org.springframework.security.oauth2.core.ClaimAccessor;
import java.time.Instant;
import java.util.Map;
/**
* A {@link ClaimAccessor} for the &quot;Standard Claims&quot; that can be returned
@ -107,12 +108,13 @@ public interface StandardClaimAccessor extends ClaimAccessor {
}
default Address getAddress() {
// TODO Impl StandardClaim.ADDRESS
return null;
Map<String, Object> addressFields = this.getClaimAsMap(StandardClaim.ADDRESS);
return (addressFields != null ?
new Address.Builder(addressFields).build() :
new Address.Builder().build());
}
default Instant getUpdatedAt() {
return this.getClaimAsInstant(StandardClaim.UPDATED_AT);
}
}

View File

@ -5,7 +5,7 @@ security:
client-authentication-method: basic
authorized-grant-type: authorization_code
redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{clientAlias}"
scopes: openid, email, profile
scopes: openid, profile, email, address, phone
authorization-uri: "https://accounts.google.com/o/oauth2/auth"
token-uri: "https://accounts.google.com/o/oauth2/token"
user-info-uri: "https://www.googleapis.com/oauth2/v3/userinfo"
@ -38,6 +38,6 @@ security:
client-authentication-method: basic
authorized-grant-type: authorization_code
redirect-uri: "{scheme}://{serverName}:{serverPort}{baseAuthorizeUri}/{clientAlias}"
scopes: openid, email, profile
scopes: openid, profile, email, address, phone
client-name: Okta
client-alias: okta