reworked id tokens, added SWD endpoint shell, started checkid endpoint shell (still needs signer service of some kind)
parent
a81dd8d5a4
commit
505ec3d39f
|
@ -0,0 +1,5 @@
|
|||
#Wed Jan 25 13:44:10 EST 2012
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
|
@ -1,4 +1,4 @@
|
|||
#Wed Jan 04 13:38:09 EST 2012
|
||||
#Wed Jan 25 13:44:09 EST 2012
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
fullBuildGoals=process-test-resources
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#Wed Jan 04 13:45:00 EST 2012
|
||||
#Wed Jan 25 13:44:10 EST 2012
|
||||
com.springsource.sts.maven.maven.automatically.update=true
|
||||
eclipse.preferences.version=1
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#Wed Jan 25 13:44:10 EST 2012
|
||||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
|
@ -3,8 +3,8 @@
|
|||
<wb-module deploy-name="openid">
|
||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
|
||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
|
||||
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
|
||||
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
|
||||
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
|
||||
<dependent-module archiveName="spring-security-oauth2-1.0.0.BUILD-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/spring-security-oauth2/spring-security-oauth2">
|
||||
<dependency-type>uses</dependency-type>
|
||||
</dependent-module>
|
||||
|
|
|
@ -2,11 +2,9 @@
|
|||
<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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.mitre</groupId>
|
||||
<artifactId>openid-connect-server</artifactId>
|
||||
<name>OpenIdConnect Server</name>
|
||||
<packaging>war</packaging>
|
||||
<version>0.1</version>
|
||||
<properties>
|
||||
<java-version>1.6</java-version>
|
||||
<org.springframework-version>3.1.0.RELEASE</org.springframework-version>
|
||||
|
@ -392,7 +390,7 @@
|
|||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.google.code.maven-replacer-plugin</groupId>
|
||||
<artifactId>maven-replacer-plugin</artifactId>
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
package org.mitre.jwt.model;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
/**
|
||||
|
@ -20,7 +26,19 @@ public class ClaimSet {
|
|||
// the LinkedHashMap preserves insertion order
|
||||
private Map<String, Object> claims = new LinkedHashMap<String, Object>();
|
||||
|
||||
/**
|
||||
public ClaimSet() {
|
||||
|
||||
}
|
||||
|
||||
public ClaimSet(JsonObject json) {
|
||||
loadFromJsonObject(json);
|
||||
}
|
||||
|
||||
public ClaimSet(String b64) {
|
||||
loadFromBase64JsonObjectString(b64);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an extension claim
|
||||
*/
|
||||
public Object getClaim(String key) {
|
||||
|
@ -86,6 +104,14 @@ public class ClaimSet {
|
|||
|
||||
|
||||
/**
|
||||
* Clear all claims from this ClaimSet
|
||||
* @see java.util.Map#clear()
|
||||
*/
|
||||
public void clear() {
|
||||
claims.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a copy of this claim set as a JsonObject. The JsonObject is not
|
||||
* backed by a live copy of this ClaimSet.
|
||||
* @return a copy of the data in this header in a JsonObject
|
||||
|
@ -128,5 +154,32 @@ public class ClaimSet {
|
|||
return o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load new claims from the given json object. Will replace any existing claims, but does not clear claim set.
|
||||
* @param json
|
||||
*/
|
||||
public void loadFromJsonObject(JsonObject json) {
|
||||
for (Entry<String, JsonElement> element : json.entrySet()) {
|
||||
if (element.getValue().isJsonPrimitive()){
|
||||
// we handle all primitives in here
|
||||
JsonPrimitive prim = element.getValue().getAsJsonPrimitive();
|
||||
setClaim(element.getKey(), prim);
|
||||
} else {
|
||||
setClaim(element.getKey(), element.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a new claims set from a Base64 encoded JSON Object string
|
||||
*/
|
||||
public void loadFromBase64JsonObjectString(String b64) {
|
||||
byte[] b64decoded = Base64.decodeBase64(b64);
|
||||
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonObject json = parser.parse(new InputStreamReader(new ByteArrayInputStream(b64decoded))).getAsJsonObject();
|
||||
|
||||
loadFromJsonObject(json);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -139,12 +139,8 @@ public class Jwt {
|
|||
String c64 = parts.get(1);
|
||||
String s64 = parts.get(2);
|
||||
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonObject hjo = parser.parse(new InputStreamReader(new ByteArrayInputStream(Base64.decodeBase64(h64)))).getAsJsonObject();
|
||||
JsonObject cjo = parser.parse(new InputStreamReader(new ByteArrayInputStream(Base64.decodeBase64(c64)))).getAsJsonObject();
|
||||
|
||||
// shuttle for return value
|
||||
Jwt jwt = new Jwt(new JwtHeader(hjo), new JwtClaims(cjo), s64);
|
||||
Jwt jwt = new Jwt(new JwtHeader(h64), new JwtClaims(c64), s64);
|
||||
|
||||
// TODO: save the wire-encoded string in the Jwt object itself?
|
||||
|
||||
|
|
|
@ -29,10 +29,21 @@ public class JwtClaims extends ClaimSet {
|
|||
//public static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz");
|
||||
|
||||
public JwtClaims() {
|
||||
|
||||
super();
|
||||
}
|
||||
|
||||
public JwtClaims(JsonObject json) {
|
||||
super(json);
|
||||
}
|
||||
|
||||
public JwtClaims(String b64) {
|
||||
super(b64);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadFromJsonObject(JsonObject json) {
|
||||
JsonObject pass = new JsonObject();
|
||||
|
||||
for (Entry<String, JsonElement> element : json.entrySet()) {
|
||||
if (element.getKey().equals(EXPIRATION)) {
|
||||
setExpiration(new Date(element.getValue().getAsLong() * 1000L));
|
||||
|
@ -51,15 +62,12 @@ public class JwtClaims extends ClaimSet {
|
|||
} else if (element.getKey().equals(TYPE)) {
|
||||
setType(element.getValue().getAsString());
|
||||
} else {
|
||||
if (element.getValue().isJsonPrimitive()){
|
||||
// we handle all primitives in here
|
||||
JsonPrimitive prim = element.getValue().getAsJsonPrimitive();
|
||||
setClaim(element.getKey(), prim);
|
||||
} else {
|
||||
setClaim(element.getKey(), element.getValue());
|
||||
}
|
||||
pass.add(element.getKey(), element.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// load all the generic claims into this object
|
||||
super.loadFromJsonObject(pass);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,7 +18,7 @@ public class JwtHeader extends ClaimSet {
|
|||
* Make an empty header
|
||||
*/
|
||||
public JwtHeader() {
|
||||
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,7 +26,22 @@ public class JwtHeader extends ClaimSet {
|
|||
* @param json
|
||||
*/
|
||||
public JwtHeader(JsonObject json) {
|
||||
super(json);
|
||||
}
|
||||
|
||||
|
||||
public JwtHeader(String b64) {
|
||||
super(b64);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all claims from the given json object into this object
|
||||
*/
|
||||
@Override
|
||||
public void loadFromJsonObject(JsonObject json) {
|
||||
|
||||
JsonObject pass = new JsonObject();
|
||||
|
||||
for (Entry<String, JsonElement> element : json.entrySet()) {
|
||||
if (element.getKey().equals(TYPE)) {
|
||||
this.setType(json.get(TYPE).getAsString());
|
||||
|
@ -35,15 +50,12 @@ public class JwtHeader extends ClaimSet {
|
|||
} else if (element.getKey().equals(ENCRYPTION_METHOD)) {
|
||||
this.setEncryptionMethod(json.get(ENCRYPTION_METHOD).getAsString());
|
||||
} else {
|
||||
if (element.getValue().isJsonPrimitive()){
|
||||
// we handle all primitives in here
|
||||
JsonPrimitive prim = element.getValue().getAsJsonPrimitive();
|
||||
setClaim(element.getKey(), prim);
|
||||
} else {
|
||||
setClaim(element.getKey(), element.getValue());
|
||||
}
|
||||
pass.add(element.getKey(), element.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// now load all the ones we didn't handly specially
|
||||
super.loadFromJsonObject(pass);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package org.mitre.openid.connect.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
|
@ -10,6 +12,11 @@ import javax.persistence.Table;
|
|||
import javax.persistence.Transient;
|
||||
|
||||
import org.mitre.jwt.model.Jwt;
|
||||
import org.mitre.jwt.model.JwtClaims;
|
||||
import org.mitre.jwt.model.JwtHeader;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
@Entity
|
||||
@Table(name="idtoken")
|
||||
|
@ -18,6 +25,24 @@ import org.mitre.jwt.model.Jwt;
|
|||
})
|
||||
public class IdToken extends Jwt {
|
||||
|
||||
/**
|
||||
* Create a blank IdToken
|
||||
*/
|
||||
public IdToken() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an IdToken from the requisite pieces.
|
||||
* @param header
|
||||
* @param claims
|
||||
* @param signature
|
||||
*/
|
||||
public IdToken(JwtHeader header, JwtClaims claims, String signature) {
|
||||
super(header, claims, signature);
|
||||
}
|
||||
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
|
@ -52,5 +77,33 @@ public class IdToken extends Jwt {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse a wire-encoded IdToken.
|
||||
*
|
||||
*/
|
||||
public static IdToken parse(String s) {
|
||||
|
||||
// TODO: this code was copied nearly verbatim from Jwt.parse, and
|
||||
// we should figure out how to re-use and abstract bits, likely
|
||||
|
||||
// split on the dots
|
||||
List<String> parts = Lists.newArrayList(Splitter.on(".").split(s));
|
||||
|
||||
if (parts.size() != 3) {
|
||||
throw new IllegalArgumentException("Invalid JWT format.");
|
||||
}
|
||||
|
||||
String h64 = parts.get(0);
|
||||
String c64 = parts.get(1);
|
||||
String s64 = parts.get(2);
|
||||
|
||||
// shuttle for return value
|
||||
IdToken idToken = new IdToken(new JwtHeader(h64), new IdTokenClaims(c64), s64);
|
||||
|
||||
// TODO: save the wire-encoded string in the Jwt object itself?
|
||||
|
||||
return idToken;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package org.mitre.openid.connect.model;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
|
@ -11,6 +13,10 @@ import javax.persistence.Transient;
|
|||
|
||||
import org.mitre.jwt.model.JwtClaims;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name="idtokenclaims")
|
||||
|
@ -23,6 +29,20 @@ public class IdTokenClaims extends JwtClaims {
|
|||
|
||||
private Long id;
|
||||
|
||||
|
||||
|
||||
public IdTokenClaims() {
|
||||
super();
|
||||
}
|
||||
|
||||
public IdTokenClaims(JsonObject json) {
|
||||
super(json);
|
||||
}
|
||||
|
||||
public IdTokenClaims(String b64) {
|
||||
super(b64);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
|
@ -74,4 +94,55 @@ public class IdTokenClaims extends JwtClaims {
|
|||
setClaim(AUTH_TIME, authTime);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the seraialized form of this claim set
|
||||
*/
|
||||
@Basic
|
||||
public String getSerializedForm() {
|
||||
// TODO Auto-generated method stub
|
||||
JsonObject o = super.getAsJsonObject();
|
||||
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the claims in this object from the serialized form. This clears all current claims from the object.
|
||||
* @param s a JSON Object string to load into this object
|
||||
* @throws IllegalArgumentException if s is not a valid JSON object string
|
||||
*/
|
||||
public void setSerializedForm(String s) {
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonElement json = parser.parse(s);
|
||||
if (json != null && json.isJsonObject()) {
|
||||
loadFromJsonObject(json.getAsJsonObject());
|
||||
} else {
|
||||
throw new IllegalArgumentException("Could not parse: " + s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load this IdToken from a JSON Object
|
||||
*/
|
||||
@Override
|
||||
public void loadFromJsonObject(JsonObject json) {
|
||||
JsonObject pass = new JsonObject();
|
||||
|
||||
for (Entry<String, JsonElement> element : json.entrySet()) {
|
||||
if (element.getKey().equals(USER_ID)) {
|
||||
setUserId(element.getValue().getAsString());
|
||||
} else if (element.getKey().equals(AUTHENTICATION_CONTEXT_CLASS_REFERENCE)) {
|
||||
setAuthContext(element.getValue().getAsString());
|
||||
} else if (element.getKey().equals(NONCE)) {
|
||||
setNonce(element.getValue().getAsString());
|
||||
} else if (element.getKey().equals(AUTH_TIME)) {
|
||||
setAuthTime(new Date(element.getValue().getAsLong() * 1000L));
|
||||
} else {
|
||||
pass.add(element.getKey(), element.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
super.loadFromJsonObject(pass);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package org.mitre.openid.connect.web;
|
||||
|
||||
import org.mitre.openid.connect.model.IdToken;
|
||||
import org.mitre.openid.connect.model.IdTokenClaims;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
@ -7,15 +8,17 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
@Controller
|
||||
@RequestMapping("/checkid")
|
||||
public class CheckIDEndpoint {
|
||||
|
||||
@RequestMapping("/")
|
||||
public ModelAndView checkID(@RequestParam("id_token") String idToken, ModelAndView mav) {
|
||||
|
||||
|
||||
@RequestMapping("/checkid")
|
||||
public ModelAndView checkID(@RequestParam("id_token") String tokenString, ModelAndView mav) {
|
||||
|
||||
IdToken token = IdToken.parse(tokenString);
|
||||
|
||||
|
||||
IdTokenClaims token = new IdTokenClaims();
|
||||
|
||||
//TODO: Set claims
|
||||
|
||||
return new ModelAndView("jsonIdTokenView", "checkId", token);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
package org.mitre.swd.web;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
@Controller
|
||||
public class SimpleWebDiscoveryEndpoint {
|
||||
|
||||
@RequestMapping(value="/.well-known/simple-web-discovery",
|
||||
params={"principal", "service=http://openid.net/specs/connect/1.0/issuer"})
|
||||
public ModelAndView openIdConnectIssuerDiscovery(@RequestParam("principal") String principal, ModelAndView modelAndView) {
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* version string Version of the provider response. "3.0" is the default.
|
||||
* issuer string The https: URL with no path component that the OP asserts as its Issuer Identifier
|
||||
* authorization_endpoint string URL of the OP's Authentication and Authorization Endpoint [OpenID.Messages]
|
||||
* token_endpoint string URL of the OP's OAuth 2.0 Token Endpoint [OpenID.Messages]
|
||||
* userinfo_endpoint string URL of the OP's UserInfo Endpoint [OpenID.Messages]
|
||||
* check_id_endpoint string URL of the OP's Check ID Endpoint [OpenID.Messages]
|
||||
* refresh_session_endpoint string URL of the OP's Refresh Session Endpoint [OpenID.Session]
|
||||
* end_session_endpoint string URL of the OP's End Session Endpoint [OpenID.Session]
|
||||
* jwk_url string URL of the OP's JSON Web Key [JWK] document. Server's signing Key
|
||||
* jwk_encryption_url string URL of the OP's JSON Web Key [JWK] document. Server's Encryption Key, if not present, its value is the same as the URL provided by jwk_url
|
||||
* x509_url string URL of the OP's X.509 certificates in PEM format.
|
||||
* x509_encryption_url string URL of the OP's X.509 certificates in PEM format. Server's Encryption Key, if not present its value is the same as the URL provided by x509_url
|
||||
* registration_endpoint string URL of the OP's Dynamic Client Registration Endpoint [OpenID.Registration]
|
||||
* scopes_supported array A JSON array containing a list of the OAuth 2.0 [OAuth2.0] scope values that this server supports. The server MUST support the openid scope value.
|
||||
* response_types_supported array A JSON array containing a list of the OAuth 2.0 response_type that this server supports. The server MUST support the code response_type.
|
||||
* acrs_supported array A JSON array containing a list of the Authentication Context Class References that this server supports.
|
||||
* user_id_types_supported array A JSON array containing a list of the user identifier types that this server supports. Valid types include pairwise and public.
|
||||
* userinfo_algs_supported array A JSON array containing a list of the JWS [JWS] and JWE [JWE] signing and encryption algorithms supported by the UserInfo Endpoint to encode the JWT [JWT].
|
||||
* id_token_algs_supported array A JSON array containing a list of the JWS [JWS] and JWE [JWE] signing and encryption algorithms supported by the Authorization Server for the ID Token to encode the JWT [JWT].
|
||||
* request_object_algs_supported array A JSON array containing a list of the JWS [JWS] and JWE [JWE] signing and encryption algorithms supported by the Authorization Server for the OpenID Request Object described in Section 2.1.2.1 of OpenID Connect Messages 1.0 [OpenID.Messages] to encode the JWT [JWT]. Servers SHOULD support HS256.
|
||||
* token_endpoint_auth_types_supported array A JSON array containing a list of authentication types supported by this Token Endpoint. The options are client_secret_post, client_secret_basic, client_secret_jwt, and private_key_jwt, as described in Section 2.2.1 of OpenID Connect Messages 1.0 [OpenID.Messages]. Other Authentication types may be defined by extension. If unspecified or omitted, the default is client_secret_basic HTTP Basic Authentication Scheme as specified in section 2.3.1 of OAuth 2.0 [OAuth2.0].
|
||||
* token_endpoint_auth_algs_supported array A JSON array containing a list of the JWS [JWS] signing algorithms supported by the Token Endpoint for the private_key_jwt method to encode the JWT [JWT]. Servers SHOULD support RS256.
|
||||
*/
|
||||
@RequestMapping("/.well-known/openid-configuration")
|
||||
public ModelAndView providerConfiguration(ModelAndView modelAndView) {
|
||||
|
||||
Map m = modelAndView.getModel();
|
||||
m.put("version", "3.0");
|
||||
// TODO: everything in the list up there
|
||||
|
||||
return modelAndView;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue