This commit is contained in:
Bill Burke 2013-07-19 21:33:44 -04:00
parent e1fe001a22
commit 33e9de654b
38 changed files with 3141 additions and 3800 deletions

View file

@ -1,8 +1,8 @@
package org.keycloak; package org.keycloak;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.keycloak.representations.AccessTokenResponse;
import org.jboss.resteasy.util.BasicAuthHelper; import org.jboss.resteasy.util.BasicAuthHelper;
import org.keycloak.representations.AccessTokenResponse;
import javax.ws.rs.BadRequestException; import javax.ws.rs.BadRequestException;
import javax.ws.rs.InternalServerErrorException; import javax.ws.rs.InternalServerErrorException;
@ -20,143 +20,116 @@ import java.util.concurrent.atomic.AtomicLong;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class AbstractOAuthClient public class AbstractOAuthClient {
{ protected String clientId;
protected String clientId; protected String password;
protected String password; protected KeyStore truststore;
protected KeyStore truststore; protected String authUrl;
protected String authUrl; protected String codeUrl;
protected String codeUrl; protected String stateCookieName = "OAuth_Token_Request_State";
protected String stateCookieName = "OAuth_Token_Request_State"; protected Client client;
protected Client client; protected final AtomicLong counter = new AtomicLong();
protected final AtomicLong counter = new AtomicLong();
protected String getStateCode() protected String getStateCode() {
{ return counter.getAndIncrement() + "/" + UUID.randomUUID().toString();
return counter.getAndIncrement() + "/" + UUID.randomUUID().toString(); }
}
public void start() public void start() {
{ if (client == null) {
if (client == null) client = new ResteasyClientBuilder().trustStore(truststore)
{ .hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY)
client = new ResteasyClientBuilder().trustStore(truststore) .connectionPoolSize(10)
.hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY) .build();
.connectionPoolSize(10) }
.build(); }
}
}
public void stop() public void stop() {
{ client.close();
client.close(); }
}
public String getClientId() public String getClientId() {
{ return clientId;
return clientId; }
}
public void setClientId(String clientId) public void setClientId(String clientId) {
{ this.clientId = clientId;
this.clientId = clientId; }
}
public String getPassword() public String getPassword() {
{ return password;
return password; }
}
public void setPassword(String password) public void setPassword(String password) {
{ this.password = password;
this.password = password; }
}
public KeyStore getTruststore() public KeyStore getTruststore() {
{ return truststore;
return truststore; }
}
public void setTruststore(KeyStore truststore) public void setTruststore(KeyStore truststore) {
{ this.truststore = truststore;
this.truststore = truststore; }
}
public String getAuthUrl() public String getAuthUrl() {
{ return authUrl;
return authUrl; }
}
public void setAuthUrl(String authUrl) public void setAuthUrl(String authUrl) {
{ this.authUrl = authUrl;
this.authUrl = authUrl; }
}
public String getCodeUrl() public String getCodeUrl() {
{ return codeUrl;
return codeUrl; }
}
public void setCodeUrl(String codeUrl) public void setCodeUrl(String codeUrl) {
{ this.codeUrl = codeUrl;
this.codeUrl = codeUrl; }
}
public String getStateCookieName() public String getStateCookieName() {
{ return stateCookieName;
return stateCookieName; }
}
public void setStateCookieName(String stateCookieName) public void setStateCookieName(String stateCookieName) {
{ this.stateCookieName = stateCookieName;
this.stateCookieName = stateCookieName; }
}
public Client getClient() public Client getClient() {
{ return client;
return client; }
}
public void setClient(Client client) public void setClient(Client client) {
{ this.client = client;
this.client = client; }
}
public String resolveBearerToken(String redirectUri, String code) public String resolveBearerToken(String redirectUri, String code) {
{ redirectUri = stripOauthParametersFromRedirect(redirectUri);
redirectUri = stripOauthParametersFromRedirect(redirectUri); String authHeader = BasicAuthHelper.createHeader(clientId, password);
String authHeader = BasicAuthHelper.createHeader(clientId, password); Form codeForm = new Form()
Form codeForm = new Form() .param("grant_type", "authorization_code")
.param("grant_type", "authorization_code") .param("code", code)
.param("code", code) .param("redirect_uri", redirectUri);
.param("redirect_uri", redirectUri); Response res = client.target(codeUrl).request().header(HttpHeaders.AUTHORIZATION, authHeader).post(Entity.form(codeForm));
Response res = client.target(codeUrl).request().header(HttpHeaders.AUTHORIZATION, authHeader).post(Entity.form(codeForm)); try {
try if (res.getStatus() == 400) {
{ throw new BadRequestException();
if (res.getStatus() == 400) } else if (res.getStatus() != 200) {
{ throw new InternalServerErrorException(new Exception("Unknown error when getting acess token"));
throw new BadRequestException(); }
} AccessTokenResponse tokenResponse = res.readEntity(AccessTokenResponse.class);
else if (res.getStatus() != 200) return tokenResponse.getToken();
{ } finally {
throw new InternalServerErrorException(new Exception("Unknown error when getting acess token")); res.close();
} }
AccessTokenResponse tokenResponse = res.readEntity(AccessTokenResponse.class); }
return tokenResponse.getToken();
}
finally
{
res.close();
}
}
protected String stripOauthParametersFromRedirect(String uri) protected String stripOauthParametersFromRedirect(String uri) {
{ System.out.println("******************** redirect_uri: " + uri);
System.out.println("******************** redirect_uri: " + uri); UriBuilder builder = UriBuilder.fromUri(uri)
UriBuilder builder = UriBuilder.fromUri(uri) .replaceQueryParam("code", null)
.replaceQueryParam("code", null) .replaceQueryParam("state", null);
.replaceQueryParam("state", null); return builder.build().toString();
return builder.build().toString(); }
}
} }

View file

@ -8,15 +8,12 @@ import java.security.Security;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class BouncyIntegration public class BouncyIntegration {
{ static {
static if (Security.getProvider("BC") == null) Security.addProvider(new BouncyCastleProvider());
{ }
if (Security.getProvider("BC") == null) Security.addProvider(new BouncyCastleProvider());
}
public static void init() public static void init() {
{ // empty, the static class does it
// empty, the static class does it }
}
} }

View file

@ -20,49 +20,43 @@ import java.security.spec.X509EncodedKeySpec;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class DerUtils public class DerUtils {
{ static {
static BouncyIntegration.init();
{ }
BouncyIntegration.init();
}
public static PrivateKey decodePrivateKey(InputStream is) public static PrivateKey decodePrivateKey(InputStream is)
throws Exception throws Exception {
{
DataInputStream dis = new DataInputStream(is); DataInputStream dis = new DataInputStream(is);
byte[] keyBytes = new byte[dis.available()]; byte[] keyBytes = new byte[dis.available()];
dis.readFully(keyBytes); dis.readFully(keyBytes);
dis.close(); dis.close();
PKCS8EncodedKeySpec spec = PKCS8EncodedKeySpec spec =
new PKCS8EncodedKeySpec(keyBytes); new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA", "BC"); KeyFactory kf = KeyFactory.getInstance("RSA", "BC");
return kf.generatePrivate(spec); return kf.generatePrivate(spec);
} }
public static PublicKey decodePublicKey(byte[] der) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException public static PublicKey decodePublicKey(byte[] der) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
{ X509EncodedKeySpec spec =
X509EncodedKeySpec spec = new X509EncodedKeySpec(der);
new X509EncodedKeySpec(der); KeyFactory kf = KeyFactory.getInstance("RSA", "BC");
KeyFactory kf = KeyFactory.getInstance("RSA", "BC"); return kf.generatePublic(spec);
return kf.generatePublic(spec); }
}
public static X509Certificate decodeCertificate(InputStream is) throws Exception public static X509Certificate decodeCertificate(InputStream is) throws Exception {
{ CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
X509Certificate cert = (X509Certificate) cf.generateCertificate(is); is.close();
is.close(); return cert;
return cert; }
}
public static PrivateKey decodePrivateKey(byte[] der) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException public static PrivateKey decodePrivateKey(byte[] der) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
{ PKCS8EncodedKeySpec spec =
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(der);
new PKCS8EncodedKeySpec(der); KeyFactory kf = KeyFactory.getInstance("RSA", "BC");
KeyFactory kf = KeyFactory.getInstance("RSA", "BC"); return kf.generatePrivate(spec);
return kf.generatePrivate(spec); }
}
} }

View file

@ -7,30 +7,27 @@ import java.util.regex.Pattern;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class EnvUtil public class EnvUtil {
{ private static final Pattern p = Pattern.compile("[$][{]([^}]+)[}]");
private static final Pattern p = Pattern.compile("[$][{]([^}]+)[}]");
/** /**
* Replaces any ${} strings with their corresponding environent variable. * Replaces any ${} strings with their corresponding environent variable.
* *
* @param val * @param val
* @return * @return
*/ */
public static String replace(String val) public static String replace(String val) {
{ Matcher matcher = p.matcher(val);
Matcher matcher = p.matcher(val); StringBuffer buf = new StringBuffer();
StringBuffer buf = new StringBuffer(); while (matcher.find()) {
while (matcher.find()) String envVar = matcher.group(1);
{ String envVal = System.getProperty(envVar);
String envVar = matcher.group(1); if (envVal == null) envVal = "NOT-SPECIFIED";
String envVal = System.getProperty(envVar); matcher.appendReplacement(buf, envVal.replace("\\", "\\\\"));
if (envVal == null) envVal = "NOT-SPECIFIED"; }
matcher.appendReplacement(buf, envVal.replace("\\", "\\\\")); matcher.appendTail(buf);
} return buf.toString();
matcher.appendTail(buf); }
return buf.toString();
}
} }

View file

@ -16,102 +16,92 @@ import java.security.cert.X509Certificate;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class PemUtils public class PemUtils {
{ static {
static BouncyIntegration.init();
{ }
BouncyIntegration.init();
}
public static X509Certificate decodeCertificate(InputStream is) throws Exception
{
byte[] der = pemToDer(is);
ByteArrayInputStream bis = new ByteArrayInputStream(der);
return DerUtils.decodeCertificate(bis);
}
public static X509Certificate decodeCertificate(String cert) throws Exception public static X509Certificate decodeCertificate(InputStream is) throws Exception {
{ byte[] der = pemToDer(is);
byte[] der = pemToDer(cert); ByteArrayInputStream bis = new ByteArrayInputStream(der);
ByteArrayInputStream bis = new ByteArrayInputStream(der); return DerUtils.decodeCertificate(bis);
return DerUtils.decodeCertificate(bis); }
}
public static X509Certificate decodeCertificate(String cert) throws Exception {
byte[] der = pemToDer(cert);
ByteArrayInputStream bis = new ByteArrayInputStream(der);
return DerUtils.decodeCertificate(bis);
}
/** /**
* Extract a public key from a PEM string * Extract a public key from a PEM string
* *
* @param pem * @param pem
* @return * @return
* @throws Exception * @throws Exception
*/ */
public static PublicKey decodePublicKey(String pem) throws Exception public static PublicKey decodePublicKey(String pem) throws Exception {
{ byte[] der = pemToDer(pem);
byte[] der = pemToDer(pem); return DerUtils.decodePublicKey(der);
return DerUtils.decodePublicKey(der); }
}
/** /**
* Extract a private key that is a PKCS8 pem string (base64 encoded PKCS8) * Extract a private key that is a PKCS8 pem string (base64 encoded PKCS8)
* *
* @param pem * @param pem
* @return * @return
* @throws Exception * @throws Exception
*/ */
public static PrivateKey decodePrivateKey(String pem) throws Exception public static PrivateKey decodePrivateKey(String pem) throws Exception {
{ byte[] der = pemToDer(pem);
byte[] der = pemToDer(pem); return DerUtils.decodePrivateKey(der);
return DerUtils.decodePrivateKey(der); }
}
public static PrivateKey decodePrivateKey(InputStream is) throws Exception public static PrivateKey decodePrivateKey(InputStream is) throws Exception {
{ String pem = pemFromStream(is);
String pem = pemFromStream(is); return decodePrivateKey(pem);
return decodePrivateKey(pem); }
}
/** /**
* Decode a PEM file to DER format * Decode a PEM file to DER format
* *
* @param is * @param is
* @return * @return
* @throws java.io.IOException * @throws java.io.IOException
*/ */
public static byte[] pemToDer(InputStream is) throws IOException public static byte[] pemToDer(InputStream is) throws IOException {
{ String pem = pemFromStream(is);
String pem = pemFromStream(is); byte[] der = pemToDer(pem);
byte[] der = pemToDer(pem); return der;
return der; }
}
/** /**
* Decode a PEM string to DER format * Decode a PEM string to DER format
* *
* @param pem * @param pem
* @return * @return
* @throws java.io.IOException * @throws java.io.IOException
*/ */
public static byte[] pemToDer(String pem) throws IOException public static byte[] pemToDer(String pem) throws IOException {
{ pem = removeBeginEnd(pem);
pem = removeBeginEnd(pem); return Base64.decode(pem);
return Base64.decode(pem); }
}
public static String removeBeginEnd(String pem) public static String removeBeginEnd(String pem) {
{ pem = pem.replaceAll("-----BEGIN (.*)-----", "");
pem = pem.replaceAll("-----BEGIN (.*)-----", ""); pem = pem.replaceAll("-----END (.*)----", "");
pem = pem.replaceAll("-----END (.*)----", ""); pem = pem.replaceAll("\r\n", "");
pem = pem.replaceAll("\r\n", ""); pem = pem.replaceAll("\n", "");
pem = pem.replaceAll("\n", ""); return pem.trim();
return pem.trim(); }
}
public static String pemFromStream(InputStream is) throws IOException public static String pemFromStream(InputStream is) throws IOException {
{ DataInputStream dis = new DataInputStream(is);
DataInputStream dis = new DataInputStream(is); byte[] keyBytes = new byte[dis.available()];
byte[] keyBytes = new byte[dis.available()]; dis.readFully(keyBytes);
dis.readFully(keyBytes); dis.close();
dis.close(); return new String(keyBytes, "utf-8");
return new String(keyBytes, "utf-8"); }
}
} }

View file

@ -12,52 +12,40 @@ import java.security.PublicKey;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RSATokenVerifier public class RSATokenVerifier {
{ public static SkeletonKeyToken verifyToken(String tokenString, ResourceMetadata metadata) throws VerificationException {
public static SkeletonKeyToken verifyToken(String tokenString, ResourceMetadata metadata) throws VerificationException PublicKey realmKey = metadata.getRealmKey();
{ String realm = metadata.getRealm();
PublicKey realmKey = metadata.getRealmKey(); return verifyToken(tokenString, realmKey, realm);
String realm = metadata.getRealm(); }
return verifyToken(tokenString, realmKey, realm);
}
public static SkeletonKeyToken verifyToken(String tokenString, PublicKey realmKey, String realm) throws VerificationException public static SkeletonKeyToken verifyToken(String tokenString, PublicKey realmKey, String realm) throws VerificationException {
{ JWSInput input = new JWSInput(tokenString);
JWSInput input = new JWSInput(tokenString); boolean verified = false;
boolean verified = false; try {
try verified = RSAProvider.verify(input, realmKey);
{ } catch (Exception ignore) {
verified = RSAProvider.verify(input, realmKey);
}
catch (Exception ignore)
{
} }
if (!verified) throw new VerificationException("Token signature not validated"); if (!verified) throw new VerificationException("Token signature not validated");
SkeletonKeyToken token = null; SkeletonKeyToken token = null;
try try {
{ token = JsonSerialization.fromBytes(SkeletonKeyToken.class, input.getContent());
token = JsonSerialization.fromBytes(SkeletonKeyToken.class, input.getContent()); } catch (IOException e) {
} throw new VerificationException(e);
catch (IOException e) }
{ if (!token.isActive()) {
throw new VerificationException(e); throw new VerificationException("Token is not active.");
} }
if (!token.isActive()) String user = token.getPrincipal();
{ if (user == null) {
throw new VerificationException("Token is not active."); throw new VerificationException("Token user was null");
} }
String user = token.getPrincipal(); if (!realm.equals(token.getAudience())) {
if (user == null) throw new VerificationException("Token audience doesn't match domain");
{
throw new VerificationException("Token user was null");
}
if (!realm.equals(token.getAudience()))
{
throw new VerificationException("Token audience doesn't match domain");
} }
return token; return token;
} }
} }

View file

@ -10,89 +10,73 @@ import javax.ws.rs.core.UriBuilder;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RealmConfiguration public class RealmConfiguration {
{ protected ResourceMetadata metadata;
protected ResourceMetadata metadata; protected ResteasyClient client;
protected ResteasyClient client; protected UriBuilder authUrl;
protected UriBuilder authUrl; protected ResteasyWebTarget codeUrl;
protected ResteasyWebTarget codeUrl; protected String clientId;
protected String clientId; protected Form credentials = new Form();
protected Form credentials = new Form(); protected boolean sslRequired = true;
protected boolean sslRequired = true; protected String stateCookieName = "OAuth_Token_Request_State";
protected String stateCookieName = "OAuth_Token_Request_State";
public ResourceMetadata getMetadata() public ResourceMetadata getMetadata() {
{ return metadata;
return metadata; }
}
public void setMetadata(ResourceMetadata metadata) public void setMetadata(ResourceMetadata metadata) {
{ this.metadata = metadata;
this.metadata = metadata; }
}
public ResteasyClient getClient() public ResteasyClient getClient() {
{ return client;
return client; }
}
public void setClient(ResteasyClient client) public void setClient(ResteasyClient client) {
{ this.client = client;
this.client = client; }
}
public UriBuilder getAuthUrl() public UriBuilder getAuthUrl() {
{ return authUrl;
return authUrl; }
}
public void setAuthUrl(UriBuilder authUrl) public void setAuthUrl(UriBuilder authUrl) {
{ this.authUrl = authUrl;
this.authUrl = authUrl; }
}
public String getClientId() public String getClientId() {
{ return clientId;
return clientId; }
}
public void setClientId(String clientId) public void setClientId(String clientId) {
{ this.clientId = clientId;
this.clientId = clientId; }
}
public Form getCredentials() public Form getCredentials() {
{ return credentials;
return credentials; }
}
public ResteasyWebTarget getCodeUrl() public ResteasyWebTarget getCodeUrl() {
{ return codeUrl;
return codeUrl; }
}
public void setCodeUrl(ResteasyWebTarget codeUrl) public void setCodeUrl(ResteasyWebTarget codeUrl) {
{ this.codeUrl = codeUrl;
this.codeUrl = codeUrl; }
}
public boolean isSslRequired() public boolean isSslRequired() {
{ return sslRequired;
return sslRequired; }
}
public void setSslRequired(boolean sslRequired) public void setSslRequired(boolean sslRequired) {
{ this.sslRequired = sslRequired;
this.sslRequired = sslRequired; }
}
public String getStateCookieName() public String getStateCookieName() {
{ return stateCookieName;
return stateCookieName; }
}
public void setStateCookieName(String stateCookieName) public void setStateCookieName(String stateCookieName) {
{ this.stateCookieName = stateCookieName;
this.stateCookieName = stateCookieName; }
}
} }

View file

@ -7,88 +7,75 @@ import java.security.PublicKey;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class ResourceMetadata public class ResourceMetadata {
{ protected String resourceName;
protected String resourceName; protected String realm;
protected String realm; protected KeyStore clientKeystore;
protected KeyStore clientKeystore; protected String clientKeyPassword;
protected String clientKeyPassword; protected KeyStore truststore;
protected KeyStore truststore; protected PublicKey realmKey;
protected PublicKey realmKey;
public String getResourceName() public String getResourceName() {
{ return resourceName;
return resourceName; }
}
public String getRealm() public String getRealm() {
{ return realm;
return realm; }
}
/** /**
* keystore that contains service's private key and certificate. * keystore that contains service's private key and certificate.
* Used when making invocations on remote HTTPS endpoints that require client-cert authentication * Used when making invocations on remote HTTPS endpoints that require client-cert authentication
* *
* @return * @return
*/ */
public KeyStore getClientKeystore() public KeyStore getClientKeystore() {
{ return clientKeystore;
return clientKeystore; }
}
public String getClientKeyPassword() public String getClientKeyPassword() {
{ return clientKeyPassword;
return clientKeyPassword; }
}
public void setClientKeyPassword(String clientKeyPassword) public void setClientKeyPassword(String clientKeyPassword) {
{ this.clientKeyPassword = clientKeyPassword;
this.clientKeyPassword = clientKeyPassword; }
}
/** /**
* Truststore to use if this service makes client invocations on remote HTTPS endpoints. * Truststore to use if this service makes client invocations on remote HTTPS endpoints.
* *
* @return * @return
*/ */
public KeyStore getTruststore() public KeyStore getTruststore() {
{ return truststore;
return truststore; }
}
/** /**
* Public key of the realm. Used to verify access tokens * Public key of the realm. Used to verify access tokens
* *
* @return * @return
*/ */
public PublicKey getRealmKey() public PublicKey getRealmKey() {
{ return realmKey;
return realmKey; }
}
public void setResourceName(String resourceName) public void setResourceName(String resourceName) {
{ this.resourceName = resourceName;
this.resourceName = resourceName; }
}
public void setRealm(String realm) public void setRealm(String realm) {
{ this.realm = realm;
this.realm = realm; }
}
public void setClientKeystore(KeyStore clientKeystore) public void setClientKeystore(KeyStore clientKeystore) {
{ this.clientKeystore = clientKeystore;
this.clientKeystore = clientKeystore; }
}
public void setTruststore(KeyStore truststore) public void setTruststore(KeyStore truststore) {
{ this.truststore = truststore;
this.truststore = truststore; }
}
public void setRealmKey(PublicKey realmKey) public void setRealmKey(PublicKey realmKey) {
{ this.realmKey = realmKey;
this.realmKey = realmKey; }
}
} }

View file

@ -14,29 +14,24 @@ import javax.ws.rs.ext.Provider;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@Provider @Provider
public class SkeletonKeyContextResolver implements ContextResolver<ObjectMapper> public class SkeletonKeyContextResolver implements ContextResolver<ObjectMapper> {
{ protected ObjectMapper mapper = new ObjectMapper();
protected ObjectMapper mapper = new ObjectMapper();
public SkeletonKeyContextResolver() public SkeletonKeyContextResolver() {
{ mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT); }
}
public SkeletonKeyContextResolver(boolean indent) public SkeletonKeyContextResolver(boolean indent) {
{ mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT); if (indent) {
if (indent) mapper.enable(SerializationConfig.Feature.INDENT_OUTPUT);
{ }
mapper.enable(SerializationConfig.Feature.INDENT_OUTPUT); }
}
}
@Override @Override
public ObjectMapper getContext(Class<?> type) public ObjectMapper getContext(Class<?> type) {
{ if (type.getPackage().getName().startsWith(getClass().getPackage().getName())) return mapper;
if (type.getPackage().getName().startsWith(getClass().getPackage().getName())) return mapper; return null;
return null; }
}
} }

View file

@ -6,53 +6,46 @@ import java.security.Principal;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class SkeletonKeyPrincipal implements Principal public class SkeletonKeyPrincipal implements Principal {
{ protected String name;
protected String name; protected String surrogate;
protected String surrogate;
public SkeletonKeyPrincipal(String name, String surrogate) public SkeletonKeyPrincipal(String name, String surrogate) {
{ this.name = name;
this.name = name; this.surrogate = surrogate;
this.surrogate = surrogate; }
}
@Override @Override
public String getName() public String getName() {
{ return name;
return name; }
}
public String getSurrogate() public String getSurrogate() {
{ return surrogate;
return surrogate; }
}
@Override @Override
public boolean equals(Object o) public boolean equals(Object o) {
{ if (this == o) return true;
if (this == o) return true; if (o == null || getClass() != o.getClass()) return false;
if (o == null || getClass() != o.getClass()) return false;
SkeletonKeyPrincipal that = (SkeletonKeyPrincipal) o; SkeletonKeyPrincipal that = (SkeletonKeyPrincipal) o;
if (!name.equals(that.name)) return false; if (!name.equals(that.name)) return false;
if (surrogate != null ? !surrogate.equals(that.surrogate) : that.surrogate != null) return false; if (surrogate != null ? !surrogate.equals(that.surrogate) : that.surrogate != null) return false;
return true; return true;
} }
@Override @Override
public int hashCode() public int hashCode() {
{ int result = name.hashCode();
int result = name.hashCode(); result = 31 * result + (surrogate != null ? surrogate.hashCode() : 0);
result = 31 * result + (surrogate != null ? surrogate.hashCode() : 0); return result;
return result; }
}
@Override @Override
public String toString() public String toString() {
{ return name;
return name; }
}
} }

View file

@ -6,29 +6,24 @@ import java.io.Serializable;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class SkeletonKeySession implements Serializable public class SkeletonKeySession implements Serializable {
{ protected String token;
protected String token; protected transient ResourceMetadata metadata;
protected transient ResourceMetadata metadata;
public SkeletonKeySession() public SkeletonKeySession() {
{ }
}
public SkeletonKeySession(String token, ResourceMetadata metadata) public SkeletonKeySession(String token, ResourceMetadata metadata) {
{ this.token = token;
this.token = token; this.metadata = metadata;
this.metadata = metadata; }
}
public String getToken() public String getToken() {
{ return token;
return token; }
}
public ResourceMetadata getMetadata() public ResourceMetadata getMetadata() {
{ return metadata;
return metadata; }
}
} }

View file

@ -4,24 +4,19 @@ package org.keycloak;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class VerificationException extends Exception public class VerificationException extends Exception {
{ public VerificationException() {
public VerificationException() }
{
}
public VerificationException(String message) public VerificationException(String message) {
{ super(message);
super(message); }
}
public VerificationException(String message, Throwable cause) public VerificationException(String message, Throwable cause) {
{ super(message, cause);
super(message, cause); }
}
public VerificationException(Throwable cause) public VerificationException(Throwable cause) {
{ super(cause);
super(cause); }
}
} }

View file

@ -1,13 +1,13 @@
package org.keycloak.jaxrs; package org.keycloak.jaxrs;
import org.jboss.resteasy.logging.Logger; import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.RSATokenVerifier; import org.keycloak.RSATokenVerifier;
import org.keycloak.ResourceMetadata; import org.keycloak.ResourceMetadata;
import org.keycloak.SkeletonKeyPrincipal; import org.keycloak.SkeletonKeyPrincipal;
import org.keycloak.SkeletonKeySession; import org.keycloak.SkeletonKeySession;
import org.keycloak.VerificationException; import org.keycloak.VerificationException;
import org.keycloak.representations.SkeletonKeyToken; import org.keycloak.representations.SkeletonKeyToken;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import javax.annotation.Priority; import javax.annotation.Priority;
import javax.ws.rs.Priorities; import javax.ws.rs.Priorities;
@ -25,105 +25,87 @@ import java.security.Principal;
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@Priority(Priorities.AUTHENTICATION) @Priority(Priorities.AUTHENTICATION)
public class JaxrsBearerTokenFilter implements ContainerRequestFilter public class JaxrsBearerTokenFilter implements ContainerRequestFilter {
{ protected ResourceMetadata resourceMetadata;
protected ResourceMetadata resourceMetadata; private static Logger log = Logger.getLogger(JaxrsBearerTokenFilter.class);
private static Logger log = Logger.getLogger(JaxrsBearerTokenFilter.class);
public JaxrsBearerTokenFilter(ResourceMetadata resourceMetadata) public JaxrsBearerTokenFilter(ResourceMetadata resourceMetadata) {
{ this.resourceMetadata = resourceMetadata;
this.resourceMetadata = resourceMetadata; }
}
protected void challengeResponse(ContainerRequestContext request, String error, String description) protected void challengeResponse(ContainerRequestContext request, String error, String description) {
{ StringBuilder header = new StringBuilder("Bearer realm=\"");
StringBuilder header = new StringBuilder("Bearer realm=\""); header.append(resourceMetadata.getRealm()).append("\"");
header.append(resourceMetadata.getRealm()).append("\""); if (error != null) {
if (error != null) header.append(", error=\"").append(error).append("\"");
{ }
header.append(", error=\"").append(error).append("\""); if (description != null) {
} header.append(", error_description=\"").append(description).append("\"");
if (description != null) }
{ request.abortWith(Response.status(401).header("WWW-Authenticate", header.toString()).build());
header.append(", error_description=\"").append(description).append("\""); return;
} }
request.abortWith(Response.status(401).header("WWW-Authenticate", header.toString()).build());
return;
}
@Context @Context
protected SecurityContext securityContext; protected SecurityContext securityContext;
@Override @Override
public void filter(ContainerRequestContext request) throws IOException public void filter(ContainerRequestContext request) throws IOException {
{ String authHeader = request.getHeaderString(HttpHeaders.AUTHORIZATION);
String authHeader = request.getHeaderString(HttpHeaders.AUTHORIZATION); if (authHeader == null) {
if (authHeader == null) challengeResponse(request, null, null);
{ return;
challengeResponse(request, null, null); }
return;
}
String[] split = authHeader.trim().split("\\s+"); String[] split = authHeader.trim().split("\\s+");
if (split == null || split.length != 2) challengeResponse(request, null, null); if (split == null || split.length != 2) challengeResponse(request, null, null);
if (!split[0].equalsIgnoreCase("Bearer")) challengeResponse(request, null, null); if (!split[0].equalsIgnoreCase("Bearer")) challengeResponse(request, null, null);
String tokenString = split[1]; String tokenString = split[1];
try try {
{ SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, resourceMetadata);
SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, resourceMetadata); SkeletonKeySession skSession = new SkeletonKeySession(tokenString, resourceMetadata);
SkeletonKeySession skSession = new SkeletonKeySession(tokenString, resourceMetadata); ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession); String callerPrincipal = securityContext.getUserPrincipal() != null ? securityContext.getUserPrincipal().getName() : null;
String callerPrincipal = securityContext.getUserPrincipal() != null ? securityContext.getUserPrincipal().getName() : null;
final SkeletonKeyPrincipal principal = new SkeletonKeyPrincipal(token.getPrincipal(), callerPrincipal); final SkeletonKeyPrincipal principal = new SkeletonKeyPrincipal(token.getPrincipal(), callerPrincipal);
final boolean isSecure = securityContext.isSecure(); final boolean isSecure = securityContext.isSecure();
final SkeletonKeyToken.Access access; final SkeletonKeyToken.Access access;
if (resourceMetadata.getResourceName() != null) if (resourceMetadata.getResourceName() != null) {
{ access = token.getResourceAccess(resourceMetadata.getResourceName());
access = token.getResourceAccess(resourceMetadata.getResourceName()); } else {
} access = token.getRealmAccess();
else
{
access = token.getRealmAccess();
}
SecurityContext ctx = new SecurityContext()
{
@Override
public Principal getUserPrincipal()
{
return principal;
} }
SecurityContext ctx = new SecurityContext() {
@Override
public Principal getUserPrincipal() {
return principal;
}
@Override @Override
public boolean isUserInRole(String role) public boolean isUserInRole(String role) {
{ if (access.getRoles() == null) return false;
if (access.getRoles() == null) return false; return access.getRoles().contains(role);
return access.getRoles().contains(role); }
}
@Override @Override
public boolean isSecure() public boolean isSecure() {
{ return isSecure;
return isSecure; }
}
@Override @Override
public String getAuthenticationScheme() public String getAuthenticationScheme() {
{ return "OAUTH_BEARER";
return "OAUTH_BEARER"; }
} };
}; request.setSecurityContext(ctx);
request.setSecurityContext(ctx); } catch (VerificationException e) {
} log.error("Failed to verify token", e);
catch (VerificationException e) challengeResponse(request, "invalid_token", e.getMessage());
{ }
log.error("Failed to verify token", e); }
challengeResponse(request, "invalid_token", e.getMessage());
}
}
} }

View file

@ -18,38 +18,35 @@ import java.net.URI;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class JaxrsOAuthClient extends AbstractOAuthClient public class JaxrsOAuthClient extends AbstractOAuthClient {
{ public Response redirect(UriInfo uriInfo, String redirectUri) {
public Response redirect(UriInfo uriInfo, String redirectUri) String state = getStateCode();
{
String state = getStateCode();
URI url = UriBuilder.fromUri(authUrl) URI url = UriBuilder.fromUri(authUrl)
.queryParam("client_id", clientId) .queryParam("client_id", clientId)
.queryParam("redirect_uri", redirectUri) .queryParam("redirect_uri", redirectUri)
.queryParam("state", state) .queryParam("state", state)
.build(); .build();
NewCookie cookie = new NewCookie(stateCookieName, state, uriInfo.getBaseUri().getPath(), null, null, -1, true); NewCookie cookie = new NewCookie(stateCookieName, state, uriInfo.getBaseUri().getPath(), null, null, -1, true);
return Response.status(302) return Response.status(302)
.location(url) .location(url)
.cookie(cookie).build(); .cookie(cookie).build();
} }
public String getBearerToken(UriInfo uriInfo, HttpHeaders headers) throws BadRequestException, InternalServerErrorException public String getBearerToken(UriInfo uriInfo, HttpHeaders headers) throws BadRequestException, InternalServerErrorException {
{ String error = uriInfo.getQueryParameters().getFirst("error");
String error = uriInfo.getQueryParameters().getFirst("error"); if (error != null) throw new BadRequestException(new Exception("OAuth error: " + error));
if (error != null) throw new BadRequestException(new Exception("OAuth error: " + error)); Cookie stateCookie = headers.getCookies().get(stateCookieName);
Cookie stateCookie = headers.getCookies().get(stateCookieName); if (stateCookie == null) throw new BadRequestException(new Exception("state cookie not set"));
if (stateCookie == null) throw new BadRequestException(new Exception("state cookie not set"));; ;
String state = uriInfo.getQueryParameters().getFirst("state"); String state = uriInfo.getQueryParameters().getFirst("state");
if (state == null) throw new BadRequestException(new Exception("state parameter was null")); if (state == null) throw new BadRequestException(new Exception("state parameter was null"));
if (!state.equals(stateCookie.getValue())) if (!state.equals(stateCookie.getValue())) {
{ throw new BadRequestException(new Exception("state parameter invalid"));
throw new BadRequestException(new Exception("state parameter invalid")); }
} String code = uriInfo.getQueryParameters().getFirst("code");
String code = uriInfo.getQueryParameters().getFirst("code"); if (code == null) throw new BadRequestException(new Exception("code parameter was null"));
if (code == null) throw new BadRequestException(new Exception("code parameter was null")); return resolveBearerToken(uriInfo.getRequestUri().toString(), code);
return resolveBearerToken(uriInfo.getRequestUri().toString(), code); }
}
} }

View file

@ -8,57 +8,48 @@ import org.codehaus.jackson.annotate.JsonProperty;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class AccessTokenResponse public class AccessTokenResponse {
{ @JsonProperty("access_token")
@JsonProperty("access_token") protected String token;
protected String token;
@JsonProperty("expires_in") @JsonProperty("expires_in")
protected long expiresIn; protected long expiresIn;
@JsonProperty("refresh_token") @JsonProperty("refresh_token")
protected String refreshToken; protected String refreshToken;
@JsonProperty("token_type") @JsonProperty("token_type")
protected String tokenType; protected String tokenType;
public String getToken() public String getToken() {
{ return token;
return token; }
}
public void setToken(String token) public void setToken(String token) {
{ this.token = token;
this.token = token; }
}
public long getExpiresIn() public long getExpiresIn() {
{ return expiresIn;
return expiresIn; }
}
public void setExpiresIn(long expiresIn) public void setExpiresIn(long expiresIn) {
{ this.expiresIn = expiresIn;
this.expiresIn = expiresIn; }
}
public String getRefreshToken() public String getRefreshToken() {
{ return refreshToken;
return refreshToken; }
}
public void setRefreshToken(String refreshToken) public void setRefreshToken(String refreshToken) {
{ this.refreshToken = refreshToken;
this.refreshToken = refreshToken; }
}
public String getTokenType() public String getTokenType() {
{ return tokenType;
return tokenType; }
}
public void setTokenType(String tokenType) public void setTokenType(String tokenType) {
{ this.tokenType = tokenType;
this.tokenType = tokenType; }
}
} }

View file

@ -8,6 +8,5 @@ import javax.ws.rs.core.MultivaluedHashMap;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class SkeletonKeyScope extends MultivaluedHashMap<String, String> public class SkeletonKeyScope extends MultivaluedHashMap<String, String> {
{
} }

View file

@ -13,190 +13,164 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class SkeletonKeyToken extends JsonWebToken public class SkeletonKeyToken extends JsonWebToken {
{ public static class Access {
public static class Access @JsonProperty("roles")
{ protected Set<String> roles;
@JsonProperty("roles") @JsonProperty("verify_caller")
protected Set<String> roles; protected Boolean verifyCaller;
@JsonProperty("verify_caller")
protected Boolean verifyCaller;
public Set<String> getRoles() public Set<String> getRoles() {
{ return roles;
return roles; }
}
public Access roles(Set<String> roles) public Access roles(Set<String> roles) {
{ this.roles = roles;
this.roles = roles; return this;
return this; }
}
@JsonIgnore @JsonIgnore
public boolean isUserInRole(String role) public boolean isUserInRole(String role) {
{ if (roles == null) return false;
if (roles == null) return false; return roles.contains(role);
return roles.contains(role); }
}
public Access addRole(String role) public Access addRole(String role) {
{ if (roles == null) roles = new HashSet<String>();
if (roles == null) roles = new HashSet<String>(); roles.add(role);
roles.add(role); return this;
return this; }
}
public Boolean getVerifyCaller() public Boolean getVerifyCaller() {
{ return verifyCaller;
return verifyCaller; }
}
public Access verifyCaller(Boolean required) public Access verifyCaller(Boolean required) {
{ this.verifyCaller = required;
this.verifyCaller = required; return this;
return this; }
} }
}
@JsonProperty("issuedFor") @JsonProperty("issuedFor")
public String issuedFor; public String issuedFor;
@JsonProperty("trusted-certs") @JsonProperty("trusted-certs")
protected Set<String> trustedCertificates; protected Set<String> trustedCertificates;
@JsonProperty("realm_access") @JsonProperty("realm_access")
protected Access realmAccess; protected Access realmAccess;
@JsonProperty("resource_access") @JsonProperty("resource_access")
protected Map<String, Access> resourceAccess = new HashMap<String, Access>(); protected Map<String, Access> resourceAccess = new HashMap<String, Access>();
public Map<String, Access> getResourceAccess() public Map<String, Access> getResourceAccess() {
{ return resourceAccess;
return resourceAccess; }
}
/** /**
* Does the realm require verifying the caller? * Does the realm require verifying the caller?
* *
* @return * @return
*/ */
@JsonIgnore @JsonIgnore
public boolean isVerifyCaller() public boolean isVerifyCaller() {
{ if (getRealmAccess() != null && getRealmAccess().getVerifyCaller() != null)
if (getRealmAccess() != null && getRealmAccess().getVerifyCaller() != null) return getRealmAccess().getVerifyCaller().booleanValue(); return getRealmAccess().getVerifyCaller().booleanValue();
return false; return false;
} }
/** /**
* Does the resource override the requirement of verifying the caller? * Does the resource override the requirement of verifying the caller?
* *
* @param resource * @param resource
* @return * @return
*/ */
@JsonIgnore @JsonIgnore
public boolean isVerifyCaller(String resource) public boolean isVerifyCaller(String resource) {
{ Access access = getResourceAccess(resource);
Access access = getResourceAccess(resource); if (access != null && access.getVerifyCaller() != null) return access.getVerifyCaller().booleanValue();
if (access != null && access.getVerifyCaller() != null) return access.getVerifyCaller().booleanValue(); return false;
return false; }
}
@JsonIgnore @JsonIgnore
public Access getResourceAccess(String resource) public Access getResourceAccess(String resource) {
{ return resourceAccess.get(resource);
return resourceAccess.get(resource); }
}
public Access addAccess(String service) public Access addAccess(String service) {
{ Access token = new Access();
Access token = new Access(); resourceAccess.put(service, token);
resourceAccess.put(service, token); return token;
return token; }
}
@Override @Override
public SkeletonKeyToken id(String id) public SkeletonKeyToken id(String id) {
{ return (SkeletonKeyToken) super.id(id);
return (SkeletonKeyToken)super.id(id); }
}
@Override @Override
public SkeletonKeyToken expiration(long expiration) public SkeletonKeyToken expiration(long expiration) {
{ return (SkeletonKeyToken) super.expiration(expiration);
return (SkeletonKeyToken)super.expiration(expiration); }
}
@Override @Override
public SkeletonKeyToken notBefore(long notBefore) public SkeletonKeyToken notBefore(long notBefore) {
{ return (SkeletonKeyToken) super.notBefore(notBefore);
return (SkeletonKeyToken)super.notBefore(notBefore); }
}
@Override @Override
public SkeletonKeyToken issuedAt(long issuedAt) public SkeletonKeyToken issuedAt(long issuedAt) {
{ return (SkeletonKeyToken) super.issuedAt(issuedAt);
return (SkeletonKeyToken)super.issuedAt(issuedAt); }
}
@Override @Override
public SkeletonKeyToken issuer(String issuer) public SkeletonKeyToken issuer(String issuer) {
{ return (SkeletonKeyToken) super.issuer(issuer);
return (SkeletonKeyToken)super.issuer(issuer); }
}
@Override @Override
public SkeletonKeyToken audience(String audience) public SkeletonKeyToken audience(String audience) {
{ return (SkeletonKeyToken) super.audience(audience);
return (SkeletonKeyToken)super.audience(audience); }
}
@Override @Override
public SkeletonKeyToken principal(String principal) public SkeletonKeyToken principal(String principal) {
{ return (SkeletonKeyToken) super.principal(principal);
return (SkeletonKeyToken)super.principal(principal); }
}
@Override @Override
public SkeletonKeyToken type(String type) public SkeletonKeyToken type(String type) {
{ return (SkeletonKeyToken) super.type(type);
return (SkeletonKeyToken)super.type(type); }
}
public Access getRealmAccess() public Access getRealmAccess() {
{ return realmAccess;
return realmAccess; }
}
public void setRealmAccess(Access realmAccess) public void setRealmAccess(Access realmAccess) {
{ this.realmAccess = realmAccess;
this.realmAccess = realmAccess; }
}
public Set<String> getTrustedCertificates() public Set<String> getTrustedCertificates() {
{ return trustedCertificates;
return trustedCertificates; }
}
public void setTrustedCertificates(Set<String> trustedCertificates) public void setTrustedCertificates(Set<String> trustedCertificates) {
{ this.trustedCertificates = trustedCertificates;
this.trustedCertificates = trustedCertificates; }
}
/** /**
* OAuth client the token was issued for. * OAuth client the token was issued for.
* *
* @return * @return
*/ */
public String getIssuedFor() public String getIssuedFor() {
{ return issuedFor;
return issuedFor; }
}
public SkeletonKeyToken issuedFor(String issuedFor) public SkeletonKeyToken issuedFor(String issuedFor) {
{ this.issuedFor = issuedFor;
this.issuedFor = issuedFor; return this;
return this; }
}
} }

View file

@ -13,137 +13,123 @@ import java.security.PublicKey;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class PublishedRealmRepresentation public class PublishedRealmRepresentation {
{ protected String realm;
protected String realm; protected String self;
protected String self;
@JsonProperty("public_key") @JsonProperty("public_key")
protected String publicKeyPem; protected String publicKeyPem;
@JsonProperty("authorization") @JsonProperty("authorization")
protected String authorizationUrl; protected String authorizationUrl;
@JsonProperty("codes") @JsonProperty("codes")
protected String codeUrl; protected String codeUrl;
@JsonProperty("grants") @JsonProperty("grants")
protected String grantUrl; protected String grantUrl;
@JsonProperty("identity-grants") @JsonProperty("identity-grants")
protected String identityGrantUrl; protected String identityGrantUrl;
@JsonIgnore @JsonProperty("admin-role")
protected volatile transient PublicKey publicKey; protected String adminRole;
@JsonIgnore
protected volatile transient PublicKey publicKey;
public String getAdminRole() {
return adminRole;
}
public void setAdminRole(String adminRole) {
this.adminRole = adminRole;
}
public String getRealm() {
return realm;
}
public void setRealm(String realm) {
this.realm = realm;
}
public String getSelf() {
return self;
}
public void setSelf(String self) {
this.self = self;
}
public String getPublicKeyPem() {
return publicKeyPem;
}
public void setPublicKeyPem(String publicKeyPem) {
this.publicKeyPem = publicKeyPem;
this.publicKey = null;
}
public String getRealm() @JsonIgnore
{ public PublicKey getPublicKey() {
return realm; if (publicKey != null) return publicKey;
} if (publicKeyPem != null) {
try {
publicKey = PemUtils.decodePublicKey(publicKeyPem);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return publicKey;
}
public void setRealm(String realm) @JsonIgnore
{ public void setPublicKey(PublicKey publicKey) {
this.realm = realm; this.publicKey = publicKey;
} StringWriter writer = new StringWriter();
PEMWriter pemWriter = new PEMWriter(writer);
public String getSelf() try {
{ pemWriter.writeObject(publicKey);
return self; pemWriter.flush();
} } catch (IOException e) {
public void setSelf(String self)
{
this.self = self;
}
public String getPublicKeyPem()
{
return publicKeyPem;
}
public void setPublicKeyPem(String publicKeyPem)
{
this.publicKeyPem = publicKeyPem;
this.publicKey = null;
}
@JsonIgnore
public PublicKey getPublicKey()
{
if (publicKey != null) return publicKey;
if (publicKeyPem != null)
{
try
{
publicKey = PemUtils.decodePublicKey(publicKeyPem);
}
catch (Exception e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} String s = writer.toString();
return publicKey; this.publicKeyPem = PemUtils.removeBeginEnd(s);
} }
@JsonIgnore
public void setPublicKey(PublicKey publicKey)
{
this.publicKey = publicKey;
StringWriter writer = new StringWriter();
PEMWriter pemWriter = new PEMWriter(writer);
try
{
pemWriter.writeObject(publicKey);
pemWriter.flush();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
String s = writer.toString();
this.publicKeyPem = PemUtils.removeBeginEnd(s);
}
public String getAuthorizationUrl() public String getAuthorizationUrl() {
{ return authorizationUrl;
return authorizationUrl; }
}
public void setAuthorizationUrl(String authorizationUrl) public void setAuthorizationUrl(String authorizationUrl) {
{ this.authorizationUrl = authorizationUrl;
this.authorizationUrl = authorizationUrl; }
}
public String getCodeUrl() public String getCodeUrl() {
{ return codeUrl;
return codeUrl; }
}
public void setCodeUrl(String codeUrl) public void setCodeUrl(String codeUrl) {
{ this.codeUrl = codeUrl;
this.codeUrl = codeUrl; }
}
public String getGrantUrl() public String getGrantUrl() {
{ return grantUrl;
return grantUrl; }
}
public void setGrantUrl(String grantUrl) public void setGrantUrl(String grantUrl) {
{ this.grantUrl = grantUrl;
this.grantUrl = grantUrl; }
}
public String getIdentityGrantUrl() public String getIdentityGrantUrl() {
{ return identityGrantUrl;
return identityGrantUrl; }
}
public void setIdentityGrantUrl(String identityGrantUrl) public void setIdentityGrantUrl(String identityGrantUrl) {
{ this.identityGrantUrl = identityGrantUrl;
this.identityGrantUrl = identityGrantUrl; }
}
} }

View file

@ -8,176 +8,147 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RealmRepresentation public class RealmRepresentation {
{ protected String self; // link
protected String self; // link protected String realm;
protected String realm; protected long tokenLifespan;
protected long tokenLifespan; protected long accessCodeLifespan;
protected long accessCodeLifespan; protected boolean enabled;
protected boolean enabled; protected boolean sslNotRequired;
protected boolean sslNotRequired; protected boolean cookieLoginAllowed;
protected boolean cookieLoginAllowed; protected Set<String> roles;
protected Set<String> roles; protected List<RequiredCredentialRepresentation> requiredCredentials;
protected List<RequiredCredentialRepresentation> requiredCredentials; protected List<UserRepresentation> users;
protected List<UserRepresentation> users; protected List<RoleMappingRepresentation> roleMappings;
protected List<RoleMappingRepresentation> roleMappings; protected List<ScopeMappingRepresentation> scopeMappings;
protected List<ScopeMappingRepresentation> scopeMappings; protected List<ResourceRepresentation> resources;
protected List<ResourceRepresentation> resources;
public String getSelf() public String getSelf() {
{ return self;
return self; }
}
public void setSelf(String self) public void setSelf(String self) {
{ this.self = self;
this.self = self; }
}
public String getRealm() public String getRealm() {
{ return realm;
return realm; }
}
public void setRealm(String realm) public void setRealm(String realm) {
{ this.realm = realm;
this.realm = realm; }
}
public List<UserRepresentation> getUsers() public List<UserRepresentation> getUsers() {
{ return users;
return users; }
}
public List<ResourceRepresentation> getResources() public List<ResourceRepresentation> getResources() {
{ return resources;
return resources; }
}
public ResourceRepresentation resource(String name) public ResourceRepresentation resource(String name) {
{ ResourceRepresentation resource = new ResourceRepresentation();
ResourceRepresentation resource = new ResourceRepresentation(); if (resources == null) resources = new ArrayList<ResourceRepresentation>();
if (resources == null) resources = new ArrayList<ResourceRepresentation>(); resources.add(resource);
resources.add(resource); resource.setName(name);
resource.setName(name); return resource;
return resource; }
}
public void setUsers(List<UserRepresentation> users) public void setUsers(List<UserRepresentation> users) {
{ this.users = users;
this.users = users; }
}
public UserRepresentation user(String username) public UserRepresentation user(String username) {
{ UserRepresentation user = new UserRepresentation();
UserRepresentation user = new UserRepresentation(); user.setUsername(username);
user.setUsername(username); if (users == null) users = new ArrayList<UserRepresentation>();
if (users == null) users = new ArrayList<UserRepresentation>(); users.add(user);
users.add(user); return user;
return user; }
}
public void setResources(List<ResourceRepresentation> resources) public void setResources(List<ResourceRepresentation> resources) {
{ this.resources = resources;
this.resources = resources; }
}
public boolean isEnabled() public boolean isEnabled() {
{ return enabled;
return enabled; }
}
public void setEnabled(boolean enabled) public void setEnabled(boolean enabled) {
{ this.enabled = enabled;
this.enabled = enabled; }
}
public boolean isSslNotRequired() public boolean isSslNotRequired() {
{ return sslNotRequired;
return sslNotRequired; }
}
public void setSslNotRequired(boolean sslNotRequired) public void setSslNotRequired(boolean sslNotRequired) {
{ this.sslNotRequired = sslNotRequired;
this.sslNotRequired = sslNotRequired; }
}
public boolean isCookieLoginAllowed() public boolean isCookieLoginAllowed() {
{ return cookieLoginAllowed;
return cookieLoginAllowed; }
}
public void setCookieLoginAllowed(boolean cookieLoginAllowed) public void setCookieLoginAllowed(boolean cookieLoginAllowed) {
{ this.cookieLoginAllowed = cookieLoginAllowed;
this.cookieLoginAllowed = cookieLoginAllowed; }
}
public long getTokenLifespan() public long getTokenLifespan() {
{ return tokenLifespan;
return tokenLifespan; }
}
public void setTokenLifespan(long tokenLifespan) public void setTokenLifespan(long tokenLifespan) {
{ this.tokenLifespan = tokenLifespan;
this.tokenLifespan = tokenLifespan; }
}
public List<RoleMappingRepresentation> getRoleMappings() public List<RoleMappingRepresentation> getRoleMappings() {
{ return roleMappings;
return roleMappings; }
}
public RoleMappingRepresentation roleMapping(String username) public RoleMappingRepresentation roleMapping(String username) {
{ RoleMappingRepresentation mapping = new RoleMappingRepresentation();
RoleMappingRepresentation mapping = new RoleMappingRepresentation(); mapping.setUsername(username);
mapping.setUsername(username); if (roleMappings == null) roleMappings = new ArrayList<RoleMappingRepresentation>();
if (roleMappings == null) roleMappings = new ArrayList<RoleMappingRepresentation>(); roleMappings.add(mapping);
roleMappings.add(mapping); return mapping;
return mapping; }
}
public List<ScopeMappingRepresentation> getScopeMappings() public List<ScopeMappingRepresentation> getScopeMappings() {
{ return scopeMappings;
return scopeMappings; }
}
public ScopeMappingRepresentation scopeMapping(String username) public ScopeMappingRepresentation scopeMapping(String username) {
{ ScopeMappingRepresentation mapping = new ScopeMappingRepresentation();
ScopeMappingRepresentation mapping = new ScopeMappingRepresentation(); mapping.setUsername(username);
mapping.setUsername(username); if (scopeMappings == null) scopeMappings = new ArrayList<ScopeMappingRepresentation>();
if (scopeMappings == null) scopeMappings = new ArrayList<ScopeMappingRepresentation>(); scopeMappings.add(mapping);
scopeMappings.add(mapping); return mapping;
return mapping; }
}
public List<RequiredCredentialRepresentation> getRequiredCredentials() public List<RequiredCredentialRepresentation> getRequiredCredentials() {
{ return requiredCredentials;
return requiredCredentials; }
}
public void setRequiredCredentials(List<RequiredCredentialRepresentation> requiredCredentials) public void setRequiredCredentials(List<RequiredCredentialRepresentation> requiredCredentials) {
{ this.requiredCredentials = requiredCredentials;
this.requiredCredentials = requiredCredentials; }
}
public long getAccessCodeLifespan() public long getAccessCodeLifespan() {
{ return accessCodeLifespan;
return accessCodeLifespan; }
}
public void setAccessCodeLifespan(long accessCodeLifespan) public void setAccessCodeLifespan(long accessCodeLifespan) {
{ this.accessCodeLifespan = accessCodeLifespan;
this.accessCodeLifespan = accessCodeLifespan; }
}
public Set<String> getRoles() public Set<String> getRoles() {
{ return roles;
return roles; }
}
public void setRoles(Set<String> roles) public void setRoles(Set<String> roles) {
{ this.roles = roles;
this.roles = roles; }
}
} }

View file

@ -4,43 +4,36 @@ package org.keycloak.representations.idm;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RequiredCredentialRepresentation public class RequiredCredentialRepresentation {
{ public static final String PASSWORD = "Password";
public static final String PASSWORD = "Password"; public static final String TOTP = "TOTP";
public static final String TOTP = "TOTP"; public static final String CLIENT_CERT = "CLIENT_CERT";
public static final String CLIENT_CERT = "CLIENT_CERT"; public static final String CALLER_PRINCIPAL = "CALLER_PRINCIPAL";
public static final String CALLER_PRINCIPAL = "CALLER_PRINCIPAL"; protected String type;
protected String type; protected boolean input;
protected boolean input; protected boolean secret;
protected boolean secret;
public String getType() public String getType() {
{ return type;
return type; }
}
public void setType(String type) public void setType(String type) {
{ this.type = type;
this.type = type; }
}
public boolean isInput() public boolean isInput() {
{ return input;
return input; }
}
public void setInput(boolean input) public void setInput(boolean input) {
{ this.input = input;
this.input = input; }
}
public boolean isSecret() public boolean isSecret() {
{ return secret;
return secret; }
}
public void setSecret(boolean secret) public void setSecret(boolean secret) {
{ this.secret = secret;
this.secret = secret; }
}
} }

View file

@ -6,92 +6,78 @@ import java.util.List;
import java.util.Set; import java.util.Set;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class ResourceRepresentation public class ResourceRepresentation {
{ protected String self; // link
protected String self; // link protected String name;
protected String name; protected boolean surrogateAuthRequired;
protected boolean surrogateAuthRequired; protected Set<String> roles;
protected Set<String> roles; protected List<RoleMappingRepresentation> roleMappings;
protected List<RoleMappingRepresentation> roleMappings; protected List<ScopeMappingRepresentation> scopeMappings;
protected List<ScopeMappingRepresentation> scopeMappings;
public String getSelf() public String getSelf() {
{ return self;
return self; }
}
public void setSelf(String self) public void setSelf(String self) {
{ this.self = self;
this.self = self; }
}
public String getName() public String getName() {
{ return name;
return name; }
}
public void setName(String name) public void setName(String name) {
{ this.name = name;
this.name = name; }
}
public boolean isSurrogateAuthRequired() public boolean isSurrogateAuthRequired() {
{ return surrogateAuthRequired;
return surrogateAuthRequired; }
}
public void setSurrogateAuthRequired(boolean surrogateAuthRequired) public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
{ this.surrogateAuthRequired = surrogateAuthRequired;
this.surrogateAuthRequired = surrogateAuthRequired; }
}
public Set<String> getRoles() public Set<String> getRoles() {
{ return roles;
return roles; }
}
public void setRoles(Set<String> roles) public void setRoles(Set<String> roles) {
{ this.roles = roles;
this.roles = roles; }
}
public ResourceRepresentation role(String role) public ResourceRepresentation role(String role) {
{ if (this.roles == null) this.roles = new HashSet<String>();
if (this.roles == null) this.roles = new HashSet<String>(); this.roles.add(role);
this.roles.add(role); return this;
return this; }
}
public List<RoleMappingRepresentation> getRoleMappings() public List<RoleMappingRepresentation> getRoleMappings() {
{ return roleMappings;
return roleMappings; }
}
public RoleMappingRepresentation roleMapping(String username) public RoleMappingRepresentation roleMapping(String username) {
{ RoleMappingRepresentation mapping = new RoleMappingRepresentation();
RoleMappingRepresentation mapping = new RoleMappingRepresentation(); mapping.setUsername(username);
mapping.setUsername(username); if (roleMappings == null) roleMappings = new ArrayList<RoleMappingRepresentation>();
if (roleMappings == null) roleMappings = new ArrayList<RoleMappingRepresentation>(); roleMappings.add(mapping);
roleMappings.add(mapping); return mapping;
return mapping; }
}
public List<ScopeMappingRepresentation> getScopeMappings() public List<ScopeMappingRepresentation> getScopeMappings() {
{ return scopeMappings;
return scopeMappings; }
}
public ScopeMappingRepresentation scopeMapping(String username) public ScopeMappingRepresentation scopeMapping(String username) {
{ ScopeMappingRepresentation mapping = new ScopeMappingRepresentation();
ScopeMappingRepresentation mapping = new ScopeMappingRepresentation(); mapping.setUsername(username);
mapping.setUsername(username); if (scopeMappings == null) scopeMappings = new ArrayList<ScopeMappingRepresentation>();
if (scopeMappings == null) scopeMappings = new ArrayList<ScopeMappingRepresentation>(); scopeMappings.add(mapping);
scopeMappings.add(mapping); return mapping;
return mapping; }
}
} }

View file

@ -4,52 +4,42 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
/** /**
*
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RoleMappingRepresentation public class RoleMappingRepresentation {
{ protected String self; // link
protected String self; // link protected String username;
protected String username; protected Set<String> roles;
protected Set<String> roles;
public String getSelf() public String getSelf() {
{ return self;
return self; }
}
public void setSelf(String self) public void setSelf(String self) {
{ this.self = self;
this.self = self; }
}
public String getUsername() public String getUsername() {
{ return username;
return username; }
}
public void setUsername(String username) public void setUsername(String username) {
{ this.username = username;
this.username = username; }
}
public Set<String> getRoles() public Set<String> getRoles() {
{ return roles;
return roles; }
}
public void setRoles(Set<String> roles) public void setRoles(Set<String> roles) {
{ this.roles = roles;
this.roles = roles; }
}
public RoleMappingRepresentation role(String role) public RoleMappingRepresentation role(String role) {
{ if (this.roles == null) this.roles = new HashSet<String>();
if (this.roles == null) this.roles = new HashSet<String>(); this.roles.add(role);
this.roles.add(role); return this;
return this; }
}
} }

View file

@ -4,52 +4,42 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
/** /**
*
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class ScopeMappingRepresentation public class ScopeMappingRepresentation {
{ protected String self; // link
protected String self; // link protected String username;
protected String username; protected Set<String> roles;
protected Set<String> roles;
public String getSelf() public String getSelf() {
{ return self;
return self; }
}
public void setSelf(String self) public void setSelf(String self) {
{ this.self = self;
this.self = self; }
}
public String getUsername() public String getUsername() {
{ return username;
return username; }
}
public void setUsername(String username) public void setUsername(String username) {
{ this.username = username;
this.username = username; }
}
public Set<String> getRoles() public Set<String> getRoles() {
{ return roles;
return roles; }
}
public void setRoles(Set<String> roles) public void setRoles(Set<String> roles) {
{ this.roles = roles;
this.roles = roles; }
}
public ScopeMappingRepresentation role(String role) public ScopeMappingRepresentation role(String role) {
{ if (this.roles == null) this.roles = new HashSet<String>();
if (this.roles == null) this.roles = new HashSet<String>(); this.roles.add(role);
this.roles.add(role); return this;
return this; }
}
} }

View file

@ -6,119 +6,99 @@ import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class UserRepresentation public class UserRepresentation {
{ public static class Credential {
public static class Credential protected String type;
{ protected String value;
protected String type; protected boolean hashed;
protected String value;
protected boolean hashed;
public String getType() public String getType() {
{ return type;
return type; }
}
public void setType(String type) public void setType(String type) {
{ this.type = type;
this.type = type; }
}
public String getValue() public String getValue() {
{ return value;
return value; }
}
public void setValue(String value) public void setValue(String value) {
{ this.value = value;
this.value = value; }
}
public boolean isHashed() public boolean isHashed() {
{ return hashed;
return hashed; }
}
public void setHashed(boolean hashed) public void setHashed(boolean hashed) {
{ this.hashed = hashed;
this.hashed = hashed; }
} }
}
protected String self; // link protected String self; // link
protected String username; protected String username;
protected boolean enabled; protected boolean enabled;
protected Map<String, String> attributes; protected Map<String, String> attributes;
protected List<Credential> credentials; protected List<Credential> credentials;
public String getSelf() public String getSelf() {
{ return self;
return self; }
}
public void setSelf(String self) public void setSelf(String self) {
{ this.self = self;
this.self = self; }
}
public String getUsername() public String getUsername() {
{ return username;
return username; }
}
public void setUsername(String username) public void setUsername(String username) {
{ this.username = username;
this.username = username; }
}
public Map<String, String> getAttributes() public Map<String, String> getAttributes() {
{ return attributes;
return attributes; }
}
public void setAttributes(Map<String, String> attributes) public void setAttributes(Map<String, String> attributes) {
{ this.attributes = attributes;
this.attributes = attributes; }
}
public List<Credential> getCredentials() public List<Credential> getCredentials() {
{ return credentials;
return credentials; }
}
public void setCredentials(List<Credential> credentials) public void setCredentials(List<Credential> credentials) {
{ this.credentials = credentials;
this.credentials = credentials; }
}
public UserRepresentation attribute(String name, String value) public UserRepresentation attribute(String name, String value) {
{ if (this.attributes == null) attributes = new HashMap<String, String>();
if (this.attributes == null) attributes = new HashMap<String, String>(); attributes.put(name, value);
attributes.put(name, value); return this;
return this; }
}
public UserRepresentation credential(String type, String value, boolean hashed) public UserRepresentation credential(String type, String value, boolean hashed) {
{ if (this.credentials == null) credentials = new ArrayList<Credential>();
if (this.credentials == null) credentials = new ArrayList<Credential>(); Credential cred = new Credential();
Credential cred = new Credential(); cred.setType(type);
cred.setType(type); cred.setValue(value);
cred.setValue(value); cred.setHashed(hashed);
cred.setHashed(hashed); credentials.add(cred);
credentials.add( cred); return this;
return this; }
}
public boolean isEnabled() public boolean isEnabled() {
{ return enabled;
return enabled; }
}
public void setEnabled(boolean enabled) public void setEnabled(boolean enabled) {
{ this.enabled = enabled;
this.enabled = enabled; }
}
} }

View file

@ -1,8 +1,8 @@
package org.keycloak.servlet; package org.keycloak.servlet;
import org.jboss.resteasy.plugins.server.servlet.ServletUtil; import org.jboss.resteasy.plugins.server.servlet.ServletUtil;
import org.keycloak.AbstractOAuthClient;
import org.jboss.resteasy.spi.ResteasyUriInfo; import org.jboss.resteasy.spi.ResteasyUriInfo;
import org.keycloak.AbstractOAuthClient;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -17,111 +17,100 @@ import java.net.URI;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class ServletOAuthClient extends AbstractOAuthClient public class ServletOAuthClient extends AbstractOAuthClient {
{ /**
/** * Start the process of obtaining an access token by redirecting the browser
* Start the process of obtaining an access token by redirecting the browser * to the authentication server
* to the authentication server *
* * @param relativePath path relative to context root you want auth server to redirect back to
* * @param request
* * @param response
* @param relativePath path relative to context root you want auth server to redirect back to * @throws IOException
* @param request */
* @param response public void redirectRelative(String relativePath, HttpServletRequest request, HttpServletResponse response) throws IOException {
* @throws IOException ResteasyUriInfo uriInfo = ServletUtil.extractUriInfo(request, null);
*/ String redirect = uriInfo.getBaseUriBuilder().path(relativePath).toTemplate();
public void redirectRelative(String relativePath, HttpServletRequest request, HttpServletResponse response) throws IOException redirect(redirect, request, response);
{ }
ResteasyUriInfo uriInfo = ServletUtil.extractUriInfo(request, null);
String redirect = uriInfo.getBaseUriBuilder().path(relativePath).toTemplate();
redirect(redirect, request, response);
}
/** /**
* Start the process of obtaining an access token by redirecting the browser * Start the process of obtaining an access token by redirecting the browser
* to the authentication server * to the authentication server
* *
* @param redirectUri full URI you want auth server to redirect back to * @param redirectUri full URI you want auth server to redirect back to
* @param request * @param request
* @param response * @param response
* @throws IOException * @throws IOException
*/ */
public void redirect(String redirectUri, HttpServletRequest request, HttpServletResponse response) throws IOException public void redirect(String redirectUri, HttpServletRequest request, HttpServletResponse response) throws IOException {
{ String state = getStateCode();
String state = getStateCode();
URI url = UriBuilder.fromUri(authUrl) URI url = UriBuilder.fromUri(authUrl)
.queryParam("client_id", clientId) .queryParam("client_id", clientId)
.queryParam("redirect_uri", redirectUri) .queryParam("redirect_uri", redirectUri)
.queryParam("state", state) .queryParam("state", state)
.build(); .build();
String cookiePath = request.getContextPath(); String cookiePath = request.getContextPath();
if (cookiePath.equals("")) cookiePath = "/"; if (cookiePath.equals("")) cookiePath = "/";
Cookie cookie = new Cookie(stateCookieName, state); Cookie cookie = new Cookie(stateCookieName, state);
cookie.setSecure(true); cookie.setSecure(true);
cookie.setPath(cookiePath); cookie.setPath(cookiePath);
response.addCookie(cookie); response.addCookie(cookie);
response.sendRedirect(url.toString()); response.sendRedirect(url.toString());
} }
protected String getCookieValue(String name, HttpServletRequest request) protected String getCookieValue(String name, HttpServletRequest request) {
{ if (request.getCookies() == null) return null;
if (request.getCookies() == null) return null;
for (Cookie cookie : request.getCookies()) for (Cookie cookie : request.getCookies()) {
{ if (cookie.getName().equals(name)) return cookie.getValue();
if (cookie.getName().equals(name)) return cookie.getValue(); }
} return null;
return null; }
}
protected String getCode(HttpServletRequest request) protected String getCode(HttpServletRequest request) {
{ String query = request.getQueryString();
String query = request.getQueryString(); if (query == null) return null;
if (query == null) return null; String[] params = query.split("&");
String[] params = query.split("&"); for (String param : params) {
for (String param : params) int eq = param.indexOf('=');
{ if (eq == -1) continue;
int eq = param.indexOf('='); String name = param.substring(0, eq);
if (eq == -1) continue; if (!name.equals("code")) continue;
String name = param.substring(0, eq); return param.substring(eq + 1);
if (!name.equals("code")) continue; }
return param.substring(eq + 1); return null;
} }
return null;
}
/** /**
* Obtain the code parameter from the url after being redirected back from the auth-server. Then * Obtain the code parameter from the url after being redirected back from the auth-server. Then
* do an authenticated request back to the auth-server to turn the access code into an access token. * do an authenticated request back to the auth-server to turn the access code into an access token.
* *
* @param request * @param request
* @return * @return
* @throws BadRequestException * @throws BadRequestException
* @throws InternalServerErrorException * @throws InternalServerErrorException
*/ */
public String getBearerToken(HttpServletRequest request) throws BadRequestException, InternalServerErrorException public String getBearerToken(HttpServletRequest request) throws BadRequestException, InternalServerErrorException {
{ String error = request.getParameter("error");
String error = request.getParameter("error"); if (error != null) throw new BadRequestException(new Exception("OAuth error: " + error));
if (error != null) throw new BadRequestException(new Exception("OAuth error: " + error)); String redirectUri = request.getRequestURL().append("?").append(request.getQueryString()).toString();
String redirectUri = request.getRequestURL().append("?").append(request.getQueryString()).toString(); String stateCookie = getCookieValue(stateCookieName, request);
String stateCookie = getCookieValue(stateCookieName, request); if (stateCookie == null) throw new BadRequestException(new Exception("state cookie not set"));
if (stateCookie == null) throw new BadRequestException(new Exception("state cookie not set")); // we can call get parameter as this should be a redirect
// we can call get parameter as this should be a redirect String state = request.getParameter("state");
String state = request.getParameter("state"); String code = request.getParameter("code");
String code = request.getParameter("code");
if (state == null) throw new BadRequestException(new Exception("state parameter was null")); if (state == null) throw new BadRequestException(new Exception("state parameter was null"));
if (!state.equals(stateCookie)) if (!state.equals(stateCookie)) {
{ throw new BadRequestException(new Exception("state parameter invalid"));
throw new BadRequestException(new Exception("state parameter invalid")); }
} if (code == null) throw new BadRequestException(new Exception("code parameter was null"));
if (code == null) throw new BadRequestException(new Exception("code parameter was null")); return resolveBearerToken(redirectUri, code);
return resolveBearerToken(redirectUri, code); }
}
} }

View file

@ -2,9 +2,6 @@
<deployment> <deployment>
<!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute --> <!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
<dependencies> <dependencies>
<!--
<module name="org.jboss.resteasy.resteasy-jaxrs" services="import"/>
<module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/> -->
<module name="org.jboss.resteasy.jose-jwt"/> <module name="org.jboss.resteasy.jose-jwt"/>
<module name="org.jboss.resteasy.resteasy-crypto"/> <module name="org.jboss.resteasy.resteasy-crypto"/>
<module name="org.bouncycastle"/> <module name="org.bouncycastle"/>

View file

@ -4,11 +4,10 @@ package org.keycloak.adapters.as7;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public interface Actions public interface Actions {
{ public static final String J_OAUTH_ADMIN_FORCED_LOGOUT = "j_oauth_admin_forced_logout";
public static final String J_OAUTH_ADMIN_FORCED_LOGOUT = "j_oauth_admin_forced_logout"; public static final String J_OAUTH_LOGOUT = "j_oauth_logout";
public static final String J_OAUTH_LOGOUT = "j_oauth_logout"; public static final String J_OAUTH_RESOLVE_ACCESS_CODE = "j_oauth_resolve_access_code";
public static final String J_OAUTH_RESOLVE_ACCESS_CODE = "j_oauth_resolve_access_code"; public static final String J_OAUTH_REMOTE_LOGOUT = "j_oauth_remote_logout";
public static final String J_OAUTH_REMOTE_LOGOUT = "j_oauth_remote_logout"; public static final String J_OAUTH_TOKEN_GRANT = "j_oauth_token_grant";
public static final String J_OAUTH_TOKEN_GRANT = "j_oauth_token_grant";
} }

View file

@ -10,10 +10,10 @@ import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext; import org.apache.catalina.core.StandardContext;
import org.apache.catalina.deploy.LoginConfig; import org.apache.catalina.deploy.LoginConfig;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.ResourceMetadata; import org.keycloak.ResourceMetadata;
import org.keycloak.adapters.as7.config.ManagedResourceConfig; import org.keycloak.adapters.as7.config.ManagedResourceConfig;
import org.keycloak.adapters.as7.config.ManagedResourceConfigLoader; import org.keycloak.adapters.as7.config.ManagedResourceConfigLoader;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import javax.security.auth.login.LoginException; import javax.security.auth.login.LoginException;
import javax.servlet.ServletException; import javax.servlet.ServletException;
@ -27,61 +27,49 @@ import java.io.IOException;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class BearerTokenAuthenticatorValve extends AuthenticatorBase implements LifecycleListener public class BearerTokenAuthenticatorValve extends AuthenticatorBase implements LifecycleListener {
{ private static final Logger log = Logger.getLogger(BearerTokenAuthenticatorValve.class);
private static final Logger log = Logger.getLogger(BearerTokenAuthenticatorValve.class); protected ManagedResourceConfig remoteSkeletonKeyConfig;
protected ManagedResourceConfig remoteSkeletonKeyConfig; protected ResourceMetadata resourceMetadata;
protected ResourceMetadata resourceMetadata;
@Override @Override
public void start() throws LifecycleException public void start() throws LifecycleException {
{ super.start();
super.start(); StandardContext standardContext = (StandardContext) context;
StandardContext standardContext = (StandardContext)context; standardContext.addLifecycleListener(this);
standardContext.addLifecycleListener(this); }
}
@Override @Override
public void lifecycleEvent(LifecycleEvent event) public void lifecycleEvent(LifecycleEvent event) {
{ if (event.getType() == Lifecycle.AFTER_START_EVENT) init();
if (event.getType() == Lifecycle.AFTER_START_EVENT) init(); }
}
protected void init() protected void init() {
{ ManagedResourceConfigLoader managedResourceConfigLoader = new ManagedResourceConfigLoader(context);
ManagedResourceConfigLoader managedResourceConfigLoader = new ManagedResourceConfigLoader(context); resourceMetadata = managedResourceConfigLoader.getResourceMetadata();
resourceMetadata = managedResourceConfigLoader.getResourceMetadata(); remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig();
remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig(); managedResourceConfigLoader.init(false);
} }
@Override @Override
public void invoke(Request request, Response response) throws IOException, ServletException public void invoke(Request request, Response response) throws IOException, ServletException {
{ try {
try super.invoke(request, response);
{ } finally {
super.invoke(request, response); ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession
} }
finally }
{
ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession
}
}
@Override @Override
protected boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException protected boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException {
{ try {
try CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, !remoteSkeletonKeyConfig.isCancelPropagation(), true);
{ if (bearer.login(request, response)) {
CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, !remoteSkeletonKeyConfig.isCancelPropagation(), true); return true;
if (bearer.login(request, response)) }
{ return false;
return true; } catch (LoginException e) {
} }
return false; return false;
} }
catch (LoginException e)
{
}
return false;
}
} }

View file

@ -2,13 +2,13 @@ package org.keycloak.adapters.as7;
import org.apache.catalina.connector.Request; import org.apache.catalina.connector.Request;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.RSATokenVerifier; import org.keycloak.RSATokenVerifier;
import org.keycloak.ResourceMetadata; import org.keycloak.ResourceMetadata;
import org.keycloak.SkeletonKeyPrincipal; import org.keycloak.SkeletonKeyPrincipal;
import org.keycloak.SkeletonKeySession; import org.keycloak.SkeletonKeySession;
import org.keycloak.VerificationException; import org.keycloak.VerificationException;
import org.keycloak.representations.SkeletonKeyToken; import org.keycloak.representations.SkeletonKeyToken;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import javax.security.auth.login.LoginException; import javax.security.auth.login.LoginException;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -21,143 +21,116 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class CatalinaBearerTokenAuthenticator public class CatalinaBearerTokenAuthenticator {
{ protected ResourceMetadata resourceMetadata;
protected ResourceMetadata resourceMetadata; protected boolean challenge;
protected boolean challenge; protected Logger log = Logger.getLogger(CatalinaBearerTokenAuthenticator.class);
protected Logger log = Logger.getLogger(CatalinaBearerTokenAuthenticator.class); protected String tokenString;
protected String tokenString; protected SkeletonKeyToken token;
protected SkeletonKeyToken token; private Principal principal;
private Principal principal; protected boolean propagateToken;
protected boolean propagateToken;
public CatalinaBearerTokenAuthenticator(ResourceMetadata resourceMetadata, boolean propagateToken, boolean challenge) public CatalinaBearerTokenAuthenticator(ResourceMetadata resourceMetadata, boolean propagateToken, boolean challenge) {
{ this.resourceMetadata = resourceMetadata;
this.resourceMetadata = resourceMetadata; this.challenge = challenge;
this.challenge = challenge; this.propagateToken = propagateToken;
this.propagateToken = propagateToken; }
}
public ResourceMetadata getResourceMetadata() public ResourceMetadata getResourceMetadata() {
{ return resourceMetadata;
return resourceMetadata; }
}
public String getTokenString() public String getTokenString() {
{ return tokenString;
return tokenString; }
}
public SkeletonKeyToken getToken() public SkeletonKeyToken getToken() {
{ return token;
return token; }
}
public Principal getPrincipal() public Principal getPrincipal() {
{ return principal;
return principal; }
}
public boolean login(Request request, HttpServletResponse response) throws LoginException, IOException public boolean login(Request request, HttpServletResponse response) throws LoginException, IOException {
{ String authHeader = request.getHeader("Authorization");
String authHeader = request.getHeader("Authorization"); if (authHeader == null) {
if (authHeader == null) if (challenge) {
{ challengeResponse(response, null, null);
if (challenge) return false;
{ } else {
challengeResponse(response, null, null); return false;
return false; }
} }
else
{
return false;
}
}
String[] split = authHeader.trim().split("\\s+"); String[] split = authHeader.trim().split("\\s+");
if (split == null || split.length != 2) challengeResponse(response, null, null); if (split == null || split.length != 2) challengeResponse(response, null, null);
if (!split[0].equalsIgnoreCase("Bearer")) challengeResponse(response, null, null); if (!split[0].equalsIgnoreCase("Bearer")) challengeResponse(response, null, null);
tokenString = split[1]; tokenString = split[1];
try try {
{ token = RSATokenVerifier.verifyToken(tokenString, resourceMetadata);
token = RSATokenVerifier.verifyToken(tokenString, resourceMetadata); } catch (VerificationException e) {
} log.error("Failed to verify token", e);
catch (VerificationException e) challengeResponse(response, "invalid_token", e.getMessage());
{ }
log.error("Failed to verify token", e); boolean verifyCaller = false;
challengeResponse(response, "invalid_token", e.getMessage()); Set<String> roles = null;
} if (resourceMetadata.getResourceName() != null) {
boolean verifyCaller = false; SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
Set<String> roles = null; if (access != null) roles = access.getRoles();
if (resourceMetadata.getResourceName() != null) verifyCaller = token.isVerifyCaller(resourceMetadata.getResourceName());
{ } else {
SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName()); verifyCaller = token.isVerifyCaller();
if (access != null) roles = access.getRoles(); SkeletonKeyToken.Access access = token.getRealmAccess();
verifyCaller = token.isVerifyCaller(resourceMetadata.getResourceName()); if (access != null) roles = access.getRoles();
} }
else String surrogate = null;
{ if (verifyCaller) {
verifyCaller = token.isVerifyCaller(); if (token.getTrustedCertificates() == null || token.getTrustedCertificates().size() == 0) {
SkeletonKeyToken.Access access = token.getRealmAccess(); response.sendError(400);
if (access != null) roles = access.getRoles(); throw new LoginException("No trusted certificates in token");
} }
String surrogate = null; // for now, we just make sure JBoss Web did two-way SSL
if (verifyCaller) // assume JBoss Web verifies the client cert
{ X509Certificate[] chain = request.getCertificateChain();
if (token.getTrustedCertificates() == null || token.getTrustedCertificates().size() == 0) if (chain == null || chain.length == 0) {
{ response.sendError(400);
response.sendError(400); throw new LoginException("No certificates provided by jboss web to verify the caller");
throw new LoginException("No trusted certificates in token"); }
} surrogate = chain[0].getSubjectX500Principal().getName();
// for now, we just make sure JBoss Web did two-way SSL }
// assume JBoss Web verifies the client cert SkeletonKeyPrincipal skeletonKeyPrincipal = new SkeletonKeyPrincipal(token.getPrincipal(), surrogate);
X509Certificate[] chain = request.getCertificateChain(); principal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), skeletonKeyPrincipal, roles);
if (chain == null || chain.length == 0) request.setUserPrincipal(principal);
{ request.setAuthType("OAUTH_BEARER");
response.sendError(400); if (propagateToken) {
throw new LoginException("No certificates provided by jboss web to verify the caller"); SkeletonKeySession skSession = new SkeletonKeySession(tokenString, resourceMetadata);
} request.setAttribute(SkeletonKeySession.class.getName(), skSession);
surrogate = chain[0].getSubjectX500Principal().getName(); ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
} }
SkeletonKeyPrincipal skeletonKeyPrincipal = new SkeletonKeyPrincipal(token.getPrincipal(), surrogate);
principal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), skeletonKeyPrincipal, roles);
request.setUserPrincipal(principal);
request.setAuthType("OAUTH_BEARER");
if (propagateToken)
{
SkeletonKeySession skSession = new SkeletonKeySession(tokenString, resourceMetadata);
request.setAttribute(SkeletonKeySession.class.getName(), skSession);
ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
}
return true; return true;
} }
protected void challengeResponse(HttpServletResponse response, String error, String description) throws LoginException protected void challengeResponse(HttpServletResponse response, String error, String description) throws LoginException {
{ StringBuilder header = new StringBuilder("Bearer realm=\"");
StringBuilder header = new StringBuilder("Bearer realm=\""); header.append(resourceMetadata.getRealm()).append("\"");
header.append(resourceMetadata.getRealm()).append("\""); if (error != null) {
if (error != null) header.append(", error=\"").append(error).append("\"");
{ }
header.append(", error=\"").append(error).append("\""); if (description != null) {
} header.append(", error_description=\"").append(description).append("\"");
if (description != null) }
{ response.setHeader("WWW-Authenticate", header.toString());
header.append(", error_description=\"").append(description).append("\""); try {
} response.sendError(401);
response.setHeader("WWW-Authenticate", header.toString()); } catch (IOException e) {
try throw new RuntimeException(e);
{ }
response.sendError(401); throw new LoginException("Challenged");
} }
catch (IOException e)
{
throw new RuntimeException(e);
}
throw new LoginException("Challenged");
}
} }

View file

@ -24,115 +24,105 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class CatalinaSecurityContextHelper public class CatalinaSecurityContextHelper {
{ public GenericPrincipal createPrincipal(Realm realm, Principal identity, Collection<String> roleSet) {
public GenericPrincipal createPrincipal(Realm realm, Principal identity, Collection<String> roleSet) Subject subject = new Subject();
{ String credentials = "";
Subject subject = new Subject(); Set<Principal> principals = subject.getPrincipals();
String credentials = ""; principals.add(identity);
Set<Principal> principals = subject.getPrincipals(); Group[] roleSets = getRoleSets(roleSet);
principals.add(identity); for (int g = 0; g < roleSets.length; g++) {
Group[] roleSets = getRoleSets(roleSet); Group group = roleSets[g];
for(int g = 0; g < roleSets.length; g ++) String name = group.getName();
{ Group subjectGroup = createGroup(name, principals);
Group group = roleSets[g]; if (subjectGroup instanceof NestableGroup) {
String name = group.getName(); /* A NestableGroup only allows Groups to be added to it so we
Group subjectGroup = createGroup(name, principals); need to add a SimpleGroup to subjectRoles to contain the roles
if( subjectGroup instanceof NestableGroup) */
{ SimpleGroup tmp = new SimpleGroup("Roles");
/* A NestableGroup only allows Groups to be added to it so we subjectGroup.addMember(tmp);
need to add a SimpleGroup to subjectRoles to contain the roles subjectGroup = tmp;
*/
SimpleGroup tmp = new SimpleGroup("Roles");
subjectGroup.addMember(tmp);
subjectGroup = tmp;
}
// Copy the group members to the Subject group
Enumeration<? extends Principal> members = group.members();
while( members.hasMoreElements() )
{
Principal role = (Principal) members.nextElement();
subjectGroup.addMember(role);
}
}
// add the CallerPrincipal group if none has been added in getRoleSets
Group callerGroup = new SimpleGroup(SecurityConstants.CALLER_PRINCIPAL_GROUP);
callerGroup.addMember(identity);
principals.add(callerGroup);
SecurityContext sc = SecurityContextAssociation.getSecurityContext();
Principal userPrincipal = getPrincipal(subject);
sc.getUtil().createSubjectInfo(userPrincipal, credentials, subject);
List<String> rolesAsStringList = new ArrayList<String>();
rolesAsStringList.addAll(roleSet);
return new JBossGenericPrincipal(realm, userPrincipal.getName(), null, rolesAsStringList,
userPrincipal, null, credentials, null, subject);
}
/**
* Get the Principal given the authenticated Subject. Currently the first principal that is not of type {@code Group} is
* considered or the single principal inside the CallerPrincipal group.
*
* @param subject
* @return the authenticated principal
*/
protected Principal getPrincipal(Subject subject) {
Principal principal = null;
Principal callerPrincipal = null;
if (subject != null) {
Set<Principal> principals = subject.getPrincipals();
if (principals != null && !principals.isEmpty()) {
for (Principal p : principals) {
if (!(p instanceof Group) && principal == null) {
principal = p;
}
if (p instanceof Group) {
Group g = Group.class.cast(p);
if (g.getName().equals(SecurityConstants.CALLER_PRINCIPAL_GROUP) && callerPrincipal == null) {
Enumeration<? extends Principal> e = g.members();
if (e.hasMoreElements())
callerPrincipal = e.nextElement();
}
}
} }
} // Copy the group members to the Subject group
} Enumeration<? extends Principal> members = group.members();
return callerPrincipal == null ? principal : callerPrincipal; while (members.hasMoreElements()) {
} Principal role = (Principal) members.nextElement();
subjectGroup.addMember(role);
}
}
// add the CallerPrincipal group if none has been added in getRoleSets
Group callerGroup = new SimpleGroup(SecurityConstants.CALLER_PRINCIPAL_GROUP);
callerGroup.addMember(identity);
principals.add(callerGroup);
SecurityContext sc = SecurityContextAssociation.getSecurityContext();
Principal userPrincipal = getPrincipal(subject);
sc.getUtil().createSubjectInfo(userPrincipal, credentials, subject);
List<String> rolesAsStringList = new ArrayList<String>();
rolesAsStringList.addAll(roleSet);
return new JBossGenericPrincipal(realm, userPrincipal.getName(), null, rolesAsStringList,
userPrincipal, null, credentials, null, subject);
protected Group createGroup(String name, Set<Principal> principals) }
{
Group roles = null;
Iterator<Principal> iter = principals.iterator();
while( iter.hasNext() )
{
Object next = iter.next();
if( (next instanceof Group) == false )
continue;
Group grp = (Group) next;
if( grp.getName().equals(name) )
{
roles = grp;
break;
}
}
// If we did not find a group create one
if( roles == null )
{
roles = new SimpleGroup(name);
principals.add(roles);
}
return roles;
}
protected Group[] getRoleSets(Collection<String> roleSet) /**
{ * Get the Principal given the authenticated Subject. Currently the first principal that is not of type {@code Group} is
SimpleGroup roles = new SimpleGroup("Roles"); * considered or the single principal inside the CallerPrincipal group.
Group[] roleSets = {roles}; *
for (String role : roleSet) * @param subject
{ * @return the authenticated principal
roles.addMember(new SimplePrincipal(role)); */
} protected Principal getPrincipal(Subject subject) {
return roleSets; Principal principal = null;
} Principal callerPrincipal = null;
if (subject != null) {
Set<Principal> principals = subject.getPrincipals();
if (principals != null && !principals.isEmpty()) {
for (Principal p : principals) {
if (!(p instanceof Group) && principal == null) {
principal = p;
}
if (p instanceof Group) {
Group g = Group.class.cast(p);
if (g.getName().equals(SecurityConstants.CALLER_PRINCIPAL_GROUP) && callerPrincipal == null) {
Enumeration<? extends Principal> e = g.members();
if (e.hasMoreElements())
callerPrincipal = e.nextElement();
}
}
}
}
}
return callerPrincipal == null ? principal : callerPrincipal;
}
protected Group createGroup(String name, Set<Principal> principals) {
Group roles = null;
Iterator<Principal> iter = principals.iterator();
while (iter.hasNext()) {
Object next = iter.next();
if ((next instanceof Group) == false)
continue;
Group grp = (Group) next;
if (grp.getName().equals(name)) {
roles = grp;
break;
}
}
// If we did not find a group create one
if (roles == null) {
roles = new SimpleGroup(name);
principals.add(roles);
}
return roles;
}
protected Group[] getRoleSets(Collection<String> roleSet) {
SimpleGroup roles = new SimpleGroup("Roles");
Group[] roleSets = {roles};
for (String role : roleSet) {
roles.addMember(new SimplePrincipal(role));
}
return roleSets;
}
} }

View file

@ -16,6 +16,7 @@ import org.jboss.logging.Logger;
import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.plugins.providers.RegisterBuiltin; import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.RealmConfiguration; import org.keycloak.RealmConfiguration;
import org.keycloak.ResourceMetadata; import org.keycloak.ResourceMetadata;
import org.keycloak.SkeletonKeyPrincipal; import org.keycloak.SkeletonKeyPrincipal;
@ -23,7 +24,6 @@ import org.keycloak.SkeletonKeySession;
import org.keycloak.adapters.as7.config.ManagedResourceConfig; import org.keycloak.adapters.as7.config.ManagedResourceConfig;
import org.keycloak.adapters.as7.config.ManagedResourceConfigLoader; import org.keycloak.adapters.as7.config.ManagedResourceConfigLoader;
import org.keycloak.representations.SkeletonKeyToken; import org.keycloak.representations.SkeletonKeyToken;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import javax.security.auth.login.LoginException; import javax.security.auth.login.LoginException;
import javax.servlet.ServletException; import javax.servlet.ServletException;
@ -42,262 +42,192 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class OAuthManagedResourceValve extends FormAuthenticator implements LifecycleListener public class OAuthManagedResourceValve extends FormAuthenticator implements LifecycleListener {
{ protected RealmConfiguration realmConfiguration;
protected RealmConfiguration realmConfiguration; private static final Logger log = Logger.getLogger(OAuthManagedResourceValve.class);
private static final Logger log = Logger.getLogger(OAuthManagedResourceValve.class); protected UserSessionManagement userSessionManagement = new UserSessionManagement();
protected UserSessionManagement userSessionManagement = new UserSessionManagement(); protected ManagedResourceConfig remoteSkeletonKeyConfig;
protected ManagedResourceConfig remoteSkeletonKeyConfig; protected ResourceMetadata resourceMetadata;
protected ResourceMetadata resourceMetadata;
@Override @Override
public void start() throws LifecycleException public void start() throws LifecycleException {
{ super.start();
super.start(); StandardContext standardContext = (StandardContext) context;
StandardContext standardContext = (StandardContext) context; standardContext.addLifecycleListener(this);
standardContext.addLifecycleListener(this); }
}
@Override @Override
public void lifecycleEvent(LifecycleEvent event) public void lifecycleEvent(LifecycleEvent event) {
{ if (event.getType() == Lifecycle.AFTER_START_EVENT) init();
if (event.getType() == Lifecycle.AFTER_START_EVENT) init(); }
}
protected void init() protected void init() {
{ ManagedResourceConfigLoader managedResourceConfigLoader = new ManagedResourceConfigLoader(context);
ManagedResourceConfigLoader managedResourceConfigLoader = new ManagedResourceConfigLoader(context); managedResourceConfigLoader.init(true);
resourceMetadata = managedResourceConfigLoader.getResourceMetadata(); resourceMetadata = managedResourceConfigLoader.getResourceMetadata();
remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig(); remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig();
String client_id = remoteSkeletonKeyConfig.getClientId(); String client_id = remoteSkeletonKeyConfig.getClientId();
if (client_id == null) if (client_id == null) {
{ throw new IllegalArgumentException("Must set client-id to use with auth server");
throw new IllegalArgumentException("Must set client-id to use with auth server"); }
} realmConfiguration = new RealmConfiguration();
realmConfiguration = new RealmConfiguration(); String authUrl = remoteSkeletonKeyConfig.getAuthUrl();
String authUrl = remoteSkeletonKeyConfig.getAuthUrl(); if (authUrl == null) {
if (authUrl == null) throw new RuntimeException("You must specify auth-url");
{ }
throw new RuntimeException("You must specify auth-url"); String tokenUrl = remoteSkeletonKeyConfig.getCodeUrl();
} if (tokenUrl == null) {
String tokenUrl = remoteSkeletonKeyConfig.getCodeUrl(); throw new RuntimeException("You mut specify code-url");
if (tokenUrl == null) }
{ realmConfiguration.setMetadata(resourceMetadata);
throw new RuntimeException("You mut specify code-url"); realmConfiguration.setClientId(client_id);
}
realmConfiguration.setMetadata(resourceMetadata);
realmConfiguration.setClientId(client_id);
for (Map.Entry<String, String> entry : managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getClientCredentials().entrySet()) for (Map.Entry<String, String> entry : managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getClientCredentials().entrySet()) {
{ realmConfiguration.getCredentials().param(entry.getKey(), entry.getValue());
realmConfiguration.getCredentials().param(entry.getKey(), entry.getValue()); }
}
int size = 10;
if (managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getConnectionPoolSize() > 0)
size = managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getConnectionPoolSize();
ResteasyClientBuilder.HostnameVerificationPolicy policy = ResteasyClientBuilder.HostnameVerificationPolicy.WILDCARD;
if (managedResourceConfigLoader.getRemoteSkeletonKeyConfig().isAllowAnyHostname())
policy = ResteasyClientBuilder.HostnameVerificationPolicy.ANY;
ResteasyProviderFactory providerFactory = new ResteasyProviderFactory();
ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(OAuthManagedResourceValve.class.getClassLoader());
try
{
ResteasyProviderFactory.getInstance(); // initialize builtins
RegisterBuiltin.register(providerFactory);
}
finally
{
Thread.currentThread().setContextClassLoader(old);
}
ResteasyClient client = new ResteasyClientBuilder()
.providerFactory(providerFactory)
.connectionPoolSize(size)
.hostnameVerification(policy)
.trustStore(resourceMetadata.getTruststore())
.keyStore(resourceMetadata.getClientKeystore(), resourceMetadata.getClientKeyPassword())
.build();
realmConfiguration.setClient(client);
realmConfiguration.setAuthUrl(UriBuilder.fromUri(authUrl).queryParam("client_id", client_id));
realmConfiguration.setCodeUrl(client.target(tokenUrl));
}
@Override ResteasyClient client = managedResourceConfigLoader.getClient();
public void invoke(Request request, Response response) throws IOException, ServletException
{
try
{
String requestURI = request.getDecodedRequestURI();
if (requestURI.endsWith("j_oauth_remote_logout"))
{
remoteLogout(request, response);
return;
}
super.invoke(request, response);
}
finally
{
ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession
}
}
@Override realmConfiguration.setClient(client);
public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException realmConfiguration.setAuthUrl(UriBuilder.fromUri(authUrl).queryParam("client_id", client_id));
{ realmConfiguration.setCodeUrl(client.target(tokenUrl));
try }
{
if (bearer(false, request, response)) return true; @Override
else if (checkLoggedIn(request, response)) public void invoke(Request request, Response response) throws IOException, ServletException {
{ try {
if (request.getSessionInternal().getNote(Constants.FORM_REQUEST_NOTE) != null) String requestURI = request.getDecodedRequestURI();
{ if (requestURI.endsWith("j_oauth_remote_logout")) {
if (restoreRequest(request, request.getSessionInternal())) remoteLogout(request, response);
{ return;
log.debug("restoreRequest");
return (true);
}
else
{
log.debug("Restore of original request failed");
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return (false);
}
} }
else super.invoke(request, response);
{ } finally {
return true; ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession
}
}
@Override
public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException {
try {
if (bearer(false, request, response)) return true;
else if (checkLoggedIn(request, response)) {
if (request.getSessionInternal().getNote(Constants.FORM_REQUEST_NOTE) != null) {
if (restoreRequest(request, request.getSessionInternal())) {
log.debug("restoreRequest");
return (true);
} else {
log.debug("Restore of original request failed");
response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return (false);
}
} else {
return true;
}
} }
}
// initiate or continue oauth2 protocol // initiate or continue oauth2 protocol
oauth(request, response); oauth(request, response);
} } catch (LoginException e) {
catch (LoginException e) }
{ return false;
} }
return false;
}
protected void remoteLogout(Request request, HttpServletResponse response) throws IOException protected void remoteLogout(Request request, HttpServletResponse response) throws IOException {
{ try {
try log.debug("->> remoteLogout: ");
{ if (!bearer(true, request, response)) {
log.debug("->> remoteLogout: "); log.debug("remoteLogout: bearer auth failed");
if (!bearer(true, request, response)) return;
{ }
log.debug("remoteLogout: bearer auth failed"); GenericPrincipal gp = (GenericPrincipal) request.getPrincipal();
if (!gp.hasRole(remoteSkeletonKeyConfig.getAdminRole())) {
log.debug("remoteLogout: role failure");
response.sendError(403);
return;
}
String user = request.getParameter("user");
if (user != null) {
userSessionManagement.logout(user);
} else {
userSessionManagement.logoutAll();
}
} catch (Exception e) {
log.error("failed to logout", e);
}
response.setStatus(204);
}
protected boolean bearer(boolean challenge, Request request, HttpServletResponse response) throws LoginException, IOException {
CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(realmConfiguration.getMetadata(), !remoteSkeletonKeyConfig.isCancelPropagation(), challenge);
if (bearer.login(request, response)) {
return true;
}
return false;
}
protected boolean checkLoggedIn(Request request, HttpServletResponse response) {
if (request.getSessionInternal() == null || request.getSessionInternal().getPrincipal() == null)
return false;
log.debug("remote logged in already");
GenericPrincipal principal = (GenericPrincipal) request.getSessionInternal().getPrincipal();
request.setUserPrincipal(principal);
request.setAuthType("OAUTH");
Session session = request.getSessionInternal();
if (session != null && !remoteSkeletonKeyConfig.isCancelPropagation()) {
SkeletonKeySession skSession = (SkeletonKeySession) session.getNote(SkeletonKeySession.class.getName());
if (skSession != null) {
request.setAttribute(SkeletonKeySession.class.getName(), skSession);
ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
}
}
return true;
}
/**
* This method always set the HTTP response, so do not continue after invoking
*/
protected void oauth(Request request, HttpServletResponse response) throws IOException {
ServletOAuthLogin oauth = new ServletOAuthLogin(realmConfiguration, request, response, request.getConnector().getRedirectPort());
String code = oauth.getCode();
if (code == null) {
String error = oauth.getError();
if (error != null) {
response.sendError(400, "OAuth " + error);
return;
} else {
saveRequest(request, request.getSessionInternal(true));
oauth.loginRedirect();
}
return; return;
} } else {
GenericPrincipal gp = (GenericPrincipal) request.getPrincipal(); if (!oauth.resolveCode(code)) return;
if (!gp.hasRole(remoteSkeletonKeyConfig.getAdminRole()))
{
log.debug("remoteLogout: role failure");
response.sendError(403);
return;
}
String user = request.getParameter("user");
if (user != null)
{
userSessionManagement.logout(user);
}
else
{
userSessionManagement.logoutAll();
}
}
catch (Exception e)
{
log.error("failed to logout", e);
}
response.setStatus(204);
}
protected boolean bearer(boolean challenge, Request request, HttpServletResponse response) throws LoginException, IOException SkeletonKeyToken token = oauth.getToken();
{ Set<String> roles = null;
CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(realmConfiguration.getMetadata(), !remoteSkeletonKeyConfig.isCancelPropagation(), challenge); if (resourceMetadata.getResourceName() != null) {
if (bearer.login(request, response)) SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
{ if (access != null) roles = access.getRoles();
return true; } else {
} SkeletonKeyToken.Access access = token.getRealmAccess();
return false; if (access != null) roles = access.getRoles();
} }
SkeletonKeyPrincipal skp = new SkeletonKeyPrincipal(token.getPrincipal(), null);
GenericPrincipal principal = new CatalinaSecurityContextHelper().createPrincipal(context.getRealm(), skp, roles);
Session session = request.getSessionInternal(true);
session.setPrincipal(principal);
session.setAuthType("OAUTH");
if (!remoteSkeletonKeyConfig.isCancelPropagation()) {
SkeletonKeySession skSession = new SkeletonKeySession(oauth.getTokenString(), realmConfiguration.getMetadata());
session.setNote(SkeletonKeySession.class.getName(), skSession);
}
protected boolean checkLoggedIn(Request request, HttpServletResponse response) String username = token.getPrincipal();
{ log.debug("userSessionManage.login: " + username);
if (request.getSessionInternal() == null || request.getSessionInternal().getPrincipal() == null) userSessionManagement.login(session, username);
return false; }
log.debug("remote logged in already"); }
GenericPrincipal principal = (GenericPrincipal) request.getSessionInternal().getPrincipal();
request.setUserPrincipal(principal);
request.setAuthType("OAUTH");
Session session = request.getSessionInternal();
if (session != null && !remoteSkeletonKeyConfig.isCancelPropagation())
{
SkeletonKeySession skSession = (SkeletonKeySession) session.getNote(SkeletonKeySession.class.getName());
if (skSession != null)
{
request.setAttribute(SkeletonKeySession.class.getName(), skSession);
ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
}
}
return true;
}
/**
* This method always set the HTTP response, so do not continue after invoking
*/
protected void oauth(Request request, HttpServletResponse response) throws IOException
{
ServletOAuthLogin oauth = new ServletOAuthLogin(realmConfiguration, request, response, request.getConnector().getRedirectPort());
String code = oauth.getCode();
if (code == null)
{
String error = oauth.getError();
if (error != null)
{
response.sendError(400, "OAuth " + error);
return;
}
else
{
saveRequest(request, request.getSessionInternal(true));
oauth.loginRedirect();
}
return;
}
else
{
if (!oauth.resolveCode(code)) return;
SkeletonKeyToken token = oauth.getToken();
Set<String> roles = null;
if (resourceMetadata.getResourceName() != null)
{
SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
if (access != null) roles = access.getRoles();
}
else
{
SkeletonKeyToken.Access access = token.getRealmAccess();
if (access != null) roles = access.getRoles();
}
SkeletonKeyPrincipal skp = new SkeletonKeyPrincipal(token.getPrincipal(), null);
GenericPrincipal principal = new CatalinaSecurityContextHelper().createPrincipal(context.getRealm(), skp, roles);
Session session = request.getSessionInternal(true);
session.setPrincipal(principal);
session.setAuthType("OAUTH");
if (!remoteSkeletonKeyConfig.isCancelPropagation())
{
SkeletonKeySession skSession = new SkeletonKeySession(oauth.getTokenString(), realmConfiguration.getMetadata());
session.setNote(SkeletonKeySession.class.getName(), skSession);
}
String username = token.getPrincipal();
log.debug("userSessionManage.login: " + username);
userSessionManagement.login(session, username);
}
}
} }

View file

@ -1,12 +1,12 @@
package org.keycloak.adapters.as7; package org.keycloak.adapters.as7;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.util.BasicAuthHelper;
import org.keycloak.RSATokenVerifier; import org.keycloak.RSATokenVerifier;
import org.keycloak.RealmConfiguration; import org.keycloak.RealmConfiguration;
import org.keycloak.VerificationException; import org.keycloak.VerificationException;
import org.keycloak.representations.AccessTokenResponse; import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.SkeletonKeyToken; import org.keycloak.representations.SkeletonKeyToken;
import org.jboss.resteasy.util.BasicAuthHelper;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -21,300 +21,254 @@ import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
/** /**
*
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class ServletOAuthLogin public class ServletOAuthLogin {
{ private static final Logger log = Logger.getLogger(ServletOAuthLogin.class);
private static final Logger log = Logger.getLogger(ServletOAuthLogin.class); protected HttpServletRequest request;
protected HttpServletRequest request; protected HttpServletResponse response;
protected HttpServletResponse response; protected boolean codePresent;
protected boolean codePresent; protected RealmConfiguration realmInfo;
protected RealmConfiguration realmInfo; protected int redirectPort;
protected int redirectPort; protected String tokenString;
protected String tokenString; protected SkeletonKeyToken token;
protected SkeletonKeyToken token;
public ServletOAuthLogin(RealmConfiguration realmInfo, HttpServletRequest request, HttpServletResponse response, int redirectPort) public ServletOAuthLogin(RealmConfiguration realmInfo, HttpServletRequest request, HttpServletResponse response, int redirectPort) {
{ this.request = request;
this.request = request; this.response = response;
this.response = response; this.realmInfo = realmInfo;
this.realmInfo = realmInfo; this.redirectPort = redirectPort;
this.redirectPort = redirectPort; }
}
public String getTokenString() public String getTokenString() {
{ return tokenString;
return tokenString; }
}
public SkeletonKeyToken getToken() public SkeletonKeyToken getToken() {
{ return token;
return token; }
}
public RealmConfiguration getRealmInfo() public RealmConfiguration getRealmInfo() {
{ return realmInfo;
return realmInfo; }
}
protected String getDefaultCookiePath() protected String getDefaultCookiePath() {
{ String path = request.getContextPath();
String path = request.getContextPath(); if ("".equals(path) || path == null) path = "/";
if ("".equals(path) || path == null) path = "/"; return path;
return path; }
}
protected String getRequestUrl() protected String getRequestUrl() {
{ return request.getRequestURL().toString();
return request.getRequestURL().toString(); }
}
protected boolean isRequestSecure() protected boolean isRequestSecure() {
{ return request.isSecure();
return request.isSecure(); }
}
protected void sendError(int code) protected void sendError(int code) {
{ try {
try response.sendError(code);
{ } catch (IOException e) {
response.sendError(code); throw new RuntimeException(e);
} }
catch (IOException e) }
{
throw new RuntimeException(e);
}
}
protected void sendRedirect(String url) protected void sendRedirect(String url) {
{ try {
try response.sendRedirect(url);
{ } catch (IOException e) {
response.sendRedirect(url); throw new RuntimeException(e);
} }
catch (IOException e) }
{
throw new RuntimeException(e);
}
}
protected Cookie getCookie(String cookieName) protected Cookie getCookie(String cookieName) {
{ if (request.getCookies() == null) return null;
if (request.getCookies() == null) return null; for (Cookie cookie : request.getCookies()) {
for (Cookie cookie : request.getCookies()) if (cookie.getName().equals(cookieName)) {
{ return cookie;
if (cookie.getName().equals(cookieName)) }
{ }
return cookie; return null;
} }
}
return null;
}
protected String getCookieValue(String cookieName) protected String getCookieValue(String cookieName) {
{ Cookie cookie = getCookie(cookieName);
Cookie cookie = getCookie(cookieName); if (cookie == null) return null;
if (cookie == null) return null; return cookie.getValue();
return cookie.getValue(); }
}
protected String getQueryParamValue(String paramName) protected String getQueryParamValue(String paramName) {
{ String query = request.getQueryString();
String query = request.getQueryString(); if (query == null) return null;
if (query == null) return null; String[] params = query.split("&");
String[] params = query.split("&"); for (String param : params) {
for (String param : params) int eq = param.indexOf('=');
{ if (eq == -1) continue;
int eq = param.indexOf('='); String name = param.substring(0, eq);
if (eq == -1) continue; if (!name.equals(paramName)) continue;
String name = param.substring(0, eq); return param.substring(eq + 1);
if (!name.equals(paramName)) continue; }
return param.substring(eq + 1); return null;
} }
return null;
}
public String getError() public String getError() {
{ return getQueryParamValue("error");
return getQueryParamValue("error"); }
}
public String getCode() public String getCode() {
{ return getQueryParamValue("code");
return getQueryParamValue("code"); }
}
protected void setCookie(String name, String value, String domain, String path, boolean secure) protected void setCookie(String name, String value, String domain, String path, boolean secure) {
{ Cookie cookie = new Cookie(name, value);
Cookie cookie = new Cookie(name, value); if (domain != null) cookie.setDomain(domain);
if (domain != null) cookie.setDomain(domain); if (path != null) cookie.setPath(path);
if (path != null) cookie.setPath(path); if (secure) cookie.setSecure(true);
if (secure) cookie.setSecure(true); response.addCookie(cookie);
response.addCookie(cookie); }
}
protected String getRedirectUri(String state) protected String getRedirectUri(String state) {
{ String url = getRequestUrl();
String url = getRequestUrl(); if (!isRequestSecure() && realmInfo.isSslRequired()) {
if (!isRequestSecure() && realmInfo.isSslRequired()) int port = redirectPort;
{ if (port < 0) {
int port = redirectPort; // disabled?
if (port < 0) return null;
{ }
// disabled? UriBuilder secureUrl = UriBuilder.fromUri(url).scheme("https").port(-1);
return null; if (port != 443) secureUrl.port(port);
} url = secureUrl.build().toString();
UriBuilder secureUrl = UriBuilder.fromUri(url).scheme("https").port(-1); }
if (port != 443) secureUrl.port(port); return realmInfo.getAuthUrl().clone()
url = secureUrl.build().toString(); .queryParam("client_id", realmInfo.getClientId())
} .queryParam("redirect_uri", url)
return realmInfo.getAuthUrl().clone() .queryParam("state", state)
.queryParam("client_id", realmInfo.getClientId()) .queryParam("login", "true")
.queryParam("redirect_uri", url) .build().toString();
.queryParam("state", state) }
.queryParam("login", "true")
.build().toString();
}
protected static final AtomicLong counter = new AtomicLong(); protected static final AtomicLong counter = new AtomicLong();
protected String getStateCode() protected String getStateCode() {
{ return counter.getAndIncrement() + "/" + UUID.randomUUID().toString();
return counter.getAndIncrement() + "/" + UUID.randomUUID().toString(); }
}
public void loginRedirect() public void loginRedirect() {
{ String state = getStateCode();
String state = getStateCode(); String redirect = getRedirectUri(state);
String redirect = getRedirectUri(state); if (redirect == null) {
if (redirect == null) sendError(Response.Status.FORBIDDEN.getStatusCode());
{ return;
sendError(Response.Status.FORBIDDEN.getStatusCode()); }
return; setCookie(realmInfo.getStateCookieName(), state, null, getDefaultCookiePath(), realmInfo.isSslRequired());
} sendRedirect(redirect);
setCookie(realmInfo.getStateCookieName(), state, null, getDefaultCookiePath(), realmInfo.isSslRequired()); }
sendRedirect(redirect);
}
public boolean checkStateCookie() public boolean checkStateCookie() {
{ Cookie stateCookie = getCookie(realmInfo.getStateCookieName());
Cookie stateCookie = getCookie(realmInfo.getStateCookieName());
if (stateCookie == null) if (stateCookie == null) {
{ sendError(400);
sendError(400); log.warn("No state cookie");
log.warn("No state cookie"); return false;
return false; }
} // reset the cookie
// reset the cookie Cookie reset = new Cookie(stateCookie.getName(), stateCookie.getValue());
Cookie reset = new Cookie(stateCookie.getName(), stateCookie.getValue()); reset.setPath(stateCookie.getPath());
reset.setPath(stateCookie.getPath()); reset.setMaxAge(0);
reset.setMaxAge(0); response.addCookie(reset);
response.addCookie(reset);
String stateCookieValue = getCookieValue(realmInfo.getStateCookieName()); String stateCookieValue = getCookieValue(realmInfo.getStateCookieName());
// its ok to call request.getParameter() because this should be a redirect // its ok to call request.getParameter() because this should be a redirect
String state = request.getParameter("state"); String state = request.getParameter("state");
if (state == null) if (state == null) {
{ sendError(400);
sendError(400); log.warn("state parameter was null");
log.warn("state parameter was null"); return false;
return false; }
} if (!state.equals(stateCookieValue)) {
if (!state.equals(stateCookieValue)) sendError(400);
{ log.warn("state parameter invalid");
sendError(400); log.warn("cookie: " + stateCookieValue);
log.warn("state parameter invalid"); log.warn("queryParam: " + state);
log.warn("cookie: " + stateCookieValue); return false;
log.warn("queryParam: " + state); }
return false; return true;
}
return true;
} }
/** /**
* Start or continue the oauth login process. * Start or continue the oauth login process.
* * <p/>
* if code query parameter is not present, then browser is redirected to authUrl. The redirect URL will be * if code query parameter is not present, then browser is redirected to authUrl. The redirect URL will be
* the URL of the current request. * the URL of the current request.
* * <p/>
* If code query parameter is present, then an access token is obtained by invoking a secure request to the codeUrl. * If code query parameter is present, then an access token is obtained by invoking a secure request to the codeUrl.
* If the access token is obtained, the browser is again redirected to the current request URL, but any OAuth * If the access token is obtained, the browser is again redirected to the current request URL, but any OAuth
* protocol specific query parameters are removed. * protocol specific query parameters are removed.
* *
* @return true if an access token was obtained * @return true if an access token was obtained
*/ */
public boolean resolveCode(String code) public boolean resolveCode(String code) {
{ // abort if not HTTPS
// abort if not HTTPS if (realmInfo.isSslRequired() && !isRequestSecure()) {
if (realmInfo.isSslRequired() && !isRequestSecure()) log.error("SSL is required");
{
log.error("SSL is required");
sendError(Response.Status.FORBIDDEN.getStatusCode());
return false;
}
if (!checkStateCookie()) return false;
String client_id = realmInfo.getClientId();
String password = realmInfo.getCredentials().asMap().getFirst("password");
String authHeader = BasicAuthHelper.createHeader(client_id, password);
String redirectUri = stripOauthParametersFromRedirect();
Form form = new Form();
form.param("grant_type", "authorization_code")
.param("code", code)
.param("redirect_uri", redirectUri);
Response res = realmInfo.getCodeUrl().request().header(HttpHeaders.AUTHORIZATION, authHeader).post(Entity.form(form));
AccessTokenResponse tokenResponse;
try
{
if (res.getStatus() != 200)
{
log.error("failed to turn code into token");
sendError(Response.Status.FORBIDDEN.getStatusCode()); sendError(Response.Status.FORBIDDEN.getStatusCode());
return false; return false;
} }
log.debug("media type: " + res.getMediaType());
log.debug("Content-Type header: " + res.getHeaderString("Content-Type"));
tokenResponse = res.readEntity(AccessTokenResponse.class);
}
finally
{
res.close();
}
tokenString = tokenResponse.getToken(); if (!checkStateCookie()) return false;
try
{
token = RSATokenVerifier.verifyToken(tokenString, realmInfo.getMetadata());
log.debug("Verification succeeded!");
}
catch (VerificationException e)
{
log.error("failed verification of token");
sendError(Response.Status.FORBIDDEN.getStatusCode());
return false;
}
// redirect to URL without oauth query parameters
sendRedirect(redirectUri);
return true;
}
/** String client_id = realmInfo.getClientId();
* strip out unwanted query parameters and redirect so bookmarks don't retain oauth protocol bits String password = realmInfo.getCredentials().asMap().getFirst("password");
*/ String authHeader = BasicAuthHelper.createHeader(client_id, password);
protected String stripOauthParametersFromRedirect() String redirectUri = stripOauthParametersFromRedirect();
{ Form form = new Form();
StringBuffer buf = request.getRequestURL().append("?").append(request.getQueryString()); form.param("grant_type", "authorization_code")
UriBuilder builder = UriBuilder.fromUri(buf.toString()) .param("code", code)
.replaceQueryParam("code", null) .param("redirect_uri", redirectUri);
.replaceQueryParam("state", null);
return builder.build().toString(); Response res = realmInfo.getCodeUrl().request().header(HttpHeaders.AUTHORIZATION, authHeader).post(Entity.form(form));
} AccessTokenResponse tokenResponse;
try {
if (res.getStatus() != 200) {
log.error("failed to turn code into token");
sendError(Response.Status.FORBIDDEN.getStatusCode());
return false;
}
log.debug("media type: " + res.getMediaType());
log.debug("Content-Type header: " + res.getHeaderString("Content-Type"));
tokenResponse = res.readEntity(AccessTokenResponse.class);
} finally {
res.close();
}
tokenString = tokenResponse.getToken();
try {
token = RSATokenVerifier.verifyToken(tokenString, realmInfo.getMetadata());
log.debug("Verification succeeded!");
} catch (VerificationException e) {
log.error("failed verification of token");
sendError(Response.Status.FORBIDDEN.getStatusCode());
return false;
}
// redirect to URL without oauth query parameters
sendRedirect(redirectUri);
return true;
}
/**
* strip out unwanted query parameters and redirect so bookmarks don't retain oauth protocol bits
*/
protected String stripOauthParametersFromRedirect() {
StringBuffer buf = request.getRequestURL().append("?").append(request.getQueryString());
UriBuilder builder = UriBuilder.fromUri(buf.toString())
.replaceQueryParam("code", null)
.replaceQueryParam("state", null);
return builder.build().toString();
}
} }

View file

@ -18,94 +18,80 @@ import java.util.concurrent.ConcurrentHashMap;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class UserSessionManagement implements SessionListener public class UserSessionManagement implements SessionListener {
{ private static final Logger log = Logger.getLogger(UserSessionManagement.class);
private static final Logger log = Logger.getLogger(UserSessionManagement.class); protected ConcurrentHashMap<String, Map<String, Session>> userSessionMap = new ConcurrentHashMap<String, Map<String, Session>>();
protected ConcurrentHashMap<String, Map<String, Session>> userSessionMap = new ConcurrentHashMap<String, Map<String, Session>>();
protected void login(Session session, String username) protected void login(Session session, String username) {
{ Map<String, Session> map = userSessionMap.get(username);
Map<String, Session> map = userSessionMap.get(username); if (map == null) {
if (map == null) final Map<String, Session> value = new HashMap<String, Session>();
{ map = userSessionMap.putIfAbsent(username, value);
final Map<String, Session> value = new HashMap<String, Session>(); if (map == null) {
map = userSessionMap.putIfAbsent(username, value); map = value;
if (map == null) }
{ }
map = value; synchronized (map) {
} map.put(session.getId(), session);
} }
synchronized (map) session.addSessionListener(this);
{ }
map.put(session.getId(), session);
}
session.addSessionListener(this);
}
public void logoutAll() public void logoutAll() {
{ List<String> users = new ArrayList<String>();
List<String> users = new ArrayList<String>(); users.addAll(userSessionMap.keySet());
users.addAll(userSessionMap.keySet()); for (String user : users) logout(user);
for (String user : users) logout(user); }
}
public void logoutAllBut(String but) public void logoutAllBut(String but) {
{ List<String> users = new ArrayList<String>();
List<String> users = new ArrayList<String>(); users.addAll(userSessionMap.keySet());
users.addAll(userSessionMap.keySet()); for (String user : users) {
for (String user : users) if (!but.equals(user)) logout(user);
{ }
if (!but.equals(user)) logout(user); }
}
}
public void logout(String user) public void logout(String user) {
{ log.debug("logoutUser: " + user);
log.debug("logoutUser: " + user); Map<String, Session> map = userSessionMap.remove(user);
Map<String, Session> map = userSessionMap.remove(user); if (map == null) {
if (map == null) log.debug("no session for user: " + user);
{ return;
log.debug("no session for user: " + user); }
return; log.debug("found session for user");
} synchronized (map) {
log.debug("found session for user"); for (Session session : map.values()) {
synchronized (map) log.debug("invalidating session for user: " + user);
{ session.setPrincipal(null);
for (Session session : map.values()) session.setAuthType(null);
{ session.getSession().invalidate();
log.debug("invalidating session for user: " + user); }
session.setPrincipal(null); }
session.setAuthType(null);
session.getSession().invalidate();
}
}
} }
public void sessionEvent(SessionEvent event) public void sessionEvent(SessionEvent event) {
{ // We only care about session destroyed events
// We only care about session destroyed events if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType())
if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType()) && (!Session.SESSION_PASSIVATED_EVENT.equals(event.getType())))
&& (!Session.SESSION_PASSIVATED_EVENT.equals(event.getType()))) return;
return;
// Look up the single session id associated with this session (if any) // Look up the single session id associated with this session (if any)
Session session = event.getSession(); Session session = event.getSession();
GenericPrincipal principal = (GenericPrincipal) session.getPrincipal(); GenericPrincipal principal = (GenericPrincipal) session.getPrincipal();
if (principal == null) return; if (principal == null) return;
session.setPrincipal(null); session.setPrincipal(null);
session.setAuthType(null); session.setAuthType(null);
String username = principal.getUserPrincipal().getName(); String username = principal.getUserPrincipal().getName();
Map<String, Session> map = userSessionMap.get(username); Map<String, Session> map = userSessionMap.get(username);
if (map == null) return; if (map == null) return;
synchronized (map) synchronized (map) {
{ map.remove(session.getId());
map.remove(session.getId()); if (map.isEmpty()) userSessionMap.remove(username);
if (map.isEmpty()) userSessionMap.remove(username); }
}
} }
} }

View file

@ -9,271 +9,229 @@ import java.util.List;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class AuthServerConfig public class AuthServerConfig {
{ @JsonProperty("realm")
@JsonProperty("realm") protected String realm;
protected String realm;
@JsonProperty("realm-private-key") @JsonProperty("realm-private-key")
protected String realmPrivateKey; protected String realmPrivateKey;
@JsonProperty("realm-public-key") @JsonProperty("realm-public-key")
protected String realmPublicKey; protected String realmPublicKey;
@JsonProperty("realm-keystore") @JsonProperty("realm-keystore")
protected String realmKeyStore; protected String realmKeyStore;
@JsonProperty("realm-keystore-password") @JsonProperty("realm-keystore-password")
protected String realmKeystorePassword; protected String realmKeystorePassword;
@JsonProperty("realm-key-alias") @JsonProperty("realm-key-alias")
protected String realmKeyAlias; protected String realmKeyAlias;
@JsonProperty("realm-private-key-password") @JsonProperty("realm-private-key-password")
protected String realmPrivateKeyPassword; protected String realmPrivateKeyPassword;
@JsonProperty("access-code-lifetime") @JsonProperty("access-code-lifetime")
protected int accessCodeLifetime; protected int accessCodeLifetime;
@JsonProperty("token-lifetime") @JsonProperty("token-lifetime")
protected int tokenLifetime; protected int tokenLifetime;
@JsonProperty("admin-role") @JsonProperty("admin-role")
protected String adminRole; protected String adminRole;
@JsonProperty("login-role") @JsonProperty("login-role")
protected String loginRole; protected String loginRole;
@JsonProperty("oauth-client-role") @JsonProperty("oauth-client-role")
protected String clientRole; protected String clientRole;
@JsonProperty("wildcard-role") @JsonProperty("wildcard-role")
protected String wildcardRole; protected String wildcardRole;
@JsonProperty("cancel-propagation") @JsonProperty("cancel-propagation")
protected boolean cancelPropagation; protected boolean cancelPropagation;
@JsonProperty("sso-disabled") @JsonProperty("sso-disabled")
protected boolean ssoDisabled; protected boolean ssoDisabled;
// these properties are optional and used to provide connection metadata when the server wants to make // these properties are optional and used to provide connection metadata when the server wants to make
// remote SSL connections // remote SSL connections
protected String truststore; protected String truststore;
@JsonProperty("truststore-password") @JsonProperty("truststore-password")
protected String truststorePassword; protected String truststorePassword;
@JsonProperty("client-keystore") @JsonProperty("client-keystore")
protected String clientKeystore; protected String clientKeystore;
@JsonProperty("client-keystore-password") @JsonProperty("client-keystore-password")
protected String clientKeystorePassword; protected String clientKeystorePassword;
@JsonProperty("client-key-password") @JsonProperty("client-key-password")
protected String clientKeyPassword; protected String clientKeyPassword;
protected List<String> resources = new ArrayList<String>(); protected List<String> resources = new ArrayList<String>();
public String getRealm() public String getRealm() {
{ return realm;
return realm; }
}
public void setRealm(String realm) public void setRealm(String realm) {
{ this.realm = realm;
this.realm = realm; }
}
public String getRealmPrivateKey() public String getRealmPrivateKey() {
{ return realmPrivateKey;
return realmPrivateKey; }
}
public void setRealmPrivateKey(String realmPrivateKey) public void setRealmPrivateKey(String realmPrivateKey) {
{ this.realmPrivateKey = realmPrivateKey;
this.realmPrivateKey = realmPrivateKey; }
}
public String getRealmPublicKey() public String getRealmPublicKey() {
{ return realmPublicKey;
return realmPublicKey; }
}
public void setRealmPublicKey(String realmPublicKey) public void setRealmPublicKey(String realmPublicKey) {
{ this.realmPublicKey = realmPublicKey;
this.realmPublicKey = realmPublicKey; }
}
public int getAccessCodeLifetime() public int getAccessCodeLifetime() {
{ return accessCodeLifetime;
return accessCodeLifetime; }
}
public void setAccessCodeLifetime(int accessCodeLifetime) public void setAccessCodeLifetime(int accessCodeLifetime) {
{ this.accessCodeLifetime = accessCodeLifetime;
this.accessCodeLifetime = accessCodeLifetime; }
}
public String getTruststore() public String getTruststore() {
{ return truststore;
return truststore; }
}
public void setTruststore(String truststore) public void setTruststore(String truststore) {
{ this.truststore = truststore;
this.truststore = truststore; }
}
public String getTruststorePassword() public String getTruststorePassword() {
{ return truststorePassword;
return truststorePassword; }
}
public void setTruststorePassword(String truststorePassword) public void setTruststorePassword(String truststorePassword) {
{ this.truststorePassword = truststorePassword;
this.truststorePassword = truststorePassword; }
}
public String getClientKeystore() public String getClientKeystore() {
{ return clientKeystore;
return clientKeystore; }
}
public void setClientKeystore(String clientKeystore) public void setClientKeystore(String clientKeystore) {
{ this.clientKeystore = clientKeystore;
this.clientKeystore = clientKeystore; }
}
public String getClientKeystorePassword() public String getClientKeystorePassword() {
{ return clientKeystorePassword;
return clientKeystorePassword; }
}
public void setClientKeystorePassword(String clientKeystorePassword) public void setClientKeystorePassword(String clientKeystorePassword) {
{ this.clientKeystorePassword = clientKeystorePassword;
this.clientKeystorePassword = clientKeystorePassword; }
}
public String getClientKeyPassword() public String getClientKeyPassword() {
{ return clientKeyPassword;
return clientKeyPassword; }
}
public void setClientKeyPassword(String clientKeyPassword) public void setClientKeyPassword(String clientKeyPassword) {
{ this.clientKeyPassword = clientKeyPassword;
this.clientKeyPassword = clientKeyPassword; }
}
public boolean isCancelPropagation() public boolean isCancelPropagation() {
{ return cancelPropagation;
return cancelPropagation; }
}
public void setCancelPropagation(boolean cancelPropagation) public void setCancelPropagation(boolean cancelPropagation) {
{ this.cancelPropagation = cancelPropagation;
this.cancelPropagation = cancelPropagation; }
}
public boolean isSsoDisabled() public boolean isSsoDisabled() {
{ return ssoDisabled;
return ssoDisabled; }
}
public void setSsoDisabled(boolean ssoDisabled) public void setSsoDisabled(boolean ssoDisabled) {
{ this.ssoDisabled = ssoDisabled;
this.ssoDisabled = ssoDisabled; }
}
public List<String> getResources() public List<String> getResources() {
{ return resources;
return resources; }
}
public String getAdminRole() public String getAdminRole() {
{ return adminRole;
return adminRole; }
}
public void setAdminRole(String adminRole) public void setAdminRole(String adminRole) {
{ this.adminRole = adminRole;
this.adminRole = adminRole; }
}
public String getLoginRole() public String getLoginRole() {
{ return loginRole;
return loginRole; }
}
public void setLoginRole(String loginRole) public void setLoginRole(String loginRole) {
{ this.loginRole = loginRole;
this.loginRole = loginRole; }
}
public String getClientRole() public String getClientRole() {
{ return clientRole;
return clientRole; }
}
public void setClientRole(String clientRole) public void setClientRole(String clientRole) {
{ this.clientRole = clientRole;
this.clientRole = clientRole; }
}
public String getWildcardRole() public String getWildcardRole() {
{ return wildcardRole;
return wildcardRole; }
}
public void setWildcardRole(String wildcardRole) public void setWildcardRole(String wildcardRole) {
{ this.wildcardRole = wildcardRole;
this.wildcardRole = wildcardRole; }
}
public String getRealmKeyStore() public String getRealmKeyStore() {
{ return realmKeyStore;
return realmKeyStore; }
}
public void setRealmKeyStore(String realmKeyStore) public void setRealmKeyStore(String realmKeyStore) {
{ this.realmKeyStore = realmKeyStore;
this.realmKeyStore = realmKeyStore; }
}
public String getRealmKeystorePassword() public String getRealmKeystorePassword() {
{ return realmKeystorePassword;
return realmKeystorePassword; }
}
public void setRealmKeystorePassword(String realmKeystorePassword) public void setRealmKeystorePassword(String realmKeystorePassword) {
{ this.realmKeystorePassword = realmKeystorePassword;
this.realmKeystorePassword = realmKeystorePassword; }
}
public String getRealmKeyAlias() public String getRealmKeyAlias() {
{ return realmKeyAlias;
return realmKeyAlias; }
}
public void setRealmKeyAlias(String realmKeyAlias) public void setRealmKeyAlias(String realmKeyAlias) {
{ this.realmKeyAlias = realmKeyAlias;
this.realmKeyAlias = realmKeyAlias; }
}
public String getRealmPrivateKeyPassword() public String getRealmPrivateKeyPassword() {
{ return realmPrivateKeyPassword;
return realmPrivateKeyPassword; }
}
public void setRealmPrivateKeyPassword(String realmPrivateKeyPassword) public void setRealmPrivateKeyPassword(String realmPrivateKeyPassword) {
{ this.realmPrivateKeyPassword = realmPrivateKeyPassword;
this.realmPrivateKeyPassword = realmPrivateKeyPassword; }
}
public int getTokenLifetime() public int getTokenLifetime() {
{ return tokenLifetime;
return tokenLifetime; }
}
public void setTokenLifetime(int tokenLifetime) public void setTokenLifetime(int tokenLifetime) {
{ this.tokenLifetime = tokenLifetime;
this.tokenLifetime = tokenLifetime; }
}
} }

View file

@ -10,204 +10,183 @@ import java.util.Map;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
@JsonPropertyOrder({"realm", "resource", "realm-public-key", "admin-role", "auth-url", "code-url", "truststore", "truststore-password", "client-id", "client-credentials"}) @JsonPropertyOrder({"realm-url", "realm", "resource", "realm-public-key", "admin-role", "auth-url", "code-url", "allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password", "client-id", "client-credentials"})
public class ManagedResourceConfig public class ManagedResourceConfig {
{ @JsonProperty("realm-url")
@JsonProperty("realm") protected String realmUrl;
protected String realm; @JsonProperty("realm")
@JsonProperty("resource") protected String realm;
protected String resource; @JsonProperty("resource")
protected String resource;
@JsonProperty("realm-public-key")
protected String realmKey;
@JsonProperty("admin-role")
protected String adminRole;
@JsonProperty("auth-url")
protected String authUrl;
@JsonProperty("code-url")
protected String codeUrl;
@JsonProperty("realm-public-key") @JsonProperty("allow-any-hostname")
protected String realmKey; protected boolean allowAnyHostname;
@JsonProperty("disable-trust-manager")
protected boolean disableTrustManager;
@JsonProperty("truststore")
protected String truststore;
@JsonProperty("truststore-password")
protected String truststorePassword;
@JsonProperty("client-id")
protected String clientId;
@JsonProperty("client-keystore")
protected String clientKeystore;
@JsonProperty("client-keystore-password")
protected String clientKeystorePassword;
@JsonProperty("client-key-password")
protected String clientKeyPassword;
@JsonProperty("client-credentials")
protected Map<String, String> clientCredentials = new HashMap<String, String>();
@JsonProperty("connection-pool-size")
protected int connectionPoolSize;
@JsonProperty("cancel-propagation")
protected boolean cancelPropagation;
@JsonProperty("admin-role") public String getRealmUrl() {
protected String adminRole; return realmUrl;
}
@JsonProperty("auth-url") public void setRealmUrl(String realmUrl) {
protected String authUrl; this.realmUrl = realmUrl;
@JsonProperty("code-url") }
protected String codeUrl;
@JsonProperty("allow-any-hostname") public String getRealm() {
protected boolean allowAnyHostname; return realm;
}
@JsonProperty("truststore") public void setRealm(String realm) {
protected String truststore; this.realm = realm;
}
@JsonProperty("truststore-password") public String getResource() {
protected String truststorePassword; return resource;
@JsonProperty("client-id") }
protected String clientId;
@JsonProperty("client-keystore")
protected String clientKeystore;
@JsonProperty("client-keystore-password")
protected String clientKeystorePassword;
@JsonProperty("client-key-password")
protected String clientKeyPassword;
@JsonProperty("client-credentials") public void setResource(String resource) {
protected Map<String, String> clientCredentials = new HashMap<String, String>(); this.resource = resource;
}
@JsonProperty("connection-pool-size") public String getRealmKey() {
protected int connectionPoolSize; return realmKey;
}
@JsonProperty("cancel-propagation") public void setRealmKey(String realmKey) {
protected boolean cancelPropagation; this.realmKey = realmKey;
}
public String getAuthUrl() {
return authUrl;
}
public String getRealm() public void setAuthUrl(String authUrl) {
{ this.authUrl = authUrl;
return realm; }
}
public void setRealm(String realm) public String getCodeUrl() {
{ return codeUrl;
this.realm = realm; }
}
public String getResource() public void setCodeUrl(String codeUrl) {
{ this.codeUrl = codeUrl;
return resource; }
}
public void setResource(String resource) public boolean isAllowAnyHostname() {
{ return allowAnyHostname;
this.resource = resource; }
}
public String getRealmKey() public void setAllowAnyHostname(boolean allowAnyHostname) {
{ this.allowAnyHostname = allowAnyHostname;
return realmKey; }
}
public void setRealmKey(String realmKey) public boolean isDisableTrustManager() {
{ return disableTrustManager;
this.realmKey = realmKey; }
}
public String getAuthUrl() public void setDisableTrustManager(boolean disableTrustManager) {
{ this.disableTrustManager = disableTrustManager;
return authUrl; }
}
public void setAuthUrl(String authUrl) public String getTruststore() {
{ return truststore;
this.authUrl = authUrl; }
}
public String getCodeUrl() public void setTruststore(String truststore) {
{ this.truststore = truststore;
return codeUrl; }
}
public void setCodeUrl(String codeUrl) public String getTruststorePassword() {
{ return truststorePassword;
this.codeUrl = codeUrl; }
}
public boolean isAllowAnyHostname() public void setTruststorePassword(String truststorePassword) {
{ this.truststorePassword = truststorePassword;
return allowAnyHostname; }
}
public void setAllowAnyHostname(boolean allowAnyHostname) public String getClientId() {
{ return clientId;
this.allowAnyHostname = allowAnyHostname; }
}
public String getTruststore() public void setClientId(String clientId) {
{ this.clientId = clientId;
return truststore; }
}
public void setTruststore(String truststore) public Map<String, String> getClientCredentials() {
{ return clientCredentials;
this.truststore = truststore; }
}
public String getTruststorePassword() public String getClientKeystore() {
{ return clientKeystore;
return truststorePassword; }
}
public void setTruststorePassword(String truststorePassword) public void setClientKeystore(String clientKeystore) {
{ this.clientKeystore = clientKeystore;
this.truststorePassword = truststorePassword; }
}
public String getClientId() public String getClientKeystorePassword() {
{ return clientKeystorePassword;
return clientId; }
}
public void setClientId(String clientId) public void setClientKeystorePassword(String clientKeystorePassword) {
{ this.clientKeystorePassword = clientKeystorePassword;
this.clientId = clientId; }
}
public Map<String, String> getClientCredentials() public String getClientKeyPassword() {
{ return clientKeyPassword;
return clientCredentials; }
}
public String getClientKeystore() public void setClientKeyPassword(String clientKeyPassword) {
{ this.clientKeyPassword = clientKeyPassword;
return clientKeystore; }
}
public void setClientKeystore(String clientKeystore) public int getConnectionPoolSize() {
{ return connectionPoolSize;
this.clientKeystore = clientKeystore; }
}
public String getClientKeystorePassword() public void setConnectionPoolSize(int connectionPoolSize) {
{ this.connectionPoolSize = connectionPoolSize;
return clientKeystorePassword; }
}
public void setClientKeystorePassword(String clientKeystorePassword) public boolean isCancelPropagation() {
{ return cancelPropagation;
this.clientKeystorePassword = clientKeystorePassword; }
}
public String getClientKeyPassword() public void setCancelPropagation(boolean cancelPropagation) {
{ this.cancelPropagation = cancelPropagation;
return clientKeyPassword; }
}
public void setClientKeyPassword(String clientKeyPassword) public String getAdminRole() {
{ return adminRole;
this.clientKeyPassword = clientKeyPassword; }
}
public int getConnectionPoolSize() public void setAdminRole(String adminRole) {
{ this.adminRole = adminRole;
return connectionPoolSize; }
}
public void setConnectionPoolSize(int connectionPoolSize)
{
this.connectionPoolSize = connectionPoolSize;
}
public boolean isCancelPropagation()
{
return cancelPropagation;
}
public void setCancelPropagation(boolean cancelPropagation)
{
this.cancelPropagation = cancelPropagation;
}
public String getAdminRole()
{
return adminRole;
}
public void setAdminRole(String adminRole)
{
this.adminRole = adminRole;
}
} }

View file

@ -4,10 +4,16 @@ import org.apache.catalina.Context;
import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.annotate.JsonSerialize; import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.keycloak.EnvUtil; import org.keycloak.EnvUtil;
import org.keycloak.PemUtils; import org.keycloak.PemUtils;
import org.keycloak.ResourceMetadata; import org.keycloak.ResourceMetadata;
import org.keycloak.representations.idm.PublishedRealmRepresentation;
import javax.ws.rs.client.WebTarget;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -16,124 +22,166 @@ import java.io.InputStream;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.PublicKey; import java.security.PublicKey;
public class ManagedResourceConfigLoader public class ManagedResourceConfigLoader {
{ static final Logger log = Logger.getLogger(ManagedResourceConfigLoader.class);
static final Logger log = Logger.getLogger(ManagedResourceConfigLoader.class); protected ManagedResourceConfig remoteSkeletonKeyConfig;
protected ManagedResourceConfig remoteSkeletonKeyConfig; protected ResourceMetadata resourceMetadata;
protected ResourceMetadata resourceMetadata; protected KeyStore clientCertKeystore;
protected KeyStore truststore;
protected ResteasyClient client;
public ManagedResourceConfigLoader(Context context) public ManagedResourceConfigLoader(Context context) {
{ ObjectMapper mapper = new ObjectMapper();
ObjectMapper mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT); InputStream is = null;
InputStream is = null; String path = context.getServletContext().getInitParameter("keycloak.config.file");
String path = context.getServletContext().getInitParameter("skeleton.key.config.file"); if (path == null) {
if (path == null) is = context.getServletContext().getResourceAsStream("/WEB-INF/resteasy-oauth.json");
{ } else {
is = context.getServletContext().getResourceAsStream("/WEB-INF/resteasy-oauth.json"); try {
} is = new FileInputStream(path);
else } catch (FileNotFoundException e) {
{ throw new RuntimeException(e);
try }
{ }
is = new FileInputStream(path); remoteSkeletonKeyConfig = null;
} try {
catch (FileNotFoundException e) remoteSkeletonKeyConfig = mapper.readValue(is, ManagedResourceConfig.class);
{ } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
remoteSkeletonKeyConfig = null;
try
{
remoteSkeletonKeyConfig = mapper.readValue(is, ManagedResourceConfig.class);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
String name = remoteSkeletonKeyConfig.getResource(); public void init(boolean setupClient) {
String realm = remoteSkeletonKeyConfig.getRealm();
if (realm == null) throw new RuntimeException("Must set 'realm' in config");
String realmKeyPem = remoteSkeletonKeyConfig.getRealmKey();
if (realmKeyPem == null)
{
throw new IllegalArgumentException("You must set the realm-public-key");
}
PublicKey realmKey = null;
try
{
realmKey = PemUtils.decodePublicKey(realmKeyPem);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
resourceMetadata = new ResourceMetadata();
resourceMetadata.setRealm(realm);
resourceMetadata.setResourceName(name);
resourceMetadata.setRealmKey(realmKey);
String truststore = remoteSkeletonKeyConfig.getTruststore();
if (truststore != null)
{
truststore = EnvUtil.replace(truststore);
String truststorePassword = remoteSkeletonKeyConfig.getTruststorePassword();
KeyStore trust = null;
try
{
trust = loadKeyStore(truststore, truststorePassword);
}
catch (Exception e)
{
throw new RuntimeException("Failed to load truststore", e);
}
resourceMetadata.setTruststore(trust);
}
String clientKeystore = remoteSkeletonKeyConfig.getClientKeystore();
String clientKeyPassword = null;
if (clientKeystore != null)
{
clientKeystore = EnvUtil.replace(clientKeystore);
String clientKeystorePassword = remoteSkeletonKeyConfig.getClientKeystorePassword();
KeyStore serverKS = null;
try
{
serverKS = loadKeyStore(clientKeystore, clientKeystorePassword);
}
catch (Exception e)
{
throw new RuntimeException("Failed to load keystore", e);
}
resourceMetadata.setClientKeystore(serverKS);
clientKeyPassword = remoteSkeletonKeyConfig.getClientKeyPassword();
resourceMetadata.setClientKeyPassword(clientKeyPassword);
}
} String truststorePath = remoteSkeletonKeyConfig.getTruststore();
public static KeyStore loadKeyStore(String filename, String password) throws Exception if (truststorePath != null) {
{ truststorePath = EnvUtil.replace(truststorePath);
KeyStore trustStore = KeyStore.getInstance(KeyStore String truststorePassword = remoteSkeletonKeyConfig.getTruststorePassword();
.getDefaultType()); truststorePath = null;
File truststoreFile = new File(filename); try {
FileInputStream trustStream = new FileInputStream(truststoreFile); this.truststore = loadKeyStore(truststorePath, truststorePassword);
trustStore.load(trustStream, password.toCharArray()); } catch (Exception e) {
trustStream.close(); throw new RuntimeException("Failed to load truststore", e);
return trustStore; }
} }
String clientKeystore = remoteSkeletonKeyConfig.getClientKeystore();
String clientKeyPassword = null;
if (clientKeystore != null) {
clientKeystore = EnvUtil.replace(clientKeystore);
String clientKeystorePassword = remoteSkeletonKeyConfig.getClientKeystorePassword();
clientCertKeystore = null;
try {
clientCertKeystore = loadKeyStore(clientKeystore, clientKeystorePassword);
} catch (Exception e) {
throw new RuntimeException("Failed to load keystore", e);
}
}
public ManagedResourceConfig getRemoteSkeletonKeyConfig() initClient();
{
return remoteSkeletonKeyConfig;
}
public ResourceMetadata getResourceMetadata() String realm = remoteSkeletonKeyConfig.getRealm();
{
return resourceMetadata;
}
if (remoteSkeletonKeyConfig.getRealmUrl() != null) {
PublishedRealmRepresentation rep = null;
try {
rep = client.target(remoteSkeletonKeyConfig.getRealmUrl()).request().get(PublishedRealmRepresentation.class);
} finally {
if (!setupClient) {
client.close();
}
}
remoteSkeletonKeyConfig.setRealm(rep.getRealm());
remoteSkeletonKeyConfig.setAuthUrl(rep.getAuthorizationUrl());
remoteSkeletonKeyConfig.setCodeUrl(rep.getCodeUrl());
remoteSkeletonKeyConfig.setRealmKey(rep.getPublicKeyPem());
remoteSkeletonKeyConfig.setAdminRole(rep.getAdminRole());
}
String resource = remoteSkeletonKeyConfig.getResource();
if (realm == null) throw new RuntimeException("Must set 'realm' in config");
String realmKeyPem = remoteSkeletonKeyConfig.getRealmKey();
if (realmKeyPem == null) {
throw new IllegalArgumentException("You must set the realm-public-key");
}
PublicKey realmKey = null;
try {
realmKey = PemUtils.decodePublicKey(realmKeyPem);
} catch (Exception e) {
throw new RuntimeException(e);
}
resourceMetadata = new ResourceMetadata();
resourceMetadata.setRealm(realm);
resourceMetadata.setResourceName(resource);
resourceMetadata.setRealmKey(realmKey);
resourceMetadata.setClientKeystore(clientCertKeystore);
clientKeyPassword = remoteSkeletonKeyConfig.getClientKeyPassword();
resourceMetadata.setClientKeyPassword(clientKeyPassword);
resourceMetadata.setTruststore(this.truststore);
}
protected void initClient() {
int size = 10;
if (remoteSkeletonKeyConfig.getConnectionPoolSize() > 0)
size = remoteSkeletonKeyConfig.getConnectionPoolSize();
ResteasyClientBuilder.HostnameVerificationPolicy policy = ResteasyClientBuilder.HostnameVerificationPolicy.WILDCARD;
if (remoteSkeletonKeyConfig.isAllowAnyHostname())
policy = ResteasyClientBuilder.HostnameVerificationPolicy.ANY;
ResteasyProviderFactory providerFactory = new ResteasyProviderFactory();
ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(ManagedResourceConfigLoader.class.getClassLoader());
try {
ResteasyProviderFactory.getInstance(); // initialize builtins
RegisterBuiltin.register(providerFactory);
} finally {
Thread.currentThread().setContextClassLoader(old);
}
ResteasyClientBuilder builder = new ResteasyClientBuilder()
.providerFactory(providerFactory)
.connectionPoolSize(size)
.hostnameVerification(policy)
.keyStore(clientCertKeystore, remoteSkeletonKeyConfig.getClientKeyPassword());
if (remoteSkeletonKeyConfig.isDisableTrustManager()) {
builder.disableTrustManager();
} else {
builder.trustStore(truststore);
}
client = builder.build();
}
public static KeyStore loadKeyStore(String filename, String password) throws Exception {
KeyStore trustStore = KeyStore.getInstance(KeyStore
.getDefaultType());
File truststoreFile = new File(filename);
FileInputStream trustStream = new FileInputStream(truststoreFile);
trustStore.load(trustStream, password.toCharArray());
trustStream.close();
return trustStore;
}
public ManagedResourceConfig getRemoteSkeletonKeyConfig() {
return remoteSkeletonKeyConfig;
}
public ResourceMetadata getResourceMetadata() {
return resourceMetadata;
}
public ResteasyClient getClient() {
return client;
}
public KeyStore getClientCertKeystore() {
return clientCertKeystore;
}
public KeyStore getTruststore() {
return truststore;
}
} }

View file

@ -19,6 +19,7 @@ import javax.ws.rs.core.UriInfo;
*/ */
public class RealmSubResource { public class RealmSubResource {
protected static final Logger logger = Logger.getLogger(RealmSubResource.class); protected static final Logger logger = Logger.getLogger(RealmSubResource.class);
public static final String ADMIN_ROLE = "$REALM-ADMIN$";
@Context @Context
protected UriInfo uriInfo; protected UriInfo uriInfo;
@ -32,8 +33,13 @@ public class RealmSubResource {
this.realm = realm; this.realm = realm;
} }
public static UriBuilder realmUrl(UriInfo uriInfo) {
UriBuilder base = uriInfo.getBaseUriBuilder()
.path(RealmsResource.class).path(RealmsResource.class, "getRealmResource");
return base;
}
@GET @GET
@Path("json")
@Produces("application/json") @Produces("application/json")
public PublishedRealmRepresentation getRealm(@PathParam("realm") String id) { public PublishedRealmRepresentation getRealm(@PathParam("realm") String id) {
return realmRep(realm, uriInfo); return realmRep(realm, uriInfo);
@ -65,26 +71,14 @@ public class RealmSubResource {
public static PublishedRealmRepresentation realmRep(RealmModel realm, UriInfo uriInfo) { public static PublishedRealmRepresentation realmRep(RealmModel realm, UriInfo uriInfo) {
PublishedRealmRepresentation rep = new PublishedRealmRepresentation(); PublishedRealmRepresentation rep = new PublishedRealmRepresentation();
rep.setRealm(realm.getName()); rep.setRealm(realm.getName());
rep.setSelf(uriInfo.getRequestUri().toString()); rep.setSelf(realmUrl(uriInfo).build(realm.getId()).toString());
rep.setPublicKeyPem(realm.getPublicKeyPem()); rep.setPublicKeyPem(realm.getPublicKeyPem());
rep.setAdminRole(ADMIN_ROLE);
UriBuilder auth = uriInfo.getBaseUriBuilder(); rep.setAuthorizationUrl(TokenService.loginPage(uriInfo).build(realm.getId()).toString());
auth.path(RealmsResource.class).path(RealmsResource.class, "getTokenService") rep.setCodeUrl(TokenService.accessCodeRequest(uriInfo).build(realm.getId()).toString());
.path(TokenService.class, "requestAccessCode"); rep.setGrantUrl(TokenService.grantRequest(uriInfo).build(realm.getId()).toString());
rep.setAuthorizationUrl(auth.build(realm.getId()).toString()); String idGrantUrl = TokenService.identityGrantRequest(uriInfo).build(realm.getId()).toString();
UriBuilder code = uriInfo.getBaseUriBuilder();
code.path(RealmsResource.class).path(RealmsResource.class, "getTokenService").path(TokenService.class, "accessRequest");
rep.setCodeUrl(code.build(realm.getId()).toString());
UriBuilder grant = uriInfo.getBaseUriBuilder();
grant.path(RealmsResource.class).path(RealmsResource.class, "getTokenService").path(TokenService.class, "accessTokenGrant");
String grantUrl = grant.build(realm.getId()).toString();
rep.setGrantUrl(grantUrl);
UriBuilder idGrant = uriInfo.getBaseUriBuilder();
grant.path(RealmsResource.class).path(RealmsResource.class, "getTokenService").path(TokenService.class, "identityTokenGrant");
String idGrantUrl = idGrant.build(realm.getId()).toString();
rep.setIdentityGrantUrl(idGrantUrl); rep.setIdentityGrantUrl(idGrantUrl);
return rep; return rep;
} }