ID Token carried through as parsed JWT instead of string, closes #832
parent
f4a1b27e2e
commit
b4520c170e
|
@ -584,7 +584,7 @@ public class OIDCAuthenticationFilter extends AbstractAuthenticationProcessingFi
|
||||||
|
|
||||||
// construct an OIDCAuthenticationToken and return a Authentication object w/the userId and the idToken
|
// construct an OIDCAuthenticationToken and return a Authentication object w/the userId and the idToken
|
||||||
|
|
||||||
OIDCAuthenticationToken token = new OIDCAuthenticationToken(userId, idClaims.getIssuer(), serverConfig, idTokenValue, accessTokenValue, refreshTokenValue);
|
OIDCAuthenticationToken token = new OIDCAuthenticationToken(userId, idClaims.getIssuer(), serverConfig, idToken, accessTokenValue, refreshTokenValue);
|
||||||
|
|
||||||
Authentication authentication = this.getAuthenticationManager().authenticate(token);
|
Authentication authentication = this.getAuthenticationManager().authenticate(token);
|
||||||
|
|
||||||
|
|
|
@ -62,30 +62,23 @@ public class OIDCAuthenticationProvider implements AuthenticationProvider {
|
||||||
|
|
||||||
OIDCAuthenticationToken token = (OIDCAuthenticationToken) authentication;
|
OIDCAuthenticationToken token = (OIDCAuthenticationToken) authentication;
|
||||||
|
|
||||||
try {
|
// get the ID Token value out
|
||||||
|
JWT idToken = token.getIdToken();
|
||||||
// get the ID Token value out
|
|
||||||
String idTokenString = token.getIdTokenValue();
|
// load the user info if we can
|
||||||
JWT idToken = JWTParser.parse(idTokenString);
|
UserInfo userInfo = userInfoFetcher.loadUserInfo(token);
|
||||||
|
|
||||||
// load the user info if we can
|
if (userInfo == null) {
|
||||||
UserInfo userInfo = userInfoFetcher.loadUserInfo(token);
|
// user info not found -- could be an error, could be fine
|
||||||
|
} else {
|
||||||
if (userInfo == null) {
|
// if we found userinfo, double check it
|
||||||
// user info not found -- could be an error, could be fine
|
if (!Strings.isNullOrEmpty(userInfo.getSub()) && !userInfo.getSub().equals(token.getSub())) {
|
||||||
} else {
|
// the userinfo came back and the user_id fields don't match what was in the id_token
|
||||||
// if we found userinfo, double check it
|
throw new UsernameNotFoundException("user_id mismatch between id_token and user_info call: " + token.getSub() + " / " + userInfo.getSub());
|
||||||
if (!Strings.isNullOrEmpty(userInfo.getSub()) && !userInfo.getSub().equals(token.getSub())) {
|
|
||||||
// the userinfo came back and the user_id fields don't match what was in the id_token
|
|
||||||
throw new UsernameNotFoundException("user_id mismatch between id_token and user_info call: " + token.getSub() + " / " + userInfo.getSub());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return createAuthenticationToken(token, authoritiesMapper.mapAuthorities(idToken, userInfo), userInfo);
|
|
||||||
} catch (ParseException e) {
|
|
||||||
logger.error("Unable to parse ID token in the token");
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return createAuthenticationToken(token, authoritiesMapper.mapAuthorities(idToken, userInfo), userInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -104,7 +97,7 @@ public class OIDCAuthenticationProvider implements AuthenticationProvider {
|
||||||
return new OIDCAuthenticationToken(token.getSub(),
|
return new OIDCAuthenticationToken(token.getSub(),
|
||||||
token.getIssuer(),
|
token.getIssuer(),
|
||||||
userInfo, authorities,
|
userInfo, authorities,
|
||||||
token.getIdTokenValue(), token.getAccessTokenValue(), token.getRefreshTokenValue());
|
token.getIdToken(), token.getAccessTokenValue(), token.getRefreshTokenValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.mitre.openid.connect.model;
|
package org.mitre.openid.connect.model;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
|
||||||
import javax.persistence.Basic;
|
import javax.persistence.Basic;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Convert;
|
import javax.persistence.Convert;
|
||||||
|
@ -32,6 +36,7 @@ import javax.persistence.Table;
|
||||||
import org.mitre.openid.connect.model.convert.JsonObjectStringConverter;
|
import org.mitre.openid.connect.model.convert.JsonObjectStringConverter;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name="user_info")
|
@Table(name="user_info")
|
||||||
|
@ -70,7 +75,7 @@ public class DefaultUserInfo implements UserInfo {
|
||||||
private Address address;
|
private Address address;
|
||||||
private String updatedTime;
|
private String updatedTime;
|
||||||
private String birthdate;
|
private String birthdate;
|
||||||
private JsonObject src; // source JSON if this is loaded remotely
|
private transient JsonObject src; // source JSON if this is loaded remotely
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -727,5 +732,26 @@ public class DefaultUserInfo implements UserInfo {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Custom serialization to handle the JSON object
|
||||||
|
*/
|
||||||
|
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||||
|
out.defaultWriteObject();
|
||||||
|
if (src == null) {
|
||||||
|
out.writeObject(null);
|
||||||
|
} else {
|
||||||
|
out.writeObject(src.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
|
in.defaultReadObject();
|
||||||
|
Object o = in.readObject();
|
||||||
|
if (o != null) {
|
||||||
|
JsonParser parser = new JsonParser();
|
||||||
|
src = parser.parse((String)o).getAsJsonObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.mitre.openid.connect.model;
|
package org.mitre.openid.connect.model;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.ObjectOutputStream;
|
||||||
|
import java.text.ParseException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@ -24,6 +28,8 @@ import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.nimbusds.jwt.JWT;
|
||||||
|
import com.nimbusds.jwt.JWTParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -35,14 +41,14 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
private static final long serialVersionUID = 22100073066377804L;
|
private static final long serialVersionUID = 22100073066377804L;
|
||||||
|
|
||||||
private final ImmutableMap<String, String> principal;
|
private final ImmutableMap<String, String> principal;
|
||||||
private final String idTokenValue; // string representation of the id token
|
|
||||||
private final String accessTokenValue; // string representation of the access token
|
private final String accessTokenValue; // string representation of the access token
|
||||||
private final String refreshTokenValue; // string representation of the refresh token
|
private final String refreshTokenValue; // string representation of the refresh token
|
||||||
|
private transient JWT idToken; // this needs a custom serializer
|
||||||
private final String issuer; // issuer URL (parsed from the id token)
|
private final String issuer; // issuer URL (parsed from the id token)
|
||||||
private final String sub; // user id (parsed from the id token)
|
private final String sub; // user id (parsed from the id token)
|
||||||
|
|
||||||
private final transient ServerConfiguration serverConfiguration; // server configuration used to fulfill this token, don't serialize it
|
private final transient ServerConfiguration serverConfiguration; // server configuration used to fulfill this token, don't serialize it
|
||||||
private final UserInfo userInfo; // user info container, don't serialize it b/c it might be huge and can be re-fetched
|
private final UserInfo userInfo; // user info container
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs OIDCAuthenticationToken with a full set of authorities, marking this as authenticated.
|
* Constructs OIDCAuthenticationToken with a full set of authorities, marking this as authenticated.
|
||||||
|
@ -57,7 +63,7 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
*/
|
*/
|
||||||
public OIDCAuthenticationToken(String subject, String issuer,
|
public OIDCAuthenticationToken(String subject, String issuer,
|
||||||
UserInfo userInfo, Collection<? extends GrantedAuthority> authorities,
|
UserInfo userInfo, Collection<? extends GrantedAuthority> authorities,
|
||||||
String idTokenValue, String accessTokenValue, String refreshTokenValue) {
|
JWT idToken, String accessTokenValue, String refreshTokenValue) {
|
||||||
|
|
||||||
super(authorities);
|
super(authorities);
|
||||||
|
|
||||||
|
@ -65,7 +71,7 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
this.userInfo = userInfo;
|
this.userInfo = userInfo;
|
||||||
this.sub = subject;
|
this.sub = subject;
|
||||||
this.issuer = issuer;
|
this.issuer = issuer;
|
||||||
this.idTokenValue = idTokenValue;
|
this.idToken = idToken;
|
||||||
this.accessTokenValue = accessTokenValue;
|
this.accessTokenValue = accessTokenValue;
|
||||||
this.refreshTokenValue = refreshTokenValue;
|
this.refreshTokenValue = refreshTokenValue;
|
||||||
|
|
||||||
|
@ -85,14 +91,14 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
*/
|
*/
|
||||||
public OIDCAuthenticationToken(String subject, String issuer,
|
public OIDCAuthenticationToken(String subject, String issuer,
|
||||||
ServerConfiguration serverConfiguration,
|
ServerConfiguration serverConfiguration,
|
||||||
String idTokenValue, String accessTokenValue, String refreshTokenValue) {
|
JWT idToken, String accessTokenValue, String refreshTokenValue) {
|
||||||
|
|
||||||
super(new ArrayList<GrantedAuthority>(0));
|
super(new ArrayList<GrantedAuthority>(0));
|
||||||
|
|
||||||
this.principal = ImmutableMap.of("sub", subject, "iss", issuer);
|
this.principal = ImmutableMap.of("sub", subject, "iss", issuer);
|
||||||
this.sub = subject;
|
this.sub = subject;
|
||||||
this.issuer = issuer;
|
this.issuer = issuer;
|
||||||
this.idTokenValue = idTokenValue;
|
this.idToken = idToken;
|
||||||
this.accessTokenValue = accessTokenValue;
|
this.accessTokenValue = accessTokenValue;
|
||||||
this.refreshTokenValue = refreshTokenValue;
|
this.refreshTokenValue = refreshTokenValue;
|
||||||
|
|
||||||
|
@ -129,8 +135,8 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
/**
|
/**
|
||||||
* @return the idTokenValue
|
* @return the idTokenValue
|
||||||
*/
|
*/
|
||||||
public String getIdTokenValue() {
|
public JWT getIdToken() {
|
||||||
return idTokenValue;
|
return idToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -168,5 +174,23 @@ public class OIDCAuthenticationToken extends AbstractAuthenticationToken {
|
||||||
return userInfo;
|
return userInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Custom serialization to handle the JSON object
|
||||||
|
*/
|
||||||
|
private void writeObject(ObjectOutputStream out) throws IOException {
|
||||||
|
out.defaultWriteObject();
|
||||||
|
if (idToken == null) {
|
||||||
|
out.writeObject(null);
|
||||||
|
} else {
|
||||||
|
out.writeObject(idToken.serialize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException, ParseException {
|
||||||
|
in.defaultReadObject();
|
||||||
|
Object o = in.readObject();
|
||||||
|
if (o != null) {
|
||||||
|
idToken = JWTParser.parse((String)o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue