Merge pull request #6 from patriot1burke/master

more
This commit is contained in:
Bill Burke 2013-07-19 18:34:21 -07:00
commit 2e45334ee2
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,8 +20,7 @@ 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;
@ -31,15 +30,12 @@ public class AbstractOAuthClient
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) client = new ResteasyClientBuilder().trustStore(truststore)
.hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY) .hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY)
.connectionPoolSize(10) .connectionPoolSize(10)
@ -47,83 +43,67 @@ public class AbstractOAuthClient
} }
} }
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()
@ -131,27 +111,20 @@ public class AbstractOAuthClient
.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) {
if (res.getStatus() == 400)
{
throw new BadRequestException(); throw new BadRequestException();
} } else if (res.getStatus() != 200) {
else if (res.getStatus() != 200)
{
throw new InternalServerErrorException(new Exception("Unknown error when getting acess token")); throw new InternalServerErrorException(new Exception("Unknown error when getting acess token"));
} }
AccessTokenResponse tokenResponse = res.readEntity(AccessTokenResponse.class); AccessTokenResponse tokenResponse = res.readEntity(AccessTokenResponse.class);
return tokenResponse.getToken(); return tokenResponse.getToken();
} } finally {
finally
{
res.close(); 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)

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,16 +20,13 @@ 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()];
@ -42,24 +39,21 @@ public class DerUtils
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");

View file

@ -7,8 +7,7 @@ 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("[$][{]([^}]+)[}]");
/** /**
@ -17,12 +16,10 @@ public class EnvUtil
* @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 envVar = matcher.group(1);
String envVal = System.getProperty(envVar); String envVal = System.getProperty(envVar);
if (envVal == null) envVal = "NOT-SPECIFIED"; if (envVal == null) envVal = "NOT-SPECIFIED";

View file

@ -16,21 +16,18 @@ 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
{ public static X509Certificate decodeCertificate(InputStream is) throws Exception {
byte[] der = pemToDer(is); byte[] der = pemToDer(is);
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 public static X509Certificate decodeCertificate(String cert) throws Exception {
{
byte[] der = pemToDer(cert); byte[] der = pemToDer(cert);
ByteArrayInputStream bis = new ByteArrayInputStream(der); ByteArrayInputStream bis = new ByteArrayInputStream(der);
return DerUtils.decodeCertificate(bis); return DerUtils.decodeCertificate(bis);
@ -44,8 +41,7 @@ public class PemUtils
* @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);
} }
@ -57,14 +53,12 @@ public class PemUtils
* @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);
} }
@ -76,8 +70,7 @@ public class PemUtils
* @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;
@ -90,14 +83,12 @@ public class PemUtils
* @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", "");
@ -106,8 +97,7 @@ public class PemUtils
} }
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);

View file

@ -12,49 +12,37 @@ 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(); PublicKey realmKey = metadata.getRealmKey();
String realm = metadata.getRealm(); String realm = metadata.getRealm();
return verifyToken(tokenString, realmKey, realm); 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); verified = RSAProvider.verify(input, realmKey);
} } catch (Exception ignore) {
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) {
catch (IOException e)
{
throw new VerificationException(e); throw new VerificationException(e);
} }
if (!token.isActive()) if (!token.isActive()) {
{
throw new VerificationException("Token is not active."); throw new VerificationException("Token is not active.");
} }
String user = token.getPrincipal(); String user = token.getPrincipal();
if (user == null) if (user == null) {
{
throw new VerificationException("Token user was null"); throw new VerificationException("Token user was null");
} }
if (!realm.equals(token.getAudience())) if (!realm.equals(token.getAudience())) {
{
throw new VerificationException("Token audience doesn't match domain"); throw new VerificationException("Token audience doesn't match domain");
} }

View file

@ -10,8 +10,7 @@ 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;
@ -21,78 +20,63 @@ public class RealmConfiguration
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,8 +7,7 @@ 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;
@ -16,13 +15,11 @@ public class ResourceMetadata
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;
} }
@ -32,18 +29,15 @@ public class ResourceMetadata
* *
* @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;
} }
@ -52,8 +46,7 @@ public class ResourceMetadata
* *
* @return * @return
*/ */
public KeyStore getTruststore() public KeyStore getTruststore() {
{
return truststore; return truststore;
} }
@ -62,33 +55,27 @@ public class ResourceMetadata
* *
* @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,28 +14,23 @@ 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,31 +6,26 @@ 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;
@ -43,16 +38,14 @@ public class SkeletonKeyPrincipal implements Principal
} }
@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,28 +6,23 @@ 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,26 +25,21 @@ 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) if (description != null) {
{
header.append(", error_description=\"").append(description).append("\""); header.append(", error_description=\"").append(description).append("\"");
} }
request.abortWith(Response.status(401).header("WWW-Authenticate", header.toString()).build()); request.abortWith(Response.status(401).header("WWW-Authenticate", header.toString()).build());
@ -55,11 +50,9 @@ public class JaxrsBearerTokenFilter implements ContainerRequestFilter
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); challengeResponse(request, null, null);
return; return;
} }
@ -72,8 +65,7 @@ public class JaxrsBearerTokenFilter implements ContainerRequestFilter
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);
@ -82,45 +74,35 @@ public class JaxrsBearerTokenFilter implements ContainerRequestFilter
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 {
else
{
access = token.getRealmAccess(); access = token.getRealmAccess();
} }
SecurityContext ctx = new SecurityContext() SecurityContext ctx = new SecurityContext() {
{
@Override @Override
public Principal getUserPrincipal() public Principal getUserPrincipal() {
{
return principal; 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) {
catch (VerificationException e)
{
log.error("Failed to verify token", e); log.error("Failed to verify token", e);
challengeResponse(request, "invalid_token", e.getMessage()); challengeResponse(request, "invalid_token", e.getMessage());
} }

View file

@ -18,10 +18,8 @@ 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)
@ -35,17 +33,16 @@ public class JaxrsOAuthClient extends AbstractOAuthClient
.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");

View file

@ -8,8 +8,7 @@ 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;
@ -22,43 +21,35 @@ public class AccessTokenResponse
@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,47 +13,39 @@ 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") @JsonProperty("roles")
protected Set<String> roles; protected Set<String> roles;
@JsonProperty("verify_caller") @JsonProperty("verify_caller")
protected Boolean verifyCaller; 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;
} }
@ -72,8 +64,7 @@ public class SkeletonKeyToken extends JsonWebToken
@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;
} }
@ -83,9 +74,9 @@ public class SkeletonKeyToken extends JsonWebToken
* @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;
} }
@ -96,91 +87,76 @@ public class SkeletonKeyToken extends JsonWebToken
* @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;
} }
@ -189,13 +165,11 @@ public class SkeletonKeyToken extends JsonWebToken
* *
* @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,8 +13,7 @@ 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;
@ -33,54 +32,53 @@ public class PublishedRealmRepresentation
@JsonProperty("identity-grants") @JsonProperty("identity-grants")
protected String identityGrantUrl; protected String identityGrantUrl;
@JsonProperty("admin-role")
protected String adminRole;
@JsonIgnore @JsonIgnore
protected volatile transient PublicKey publicKey; protected volatile transient PublicKey publicKey;
public String getAdminRole() {
return adminRole;
}
public String getRealm() public void setAdminRole(String adminRole) {
{ this.adminRole = adminRole;
}
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 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 getPublicKeyPem() public String getPublicKeyPem() {
{
return publicKeyPem; return publicKeyPem;
} }
public void setPublicKeyPem(String publicKeyPem) public void setPublicKeyPem(String publicKeyPem) {
{
this.publicKeyPem = publicKeyPem; this.publicKeyPem = publicKeyPem;
this.publicKey = null; this.publicKey = null;
} }
@JsonIgnore @JsonIgnore
public PublicKey getPublicKey() public PublicKey getPublicKey() {
{
if (publicKey != null) return publicKey; if (publicKey != null) return publicKey;
if (publicKeyPem != null) if (publicKeyPem != null) {
{ try {
try
{
publicKey = PemUtils.decodePublicKey(publicKeyPem); publicKey = PemUtils.decodePublicKey(publicKeyPem);
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@ -88,18 +86,14 @@ public class PublishedRealmRepresentation
} }
@JsonIgnore @JsonIgnore
public void setPublicKey(PublicKey publicKey) public void setPublicKey(PublicKey publicKey) {
{
this.publicKey = publicKey; this.publicKey = publicKey;
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
PEMWriter pemWriter = new PEMWriter(writer); PEMWriter pemWriter = new PEMWriter(writer);
try try {
{
pemWriter.writeObject(publicKey); pemWriter.writeObject(publicKey);
pemWriter.flush(); pemWriter.flush();
} } catch (IOException e) {
catch (IOException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
String s = writer.toString(); String s = writer.toString();
@ -107,43 +101,35 @@ public class PublishedRealmRepresentation
} }
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,8 +8,7 @@ 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;
@ -25,38 +24,31 @@ public class RealmRepresentation
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);
@ -64,13 +56,11 @@ public class RealmRepresentation
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>();
@ -78,58 +68,47 @@ public class RealmRepresentation
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>();
@ -137,13 +116,11 @@ public class RealmRepresentation
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>();
@ -151,33 +128,27 @@ public class RealmRepresentation
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,8 +4,7 @@ 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";
@ -14,33 +13,27 @@ public class RequiredCredentialRepresentation
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

@ -9,8 +9,7 @@ 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;
@ -18,60 +17,49 @@ public class ResourceRepresentation
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>();
@ -79,13 +67,11 @@ public class ResourceRepresentation
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>();

View file

@ -4,49 +4,39 @@ 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,49 +4,39 @@ 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

@ -9,41 +9,33 @@ 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 type;
protected String value; protected String value;
protected boolean hashed; 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;
} }
} }
@ -54,55 +46,45 @@ public class UserRepresentation
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);
@ -112,13 +94,11 @@ public class UserRepresentation
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,21 +17,17 @@ 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 relativePath path relative to context root you want auth server to redirect back to
* @param request * @param request
* @param response * @param response
* @throws IOException * @throws IOException
*/ */
public void redirectRelative(String relativePath, HttpServletRequest request, HttpServletResponse response) throws IOException public void redirectRelative(String relativePath, HttpServletRequest request, HttpServletResponse response) throws IOException {
{
ResteasyUriInfo uriInfo = ServletUtil.extractUriInfo(request, null); ResteasyUriInfo uriInfo = ServletUtil.extractUriInfo(request, null);
String redirect = uriInfo.getBaseUriBuilder().path(relativePath).toTemplate(); String redirect = uriInfo.getBaseUriBuilder().path(relativePath).toTemplate();
redirect(redirect, request, response); redirect(redirect, request, response);
@ -47,8 +43,7 @@ public class ServletOAuthClient extends AbstractOAuthClient
* @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)
@ -66,24 +61,20 @@ public class ServletOAuthClient extends AbstractOAuthClient
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('='); int eq = param.indexOf('=');
if (eq == -1) continue; if (eq == -1) continue;
String name = param.substring(0, eq); String name = param.substring(0, eq);
@ -103,8 +94,7 @@ public class ServletOAuthClient extends AbstractOAuthClient
* @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();
@ -115,8 +105,7 @@ public class ServletOAuthClient extends AbstractOAuthClient
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"));

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,8 +4,7 @@ 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";

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,60 +27,48 @@ 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); super.invoke(request, response);
} } finally {
finally
{
ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession 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); CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, !remoteSkeletonKeyConfig.isCancelPropagation(), true);
if (bearer.login(request, response)) if (bearer.login(request, response)) {
{
return true; return true;
} }
return false; return false;
} } catch (LoginException e) {
catch (LoginException e)
{
} }
return false; 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,8 +21,7 @@ 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);
@ -31,45 +30,35 @@ public class CatalinaBearerTokenAuthenticator
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) {
if (challenge)
{
challengeResponse(response, null, null); challengeResponse(response, null, null);
return false; return false;
} } else {
else
{
return false; return false;
} }
} }
@ -81,42 +70,33 @@ public class CatalinaBearerTokenAuthenticator
tokenString = split[1]; tokenString = split[1];
try try {
{
token = RSATokenVerifier.verifyToken(tokenString, resourceMetadata); token = RSATokenVerifier.verifyToken(tokenString, resourceMetadata);
} } catch (VerificationException e) {
catch (VerificationException e)
{
log.error("Failed to verify token", e); log.error("Failed to verify token", e);
challengeResponse(response, "invalid_token", e.getMessage()); challengeResponse(response, "invalid_token", e.getMessage());
} }
boolean verifyCaller = false; boolean verifyCaller = false;
Set<String> roles = null; Set<String> roles = null;
if (resourceMetadata.getResourceName() != null) if (resourceMetadata.getResourceName() != null) {
{
SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName()); SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
if (access != null) roles = access.getRoles(); if (access != null) roles = access.getRoles();
verifyCaller = token.isVerifyCaller(resourceMetadata.getResourceName()); verifyCaller = token.isVerifyCaller(resourceMetadata.getResourceName());
} } else {
else
{
verifyCaller = token.isVerifyCaller(); verifyCaller = token.isVerifyCaller();
SkeletonKeyToken.Access access = token.getRealmAccess(); SkeletonKeyToken.Access access = token.getRealmAccess();
if (access != null) roles = access.getRoles(); if (access != null) roles = access.getRoles();
} }
String surrogate = null; String surrogate = null;
if (verifyCaller) if (verifyCaller) {
{ if (token.getTrustedCertificates() == null || token.getTrustedCertificates().size() == 0) {
if (token.getTrustedCertificates() == null || token.getTrustedCertificates().size() == 0)
{
response.sendError(400); response.sendError(400);
throw new LoginException("No trusted certificates in token"); throw new LoginException("No trusted certificates in token");
} }
// for now, we just make sure JBoss Web did two-way SSL // for now, we just make sure JBoss Web did two-way SSL
// assume JBoss Web verifies the client cert // assume JBoss Web verifies the client cert
X509Certificate[] chain = request.getCertificateChain(); X509Certificate[] chain = request.getCertificateChain();
if (chain == null || chain.length == 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 certificates provided by jboss web to verify the caller");
} }
@ -126,8 +106,7 @@ public class CatalinaBearerTokenAuthenticator
principal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), skeletonKeyPrincipal, roles); principal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), skeletonKeyPrincipal, roles);
request.setUserPrincipal(principal); request.setUserPrincipal(principal);
request.setAuthType("OAUTH_BEARER"); request.setAuthType("OAUTH_BEARER");
if (propagateToken) if (propagateToken) {
{
SkeletonKeySession skSession = new SkeletonKeySession(tokenString, resourceMetadata); SkeletonKeySession skSession = new SkeletonKeySession(tokenString, resourceMetadata);
request.setAttribute(SkeletonKeySession.class.getName(), skSession); request.setAttribute(SkeletonKeySession.class.getName(), skSession);
ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession); ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
@ -137,25 +116,19 @@ public class CatalinaBearerTokenAuthenticator
} }
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) if (description != null) {
{
header.append(", error_description=\"").append(description).append("\""); header.append(", error_description=\"").append(description).append("\"");
} }
response.setHeader("WWW-Authenticate", header.toString()); response.setHeader("WWW-Authenticate", header.toString());
try try {
{
response.sendError(401); response.sendError(401);
} } catch (IOException e) {
catch (IOException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
throw new LoginException("Challenged"); throw new LoginException("Challenged");

View file

@ -24,22 +24,18 @@ 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(); Subject subject = new Subject();
String credentials = ""; String credentials = "";
Set<Principal> principals = subject.getPrincipals(); Set<Principal> principals = subject.getPrincipals();
principals.add(identity); principals.add(identity);
Group[] roleSets = getRoleSets(roleSet); Group[] roleSets = getRoleSets(roleSet);
for(int g = 0; g < roleSets.length; g ++) for (int g = 0; g < roleSets.length; g++) {
{
Group group = roleSets[g]; Group group = roleSets[g];
String name = group.getName(); String name = group.getName();
Group subjectGroup = createGroup(name, principals); Group subjectGroup = createGroup(name, principals);
if( subjectGroup instanceof NestableGroup) if (subjectGroup instanceof NestableGroup) {
{
/* A NestableGroup only allows Groups to be added to it so we /* A NestableGroup only allows Groups to be added to it so we
need to add a SimpleGroup to subjectRoles to contain the roles need to add a SimpleGroup to subjectRoles to contain the roles
*/ */
@ -49,8 +45,7 @@ public class CatalinaSecurityContextHelper
} }
// Copy the group members to the Subject group // Copy the group members to the Subject group
Enumeration<? extends Principal> members = group.members(); Enumeration<? extends Principal> members = group.members();
while( members.hasMoreElements() ) while (members.hasMoreElements()) {
{
Principal role = (Principal) members.nextElement(); Principal role = (Principal) members.nextElement();
subjectGroup.addMember(role); subjectGroup.addMember(role);
} }
@ -68,6 +63,7 @@ public class CatalinaSecurityContextHelper
userPrincipal, null, credentials, null, subject); userPrincipal, null, credentials, null, subject);
} }
/** /**
* Get the Principal given the authenticated Subject. Currently the first principal that is not of type {@code Group} is * 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. * considered or the single principal inside the CallerPrincipal group.
@ -99,37 +95,31 @@ public class CatalinaSecurityContextHelper
return callerPrincipal == null ? principal : callerPrincipal; return callerPrincipal == null ? principal : callerPrincipal;
} }
protected Group createGroup(String name, Set<Principal> principals) protected Group createGroup(String name, Set<Principal> principals) {
{
Group roles = null; Group roles = null;
Iterator<Principal> iter = principals.iterator(); Iterator<Principal> iter = principals.iterator();
while( iter.hasNext() ) while (iter.hasNext()) {
{
Object next = iter.next(); Object next = iter.next();
if ((next instanceof Group) == false) if ((next instanceof Group) == false)
continue; continue;
Group grp = (Group) next; Group grp = (Group) next;
if( grp.getName().equals(name) ) if (grp.getName().equals(name)) {
{
roles = grp; roles = grp;
break; break;
} }
} }
// If we did not find a group create one // If we did not find a group create one
if( roles == null ) if (roles == null) {
{
roles = new SimpleGroup(name); roles = new SimpleGroup(name);
principals.add(roles); principals.add(roles);
} }
return roles; return roles;
} }
protected Group[] getRoleSets(Collection<String> roleSet) protected Group[] getRoleSets(Collection<String> roleSet) {
{
SimpleGroup roles = new SimpleGroup("Roles"); SimpleGroup roles = new SimpleGroup("Roles");
Group[] roleSets = {roles}; Group[] roleSets = {roles};
for (String role : roleSet) for (String role : roleSet) {
{
roles.addMember(new SimplePrincipal(role)); roles.addMember(new SimplePrincipal(role));
} }
return roleSets; return roleSets;

View file

@ -25,6 +25,9 @@ import org.jboss.resteasy.jose.jws.crypto.RSAProvider;
import org.jboss.resteasy.jwt.JsonSerialization; import org.jboss.resteasy.jwt.JsonSerialization;
import org.jboss.resteasy.plugins.providers.RegisterBuiltin; import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
import org.jboss.resteasy.plugins.server.servlet.ServletUtil; import org.jboss.resteasy.plugins.server.servlet.ServletUtil;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.ResteasyUriInfo;
import org.jboss.resteasy.util.BasicAuthHelper;
import org.keycloak.EnvUtil; import org.keycloak.EnvUtil;
import org.keycloak.PemUtils; import org.keycloak.PemUtils;
import org.keycloak.ResourceMetadata; import org.keycloak.ResourceMetadata;
@ -33,9 +36,6 @@ import org.keycloak.adapters.as7.config.AuthServerConfig;
import org.keycloak.adapters.as7.config.ManagedResourceConfig; import org.keycloak.adapters.as7.config.ManagedResourceConfig;
import org.keycloak.representations.AccessTokenResponse; import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.SkeletonKeyToken; import org.keycloak.representations.SkeletonKeyToken;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.ResteasyUriInfo;
import org.jboss.resteasy.util.BasicAuthHelper;
import javax.security.auth.login.LoginException; import javax.security.auth.login.LoginException;
import javax.servlet.RequestDispatcher; import javax.servlet.RequestDispatcher;
@ -79,12 +79,10 @@ 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 OAuthAuthenticationServerValve extends FormAuthenticator implements LifecycleListener public class OAuthAuthenticationServerValve extends FormAuthenticator implements LifecycleListener {
{
public static class AccessCode public static class AccessCode {
{
protected String id = UUID.randomUUID().toString() + System.currentTimeMillis(); protected String id = UUID.randomUUID().toString() + System.currentTimeMillis();
protected long expiration; protected long expiration;
protected SkeletonKeyToken token; protected SkeletonKeyToken token;
@ -92,63 +90,51 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
protected boolean sso; protected boolean sso;
protected String redirect; protected String redirect;
public boolean isExpired() public boolean isExpired() {
{
return expiration != 0 && (System.currentTimeMillis() / 1000) > expiration; return expiration != 0 && (System.currentTimeMillis() / 1000) > expiration;
} }
public String getId() public String getId() {
{
return id; return id;
} }
public long getExpiration() public long getExpiration() {
{
return expiration; return expiration;
} }
public void setExpiration(long expiration) public void setExpiration(long expiration) {
{
this.expiration = expiration; this.expiration = expiration;
} }
public SkeletonKeyToken getToken() public SkeletonKeyToken getToken() {
{
return token; return token;
} }
public void setToken(SkeletonKeyToken token) public void setToken(SkeletonKeyToken token) {
{
this.token = token; this.token = token;
} }
public String getClient() public String getClient() {
{
return client; return client;
} }
public void setClient(String client) public void setClient(String client) {
{
this.client = client; this.client = client;
} }
public boolean isSso() public boolean isSso() {
{
return sso; return sso;
} }
public void setSso(boolean sso) public void setSso(boolean sso) {
{
this.sso = sso; this.sso = sso;
} }
public String getRedirect() public String getRedirect() {
{
return redirect; return redirect;
} }
public void setRedirect(String redirect) public void setRedirect(String redirect) {
{
this.redirect = redirect; this.redirect = redirect;
} }
} }
@ -158,8 +144,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
private static AtomicLong counter = new AtomicLong(1); private static AtomicLong counter = new AtomicLong(1);
private static String generateId() private static String generateId() {
{
return counter.getAndIncrement() + "." + UUID.randomUUID().toString(); return counter.getAndIncrement() + "." + UUID.randomUUID().toString();
} }
@ -174,8 +159,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
protected ObjectWriter accessTokenResponseWriter; protected ObjectWriter accessTokenResponseWriter;
protected ObjectWriter mapWriter; protected ObjectWriter mapWriter;
private static KeyStore loadKeyStore(String filename, String password) throws Exception private static KeyStore loadKeyStore(String filename, String password) throws Exception {
{
KeyStore trustStore = KeyStore.getInstance(KeyStore KeyStore trustStore = KeyStore.getInstance(KeyStore
.getDefaultType()); .getDefaultType());
File truststoreFile = new File(filename); File truststoreFile = new File(filename);
@ -186,21 +170,18 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
} }
@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() {
{
mapper = new ObjectMapper(); mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT); mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
accessTokenResponseWriter = mapper.writerWithType(AccessTokenResponse.class); accessTokenResponseWriter = mapper.writerWithType(AccessTokenResponse.class);
@ -208,95 +189,66 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
InputStream is = null; InputStream is = null;
String path = context.getServletContext().getInitParameter("skeleton.key.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"); is = context.getServletContext().getResourceAsStream("/WEB-INF/resteasy-oauth.json");
} } else {
else try {
{
try
{
is = new FileInputStream(path); is = new FileInputStream(path);
} } catch (FileNotFoundException e) {
catch (FileNotFoundException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
try try {
{
skeletonKeyConfig = mapper.readValue(is, AuthServerConfig.class); skeletonKeyConfig = mapper.readValue(is, AuthServerConfig.class);
} } catch (IOException e) {
catch (IOException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
if (skeletonKeyConfig.getLoginRole() == null) if (skeletonKeyConfig.getLoginRole() == null) {
{
throw new RuntimeException("You must define the login-role in your config file"); throw new RuntimeException("You must define the login-role in your config file");
} }
if (skeletonKeyConfig.getClientRole() == null) if (skeletonKeyConfig.getClientRole() == null) {
{
throw new RuntimeException("You must define the oauth-client-role in your config file"); throw new RuntimeException("You must define the oauth-client-role in your config file");
} }
if (skeletonKeyConfig.getRealmPrivateKey() != null) if (skeletonKeyConfig.getRealmPrivateKey() != null) {
{ try {
try
{
realmPrivateKey = PemUtils.decodePrivateKey(skeletonKeyConfig.getRealmPrivateKey()); realmPrivateKey = PemUtils.decodePrivateKey(skeletonKeyConfig.getRealmPrivateKey());
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
if (skeletonKeyConfig.getRealmPublicKey() != null) if (skeletonKeyConfig.getRealmPublicKey() != null) {
{ try {
try
{
realmPublicKey = PemUtils.decodePublicKey(skeletonKeyConfig.getRealmPublicKey()); realmPublicKey = PemUtils.decodePublicKey(skeletonKeyConfig.getRealmPublicKey());
realmPublicKeyPem = skeletonKeyConfig.getRealmPublicKey(); realmPublicKeyPem = skeletonKeyConfig.getRealmPublicKey();
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
if (skeletonKeyConfig.getRealmKeyStore() != null) if (skeletonKeyConfig.getRealmKeyStore() != null) {
{
if (skeletonKeyConfig.getRealmKeyAlias() == null) throw new RuntimeException("Must define realm-key-alias"); if (skeletonKeyConfig.getRealmKeyAlias() == null) throw new RuntimeException("Must define realm-key-alias");
String keystorePath = EnvUtil.replace(skeletonKeyConfig.getRealmKeyStore()); String keystorePath = EnvUtil.replace(skeletonKeyConfig.getRealmKeyStore());
try try {
{
KeyStore ks = loadKeyStore(keystorePath, skeletonKeyConfig.getRealmKeystorePassword()); KeyStore ks = loadKeyStore(keystorePath, skeletonKeyConfig.getRealmKeystorePassword());
if (realmPrivateKey == null) if (realmPrivateKey == null) {
{
realmPrivateKey = (PrivateKey) ks.getKey(skeletonKeyConfig.getRealmKeyAlias(), skeletonKeyConfig.getRealmPrivateKeyPassword().toCharArray()); realmPrivateKey = (PrivateKey) ks.getKey(skeletonKeyConfig.getRealmKeyAlias(), skeletonKeyConfig.getRealmPrivateKeyPassword().toCharArray());
} }
if (realmPublicKey == null) if (realmPublicKey == null) {
{
Certificate cert = ks.getCertificate(skeletonKeyConfig.getRealmKeyAlias()); Certificate cert = ks.getCertificate(skeletonKeyConfig.getRealmKeyAlias());
realmPublicKey = cert.getPublicKey(); realmPublicKey = cert.getPublicKey();
} }
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
if (realmPublicKey == null) throw new RuntimeException("You have not declared a keystore or public key"); if (realmPublicKey == null) throw new RuntimeException("You have not declared a keystore or public key");
if (realmPrivateKey == null) throw new RuntimeException("You have not declared a keystore or private key"); if (realmPrivateKey == null) throw new RuntimeException("You have not declared a keystore or private key");
if (realmPublicKeyPem == null) if (realmPublicKeyPem == null) {
{
StringWriter sw = new StringWriter(); StringWriter sw = new StringWriter();
PEMWriter writer = new PEMWriter(sw); PEMWriter writer = new PEMWriter(sw);
try try {
{
writer.writeObject(realmPublicKey); writer.writeObject(realmPublicKey);
writer.flush(); writer.flush();
} } catch (IOException e) {
catch (IOException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
realmPublicKeyPem = sw.toString(); realmPublicKeyPem = sw.toString();
@ -305,47 +257,36 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
providers = new ResteasyProviderFactory(); providers = new ResteasyProviderFactory();
ClassLoader old = Thread.currentThread().getContextClassLoader(); ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(OAuthAuthenticationServerValve.class.getClassLoader()); Thread.currentThread().setContextClassLoader(OAuthAuthenticationServerValve.class.getClassLoader());
try try {
{
ResteasyProviderFactory.getInstance(); // initialize builtins ResteasyProviderFactory.getInstance(); // initialize builtins
RegisterBuiltin.register(providers); RegisterBuiltin.register(providers);
} } finally {
finally
{
Thread.currentThread().setContextClassLoader(old); Thread.currentThread().setContextClassLoader(old);
} }
resourceMetadata = new ResourceMetadata(); resourceMetadata = new ResourceMetadata();
resourceMetadata.setRealm(skeletonKeyConfig.getRealm()); resourceMetadata.setRealm(skeletonKeyConfig.getRealm());
resourceMetadata.setRealmKey(realmPublicKey); resourceMetadata.setRealmKey(realmPublicKey);
String truststore = skeletonKeyConfig.getTruststore(); String truststore = skeletonKeyConfig.getTruststore();
if (truststore != null) if (truststore != null) {
{
truststore = EnvUtil.replace(truststore); truststore = EnvUtil.replace(truststore);
String truststorePassword = skeletonKeyConfig.getTruststorePassword(); String truststorePassword = skeletonKeyConfig.getTruststorePassword();
KeyStore trust = null; KeyStore trust = null;
try try {
{
trust = loadKeyStore(truststore, truststorePassword); trust = loadKeyStore(truststore, truststorePassword);
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException("Failed to load truststore", e); throw new RuntimeException("Failed to load truststore", e);
} }
resourceMetadata.setTruststore(trust); resourceMetadata.setTruststore(trust);
} }
String clientKeystore = skeletonKeyConfig.getClientKeystore(); String clientKeystore = skeletonKeyConfig.getClientKeystore();
String clientKeyPassword = null; String clientKeyPassword = null;
if (clientKeystore != null) if (clientKeystore != null) {
{
clientKeystore = EnvUtil.replace(clientKeystore); clientKeystore = EnvUtil.replace(clientKeystore);
String clientKeystorePassword = skeletonKeyConfig.getClientKeystorePassword(); String clientKeystorePassword = skeletonKeyConfig.getClientKeystorePassword();
KeyStore serverKS = null; KeyStore serverKS = null;
try try {
{
serverKS = loadKeyStore(clientKeystore, clientKeystorePassword); serverKS = loadKeyStore(clientKeystore, clientKeystorePassword);
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException("Failed to load keystore", e); throw new RuntimeException("Failed to load keystore", e);
} }
resourceMetadata.setClientKeystore(serverKS); resourceMetadata.setClientKeystore(serverKS);
@ -355,66 +296,48 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
} }
@Override @Override
public void invoke(Request request, Response response) throws IOException, ServletException public void invoke(Request request, Response response) throws IOException, ServletException {
{ try {
try
{
String contextPath = request.getContextPath(); String contextPath = request.getContextPath();
String requestURI = request.getDecodedRequestURI(); String requestURI = request.getDecodedRequestURI();
log.debug("--- invoke: " + requestURI); log.debug("--- invoke: " + requestURI);
if (request.getMethod().equalsIgnoreCase("GET") if (request.getMethod().equalsIgnoreCase("GET")
&& context.getLoginConfig().getLoginPage().equals(request.getRequestPathMB().toString())) && context.getLoginConfig().getLoginPage().equals(request.getRequestPathMB().toString())) {
{
if (handleLoginPage(request, response)) return; if (handleLoginPage(request, response)) return;
} } else if (request.getMethod().equalsIgnoreCase("GET")
else if (request.getMethod().equalsIgnoreCase("GET") && requestURI.endsWith(Actions.J_OAUTH_LOGOUT)) {
&& requestURI.endsWith(Actions.J_OAUTH_LOGOUT))
{
logoutCurrentUser(request, response); logoutCurrentUser(request, response);
return; return;
} } else if (request.getMethod().equalsIgnoreCase("POST")
else if (request.getMethod().equalsIgnoreCase("POST") && requestURI.endsWith(Actions.J_OAUTH_ADMIN_FORCED_LOGOUT)) {
&& requestURI.endsWith(Actions.J_OAUTH_ADMIN_FORCED_LOGOUT))
{
adminLogout(request, response); adminLogout(request, response);
return; return;
} } else if (request.getMethod().equalsIgnoreCase("POST")
else if (request.getMethod().equalsIgnoreCase("POST")
&& requestURI.startsWith(contextPath) && && requestURI.startsWith(contextPath) &&
requestURI.endsWith(Constants.FORM_ACTION) requestURI.endsWith(Constants.FORM_ACTION)
&& request.getParameter("client_id") != null) && request.getParameter("client_id") != null) {
{
handleOAuth(request, response); handleOAuth(request, response);
return; return;
} } else if (request.getMethod().equalsIgnoreCase("POST")
else if (request.getMethod().equalsIgnoreCase("POST") && requestURI.endsWith(Actions.J_OAUTH_TOKEN_GRANT)) {
&& requestURI.endsWith(Actions.J_OAUTH_TOKEN_GRANT))
{
tokenGrant(request, response); tokenGrant(request, response);
return; return;
} } else if (request.getMethod().equalsIgnoreCase("POST")
else if (request.getMethod().equalsIgnoreCase("POST")
&& requestURI.startsWith(contextPath) && && requestURI.startsWith(contextPath) &&
requestURI.endsWith(Actions.J_OAUTH_RESOLVE_ACCESS_CODE)) requestURI.endsWith(Actions.J_OAUTH_RESOLVE_ACCESS_CODE)) {
{
resolveAccessCode(request, response); resolveAccessCode(request, response);
return; return;
} } else if (request.getMethod().equalsIgnoreCase("GET")
else if (request.getMethod().equalsIgnoreCase("GET")
&& requestURI.startsWith(contextPath) && && requestURI.startsWith(contextPath) &&
requestURI.endsWith("j_oauth_realm_info.html")) requestURI.endsWith("j_oauth_realm_info.html")) {
{
publishRealmInfoHtml(request, response); publishRealmInfoHtml(request, response);
return; return;
} }
// propagate the skeleton key token string? // propagate the skeleton key token string?
if (!skeletonKeyConfig.isCancelPropagation()) if (!skeletonKeyConfig.isCancelPropagation()) {
{ if (request.getAttribute(SkeletonKeySession.class.getName()) == null && request.getSessionInternal() != null) {
if (request.getAttribute(SkeletonKeySession.class.getName()) == null && request.getSessionInternal() != null)
{
SkeletonKeySession skSession = (SkeletonKeySession) request.getSessionInternal().getNote(SkeletonKeySession.class.getName()); SkeletonKeySession skSession = (SkeletonKeySession) request.getSessionInternal().getNote(SkeletonKeySession.class.getName());
if (skSession != null) if (skSession != null) {
{
request.setAttribute(SkeletonKeySession.class.getName(), skSession); request.setAttribute(SkeletonKeySession.class.getName(), skSession);
ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession); ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
} }
@ -422,15 +345,12 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
} }
request.setAttribute("OAUTH_FORM_ACTION", "j_security_check"); request.setAttribute("OAUTH_FORM_ACTION", "j_security_check");
super.invoke(request, response); super.invoke(request, response);
} } finally {
finally
{
ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession
} }
} }
protected boolean handleLoginPage(Request request, Response response) throws IOException, ServletException protected boolean handleLoginPage(Request request, Response response) throws IOException, ServletException {
{
String client_id = request.getParameter("client_id"); String client_id = request.getParameter("client_id");
// if this is not an OAUTH redirect, just return and let the default flow happen // if this is not an OAUTH redirect, just return and let the default flow happen
if (client_id == null) return false; if (client_id == null) return false;
@ -438,8 +358,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
String redirect_uri = request.getParameter("redirect_uri"); String redirect_uri = request.getParameter("redirect_uri");
String state = request.getParameter("state"); String state = request.getParameter("state");
if (redirect_uri == null) if (redirect_uri == null) {
{
response.sendError(400, "No oauth redirect query parameter set"); response.sendError(400, "No oauth redirect query parameter set");
return true; return true;
} }
@ -449,14 +368,11 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
else if (!skeletonKeyConfig.isSsoDisabled() else if (!skeletonKeyConfig.isSsoDisabled()
&& request.getSessionInternal() != null && request.getSessionInternal() != null
&& request.getSessionInternal().getPrincipal() != null && request.getSessionInternal().getPrincipal() != null
&& request.getParameter("login") != null) && request.getParameter("login") != null) {
{
log.debug("We're ALREADY LOGGED IN!!!"); log.debug("We're ALREADY LOGGED IN!!!");
GenericPrincipal gp = (GenericPrincipal) request.getSessionInternal().getPrincipal(); GenericPrincipal gp = (GenericPrincipal) request.getSessionInternal().getPrincipal();
redirectAccessCode(true, response, redirect_uri, client_id, state, gp); redirectAccessCode(true, response, redirect_uri, client_id, state, gp);
} } else {
else
{
UriBuilder builder = UriBuilder.fromUri("j_security_check") UriBuilder builder = UriBuilder.fromUri("j_security_check")
.queryParam("redirect_uri", redirect_uri) .queryParam("redirect_uri", redirect_uri)
.queryParam("client_id", client_id); .queryParam("client_id", client_id);
@ -468,66 +384,49 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
return true; return true;
} }
protected GenericPrincipal checkLoggedIn(Request request, HttpServletResponse response) protected GenericPrincipal checkLoggedIn(Request request, HttpServletResponse response) {
{ if (request.getPrincipal() != null) {
if (request.getPrincipal() != null)
{
return (GenericPrincipal) request.getPrincipal(); return (GenericPrincipal) request.getPrincipal();
} } else if (request.getSessionInternal() != null && request.getSessionInternal().getPrincipal() != null) {
else if (request.getSessionInternal() != null && request.getSessionInternal().getPrincipal() != null)
{
return (GenericPrincipal) request.getSessionInternal().getPrincipal(); return (GenericPrincipal) request.getSessionInternal().getPrincipal();
} }
return null; return null;
} }
protected void adminLogout(Request request, HttpServletResponse response) throws IOException protected void adminLogout(Request request, HttpServletResponse response) throws IOException {
{
log.debug("<< adminLogout"); log.debug("<< adminLogout");
GenericPrincipal gp = checkLoggedIn(request, response); GenericPrincipal gp = checkLoggedIn(request, response);
if (gp == null) if (gp == null) {
{ if (bearer(request, response, false)) {
if (bearer(request, response, false))
{
gp = (GenericPrincipal) request.getPrincipal(); gp = (GenericPrincipal) request.getPrincipal();
} } else {
else
{
response.sendError(403); response.sendError(403);
return; return;
} }
} }
if (!gp.hasRole(skeletonKeyConfig.getAdminRole())) if (!gp.hasRole(skeletonKeyConfig.getAdminRole())) {
{
response.sendError(403); response.sendError(403);
return; return;
} }
String logoutUser = request.getParameter("user"); String logoutUser = request.getParameter("user");
if (logoutUser != null) if (logoutUser != null) {
{
userSessionManagement.logout(logoutUser); userSessionManagement.logout(logoutUser);
logoutResources(logoutUser, gp.getName()); logoutResources(logoutUser, gp.getName());
} } else {
else
{
userSessionManagement.logoutAllBut(gp.getName()); userSessionManagement.logoutAllBut(gp.getName());
logoutResources(null, gp.getName()); logoutResources(null, gp.getName());
} }
String forwardTo = request.getParameter("forward"); String forwardTo = request.getParameter("forward");
if (forwardTo == null) if (forwardTo == null) {
{
response.setStatus(204); response.setStatus(204);
return; return;
} }
RequestDispatcher disp = RequestDispatcher disp =
context.getServletContext().getRequestDispatcher(forwardTo); context.getServletContext().getRequestDispatcher(forwardTo);
try try {
{
disp.forward(request.getRequest(), response); disp.forward(request.getRequest(), response);
} } catch (Throwable t) {
catch (Throwable t)
{
request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t); request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"failed to forward"); "failed to forward");
@ -537,10 +436,8 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
} }
protected void logoutCurrentUser(Request request, HttpServletResponse response) throws IOException protected void logoutCurrentUser(Request request, HttpServletResponse response) throws IOException {
{ if (request.getSessionInternal() == null || request.getSessionInternal().getPrincipal() == null) {
if (request.getSessionInternal() == null || request.getSessionInternal().getPrincipal() == null)
{
redirectToWelcomePage(request, response); redirectToWelcomePage(request, response);
return; return;
} }
@ -555,10 +452,8 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
redirectToWelcomePage(request, response); redirectToWelcomePage(request, response);
} }
protected void logoutResources(String username, String admin) protected void logoutResources(String username, String admin) {
{ if (skeletonKeyConfig.getResources().size() != 0) {
if (skeletonKeyConfig.getResources().size() != 0)
{
SkeletonKeyToken token = new SkeletonKeyToken(); SkeletonKeyToken token = new SkeletonKeyToken();
token.id(generateId()); token.id(generateId());
token.principal(admin); token.principal(admin);
@ -573,12 +468,9 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
.trustStore(resourceMetadata.getTruststore()) .trustStore(resourceMetadata.getTruststore())
.keyStore(resourceMetadata.getClientKeystore(), resourceMetadata.getClientKeyPassword()) .keyStore(resourceMetadata.getClientKeystore(), resourceMetadata.getClientKeyPassword())
.build(); .build();
try try {
{ for (String resource : skeletonKeyConfig.getResources()) {
for (String resource : skeletonKeyConfig.getResources()) try {
{
try
{
log.debug("logging out: " + resource); log.debug("logging out: " + resource);
WebTarget target = client.target(resource).path(Actions.J_OAUTH_REMOTE_LOGOUT); WebTarget target = client.target(resource).path(Actions.J_OAUTH_REMOTE_LOGOUT);
if (username != null) target = target.queryParam("user", username); if (username != null) target = target.queryParam("user", username);
@ -587,38 +479,29 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
.put(null); .put(null);
if (response.getStatus() != 204) log.error("Failed to log out"); if (response.getStatus() != 204) log.error("Failed to log out");
response.close(); response.close();
} } catch (Exception ignored) {
catch (Exception ignored)
{
log.error("Failed to log out", ignored); log.error("Failed to log out", ignored);
} }
} }
} } finally {
finally
{
client.close(); client.close();
} }
} }
} }
protected void redirectToWelcomePage(Request request, HttpServletResponse response) throws IOException protected void redirectToWelcomePage(Request request, HttpServletResponse response) throws IOException {
{
ResteasyUriInfo uriInfo = ServletUtil.extractUriInfo(request, null); ResteasyUriInfo uriInfo = ServletUtil.extractUriInfo(request, null);
String[] welcomes = context.findWelcomeFiles(); String[] welcomes = context.findWelcomeFiles();
if (welcomes.length > 0) if (welcomes.length > 0) {
{
UriBuilder welcome = uriInfo.getBaseUriBuilder().path(welcomes[0]); UriBuilder welcome = uriInfo.getBaseUriBuilder().path(welcomes[0]);
response.sendRedirect(welcome.toTemplate()); response.sendRedirect(welcome.toTemplate());
} } else {
else
{
response.setStatus(204); response.setStatus(204);
} }
} }
protected void publishRealmInfoHtml(Request request, HttpServletResponse response) throws IOException protected void publishRealmInfoHtml(Request request, HttpServletResponse response) throws IOException {
{
ManagedResourceConfig rep = getRealmRepresentation(request); ManagedResourceConfig rep = getRealmRepresentation(request);
StringWriter writer; StringWriter writer;
String json; String json;
@ -663,8 +546,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
} }
protected ManagedResourceConfig getRealmRepresentation(Request request) protected ManagedResourceConfig getRealmRepresentation(Request request) {
{
ManagedResourceConfig rep = new ManagedResourceConfig(); ManagedResourceConfig rep = new ManagedResourceConfig();
ResteasyUriInfo uriInfo = ServletUtil.extractUriInfo(request, null); ResteasyUriInfo uriInfo = ServletUtil.extractUriInfo(request, null);
UriBuilder authUrl = uriInfo.getBaseUriBuilder().path(context.getLoginConfig().getLoginPage()); UriBuilder authUrl = uriInfo.getBaseUriBuilder().path(context.getLoginConfig().getLoginPage());
@ -677,36 +559,27 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
return rep; return rep;
} }
public boolean bearer(Request request, HttpServletResponse response, boolean propagate) throws IOException public boolean bearer(Request request, HttpServletResponse response, boolean propagate) throws IOException {
{ if (request.getHeader("Authorization") != null) {
if (request.getHeader("Authorization") != null)
{
CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, true, false); CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, true, false);
try try {
{ if (bearer.login(request, response)) {
if (bearer.login(request, response))
{
return true; return true;
} }
} } catch (LoginException e) {
catch (LoginException e)
{
} }
} }
return false; return false;
} }
@Override @Override
protected void register(Request request, HttpServletResponse response, Principal principal, String authType, String username, String password) protected void register(Request request, HttpServletResponse response, Principal principal, String authType, String username, String password) {
{
super.register(request, response, principal, authType, username, password); super.register(request, response, principal, authType, username, password);
log.debug("authenticate userSessionManage.login(): " + principal.getName()); log.debug("authenticate userSessionManage.login(): " + principal.getName());
userSessionManagement.login(request.getSessionInternal(), principal.getName()); userSessionManagement.login(request.getSessionInternal(), principal.getName());
if (!skeletonKeyConfig.isCancelPropagation()) if (!skeletonKeyConfig.isCancelPropagation()) {
{
GenericPrincipal gp = (GenericPrincipal) request.getPrincipal(); GenericPrincipal gp = (GenericPrincipal) request.getPrincipal();
if (gp != null) if (gp != null) {
{
SkeletonKeyToken token = buildToken(gp); SkeletonKeyToken token = buildToken(gp);
String stringToken = buildTokenString(realmPrivateKey, token); String stringToken = buildTokenString(realmPrivateKey, token);
SkeletonKeySession skSession = new SkeletonKeySession(stringToken, resourceMetadata); SkeletonKeySession skSession = new SkeletonKeySession(stringToken, resourceMetadata);
@ -718,20 +591,16 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
} }
@Override @Override
public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException {
{ if (bearer(request, response, true)) {
if (bearer(request, response, true))
{
return true; return true;
} }
return super.authenticate(request, response, config); return super.authenticate(request, response, config);
} }
protected void resolveAccessCode(Request request, Response response) throws IOException protected void resolveAccessCode(Request request, Response response) throws IOException {
{ if (!request.isSecure()) {
if (!request.isSecure())
{
response.sendError(400); response.sendError(400);
return; return;
} }
@ -740,16 +609,12 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
String code = request.getParameter("code"); String code = request.getParameter("code");
JWSInput input = new JWSInput(code, providers); JWSInput input = new JWSInput(code, providers);
boolean verifiedCode = false; boolean verifiedCode = false;
try try {
{
verifiedCode = RSAProvider.verify(input, realmPublicKey); verifiedCode = RSAProvider.verify(input, realmPublicKey);
} } catch (Exception ignored) {
catch (Exception ignored)
{
log.error("Failed to verify signature", ignored); log.error("Failed to verify signature", ignored);
} }
if (!verifiedCode) if (!verifiedCode) {
{
Map<String, String> res = new HashMap<String, String>(); Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant"); res.put("error", "invalid_grant");
res.put("error_description", "Unable to verify code signature"); res.put("error_description", "Unable to verify code signature");
@ -764,19 +629,16 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
String redirect = request.getParameter("redirect_uri"); String redirect = request.getParameter("redirect_uri");
GenericPrincipal gp = basicAuth(request, response); GenericPrincipal gp = basicAuth(request, response);
if (gp == null) if (gp == null) {
{
log.error("Failed to authenticate client_id"); log.error("Failed to authenticate client_id");
return; return;
} }
if (accessCode == null) if (accessCode == null) {
{
log.error("No access code: " + code); log.error("No access code: " + code);
response.sendError(400); response.sendError(400);
return; return;
} }
if (accessCode.isExpired()) if (accessCode.isExpired()) {
{
log.debug("Access code expired"); log.debug("Access code expired");
Map<String, String> res = new HashMap<String, String>(); Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant"); res.put("error", "invalid_grant");
@ -787,8 +649,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
response.getOutputStream().flush(); response.getOutputStream().flush();
return; return;
} }
if (!accessCode.getToken().isActive()) if (!accessCode.getToken().isActive()) {
{
log.debug("token not active"); log.debug("token not active");
Map<String, String> res = new HashMap<String, String>(); Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant"); res.put("error", "invalid_grant");
@ -799,8 +660,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
response.getOutputStream().flush(); response.getOutputStream().flush();
return; return;
} }
if (!gp.getName().equals(accessCode.getClient())) if (!gp.getName().equals(accessCode.getClient())) {
{
log.debug("not equal client"); log.debug("not equal client");
Map<String, String> res = new HashMap<String, String>(); Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant"); res.put("error", "invalid_grant");
@ -811,8 +671,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
response.getOutputStream().flush(); response.getOutputStream().flush();
return; return;
} }
if (!accessCode.getRedirect().equals(redirect)) if (!accessCode.getRedirect().equals(redirect)) {
{
log.debug("not equal redirect"); log.debug("not equal redirect");
Map<String, String> res = new HashMap<String, String>(); Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant"); res.put("error", "invalid_grant");
@ -823,8 +682,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
response.getOutputStream().flush(); response.getOutputStream().flush();
return; return;
} }
if (accessCode.isSso() && !gp.hasRole(skeletonKeyConfig.getLoginRole())) if (accessCode.isSso() && !gp.hasRole(skeletonKeyConfig.getLoginRole())) {
{
// we did not authenticate user on an access code request because a session was already established // we did not authenticate user on an access code request because a session was already established
// but, the client_id does not have permission to bypass this on a simple grant. We want // but, the client_id does not have permission to bypass this on a simple grant. We want
// to always ask for credentials from a simple oath request // to always ask for credentials from a simple oath request
@ -838,9 +696,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
mapWriter.writeValue(response.getOutputStream(), res); mapWriter.writeValue(response.getOutputStream(), res);
response.getOutputStream().flush(); response.getOutputStream().flush();
return; return;
} } else if (!gp.hasRole(skeletonKeyConfig.getClientRole()) && !gp.hasRole(skeletonKeyConfig.getLoginRole())) {
else if (!gp.hasRole(skeletonKeyConfig.getClientRole()) && !gp.hasRole(skeletonKeyConfig.getLoginRole()))
{
log.debug("does not have login or client role permission for access token request"); log.debug("does not have login or client role permission for access token request");
Map<String, String> res = new HashMap<String, String>(); Map<String, String> res = new HashMap<String, String>();
res.put("error", "invalid_grant"); res.put("error", "invalid_grant");
@ -855,8 +711,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
String wildcard = skeletonKeyConfig.getWildcardRole() == null ? "*" : skeletonKeyConfig.getWildcardRole(); String wildcard = skeletonKeyConfig.getWildcardRole() == null ? "*" : skeletonKeyConfig.getWildcardRole();
Set<String> codeRoles = accessCode.getToken().getRealmAccess().getRoles(); Set<String> codeRoles = accessCode.getToken().getRealmAccess().getRoles();
if (codeRoles != null && if (codeRoles != null &&
(codeRoles.contains(skeletonKeyConfig.getClientRole()) || codeRoles.contains(skeletonKeyConfig.getLoginRole()))) (codeRoles.contains(skeletonKeyConfig.getClientRole()) || codeRoles.contains(skeletonKeyConfig.getLoginRole()))) {
{
// we store roles a oauth client is granted in the user role mapping, remove those roles as we don't want those clients with those // we store roles a oauth client is granted in the user role mapping, remove those roles as we don't want those clients with those
// permissions if they are logging in. // permissions if they are logging in.
Set<String> newRoles = new HashSet<String>(); Set<String> newRoles = new HashSet<String>();
@ -871,19 +726,15 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
// Also, if the client has the "wildcard" role, then we don't need to filter out roles // Also, if the client has the "wildcard" role, then we don't need to filter out roles
if (codeRoles != null if (codeRoles != null
&& !gp.hasRole(wildcard) && !gp.hasRole(wildcard)
&& !gp.hasRole(skeletonKeyConfig.getLoginRole())) && !gp.hasRole(skeletonKeyConfig.getLoginRole())) {
{
Set<String> clientAllowed = new HashSet<String>(); Set<String> clientAllowed = new HashSet<String>();
for (String role : gp.getRoles()) for (String role : gp.getRoles()) {
{
clientAllowed.add(role); clientAllowed.add(role);
} }
Set<String> newRoles = new HashSet<String>(); Set<String> newRoles = new HashSet<String>();
newRoles.addAll(codeRoles); newRoles.addAll(codeRoles);
for (String role : newRoles) for (String role : newRoles) {
{ if (!clientAllowed.contains(role)) {
if (!clientAllowed.contains(role))
{
codeRoles.remove(role); codeRoles.remove(role);
} }
} }
@ -895,30 +746,24 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
response.getOutputStream().flush(); response.getOutputStream().flush();
} }
protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token) protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token) {
{
String encodedToken = buildTokenString(privateKey, token); String encodedToken = buildTokenString(privateKey, token);
AccessTokenResponse res = new AccessTokenResponse(); AccessTokenResponse res = new AccessTokenResponse();
res.setToken(encodedToken); res.setToken(encodedToken);
res.setTokenType("bearer"); res.setTokenType("bearer");
if (token.getExpiration() != 0) if (token.getExpiration() != 0) {
{
long time = token.getExpiration() - (System.currentTimeMillis() / 1000); long time = token.getExpiration() - (System.currentTimeMillis() / 1000);
res.setExpiresIn(time); res.setExpiresIn(time);
} }
return res; return res;
} }
protected String buildTokenString(PrivateKey privateKey, SkeletonKeyToken token) protected String buildTokenString(PrivateKey privateKey, SkeletonKeyToken token) {
{
byte[] tokenBytes = null; byte[] tokenBytes = null;
try try {
{
tokenBytes = JsonSerialization.toByteArray(token, false); tokenBytes = JsonSerialization.toByteArray(token, false);
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return new JWSBuilder() return new JWSBuilder()
@ -927,8 +772,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
} }
protected void handleOAuth(Request request, Response response) throws IOException protected void handleOAuth(Request request, Response response) throws IOException {
{
log.debug("<--- Begin oauthAuthenticate"); log.debug("<--- Begin oauthAuthenticate");
String redirect_uri = request.getParameter("redirect_uri"); String redirect_uri = request.getParameter("redirect_uri");
String client_id = request.getParameter("client_id"); String client_id = request.getParameter("client_id");
@ -936,8 +780,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
String username = request.getParameter(Constants.FORM_USERNAME); String username = request.getParameter(Constants.FORM_USERNAME);
String password = request.getParameter(Constants.FORM_PASSWORD); String password = request.getParameter(Constants.FORM_PASSWORD);
Principal principal = context.getRealm().authenticate(username, password); Principal principal = context.getRealm().authenticate(username, password);
if (principal == null) if (principal == null) {
{
UriBuilder builder = UriBuilder.fromUri(redirect_uri).queryParam("error", "unauthorized_client"); UriBuilder builder = UriBuilder.fromUri(redirect_uri).queryParam("error", "unauthorized_client");
if (state != null) builder.queryParam("state", state); if (state != null) builder.queryParam("state", state);
response.sendRedirect(builder.toTemplate()); response.sendRedirect(builder.toTemplate());
@ -951,10 +794,8 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
return; return;
} }
protected void tokenGrant(Request request, Response response) throws IOException protected void tokenGrant(Request request, Response response) throws IOException {
{ if (!request.isSecure()) {
if (!request.isSecure())
{
response.sendError(400); response.sendError(400);
return; return;
} }
@ -968,39 +809,33 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
response.getOutputStream().flush(); response.getOutputStream().flush();
} }
protected GenericPrincipal basicAuth(Request request, Response response) throws IOException protected GenericPrincipal basicAuth(Request request, Response response) throws IOException {
{
String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION); String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if (authHeader == null) if (authHeader == null) {
{
basicAuthError(response); basicAuthError(response);
return null; return null;
} }
String[] creds = BasicAuthHelper.parseHeader(authHeader); String[] creds = BasicAuthHelper.parseHeader(authHeader);
if (creds == null) if (creds == null) {
{
basicAuthError(response); basicAuthError(response);
return null; return null;
} }
String username = creds[0]; String username = creds[0];
String password = creds[1]; String password = creds[1];
GenericPrincipal gp = (GenericPrincipal) context.getRealm().authenticate(username, password); GenericPrincipal gp = (GenericPrincipal) context.getRealm().authenticate(username, password);
if (gp == null) if (gp == null) {
{
basicAuthError(response); basicAuthError(response);
return null; return null;
} }
return gp; return gp;
} }
protected void basicAuthError(Response response) throws IOException protected void basicAuthError(Response response) throws IOException {
{
response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"" + context.getLoginConfig().getRealmName() + "\""); response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"" + context.getLoginConfig().getRealmName() + "\"");
response.sendError(401); response.sendError(401);
} }
protected void redirectAccessCode(boolean sso, Response response, String redirect_uri, String client_id, String state, GenericPrincipal gp) throws IOException protected void redirectAccessCode(boolean sso, Response response, String redirect_uri, String client_id, String state, GenericPrincipal gp) throws IOException {
{
SkeletonKeyToken token = buildToken(gp); SkeletonKeyToken token = buildToken(gp);
AccessCode code = new AccessCode(); AccessCode code = new AccessCode();
code.setToken(token); code.setToken(token);
@ -1012,12 +847,9 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
accessCodeMap.put(code.getId(), code); accessCodeMap.put(code.getId(), code);
log.debug("--- sign access code"); log.debug("--- sign access code");
String accessCode = null; String accessCode = null;
try try {
{
accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realmPrivateKey); accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realmPrivateKey);
} } catch (UnsupportedEncodingException e) {
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
log.debug("--- build redirect"); log.debug("--- build redirect");
@ -1027,20 +859,17 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
log.debug("<--- end oauthAuthenticate"); log.debug("<--- end oauthAuthenticate");
} }
protected SkeletonKeyToken buildToken(GenericPrincipal gp) protected SkeletonKeyToken buildToken(GenericPrincipal gp) {
{
SkeletonKeyToken token = new SkeletonKeyToken(); SkeletonKeyToken token = new SkeletonKeyToken();
token.id(generateId()); token.id(generateId());
token.principal(gp.getName()); token.principal(gp.getName());
token.audience(skeletonKeyConfig.getRealm()); token.audience(skeletonKeyConfig.getRealm());
int expiration = skeletonKeyConfig.getAccessCodeLifetime() == 0 ? 3600 : skeletonKeyConfig.getAccessCodeLifetime(); int expiration = skeletonKeyConfig.getAccessCodeLifetime() == 0 ? 3600 : skeletonKeyConfig.getAccessCodeLifetime();
if (skeletonKeyConfig.getTokenLifetime() > 0) if (skeletonKeyConfig.getTokenLifetime() > 0) {
{
token.expiration((System.currentTimeMillis() / 1000) + expiration); token.expiration((System.currentTimeMillis() / 1000) + expiration);
} }
SkeletonKeyToken.Access realmAccess = new SkeletonKeyToken.Access(); SkeletonKeyToken.Access realmAccess = new SkeletonKeyToken.Access();
for (String role : gp.getRoles()) for (String role : gp.getRoles()) {
{
realmAccess.addRole(role); realmAccess.addRole(role);
} }
token.setRealmAccess(realmAccess); token.setRealmAccess(realmAccess);

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,8 +42,7 @@ 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();
@ -52,179 +51,123 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
@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(); String tokenUrl = remoteSkeletonKeyConfig.getCodeUrl();
if (tokenUrl == null) if (tokenUrl == null) {
{
throw new RuntimeException("You mut specify code-url"); throw new RuntimeException("You mut specify code-url");
} }
realmConfiguration.setMetadata(resourceMetadata); realmConfiguration.setMetadata(resourceMetadata);
realmConfiguration.setClientId(client_id); 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) ResteasyClient client = managedResourceConfigLoader.getClient();
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.setClient(client);
realmConfiguration.setAuthUrl(UriBuilder.fromUri(authUrl).queryParam("client_id", client_id)); realmConfiguration.setAuthUrl(UriBuilder.fromUri(authUrl).queryParam("client_id", client_id));
realmConfiguration.setCodeUrl(client.target(tokenUrl)); realmConfiguration.setCodeUrl(client.target(tokenUrl));
} }
@Override @Override
public void invoke(Request request, Response response) throws IOException, ServletException public void invoke(Request request, Response response) throws IOException, ServletException {
{ try {
try
{
String requestURI = request.getDecodedRequestURI(); String requestURI = request.getDecodedRequestURI();
if (requestURI.endsWith("j_oauth_remote_logout")) if (requestURI.endsWith("j_oauth_remote_logout")) {
{
remoteLogout(request, response); remoteLogout(request, response);
return; return;
} }
super.invoke(request, response); super.invoke(request, response);
} } finally {
finally
{
ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession
} }
} }
@Override @Override
public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException {
{ try {
try
{
if (bearer(false, request, response)) return true; if (bearer(false, request, response)) return true;
else if (checkLoggedIn(request, response)) else if (checkLoggedIn(request, response)) {
{ if (request.getSessionInternal().getNote(Constants.FORM_REQUEST_NOTE) != null) {
if (request.getSessionInternal().getNote(Constants.FORM_REQUEST_NOTE) != null) if (restoreRequest(request, request.getSessionInternal())) {
{
if (restoreRequest(request, request.getSessionInternal()))
{
log.debug("restoreRequest"); log.debug("restoreRequest");
return (true); return (true);
} } else {
else
{
log.debug("Restore of original request failed"); log.debug("Restore of original request failed");
response.sendError(HttpServletResponse.SC_BAD_REQUEST); response.sendError(HttpServletResponse.SC_BAD_REQUEST);
return (false); return (false);
} }
} } else {
else
{
return true; 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: "); log.debug("->> remoteLogout: ");
if (!bearer(true, request, response)) if (!bearer(true, request, response)) {
{
log.debug("remoteLogout: bearer auth failed"); log.debug("remoteLogout: bearer auth failed");
return; return;
} }
GenericPrincipal gp = (GenericPrincipal) request.getPrincipal(); GenericPrincipal gp = (GenericPrincipal) request.getPrincipal();
if (!gp.hasRole(remoteSkeletonKeyConfig.getAdminRole())) if (!gp.hasRole(remoteSkeletonKeyConfig.getAdminRole())) {
{
log.debug("remoteLogout: role failure"); log.debug("remoteLogout: role failure");
response.sendError(403); response.sendError(403);
return; return;
} }
String user = request.getParameter("user"); String user = request.getParameter("user");
if (user != null) if (user != null) {
{
userSessionManagement.logout(user); userSessionManagement.logout(user);
} } else {
else
{
userSessionManagement.logoutAll(); userSessionManagement.logoutAll();
} }
} } catch (Exception e) {
catch (Exception e)
{
log.error("failed to logout", e); log.error("failed to logout", e);
} }
response.setStatus(204); response.setStatus(204);
} }
protected boolean bearer(boolean challenge, Request request, HttpServletResponse response) throws LoginException, IOException protected boolean bearer(boolean challenge, Request request, HttpServletResponse response) throws LoginException, IOException {
{
CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(realmConfiguration.getMetadata(), !remoteSkeletonKeyConfig.isCancelPropagation(), challenge); CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(realmConfiguration.getMetadata(), !remoteSkeletonKeyConfig.isCancelPropagation(), challenge);
if (bearer.login(request, response)) if (bearer.login(request, response)) {
{
return true; return true;
} }
return false; return false;
} }
protected boolean checkLoggedIn(Request request, HttpServletResponse response) protected boolean checkLoggedIn(Request request, HttpServletResponse response) {
{
if (request.getSessionInternal() == null || request.getSessionInternal().getPrincipal() == null) if (request.getSessionInternal() == null || request.getSessionInternal().getPrincipal() == null)
return false; return false;
log.debug("remote logged in already"); log.debug("remote logged in already");
@ -232,11 +175,9 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
request.setUserPrincipal(principal); request.setUserPrincipal(principal);
request.setAuthType("OAUTH"); request.setAuthType("OAUTH");
Session session = request.getSessionInternal(); Session session = request.getSessionInternal();
if (session != null && !remoteSkeletonKeyConfig.isCancelPropagation()) if (session != null && !remoteSkeletonKeyConfig.isCancelPropagation()) {
{
SkeletonKeySession skSession = (SkeletonKeySession) session.getNote(SkeletonKeySession.class.getName()); SkeletonKeySession skSession = (SkeletonKeySession) session.getNote(SkeletonKeySession.class.getName());
if (skSession != null) if (skSession != null) {
{
request.setAttribute(SkeletonKeySession.class.getName(), skSession); request.setAttribute(SkeletonKeySession.class.getName(), skSession);
ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession); ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
@ -248,38 +189,28 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
/** /**
* This method always set the HTTP response, so do not continue after invoking * This method always set the HTTP response, so do not continue after invoking
*/ */
protected void oauth(Request request, HttpServletResponse response) throws IOException protected void oauth(Request request, HttpServletResponse response) throws IOException {
{
ServletOAuthLogin oauth = new ServletOAuthLogin(realmConfiguration, request, response, request.getConnector().getRedirectPort()); ServletOAuthLogin oauth = new ServletOAuthLogin(realmConfiguration, request, response, request.getConnector().getRedirectPort());
String code = oauth.getCode(); String code = oauth.getCode();
if (code == null) if (code == null) {
{
String error = oauth.getError(); String error = oauth.getError();
if (error != null) if (error != null) {
{
response.sendError(400, "OAuth " + error); response.sendError(400, "OAuth " + error);
return; return;
} } else {
else
{
saveRequest(request, request.getSessionInternal(true)); saveRequest(request, request.getSessionInternal(true));
oauth.loginRedirect(); oauth.loginRedirect();
} }
return; return;
} } else {
else
{
if (!oauth.resolveCode(code)) return; if (!oauth.resolveCode(code)) return;
SkeletonKeyToken token = oauth.getToken(); SkeletonKeyToken token = oauth.getToken();
Set<String> roles = null; Set<String> roles = null;
if (resourceMetadata.getResourceName() != null) if (resourceMetadata.getResourceName() != null) {
{
SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName()); SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
if (access != null) roles = access.getRoles(); if (access != null) roles = access.getRoles();
} } else {
else
{
SkeletonKeyToken.Access access = token.getRealmAccess(); SkeletonKeyToken.Access access = token.getRealmAccess();
if (access != null) roles = access.getRoles(); if (access != null) roles = access.getRoles();
} }
@ -288,8 +219,7 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
Session session = request.getSessionInternal(true); Session session = request.getSessionInternal(true);
session.setPrincipal(principal); session.setPrincipal(principal);
session.setAuthType("OAUTH"); session.setAuthType("OAUTH");
if (!remoteSkeletonKeyConfig.isCancelPropagation()) if (!remoteSkeletonKeyConfig.isCancelPropagation()) {
{
SkeletonKeySession skSession = new SkeletonKeySession(oauth.getTokenString(), realmConfiguration.getMetadata()); SkeletonKeySession skSession = new SkeletonKeySession(oauth.getTokenString(), realmConfiguration.getMetadata());
session.setNote(SkeletonKeySession.class.getName(), skSession); session.setNote(SkeletonKeySession.class.getName(), skSession);
} }

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,12 +21,10 @@ 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;
@ -36,97 +34,76 @@ public class ServletOAuthLogin
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); response.sendError(code);
} } catch (IOException e) {
catch (IOException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
protected void sendRedirect(String url) protected void sendRedirect(String url) {
{ try {
try
{
response.sendRedirect(url); response.sendRedirect(url);
} } catch (IOException e) {
catch (IOException e)
{
throw new RuntimeException(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)) {
if (cookie.getName().equals(cookieName))
{
return cookie; 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('='); int eq = param.indexOf('=');
if (eq == -1) continue; if (eq == -1) continue;
String name = param.substring(0, eq); String name = param.substring(0, eq);
@ -136,18 +113,15 @@ public class ServletOAuthLogin
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);
@ -155,14 +129,11 @@ public class ServletOAuthLogin
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; int port = redirectPort;
if (port < 0) if (port < 0) {
{
// disabled? // disabled?
return null; return null;
} }
@ -180,17 +151,14 @@ public class ServletOAuthLogin
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()); sendError(Response.Status.FORBIDDEN.getStatusCode());
return; return;
} }
@ -198,12 +166,10 @@ public class ServletOAuthLogin
sendRedirect(redirect); 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;
@ -217,14 +183,12 @@ public class ServletOAuthLogin
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); sendError(400);
log.warn("state parameter invalid"); log.warn("state parameter invalid");
log.warn("cookie: " + stateCookieValue); log.warn("cookie: " + stateCookieValue);
@ -237,21 +201,19 @@ public class ServletOAuthLogin
/** /**
* 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()); sendError(Response.Status.FORBIDDEN.getStatusCode());
return false; return false;
@ -270,10 +232,8 @@ public class ServletOAuthLogin
Response res = realmInfo.getCodeUrl().request().header(HttpHeaders.AUTHORIZATION, authHeader).post(Entity.form(form)); Response res = realmInfo.getCodeUrl().request().header(HttpHeaders.AUTHORIZATION, authHeader).post(Entity.form(form));
AccessTokenResponse tokenResponse; AccessTokenResponse tokenResponse;
try try {
{ if (res.getStatus() != 200) {
if (res.getStatus() != 200)
{
log.error("failed to turn code into token"); log.error("failed to turn code into token");
sendError(Response.Status.FORBIDDEN.getStatusCode()); sendError(Response.Status.FORBIDDEN.getStatusCode());
return false; return false;
@ -281,20 +241,15 @@ public class ServletOAuthLogin
log.debug("media type: " + res.getMediaType()); log.debug("media type: " + res.getMediaType());
log.debug("Content-Type header: " + res.getHeaderString("Content-Type")); log.debug("Content-Type header: " + res.getHeaderString("Content-Type"));
tokenResponse = res.readEntity(AccessTokenResponse.class); tokenResponse = res.readEntity(AccessTokenResponse.class);
} } finally {
finally
{
res.close(); res.close();
} }
tokenString = tokenResponse.getToken(); tokenString = tokenResponse.getToken();
try try {
{
token = RSATokenVerifier.verifyToken(tokenString, realmInfo.getMetadata()); token = RSATokenVerifier.verifyToken(tokenString, realmInfo.getMetadata());
log.debug("Verification succeeded!"); log.debug("Verification succeeded!");
} } catch (VerificationException e) {
catch (VerificationException e)
{
log.error("failed verification of token"); log.error("failed verification of token");
sendError(Response.Status.FORBIDDEN.getStatusCode()); sendError(Response.Status.FORBIDDEN.getStatusCode());
return false; return false;
@ -307,8 +262,7 @@ public class ServletOAuthLogin
/** /**
* strip out unwanted query parameters and redirect so bookmarks don't retain oauth protocol bits * strip out unwanted query parameters and redirect so bookmarks don't retain oauth protocol bits
*/ */
protected String stripOauthParametersFromRedirect() protected String stripOauthParametersFromRedirect() {
{
StringBuffer buf = request.getRequestURL().append("?").append(request.getQueryString()); StringBuffer buf = request.getRequestURL().append("?").append(request.getQueryString());
UriBuilder builder = UriBuilder.fromUri(buf.toString()) UriBuilder builder = UriBuilder.fromUri(buf.toString())
.replaceQueryParam("code", null) .replaceQueryParam("code", null)

View file

@ -18,62 +18,50 @@ 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>(); final Map<String, Session> value = new HashMap<String, Session>();
map = userSessionMap.putIfAbsent(username, value); map = userSessionMap.putIfAbsent(username, value);
if (map == null) if (map == null) {
{
map = value; map = value;
} }
} }
synchronized (map) synchronized (map) {
{
map.put(session.getId(), session); map.put(session.getId(), session);
} }
session.addSessionListener(this); 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); log.debug("no session for user: " + user);
return; return;
} }
log.debug("found session for user"); log.debug("found session for user");
synchronized (map) synchronized (map) {
{ for (Session session : map.values()) {
for (Session session : map.values())
{
log.debug("invalidating session for user: " + user); log.debug("invalidating session for user: " + user);
session.setPrincipal(null); session.setPrincipal(null);
session.setAuthType(null); session.setAuthType(null);
@ -83,8 +71,7 @@ public class UserSessionManagement implements SessionListener
} }
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())))
@ -100,8 +87,7 @@ public class UserSessionManagement implements SessionListener
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,8 +9,7 @@ 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;
@ -72,208 +71,167 @@ public class AuthServerConfig
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,20 +10,18 @@ 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")
protected String realmUrl;
@JsonProperty("realm") @JsonProperty("realm")
protected String realm; protected String realm;
@JsonProperty("resource") @JsonProperty("resource")
protected String resource; protected String resource;
@JsonProperty("realm-public-key") @JsonProperty("realm-public-key")
protected String realmKey; protected String realmKey;
@JsonProperty("admin-role") @JsonProperty("admin-role")
protected String adminRole; protected String adminRole;
@JsonProperty("auth-url") @JsonProperty("auth-url")
protected String authUrl; protected String authUrl;
@JsonProperty("code-url") @JsonProperty("code-url")
@ -31,10 +29,10 @@ public class ManagedResourceConfig
@JsonProperty("allow-any-hostname") @JsonProperty("allow-any-hostname")
protected boolean allowAnyHostname; protected boolean allowAnyHostname;
@JsonProperty("disable-trust-manager")
protected boolean disableTrustManager;
@JsonProperty("truststore") @JsonProperty("truststore")
protected String truststore; protected String truststore;
@JsonProperty("truststore-password") @JsonProperty("truststore-password")
protected String truststorePassword; protected String truststorePassword;
@JsonProperty("client-id") @JsonProperty("client-id")
@ -45,169 +43,150 @@ public class ManagedResourceConfig
protected String clientKeystorePassword; protected String clientKeystorePassword;
@JsonProperty("client-key-password") @JsonProperty("client-key-password")
protected String clientKeyPassword; protected String clientKeyPassword;
@JsonProperty("client-credentials") @JsonProperty("client-credentials")
protected Map<String, String> clientCredentials = new HashMap<String, String>(); protected Map<String, String> clientCredentials = new HashMap<String, String>();
@JsonProperty("connection-pool-size") @JsonProperty("connection-pool-size")
protected int connectionPoolSize; protected int connectionPoolSize;
@JsonProperty("cancel-propagation") @JsonProperty("cancel-propagation")
protected boolean cancelPropagation; protected boolean cancelPropagation;
public String getRealmUrl() {
return realmUrl;
}
public String getRealm() public void setRealmUrl(String realmUrl) {
{ this.realmUrl = realmUrl;
}
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 getResource() public String getResource() {
{
return resource; return resource;
} }
public void setResource(String resource) public void setResource(String resource) {
{
this.resource = resource; this.resource = resource;
} }
public String getRealmKey() public String getRealmKey() {
{
return realmKey; return realmKey;
} }
public void setRealmKey(String realmKey) public void setRealmKey(String realmKey) {
{
this.realmKey = realmKey; this.realmKey = realmKey;
} }
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 boolean isAllowAnyHostname() public boolean isAllowAnyHostname() {
{
return allowAnyHostname; return allowAnyHostname;
} }
public void setAllowAnyHostname(boolean allowAnyHostname) public void setAllowAnyHostname(boolean allowAnyHostname) {
{
this.allowAnyHostname = allowAnyHostname; this.allowAnyHostname = allowAnyHostname;
} }
public String getTruststore() public boolean isDisableTrustManager() {
{ return disableTrustManager;
}
public void setDisableTrustManager(boolean disableTrustManager) {
this.disableTrustManager = disableTrustManager;
}
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 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 Map<String, String> getClientCredentials() public Map<String, String> getClientCredentials() {
{
return clientCredentials; return clientCredentials;
} }
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 int getConnectionPoolSize() public int getConnectionPoolSize() {
{
return connectionPoolSize; return connectionPoolSize;
} }
public void setConnectionPoolSize(int connectionPoolSize) public void setConnectionPoolSize(int connectionPoolSize) {
{
this.connectionPoolSize = connectionPoolSize; this.connectionPoolSize = connectionPoolSize;
} }
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 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;
} }
} }

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,107 +22,140 @@ 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("skeleton.key.config.file"); String path = context.getServletContext().getInitParameter("keycloak.config.file");
if (path == null) if (path == null) {
{
is = context.getServletContext().getResourceAsStream("/WEB-INF/resteasy-oauth.json"); is = context.getServletContext().getResourceAsStream("/WEB-INF/resteasy-oauth.json");
} } else {
else try {
{
try
{
is = new FileInputStream(path); is = new FileInputStream(path);
} } catch (FileNotFoundException e) {
catch (FileNotFoundException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
remoteSkeletonKeyConfig = null; remoteSkeletonKeyConfig = null;
try try {
{
remoteSkeletonKeyConfig = mapper.readValue(is, ManagedResourceConfig.class); remoteSkeletonKeyConfig = mapper.readValue(is, ManagedResourceConfig.class);
} } catch (IOException e) {
catch (IOException e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
}
public void init(boolean setupClient) {
String truststorePath = remoteSkeletonKeyConfig.getTruststore();
if (truststorePath != null) {
truststorePath = EnvUtil.replace(truststorePath);
String truststorePassword = remoteSkeletonKeyConfig.getTruststorePassword();
truststorePath = null;
try {
this.truststore = loadKeyStore(truststorePath, truststorePassword);
} catch (Exception e) {
throw new RuntimeException("Failed to load truststore", e);
}
}
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);
}
}
initClient();
String name = remoteSkeletonKeyConfig.getResource();
String realm = remoteSkeletonKeyConfig.getRealm(); String realm = remoteSkeletonKeyConfig.getRealm();
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"); if (realm == null) throw new RuntimeException("Must set 'realm' in config");
String realmKeyPem = remoteSkeletonKeyConfig.getRealmKey(); String realmKeyPem = remoteSkeletonKeyConfig.getRealmKey();
if (realmKeyPem == null) if (realmKeyPem == null) {
{
throw new IllegalArgumentException("You must set the realm-public-key"); throw new IllegalArgumentException("You must set the realm-public-key");
} }
PublicKey realmKey = null; PublicKey realmKey = null;
try try {
{
realmKey = PemUtils.decodePublicKey(realmKeyPem); realmKey = PemUtils.decodePublicKey(realmKeyPem);
} } catch (Exception e) {
catch (Exception e)
{
throw new RuntimeException(e); throw new RuntimeException(e);
} }
resourceMetadata = new ResourceMetadata(); resourceMetadata = new ResourceMetadata();
resourceMetadata.setRealm(realm); resourceMetadata.setRealm(realm);
resourceMetadata.setResourceName(name); resourceMetadata.setResourceName(resource);
resourceMetadata.setRealmKey(realmKey); resourceMetadata.setRealmKey(realmKey);
resourceMetadata.setClientKeystore(clientCertKeystore);
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(); clientKeyPassword = remoteSkeletonKeyConfig.getClientKeyPassword();
resourceMetadata.setClientKeyPassword(clientKeyPassword); resourceMetadata.setClientKeyPassword(clientKeyPassword);
} resourceMetadata.setTruststore(this.truststore);
} }
public static KeyStore loadKeyStore(String filename, String password) throws Exception
{ 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 KeyStore trustStore = KeyStore.getInstance(KeyStore
.getDefaultType()); .getDefaultType());
File truststoreFile = new File(filename); File truststoreFile = new File(filename);
@ -126,14 +165,23 @@ public class ManagedResourceConfigLoader
return trustStore; return trustStore;
} }
public ManagedResourceConfig getRemoteSkeletonKeyConfig() public ManagedResourceConfig getRemoteSkeletonKeyConfig() {
{
return remoteSkeletonKeyConfig; return remoteSkeletonKeyConfig;
} }
public ResourceMetadata getResourceMetadata() public ResourceMetadata getResourceMetadata() {
{
return resourceMetadata; 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;
} }