commit
bc3961af56
48 changed files with 912 additions and 107 deletions
|
@ -192,6 +192,19 @@ module.factory('ApplicationCredentials', function($resource) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
module.factory('ApplicationOrigins', function($resource) {
|
||||||
|
return $resource('/auth-server/rest/saas/admin/realms/:realm/applications/:application/allowed-origins', {
|
||||||
|
realm : '@realm',
|
||||||
|
application : '@application'
|
||||||
|
}, {
|
||||||
|
update : {
|
||||||
|
method : 'PUT',
|
||||||
|
isArray : true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.factory('Current', function($resource) {
|
module.factory('Current', function($resource) {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package org.keycloak;
|
package org.keycloak;
|
||||||
|
|
||||||
|
import org.keycloak.representations.SkeletonKeyToken;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,21 +9,27 @@ import java.io.Serializable;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class SkeletonKeySession implements Serializable {
|
public class SkeletonKeySession implements Serializable {
|
||||||
protected String token;
|
protected String tokenString;
|
||||||
|
protected SkeletonKeyToken token;
|
||||||
protected transient ResourceMetadata metadata;
|
protected transient ResourceMetadata metadata;
|
||||||
|
|
||||||
public SkeletonKeySession() {
|
public SkeletonKeySession() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SkeletonKeySession(String token, ResourceMetadata metadata) {
|
public SkeletonKeySession(String tokenString, SkeletonKeyToken token, ResourceMetadata metadata) {
|
||||||
|
this.tokenString = tokenString;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getToken() {
|
public SkeletonKeyToken getToken() {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTokenString() {
|
||||||
|
return tokenString;
|
||||||
|
}
|
||||||
|
|
||||||
public ResourceMetadata getMetadata() {
|
public ResourceMetadata getMetadata() {
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ public class JaxrsBearerTokenFilter implements ContainerRequestFilter {
|
||||||
|
|
||||||
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, token, resourceMetadata);
|
||||||
ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
|
ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
|
||||||
String callerPrincipal = securityContext.getUserPrincipal() != null ? securityContext.getUserPrincipal().getName() : null;
|
String callerPrincipal = securityContext.getUserPrincipal() != null ? securityContext.getUserPrincipal().getName() : null;
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,7 @@ import org.codehaus.jackson.annotate.JsonIgnore;
|
||||||
import org.codehaus.jackson.annotate.JsonProperty;
|
import org.codehaus.jackson.annotate.JsonProperty;
|
||||||
import org.jboss.resteasy.jwt.JsonWebToken;
|
import org.jboss.resteasy.jwt.JsonWebToken;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -57,6 +54,8 @@ public class SkeletonKeyToken extends JsonWebToken {
|
||||||
@JsonProperty("trusted-certs")
|
@JsonProperty("trusted-certs")
|
||||||
protected Set<String> trustedCertificates;
|
protected Set<String> trustedCertificates;
|
||||||
|
|
||||||
|
@JsonProperty("allowed-origins")
|
||||||
|
protected Set<String> allowedOrigins;
|
||||||
|
|
||||||
@JsonProperty("realm_access")
|
@JsonProperty("realm_access")
|
||||||
protected Access realmAccess;
|
protected Access realmAccess;
|
||||||
|
@ -144,6 +143,14 @@ public class SkeletonKeyToken extends JsonWebToken {
|
||||||
return (SkeletonKeyToken) super.type(type);
|
return (SkeletonKeyToken) super.type(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getAllowedOrigins() {
|
||||||
|
return allowedOrigins;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowedOrigins(Set<String> allowedOrigins) {
|
||||||
|
this.allowedOrigins = allowedOrigins;
|
||||||
|
}
|
||||||
|
|
||||||
public Access getRealmAccess() {
|
public Access getRealmAccess() {
|
||||||
return realmAccess;
|
return realmAccess;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ public class CustomerDatabaseClient
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Response response = client.target("http://localhost:8080/database/customers").request()
|
Response response = client.target("http://localhost:8080/database/customers").request()
|
||||||
.header(HttpHeaders.AUTHORIZATION, "Bearer " + session.getToken()).get();
|
.header(HttpHeaders.AUTHORIZATION, "Bearer " + session.getTokenString()).get();
|
||||||
return response.readEntity(new GenericType<List<String>>(){});
|
return response.readEntity(new GenericType<List<String>>(){});
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||||
"auth-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/login",
|
"auth-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/login",
|
||||||
"code-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes",
|
"code-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes",
|
||||||
"ssl-not-required" : true,
|
"ssl-not-required" : true,
|
||||||
|
"expose-token" : true,
|
||||||
"credentials" : {
|
"credentials" : {
|
||||||
"password" : "password"
|
"password" : "password"
|
||||||
}
|
}
|
||||||
|
|
38
examples/as7-eap-demo/customer-app/src/main/webapp/customers/cors-test.html
Executable file
38
examples/as7-eap-demo/customer-app/src/main/webapp/customers/cors-test.html
Executable file
|
@ -0,0 +1,38 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
console.log('here!!!!!');
|
||||||
|
var xhr1 = new XMLHttpRequest();
|
||||||
|
xhr1.open('GET', '/customer-portal/K_QUERY_BEARER_TOKEN');
|
||||||
|
xhr1.onreadystatechange = function () {
|
||||||
|
console.log('got here');
|
||||||
|
if (this.status == 200 && this.readyState == 4) {
|
||||||
|
var token = this.responseText;
|
||||||
|
console.log('Access token: ' + token);
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', 'http://localhost:8080/database/customers');
|
||||||
|
xhr.withCredentials = true;
|
||||||
|
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
|
||||||
|
xhr.onreadystatechange = function () {
|
||||||
|
console.log('got auth success');
|
||||||
|
if (this.status == 200 && this.readyState == 4) {
|
||||||
|
console.log('db response: ' + this.responseText);
|
||||||
|
} else if (this.status != 200) {
|
||||||
|
console.log('there was an error:' + this.status);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.send();
|
||||||
|
} else if (this.status != 200) {
|
||||||
|
console.log('there was an error on get bearer token:' + this.status);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr1.send();
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,5 +1,7 @@
|
||||||
{
|
{
|
||||||
"realm" : "demo",
|
"realm" : "demo",
|
||||||
"resource" : "database-service",
|
"resource" : "database-service",
|
||||||
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB"
|
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||||
|
"enable-cors" : true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
73
examples/as7-eap-dev/customer-app/pom.xml
Executable file
73
examples/as7-eap-dev/customer-app/pom.xml
Executable file
|
@ -0,0 +1,73 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-parent</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.0-alpha-1</version>
|
||||||
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.keycloak.example.as7.demo</groupId>
|
||||||
|
<artifactId>customer-portal-example</artifactId>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
<name>Customer Portal - Secured via Valve</name>
|
||||||
|
<description/>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>jboss</id>
|
||||||
|
<name>jboss repo</name>
|
||||||
|
<url>http://repository.jboss.org/nexus/content/groups/public/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.spec.javax.servlet</groupId>
|
||||||
|
<artifactId>jboss-servlet-api_3.0_spec</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
|
<artifactId>resteasy-client</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-as7-adapter</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>customer-portal</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jboss.as.plugins</groupId>
|
||||||
|
<artifactId>jboss-as-maven-plugin</artifactId>
|
||||||
|
<version>7.4.Final</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>1.6</source>
|
||||||
|
<target>1.6</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<jboss-deployment-structure>
|
||||||
|
<deployment>
|
||||||
|
<!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
|
||||||
|
<dependencies>
|
||||||
|
<module name="org.bouncycastle"/>
|
||||||
|
<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" />
|
||||||
|
</dependencies>
|
||||||
|
</deployment>
|
||||||
|
</jboss-deployment-structure>
|
5
examples/as7-eap-dev/customer-app/src/main/webapp/WEB-INF/jboss-web.xml
Executable file
5
examples/as7-eap-dev/customer-app/src/main/webapp/WEB-INF/jboss-web.xml
Executable file
|
@ -0,0 +1,5 @@
|
||||||
|
<jboss-web>
|
||||||
|
<valve>
|
||||||
|
<class-name>org.keycloak.adapters.as7.OAuthManagedResourceValve</class-name>
|
||||||
|
</valve>
|
||||||
|
</jboss-web>
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"realm" : "demo",
|
||||||
|
"resource" : "customer-portal",
|
||||||
|
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||||
|
"auth-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/login",
|
||||||
|
"code-url" : "http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes",
|
||||||
|
"ssl-not-required" : true,
|
||||||
|
"expose-token" : true,
|
||||||
|
"credentials" : {
|
||||||
|
"password" : "password"
|
||||||
|
}
|
||||||
|
}
|
49
examples/as7-eap-dev/customer-app/src/main/webapp/WEB-INF/web.xml
Executable file
49
examples/as7-eap-dev/customer-app/src/main/webapp/WEB-INF/web.xml
Executable file
|
@ -0,0 +1,49 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||||
|
version="3.0">
|
||||||
|
|
||||||
|
<module-name>customer-portal</module-name>
|
||||||
|
|
||||||
|
<security-constraint>
|
||||||
|
<web-resource-collection>
|
||||||
|
<web-resource-name>Admins</web-resource-name>
|
||||||
|
<url-pattern>/admin/*</url-pattern>
|
||||||
|
</web-resource-collection>
|
||||||
|
<auth-constraint>
|
||||||
|
<role-name>admin</role-name>
|
||||||
|
</auth-constraint>
|
||||||
|
</security-constraint>
|
||||||
|
<security-constraint>
|
||||||
|
<web-resource-collection>
|
||||||
|
<web-resource-name>Customers</web-resource-name>
|
||||||
|
<url-pattern>/customers/*</url-pattern>
|
||||||
|
</web-resource-collection>
|
||||||
|
<auth-constraint>
|
||||||
|
<role-name>user</role-name>
|
||||||
|
</auth-constraint>
|
||||||
|
</security-constraint>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<security-constraint>
|
||||||
|
<web-resource-collection>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</web-resource-collection>
|
||||||
|
<user-data-constraint>
|
||||||
|
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
|
||||||
|
</user-data-constraint>
|
||||||
|
</security-constraint> -->
|
||||||
|
|
||||||
|
<login-config>
|
||||||
|
<auth-method>BASIC</auth-method>
|
||||||
|
<realm-name>commerce</realm-name>
|
||||||
|
</login-config>
|
||||||
|
|
||||||
|
<security-role>
|
||||||
|
<role-name>admin</role-name>
|
||||||
|
</security-role>
|
||||||
|
<security-role>
|
||||||
|
<role-name>user</role-name>
|
||||||
|
</security-role>
|
||||||
|
</web-app>
|
|
@ -0,0 +1,11 @@
|
||||||
|
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
|
||||||
|
pageEncoding="ISO-8859-1"%>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Customer Admin Iterface</title>
|
||||||
|
</head>
|
||||||
|
<body bgcolor="#E3F6CE">
|
||||||
|
<h1>Customer Admin Interface</h1>
|
||||||
|
User <b><%=request.getUserPrincipal().getName()%></b> made this request.
|
||||||
|
</body>
|
||||||
|
</html>
|
38
examples/as7-eap-dev/customer-app/src/main/webapp/customers/cors-test.html
Executable file
38
examples/as7-eap-dev/customer-app/src/main/webapp/customers/cors-test.html
Executable file
|
@ -0,0 +1,38 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
console.log('here!!!!!');
|
||||||
|
var xhr1 = new XMLHttpRequest();
|
||||||
|
xhr1.open('GET', '/customer-portal/K_QUERY_BEARER_TOKEN');
|
||||||
|
xhr1.onreadystatechange = function () {
|
||||||
|
console.log('got here');
|
||||||
|
if (this.status == 200 && this.readyState == 4) {
|
||||||
|
var token = this.responseText;
|
||||||
|
console.log('Access token: ' + token);
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', 'http://localhost:8080/database/customers');
|
||||||
|
xhr.withCredentials = true;
|
||||||
|
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
|
||||||
|
xhr.onreadystatechange = function () {
|
||||||
|
console.log('got auth success');
|
||||||
|
if (this.status == 200 && this.readyState == 4) {
|
||||||
|
console.log('db response: ' + this.responseText);
|
||||||
|
} else if (this.status != 200) {
|
||||||
|
console.log('there was an error:' + this.status);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr.send();
|
||||||
|
} else if (this.status != 200) {
|
||||||
|
console.log('there was an error on get bearer token:' + this.status);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
xhr1.send();
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
27
examples/as7-eap-dev/customer-app/src/main/webapp/customers/view.jsp
Executable file
27
examples/as7-eap-dev/customer-app/src/main/webapp/customers/view.jsp
Executable file
|
@ -0,0 +1,27 @@
|
||||||
|
<%@ page import="javax.ws.rs.core.*" language="java" contentType="text/html; charset=ISO-8859-1"
|
||||||
|
pageEncoding="ISO-8859-1"%>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Customer View Page</title>
|
||||||
|
</head>
|
||||||
|
<body bgcolor="#E3F6CE">
|
||||||
|
<%
|
||||||
|
String logoutUri = UriBuilder.fromUri("http://localhost:8080/auth-server/rest/realms/demo/tokens/logout")
|
||||||
|
.queryParam("redirect_uri", "http://localhost:8080/customer-portal").build().toString();
|
||||||
|
%>
|
||||||
|
<p>Goto: <a href="http://localhost:8080/product-portal">products</a> | <a href="<%=logoutUri%>">logout</a></p>
|
||||||
|
User <b><%=request.getUserPrincipal().getName()%></b> made this request.
|
||||||
|
<h2>Customer Listing</h2>
|
||||||
|
<%
|
||||||
|
java.util.List<String> list = org.jboss.resteasy.example.oauth.CustomerDatabaseClient.getCustomers(request);
|
||||||
|
for (String cust : list)
|
||||||
|
{
|
||||||
|
out.print("<p>");
|
||||||
|
out.print(cust);
|
||||||
|
out.println("</p>");
|
||||||
|
|
||||||
|
}
|
||||||
|
%>
|
||||||
|
<br><br>
|
||||||
|
</body>
|
||||||
|
</html>
|
14
examples/as7-eap-dev/customer-app/src/main/webapp/index.html
Normal file
14
examples/as7-eap-dev/customer-app/src/main/webapp/index.html
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||||
|
"http://www.w3.org/TR/html4/loose.dtd">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title></title>
|
||||||
|
</head>
|
||||||
|
<body bgcolor="#E3F6CE">
|
||||||
|
<h1>Customer Portal</h1>
|
||||||
|
|
||||||
|
<p><a href="customers/view.jsp">Customer Listing</a></p>
|
||||||
|
<p><a href="admin/admin.html">Customer Admin Interface</a></p>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
62
examples/as7-eap-dev/database-service/pom.xml
Executable file
62
examples/as7-eap-dev/database-service/pom.xml
Executable file
|
@ -0,0 +1,62 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<parent>
|
||||||
|
<artifactId>keycloak-parent</artifactId>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<version>1.0-alpha-1</version>
|
||||||
|
<relativePath>../../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.keycloak.example.as7.demo</groupId>
|
||||||
|
<artifactId>database-service</artifactId>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
<name>JAX-RS Database Service Using OAuth Bearer Tokens</name>
|
||||||
|
<description/>
|
||||||
|
<url>http://maven.apache.org</url>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>jboss</id>
|
||||||
|
<name>jboss repo</name>
|
||||||
|
<url>http://repository.jboss.org/nexus/content/groups/public/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
|
<artifactId>resteasy-client</artifactId>
|
||||||
|
<scope>provided</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-core</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-as7-adapter</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>database</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jboss.as.plugins</groupId>
|
||||||
|
<artifactId>jboss-as-maven-plugin</artifactId>
|
||||||
|
<version>7.4.Final</version>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>1.6</source>
|
||||||
|
<target>1.6</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.jboss.resteasy.example.oauth;
|
||||||
|
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
@Path("customers")
|
||||||
|
public class CustomerService
|
||||||
|
{
|
||||||
|
@GET
|
||||||
|
@Produces("application/json")
|
||||||
|
public List<String> getCustomers()
|
||||||
|
{
|
||||||
|
ArrayList<String> rtn = new ArrayList<String>();
|
||||||
|
rtn.add("Bill Burke");
|
||||||
|
rtn.add("Ron Sigal");
|
||||||
|
rtn.add("Weinan Li");
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.jboss.resteasy.example.oauth;
|
||||||
|
|
||||||
|
import javax.ws.rs.ApplicationPath;
|
||||||
|
import javax.ws.rs.core.Application;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
@ApplicationPath("/")
|
||||||
|
public class DataApplication extends Application
|
||||||
|
{
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package org.jboss.resteasy.example.oauth;
|
||||||
|
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
@Path("products")
|
||||||
|
public class ProductService
|
||||||
|
{
|
||||||
|
@GET
|
||||||
|
@Produces("application/json")
|
||||||
|
public List<String> getProducts()
|
||||||
|
{
|
||||||
|
ArrayList<String> rtn = new ArrayList<String>();
|
||||||
|
rtn.add("iphone");
|
||||||
|
rtn.add("ipad");
|
||||||
|
rtn.add("ipod");
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<jboss-deployment-structure>
|
||||||
|
<deployment>
|
||||||
|
<!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
|
||||||
|
<dependencies>
|
||||||
|
<module name="org.bouncycastle"/>
|
||||||
|
<module name="org.jboss.resteasy.jose-jwt" />
|
||||||
|
</dependencies>
|
||||||
|
</deployment>
|
||||||
|
</jboss-deployment-structure>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<jboss-web>
|
||||||
|
<valve>
|
||||||
|
<class-name>org.keycloak.adapters.as7.BearerTokenAuthenticatorValve</class-name>
|
||||||
|
</valve>
|
||||||
|
</jboss-web>
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"realm" : "demo",
|
||||||
|
"resource" : "database-service",
|
||||||
|
"realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
|
||||||
|
"enable-cors" : true
|
||||||
|
|
||||||
|
}
|
29
examples/as7-eap-dev/database-service/src/main/webapp/WEB-INF/web.xml
Executable file
29
examples/as7-eap-dev/database-service/src/main/webapp/WEB-INF/web.xml
Executable file
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
|
||||||
|
version="3.0">
|
||||||
|
|
||||||
|
<module-name>database</module-name>
|
||||||
|
|
||||||
|
<security-constraint>
|
||||||
|
<web-resource-collection>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</web-resource-collection>
|
||||||
|
<!-- <user-data-constraint>
|
||||||
|
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
|
||||||
|
</user-data-constraint> -->
|
||||||
|
<auth-constraint>
|
||||||
|
<role-name>user</role-name>
|
||||||
|
</auth-constraint>
|
||||||
|
</security-constraint>
|
||||||
|
|
||||||
|
<login-config>
|
||||||
|
<auth-method>BASIC</auth-method>
|
||||||
|
<realm-name>commerce</realm-name>
|
||||||
|
</login-config>
|
||||||
|
|
||||||
|
<security-role>
|
||||||
|
<role-name>user</role-name>
|
||||||
|
</security-role>
|
||||||
|
</web-app>
|
|
@ -68,6 +68,7 @@
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"adminUrl": "http://localhost:8080/customer-portal/j_admin_request",
|
"adminUrl": "http://localhost:8080/customer-portal/j_admin_request",
|
||||||
"useRealmMappings": true,
|
"useRealmMappings": true,
|
||||||
|
"webOrigins" : [ "http://localhost1:8080"],
|
||||||
"credentials": [
|
"credentials": [
|
||||||
{
|
{
|
||||||
"type": "password",
|
"type": "password",
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
package org.keycloak.adapters.as7;
|
||||||
|
|
||||||
|
import org.apache.catalina.Container;
|
||||||
|
import org.apache.catalina.Session;
|
||||||
|
import org.apache.catalina.Valve;
|
||||||
|
import org.apache.catalina.connector.Request;
|
||||||
|
import org.apache.catalina.connector.Response;
|
||||||
|
import org.apache.catalina.valves.ValveBase;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.jboss.resteasy.spi.ResteasyProviderFactory;
|
||||||
|
import org.keycloak.SkeletonKeySession;
|
||||||
|
import org.keycloak.adapters.as7.config.ManagedResourceConfig;
|
||||||
|
import org.keycloak.representations.SkeletonKeyToken;
|
||||||
|
|
||||||
|
import javax.management.ObjectName;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre-installed actions that must be authenticated
|
||||||
|
*
|
||||||
|
* Actions include:
|
||||||
|
*
|
||||||
|
* CORS Origin Check and Response headers
|
||||||
|
* K_QUERY_BEARER_TOKEN: Get bearer token from server for Javascripts CORS requests
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class AuthenticatedActionsValve extends ValveBase {
|
||||||
|
private static final Logger log = Logger.getLogger(AuthenticatedActionsValve.class);
|
||||||
|
protected ManagedResourceConfig config;
|
||||||
|
|
||||||
|
public AuthenticatedActionsValve(ManagedResourceConfig config, Valve next, Container container, ObjectName controller) {
|
||||||
|
this.config = config;
|
||||||
|
if (next == null) throw new RuntimeException("WTF is next null?!");
|
||||||
|
setNext(next);
|
||||||
|
setContainer(container);
|
||||||
|
setController(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void invoke(Request request, Response response) throws IOException, ServletException {
|
||||||
|
log.debugv("AuthenticatedActionsValve.invoke {0}", request.getRequestURI());
|
||||||
|
SkeletonKeySession session = getSkeletonKeySession(request);
|
||||||
|
if (corsRequest(request, response, session)) return;
|
||||||
|
String requestUri = request.getRequestURI();
|
||||||
|
if (requestUri.endsWith("K_QUERY_BEARER_TOKEN")) {
|
||||||
|
queryBearerToken(request, response, session);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getNext().invoke(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkeletonKeySession getSkeletonKeySession(Request request) {
|
||||||
|
SkeletonKeySession skSession = (SkeletonKeySession)request.getAttribute(SkeletonKeySession.class.getName());
|
||||||
|
if (skSession != null) return skSession;
|
||||||
|
Session session = request.getSessionInternal();
|
||||||
|
if (session != null) {
|
||||||
|
return (SkeletonKeySession) session.getNote(SkeletonKeySession.class.getName());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void queryBearerToken(Request request, Response response, SkeletonKeySession session) throws IOException, ServletException {
|
||||||
|
log.debugv("queryBearerToken {0}",request.getRequestURI());
|
||||||
|
if (abortTokenResponse(request, response, session)) return;
|
||||||
|
response.setContentType("text/plain");
|
||||||
|
response.getOutputStream().write(session.getTokenString().getBytes());
|
||||||
|
response.getOutputStream().flush();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean abortTokenResponse(Request request, Response response, SkeletonKeySession session) throws IOException {
|
||||||
|
if (session == null) {
|
||||||
|
log.debugv("session was null, sending back 401: {0}",request.getRequestURI());
|
||||||
|
response.sendError(401);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!config.isExposeToken()) {
|
||||||
|
response.setStatus(200);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!config.isCors() && request.getHeader("Origin") != null) {
|
||||||
|
response.setStatus(200);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean corsRequest(Request request, Response response, SkeletonKeySession session) throws IOException {
|
||||||
|
if (!config.isCors()) return false;
|
||||||
|
log.debugv("CORS enabled + request.getRequestURI()");
|
||||||
|
String origin = request.getHeader("Origin");
|
||||||
|
log.debugv("Origin: {0} uri: {1}", origin, request.getRequestURI());
|
||||||
|
if (session != null && origin != null) {
|
||||||
|
SkeletonKeyToken token = session.getToken();
|
||||||
|
Set<String> allowedOrigins = token.getAllowedOrigins();
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
for (String a : allowedOrigins) log.debug(" " + a);
|
||||||
|
}
|
||||||
|
if (allowedOrigins == null || (!allowedOrigins.contains("*") && !allowedOrigins.contains(origin))) {
|
||||||
|
if (allowedOrigins == null) {
|
||||||
|
log.debugv("allowedOrigins was null in token");
|
||||||
|
}
|
||||||
|
if (!allowedOrigins.contains("*") && !allowedOrigins.contains(origin)) {
|
||||||
|
log.debugv("allowedOrigins did not contain origin");
|
||||||
|
|
||||||
|
}
|
||||||
|
response.sendError(403);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
log.debugv("returning origin: {0}", origin);
|
||||||
|
response.setHeader("Access-Control-Allow-Origin", origin);
|
||||||
|
response.setHeader("Access-Control-Allow-Credentials", "true");
|
||||||
|
} else {
|
||||||
|
log.debugv("session or origin was null: {0}", request.getRequestURI());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,11 +49,17 @@ public class BearerTokenAuthenticatorValve extends AuthenticatorBase implements
|
||||||
remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig();
|
remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig();
|
||||||
managedResourceConfigLoader.init(false);
|
managedResourceConfigLoader.init(false);
|
||||||
resourceMetadata = managedResourceConfigLoader.getResourceMetadata();
|
resourceMetadata = managedResourceConfigLoader.getResourceMetadata();
|
||||||
|
AuthenticatedActionsValve actions = new AuthenticatedActionsValve(remoteSkeletonKeyConfig, getNext(), getContainer(), getController());
|
||||||
|
setNext(actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invoke(Request request, Response response) throws IOException, ServletException {
|
public void invoke(Request request, Response response) throws IOException, ServletException {
|
||||||
try {
|
try {
|
||||||
|
log.debugv("{0} {1}", request.getMethod(), request.getRequestURI());
|
||||||
|
if (remoteSkeletonKeyConfig.isCors() && new CorsPreflightChecker(remoteSkeletonKeyConfig).checkCorsPreflight(request, response)) {
|
||||||
|
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
|
||||||
|
@ -63,7 +69,7 @@ public class BearerTokenAuthenticatorValve extends AuthenticatorBase implements
|
||||||
@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, remoteSkeletonKeyConfig.isUseResourceRoleMappings());
|
CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, true, remoteSkeletonKeyConfig.isUseResourceRoleMappings());
|
||||||
if (bearer.login(request, response)) {
|
if (bearer.login(request, response)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,13 +29,11 @@ public class CatalinaBearerTokenAuthenticator {
|
||||||
protected String tokenString;
|
protected String tokenString;
|
||||||
protected SkeletonKeyToken token;
|
protected SkeletonKeyToken token;
|
||||||
private Principal principal;
|
private Principal principal;
|
||||||
protected boolean propagateToken;
|
|
||||||
protected boolean useResourceRoleMappings;
|
protected boolean useResourceRoleMappings;
|
||||||
|
|
||||||
public CatalinaBearerTokenAuthenticator(ResourceMetadata resourceMetadata, boolean propagateToken, boolean challenge, boolean useResourceRoleMappings) {
|
public CatalinaBearerTokenAuthenticator(ResourceMetadata resourceMetadata, boolean challenge, boolean useResourceRoleMappings) {
|
||||||
this.resourceMetadata = resourceMetadata;
|
this.resourceMetadata = resourceMetadata;
|
||||||
this.challenge = challenge;
|
this.challenge = challenge;
|
||||||
this.propagateToken = propagateToken;
|
|
||||||
this.useResourceRoleMappings = useResourceRoleMappings;
|
this.useResourceRoleMappings = useResourceRoleMappings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,11 +107,9 @@ 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) {
|
SkeletonKeySession skSession = new SkeletonKeySession(tokenString, token, 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package org.keycloak.adapters.as7;
|
||||||
|
|
||||||
|
import org.apache.catalina.connector.Request;
|
||||||
|
import org.apache.catalina.connector.Response;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
|
import org.keycloak.adapters.as7.config.ManagedResourceConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class CorsPreflightChecker {
|
||||||
|
private static final Logger log = Logger.getLogger(CorsPreflightChecker.class);
|
||||||
|
protected ManagedResourceConfig config;
|
||||||
|
|
||||||
|
public CorsPreflightChecker(ManagedResourceConfig config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkCorsPreflight(Request request, Response response) {
|
||||||
|
log.debugv("checkCorsPreflight {0}", request.getRequestURI());
|
||||||
|
if (!request.getMethod().equalsIgnoreCase("OPTIONS")) {
|
||||||
|
log.debug("checkCorsPreflight: not options ");
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
if (request.getHeader("Origin") == null) {
|
||||||
|
log.debug("checkCorsPreflight: no origin header");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
log.debug("Preflight request returning");
|
||||||
|
response.setStatus(200);
|
||||||
|
String origin = request.getHeader("Origin");
|
||||||
|
response.setHeader("Access-Control-Allow-Origin", origin);
|
||||||
|
response.setHeader("Access-Control-Allow-Credentials", "true");
|
||||||
|
String requestMethods = request.getHeader("Access-Control-Request-Method");
|
||||||
|
if (requestMethods != null) {
|
||||||
|
if (config.getCorsAllowedMethods() != null) {
|
||||||
|
requestMethods = config.getCorsAllowedMethods();
|
||||||
|
}
|
||||||
|
response.setHeader("Access-Control-Allow-Methods", requestMethods);
|
||||||
|
}
|
||||||
|
String allowHeaders = request.getHeader("Access-Control-Request-Headers");
|
||||||
|
if (allowHeaders != null) {
|
||||||
|
if (config.getCorsAllowedHeaders() != null) {
|
||||||
|
allowHeaders = config.getCorsAllowedHeaders();
|
||||||
|
}
|
||||||
|
response.setHeader("Access-Control-Allow-Headers", allowHeaders);
|
||||||
|
}
|
||||||
|
if (config.getCorsMaxAge() > -1) {
|
||||||
|
response.setHeader("Access-Control-Max-Age", Integer.toString(config.getCorsMaxAge()));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -561,7 +561,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
|
||||||
|
|
||||||
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, false);
|
CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, false, false);
|
||||||
try {
|
try {
|
||||||
if (bearer.login(request, response)) {
|
if (bearer.login(request, response)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -582,7 +582,7 @@ public class OAuthAuthenticationServerValve extends FormAuthenticator implements
|
||||||
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, token, resourceMetadata);
|
||||||
request.setAttribute(SkeletonKeySession.class.getName(), skSession);
|
request.setAttribute(SkeletonKeySession.class.getName(), skSession);
|
||||||
ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
|
ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
|
||||||
request.getSessionInternal(true).setNote(SkeletonKeySession.class.getName(), skSession);
|
request.getSessionInternal(true).setNote(SkeletonKeySession.class.getName(), skSession);
|
||||||
|
|
|
@ -70,6 +70,7 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
|
||||||
managedResourceConfigLoader.init(true);
|
managedResourceConfigLoader.init(true);
|
||||||
resourceMetadata = managedResourceConfigLoader.getResourceMetadata();
|
resourceMetadata = managedResourceConfigLoader.getResourceMetadata();
|
||||||
remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig();
|
remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig();
|
||||||
|
|
||||||
realmConfiguration = new RealmConfiguration();
|
realmConfiguration = new RealmConfiguration();
|
||||||
String authUrl = remoteSkeletonKeyConfig.getAuthUrl();
|
String authUrl = remoteSkeletonKeyConfig.getAuthUrl();
|
||||||
if (authUrl == null) {
|
if (authUrl == null) {
|
||||||
|
@ -91,11 +92,16 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
|
||||||
realmConfiguration.setClient(client);
|
realmConfiguration.setClient(client);
|
||||||
realmConfiguration.setAuthUrl(UriBuilder.fromUri(authUrl).queryParam("client_id", resourceMetadata.getResourceName()));
|
realmConfiguration.setAuthUrl(UriBuilder.fromUri(authUrl).queryParam("client_id", resourceMetadata.getResourceName()));
|
||||||
realmConfiguration.setCodeUrl(client.target(tokenUrl));
|
realmConfiguration.setCodeUrl(client.target(tokenUrl));
|
||||||
|
AuthenticatedActionsValve actions = new AuthenticatedActionsValve(remoteSkeletonKeyConfig, getNext(), getContainer(), getController());
|
||||||
|
setNext(actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invoke(Request request, Response response) throws IOException, ServletException {
|
public void invoke(Request request, Response response) throws IOException, ServletException {
|
||||||
try {
|
try {
|
||||||
|
if (remoteSkeletonKeyConfig.isCors() && new CorsPreflightChecker(remoteSkeletonKeyConfig).checkCorsPreflight(request, response)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
String requestURI = request.getDecodedRequestURI();
|
String requestURI = request.getDecodedRequestURI();
|
||||||
if (requestURI.endsWith("j_admin_request")) {
|
if (requestURI.endsWith("j_admin_request")) {
|
||||||
adminRequest(request, response);
|
adminRequest(request, response);
|
||||||
|
@ -163,7 +169,7 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
|
||||||
|
|
||||||
protected void remoteLogout(JWSInput token, HttpServletResponse response) throws IOException {
|
protected void remoteLogout(JWSInput token, HttpServletResponse response) throws IOException {
|
||||||
try {
|
try {
|
||||||
log.info("->> remoteLogout: ");
|
log.debug("->> remoteLogout: ");
|
||||||
LogoutAction action = JsonSerialization.fromBytes(LogoutAction.class, token.getContent());
|
LogoutAction action = JsonSerialization.fromBytes(LogoutAction.class, token.getContent());
|
||||||
if (action.isExpired()) {
|
if (action.isExpired()) {
|
||||||
log.warn("admin request failed, expired token");
|
log.warn("admin request failed, expired token");
|
||||||
|
@ -183,10 +189,10 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
|
||||||
}
|
}
|
||||||
String user = action.getUser();
|
String user = action.getUser();
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
log.info("logout of session for: " + user);
|
log.debug("logout of session for: " + user);
|
||||||
userSessionManagement.logout(user);
|
userSessionManagement.logout(user);
|
||||||
} else {
|
} else {
|
||||||
log.info("logout of all sessions");
|
log.debug("logout of all sessions");
|
||||||
userSessionManagement.logoutAll();
|
userSessionManagement.logoutAll();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -197,7 +203,7 @@ public class OAuthManagedResourceValve extends FormAuthenticator implements Life
|
||||||
}
|
}
|
||||||
|
|
||||||
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, remoteSkeletonKeyConfig.isUseResourceRoleMappings());
|
CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(realmConfiguration.getMetadata(), challenge, remoteSkeletonKeyConfig.isUseResourceRoleMappings());
|
||||||
if (bearer.login(request, response)) {
|
if (bearer.login(request, response)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +218,7 @@ 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) {
|
||||||
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);
|
||||||
|
@ -256,10 +262,8 @@ 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()) {
|
SkeletonKeySession skSession = new SkeletonKeySession(oauth.getTokenString(), token, realmConfiguration.getMetadata());
|
||||||
SkeletonKeySession skSession = new SkeletonKeySession(oauth.getTokenString(), realmConfiguration.getMetadata());
|
session.setNote(SkeletonKeySession.class.getName(), skSession);
|
||||||
session.setNote(SkeletonKeySession.class.getName(), skSession);
|
|
||||||
}
|
|
||||||
|
|
||||||
String username = token.getPrincipal();
|
String username = token.getPrincipal();
|
||||||
log.debug("userSessionManage.login: " + username);
|
log.debug("userSessionManage.login: " + username);
|
||||||
|
|
|
@ -76,7 +76,7 @@ public class ServletOAuthLogin {
|
||||||
|
|
||||||
protected void sendRedirect(String url) {
|
protected void sendRedirect(String url) {
|
||||||
try {
|
try {
|
||||||
log.info("Sending redirect to: " + url);
|
log.debugv("Sending redirect to: {0}", url);
|
||||||
response.sendRedirect(url);
|
response.sendRedirect(url);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
@ -175,7 +175,7 @@ public class ServletOAuthLogin {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// reset the cookie
|
// reset the cookie
|
||||||
log.info("** reseting application state cookie");
|
log.debug("** reseting application state cookie");
|
||||||
Cookie reset = new Cookie(realmInfo.getStateCookieName(), "");
|
Cookie reset = new Cookie(realmInfo.getStateCookieName(), "");
|
||||||
reset.setPath(getDefaultCookiePath());
|
reset.setPath(getDefaultCookiePath());
|
||||||
reset.setMaxAge(0);
|
reset.setMaxAge(0);
|
||||||
|
@ -257,7 +257,7 @@ public class ServletOAuthLogin {
|
||||||
tokenString = tokenResponse.getToken();
|
tokenString = tokenResponse.getToken();
|
||||||
try {
|
try {
|
||||||
token = RSATokenVerifier.verifyToken(tokenString, realmInfo.getMetadata());
|
token = RSATokenVerifier.verifyToken(tokenString, realmInfo.getMetadata());
|
||||||
log.info("Token Verification succeeded!");
|
log.debug("Token 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());
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.codehaus.jackson.annotate.JsonPropertyOrder;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -49,8 +50,16 @@ public class ManagedResourceConfig {
|
||||||
protected Map<String, String> credentials = new HashMap<String, String>();
|
protected Map<String, String> credentials = new HashMap<String, String>();
|
||||||
@JsonProperty("connection-pool-size")
|
@JsonProperty("connection-pool-size")
|
||||||
protected int connectionPoolSize;
|
protected int connectionPoolSize;
|
||||||
@JsonProperty("cancel-propagation")
|
@JsonProperty("enable-cors")
|
||||||
protected boolean cancelPropagation;
|
protected boolean cors;
|
||||||
|
@JsonProperty("cors-max-age")
|
||||||
|
protected int corsMaxAge = -1;
|
||||||
|
@JsonProperty("cors-allowed-headers")
|
||||||
|
protected String corsAllowedHeaders;
|
||||||
|
@JsonProperty("cors-allowed-methods")
|
||||||
|
protected String corsAllowedMethods;
|
||||||
|
@JsonProperty("expose-token")
|
||||||
|
protected boolean exposeToken;
|
||||||
|
|
||||||
public boolean isUseResourceRoleMappings() {
|
public boolean isUseResourceRoleMappings() {
|
||||||
return useResourceRoleMappings;
|
return useResourceRoleMappings;
|
||||||
|
@ -184,14 +193,6 @@ public class ManagedResourceConfig {
|
||||||
this.connectionPoolSize = connectionPoolSize;
|
this.connectionPoolSize = connectionPoolSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCancelPropagation() {
|
|
||||||
return cancelPropagation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCancelPropagation(boolean cancelPropagation) {
|
|
||||||
this.cancelPropagation = cancelPropagation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAdminRole() {
|
public String getAdminRole() {
|
||||||
return adminRole;
|
return adminRole;
|
||||||
}
|
}
|
||||||
|
@ -199,4 +200,44 @@ public class ManagedResourceConfig {
|
||||||
public void setAdminRole(String adminRole) {
|
public void setAdminRole(String adminRole) {
|
||||||
this.adminRole = adminRole;
|
this.adminRole = adminRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isCors() {
|
||||||
|
return cors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCors(boolean cors) {
|
||||||
|
this.cors = cors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCorsMaxAge() {
|
||||||
|
return corsMaxAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCorsMaxAge(int corsMaxAge) {
|
||||||
|
this.corsMaxAge = corsMaxAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCorsAllowedHeaders() {
|
||||||
|
return corsAllowedHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCorsAllowedHeaders(String corsAllowedHeaders) {
|
||||||
|
this.corsAllowedHeaders = corsAllowedHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCorsAllowedMethods() {
|
||||||
|
return corsAllowedMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCorsAllowedMethods(String corsAllowedMethods) {
|
||||||
|
this.corsAllowedMethods = corsAllowedMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExposeToken() {
|
||||||
|
return exposeToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExposeToken(boolean exposeToken) {
|
||||||
|
this.exposeToken = exposeToken;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jboss.resteasy.logging.Logger;
|
||||||
import org.keycloak.models.*;
|
import org.keycloak.models.*;
|
||||||
import org.keycloak.representations.idm.*;
|
import org.keycloak.representations.idm.*;
|
||||||
|
|
||||||
|
@ -13,6 +14,7 @@ import org.keycloak.representations.idm.*;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class ApplicationManager {
|
public class ApplicationManager {
|
||||||
|
protected Logger logger = Logger.getLogger(ApplicationManager.class);
|
||||||
|
|
||||||
protected RealmManager realmManager;
|
protected RealmManager realmManager;
|
||||||
|
|
||||||
|
@ -21,6 +23,7 @@ public class ApplicationManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ApplicationModel createApplication(RealmModel realm, RoleModel loginRole, ApplicationRepresentation resourceRep) {
|
public ApplicationModel createApplication(RealmModel realm, RoleModel loginRole, ApplicationRepresentation resourceRep) {
|
||||||
|
logger.debug("************ CREATE APPLICATION: {0}" + resourceRep.getName());
|
||||||
ApplicationModel applicationModel = realm.addApplication(resourceRep.getName());
|
ApplicationModel applicationModel = realm.addApplication(resourceRep.getName());
|
||||||
applicationModel.setEnabled(resourceRep.isEnabled());
|
applicationModel.setEnabled(resourceRep.isEnabled());
|
||||||
applicationModel.setManagementUrl(resourceRep.getAdminUrl());
|
applicationModel.setManagementUrl(resourceRep.getAdminUrl());
|
||||||
|
@ -44,6 +47,7 @@ public class ApplicationManager {
|
||||||
}
|
}
|
||||||
if (resourceRep.getWebOrigins() != null) {
|
if (resourceRep.getWebOrigins() != null) {
|
||||||
for (String webOrigin : resourceRep.getWebOrigins()) {
|
for (String webOrigin : resourceRep.getWebOrigins()) {
|
||||||
|
logger.debug("Application: {0} webOrigin: {1}", resourceUser.getLoginName(), webOrigin);
|
||||||
resourceUser.addWebOrigin(webOrigin);
|
resourceUser.addWebOrigin(webOrigin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ public class AuthenticationManager {
|
||||||
SkeletonKeyToken identityToken = createIdentityToken(realm, user.getLoginName());
|
SkeletonKeyToken identityToken = createIdentityToken(realm, user.getLoginName());
|
||||||
String encoded = encodeToken(realm, identityToken);
|
String encoded = encodeToken(realm, identityToken);
|
||||||
boolean secureOnly = !realm.isSslNotRequired();
|
boolean secureOnly = !realm.isSslNotRequired();
|
||||||
logger.info("creatingLoginCookie - name: " + cookieName + " path: " + cookiePath);
|
logger.debug("creatingLoginCookie - name: {0} path: {1}", cookieName, cookiePath);
|
||||||
NewCookie cookie = new NewCookie(cookieName, encoded, cookiePath, null, null, NewCookie.DEFAULT_MAX_AGE, secureOnly, true);
|
NewCookie cookie = new NewCookie(cookieName, encoded, cookiePath, null, null, NewCookie.DEFAULT_MAX_AGE, secureOnly, true);
|
||||||
return cookie;
|
return cookie;
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ public class AuthenticationManager {
|
||||||
|
|
||||||
public void expireIdentityCookie(RealmModel realm, UriInfo uriInfo) {
|
public void expireIdentityCookie(RealmModel realm, UriInfo uriInfo) {
|
||||||
URI uri = RealmsResource.realmBaseUrl(uriInfo).build(realm.getId());
|
URI uri = RealmsResource.realmBaseUrl(uriInfo).build(realm.getId());
|
||||||
logger.info("Expiring identity cookie");
|
logger.debug("Expiring identity cookie");
|
||||||
String path = uri.getPath();
|
String path = uri.getPath();
|
||||||
String cookieName = KEYCLOAK_IDENTITY_COOKIE;
|
String cookieName = KEYCLOAK_IDENTITY_COOKIE;
|
||||||
expireCookie(cookieName, path);
|
expireCookie(cookieName, path);
|
||||||
|
@ -113,10 +113,10 @@ public class AuthenticationManager {
|
||||||
public void expireCookie(String cookieName, String path) {
|
public void expireCookie(String cookieName, String path) {
|
||||||
HttpResponse response = ResteasyProviderFactory.getContextData(HttpResponse.class);
|
HttpResponse response = ResteasyProviderFactory.getContextData(HttpResponse.class);
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
logger.info("can't expire identity cookie, no HttpResponse");
|
logger.debug("can't expire identity cookie, no HttpResponse");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
logger.info("Expiring cookie: " + cookieName + " path: " + path);
|
logger.debug("Expiring cookie: {0} path: {1}", cookieName, path);
|
||||||
NewCookie expireIt = new NewCookie(cookieName, "", path, null, "Expiring cookie", 0, false);
|
NewCookie expireIt = new NewCookie(cookieName, "", path, null, "Expiring cookie", 0, false);
|
||||||
response.addNewCookie(expireIt);
|
response.addNewCookie(expireIt);
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ public class AuthenticationManager {
|
||||||
protected UserModel authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String cookieName) {
|
protected UserModel authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String cookieName) {
|
||||||
Cookie cookie = headers.getCookies().get(cookieName);
|
Cookie cookie = headers.getCookies().get(cookieName);
|
||||||
if (cookie == null) {
|
if (cookie == null) {
|
||||||
logger.info("authenticateCookie could not find cookie: " + cookieName);
|
logger.debug("authenticateCookie could not find cookie: {0}", cookieName);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,19 +155,19 @@ public class AuthenticationManager {
|
||||||
try {
|
try {
|
||||||
SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getId());
|
SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getId());
|
||||||
if (!token.isActive()) {
|
if (!token.isActive()) {
|
||||||
logger.info("identity cookie expired");
|
logger.debug("identity cookie expired");
|
||||||
expireIdentityCookie(realm, uriInfo);
|
expireIdentityCookie(realm, uriInfo);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
UserModel user = realm.getUser(token.getPrincipal());
|
UserModel user = realm.getUser(token.getPrincipal());
|
||||||
if (user == null || !user.isEnabled()) {
|
if (user == null || !user.isEnabled()) {
|
||||||
logger.info("Unknown user in identity cookie");
|
logger.debug("Unknown user in identity cookie");
|
||||||
expireIdentityCookie(realm, uriInfo);
|
expireIdentityCookie(realm, uriInfo);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
} catch (VerificationException e) {
|
} catch (VerificationException e) {
|
||||||
logger.info("Failed to verify identity cookie", e);
|
logger.debug("Failed to verify identity cookie", e);
|
||||||
expireIdentityCookie(realm, uriInfo);
|
expireIdentityCookie(realm, uriInfo);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -204,12 +204,12 @@ public class AuthenticationManager {
|
||||||
|
|
||||||
public AuthenticationStatus authenticateForm(RealmModel realm, UserModel user, MultivaluedMap<String, String> formData) {
|
public AuthenticationStatus authenticateForm(RealmModel realm, UserModel user, MultivaluedMap<String, String> formData) {
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
logger.info("Not Authenticated! Incorrect user name");
|
logger.debug("Not Authenticated! Incorrect user name");
|
||||||
return AuthenticationStatus.INVALID_USER;
|
return AuthenticationStatus.INVALID_USER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user.isEnabled()) {
|
if (!user.isEnabled()) {
|
||||||
logger.info("Account is disabled, contact admin.");
|
logger.debug("Account is disabled, contact admin.");
|
||||||
return AuthenticationStatus.ACCOUNT_DISABLED;
|
return AuthenticationStatus.ACCOUNT_DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,12 +241,12 @@ public class AuthenticationManager {
|
||||||
logger.warn("TOTP token not provided");
|
logger.warn("TOTP token not provided");
|
||||||
return AuthenticationStatus.MISSING_TOTP;
|
return AuthenticationStatus.MISSING_TOTP;
|
||||||
}
|
}
|
||||||
logger.info("validating TOTP");
|
logger.debug("validating TOTP");
|
||||||
if (!realm.validateTOTP(user, password, token)) {
|
if (!realm.validateTOTP(user, password, token)) {
|
||||||
return AuthenticationStatus.INVALID_CREDENTIALS;
|
return AuthenticationStatus.INVALID_CREDENTIALS;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.info("validating password for user: " + user.getLoginName());
|
logger.debug("validating password for user: " + user.getLoginName());
|
||||||
if (!realm.validatePassword(user, password)) {
|
if (!realm.validatePassword(user, password)) {
|
||||||
return AuthenticationStatus.INVALID_CREDENTIALS;
|
return AuthenticationStatus.INVALID_CREDENTIALS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class ResourceAdminManager {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
List<ApplicationModel> resources = realm.getApplications();
|
List<ApplicationModel> resources = realm.getApplications();
|
||||||
logger.info("logging out " + resources.size() + " resoures.");
|
logger.debug("logging out {0} resources ", resources.size());
|
||||||
for (ApplicationModel resource : resources) {
|
for (ApplicationModel resource : resources) {
|
||||||
logoutResource(realm, resource, user, client);
|
logoutResource(realm, resource, user, client);
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ public class ResourceAdminManager {
|
||||||
String token = new TokenManager().encodeToken(realm, adminAction);
|
String token = new TokenManager().encodeToken(realm, adminAction);
|
||||||
Form form = new Form();
|
Form form = new Form();
|
||||||
form.param("token", token);
|
form.param("token", token);
|
||||||
logger.info("logout user: " + user + " resource: " + resource.getName() + " url" + managementUrl);
|
logger.debug("logout user: {0} resource: {1} url: {2}", user, resource.getName(), managementUrl);
|
||||||
Response response = client.target(managementUrl).queryParam("action", "logout").request().post(Entity.form(form));
|
Response response = client.target(managementUrl).queryParam("action", "logout").request().post(Entity.form(form));
|
||||||
boolean success = response.getStatus() == 204;
|
boolean success = response.getStatus() == 204;
|
||||||
response.close();
|
response.close();
|
||||||
|
|
|
@ -11,6 +11,7 @@ import org.keycloak.representations.SkeletonKeyToken;
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -88,8 +89,6 @@ public class TokenManager {
|
||||||
|
|
||||||
|
|
||||||
createToken(code, realm, client, user);
|
createToken(code, realm, client, user);
|
||||||
logger.info("tokenmanager: access code id: " + code.getId());
|
|
||||||
logger.info("accesscode setExpiration: " + (System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
|
|
||||||
code.setRealm(realm);
|
code.setRealm(realm);
|
||||||
code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
|
code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
|
||||||
code.setClient(client);
|
code.setClient(client);
|
||||||
|
@ -117,6 +116,10 @@ public class TokenManager {
|
||||||
if (realm.getTokenLifespan() > 0) {
|
if (realm.getTokenLifespan() > 0) {
|
||||||
token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
|
token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
|
||||||
}
|
}
|
||||||
|
Set<String> allowedOrigins = client.getWebOrigins();
|
||||||
|
if (allowedOrigins != null) {
|
||||||
|
token.setAllowedOrigins(allowedOrigins);
|
||||||
|
}
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,13 +142,13 @@ public class RequiredActionsService {
|
||||||
@POST
|
@POST
|
||||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||||
public Response updatePassword(final MultivaluedMap<String, String> formData) {
|
public Response updatePassword(final MultivaluedMap<String, String> formData) {
|
||||||
logger.info("updatePassword");
|
logger.debug("updatePassword");
|
||||||
AccessCodeEntry accessCode = getAccessCodeEntry(RequiredAction.UPDATE_PASSWORD);
|
AccessCodeEntry accessCode = getAccessCodeEntry(RequiredAction.UPDATE_PASSWORD);
|
||||||
if (accessCode == null) {
|
if (accessCode == null) {
|
||||||
logger.info("updatePassword access code is null");
|
logger.debug("updatePassword access code is null");
|
||||||
return forwardToErrorPage();
|
return forwardToErrorPage();
|
||||||
}
|
}
|
||||||
logger.info("updatePassword has access code");
|
logger.debug("updatePassword has access code");
|
||||||
|
|
||||||
UserModel user = getUser(accessCode);
|
UserModel user = getUser(accessCode);
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ public class RequiredActionsService {
|
||||||
|
|
||||||
realm.updateCredential(user, credentials);
|
realm.updateCredential(user, credentials);
|
||||||
|
|
||||||
logger.info("updatePassword updated credential");
|
logger.debug("updatePassword updated credential");
|
||||||
|
|
||||||
user.removeRequiredAction(RequiredAction.UPDATE_PASSWORD);
|
user.removeRequiredAction(RequiredAction.UPDATE_PASSWORD);
|
||||||
if (accessCode != null) {
|
if (accessCode != null) {
|
||||||
|
@ -269,7 +269,7 @@ public class RequiredActionsService {
|
||||||
private AccessCodeEntry getAccessCodeEntry(RequiredAction requiredAction) {
|
private AccessCodeEntry getAccessCodeEntry(RequiredAction requiredAction) {
|
||||||
String code = uriInfo.getQueryParameters().getFirst(FormFlows.CODE);
|
String code = uriInfo.getQueryParameters().getFirst(FormFlows.CODE);
|
||||||
if (code == null) {
|
if (code == null) {
|
||||||
logger.info("getAccessCodeEntry code as not in query param");
|
logger.debug("getAccessCodeEntry code as not in query param");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,31 +278,31 @@ public class RequiredActionsService {
|
||||||
try {
|
try {
|
||||||
verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
|
verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
logger.info("getAccessCodeEntry code failed verification");
|
logger.debug("getAccessCodeEntry code failed verification");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!verifiedCode) {
|
if (!verifiedCode) {
|
||||||
logger.info("getAccessCodeEntry code failed verification2");
|
logger.debug("getAccessCodeEntry code failed verification2");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String key = input.readContent(String.class);
|
String key = input.readContent(String.class);
|
||||||
AccessCodeEntry accessCodeEntry = tokenManager.getAccessCode(key);
|
AccessCodeEntry accessCodeEntry = tokenManager.getAccessCode(key);
|
||||||
if (accessCodeEntry == null) {
|
if (accessCodeEntry == null) {
|
||||||
logger.info("getAccessCodeEntry access code entry null");
|
logger.debug("getAccessCodeEntry access code entry null");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accessCodeEntry.isExpired()) {
|
if (accessCodeEntry.isExpired()) {
|
||||||
logger.info("getAccessCodeEntry: access code id: " + accessCodeEntry.getId());
|
logger.debug("getAccessCodeEntry: access code id: {0}", accessCodeEntry.getId());
|
||||||
logger.info("getAccessCodeEntry access code entry expired: " + accessCodeEntry.getExpiration());
|
logger.debug("getAccessCodeEntry access code entry expired: {0}", accessCodeEntry.getExpiration());
|
||||||
logger.info("getAccessCodeEntry current time: " + (System.currentTimeMillis() / 1000));
|
logger.debug("getAccessCodeEntry current time: {0}", (System.currentTimeMillis() / 1000));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (accessCodeEntry.getRequiredActions() == null || !accessCodeEntry.getRequiredActions().contains(requiredAction)) {
|
if (accessCodeEntry.getRequiredActions() == null || !accessCodeEntry.getRequiredActions().contains(requiredAction)) {
|
||||||
logger.info("getAccessCodeEntry required actions null || entry does not contain required action: " + (accessCodeEntry.getRequiredActions() == null) + "|" + !accessCodeEntry.getRequiredActions().contains(requiredAction) );
|
logger.debug("getAccessCodeEntry required actions null || entry does not contain required action: {0}|{1}", (accessCodeEntry.getRequiredActions() == null),!accessCodeEntry.getRequiredActions().contains(requiredAction) );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,7 +323,7 @@ public class RequiredActionsService {
|
||||||
return Flows.forms(realm, request, uriInfo).setAccessCode(accessCode).setUser(user)
|
return Flows.forms(realm, request, uriInfo).setAccessCode(accessCode).setUser(user)
|
||||||
.forwardToAction(requiredActions.iterator().next());
|
.forwardToAction(requiredActions.iterator().next());
|
||||||
} else {
|
} else {
|
||||||
logger.info("redirectOauth: redirecting to: " + accessCode.getRedirectUri());
|
logger.debug("redirectOauth: redirecting to: {0}", accessCode.getRedirectUri());
|
||||||
accessCode.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
|
accessCode.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
|
||||||
return Flows.oauth(realm, request, uriInfo, authManager, tokenManager).redirectAccessCode(accessCode,
|
return Flows.oauth(realm, request, uriInfo, authManager, tokenManager).redirectAccessCode(accessCode,
|
||||||
accessCode.getState(), accessCode.getRedirectUri());
|
accessCode.getState(), accessCode.getRedirectUri());
|
||||||
|
|
|
@ -95,6 +95,67 @@ public class SaasService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** CORS TESTING, Keep for later
|
||||||
|
|
||||||
|
@Path("ping")
|
||||||
|
@GET
|
||||||
|
@NoCache
|
||||||
|
@Produces("text/plain")
|
||||||
|
public Response ping(@Context HttpHeaders headers) {
|
||||||
|
logger.info("************** GET PING");
|
||||||
|
for (String header : headers.getRequestHeaders().keySet()) {
|
||||||
|
logger.info(" header --- " + header + ": " + headers.getHeaderString(header));
|
||||||
|
}
|
||||||
|
for (String cookieName : headers.getCookies().keySet()) {
|
||||||
|
logger.info(" cookie --- " + cookieName);
|
||||||
|
|
||||||
|
}
|
||||||
|
return Response.ok("ping", MediaType.TEXT_PLAIN_TYPE).header("Access-Control-Allow-Origin", headers.getHeaderString("Origin")).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("ping")
|
||||||
|
@DELETE
|
||||||
|
@NoCache
|
||||||
|
@Produces("text/plain")
|
||||||
|
public Response deletePing(@Context HttpHeaders headers) {
|
||||||
|
logger.info("************** DELETE PING");
|
||||||
|
for (String header : headers.getRequestHeaders().keySet()) {
|
||||||
|
logger.info(" header --- " + header + ": " + headers.getHeaderString(header));
|
||||||
|
}
|
||||||
|
for (String cookieName : headers.getCookies().keySet()) {
|
||||||
|
logger.info(" cookie --- " + cookieName);
|
||||||
|
|
||||||
|
}
|
||||||
|
return Response.ok("ping", MediaType.TEXT_PLAIN_TYPE).header("Access-Control-Allow-Origin", headers.getHeaderString("Origin")).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Path("ping")
|
||||||
|
@OPTIONS
|
||||||
|
@NoCache
|
||||||
|
@Produces("text/plain")
|
||||||
|
public Response optionsPing(@Context HttpHeaders headers) {
|
||||||
|
logger.info("************** OPTIONS PING");
|
||||||
|
for (String header : headers.getRequestHeaders().keySet()) {
|
||||||
|
logger.info(" " + header + ": " + headers.getHeaderString(header));
|
||||||
|
}
|
||||||
|
for (String cookieName : headers.getCookies().keySet()) {
|
||||||
|
logger.info(" cookie --- " + cookieName);
|
||||||
|
|
||||||
|
}
|
||||||
|
Response.ResponseBuilder ok = Response.ok();
|
||||||
|
ok
|
||||||
|
.header("Access-Control-Allow-Origin", headers.getHeaderString("Origin"));
|
||||||
|
if (headers.getHeaderString("Access-Control-Request-Method") != null) {
|
||||||
|
ok.header("Access-Control-Allow-Methods", headers.getHeaderString("Access-Control-Request-Method"));
|
||||||
|
}
|
||||||
|
return ok.header("Access-Control-Allow-Headers", HttpHeaders.AUTHORIZATION)
|
||||||
|
.header("Access-Control-Allow-Credentials", "true")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
@Path("keepalive")
|
@Path("keepalive")
|
||||||
@GET
|
@GET
|
||||||
@NoCache
|
@NoCache
|
||||||
|
@ -191,11 +252,11 @@ public class SaasService {
|
||||||
|
|
||||||
JaxrsOAuthClient oauth = new JaxrsOAuthClient();
|
JaxrsOAuthClient oauth = new JaxrsOAuthClient();
|
||||||
String authUrl = TokenService.loginPageUrl(uriInfo).build(Constants.ADMIN_REALM).toString();
|
String authUrl = TokenService.loginPageUrl(uriInfo).build(Constants.ADMIN_REALM).toString();
|
||||||
logger.info("authUrl: " + authUrl);
|
logger.debug("authUrl: {0}", authUrl);
|
||||||
oauth.setAuthUrl(authUrl);
|
oauth.setAuthUrl(authUrl);
|
||||||
oauth.setClientId(Constants.ADMIN_CONSOLE_APPLICATION);
|
oauth.setClientId(Constants.ADMIN_CONSOLE_APPLICATION);
|
||||||
URI redirectUri = uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "loginRedirect").build();
|
URI redirectUri = uriInfo.getBaseUriBuilder().path(SaasService.class).path(SaasService.class, "loginRedirect").build();
|
||||||
logger.info("redirectUri: " + redirectUri.toString());
|
logger.debug("redirectUri: {0}", redirectUri.toString());
|
||||||
oauth.setStateCookiePath(redirectUri.getPath());
|
oauth.setStateCookiePath(redirectUri.getPath());
|
||||||
return oauth.redirect(uriInfo, redirectUri.toString());
|
return oauth.redirect(uriInfo, redirectUri.toString());
|
||||||
}
|
}
|
||||||
|
@ -210,7 +271,7 @@ public class SaasService {
|
||||||
|
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
logger.info("loginRedirect ********************** <---");
|
logger.debug("loginRedirect ********************** <---");
|
||||||
if (error != null) {
|
if (error != null) {
|
||||||
logger.debug("error from oauth");
|
logger.debug("error from oauth");
|
||||||
throw new ForbiddenException("error");
|
throw new ForbiddenException("error");
|
||||||
|
@ -276,7 +337,7 @@ public class SaasService {
|
||||||
logger.debug("not allowed");
|
logger.debug("not allowed");
|
||||||
throw new ForbiddenException();
|
throw new ForbiddenException();
|
||||||
}
|
}
|
||||||
logger.info("loginRedirect SUCCESS");
|
logger.debug("loginRedirect SUCCESS");
|
||||||
NewCookie cookie = authManager.createSaasIdentityCookie(realm, accessCode.getUser(), uriInfo);
|
NewCookie cookie = authManager.createSaasIdentityCookie(realm, accessCode.getUser(), uriInfo);
|
||||||
return Response.status(302).cookie(cookie).location(contextRoot(uriInfo).path(adminPath).build()).build();
|
return Response.status(302).cookie(cookie).location(contextRoot(uriInfo).path(adminPath).build()).build();
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -308,7 +369,7 @@ public class SaasService {
|
||||||
@POST
|
@POST
|
||||||
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
|
||||||
public Response processLogin(final MultivaluedMap<String, String> formData) {
|
public Response processLogin(final MultivaluedMap<String, String> formData) {
|
||||||
logger.info("processLogin start");
|
logger.debug("processLogin start");
|
||||||
RealmManager realmManager = new RealmManager(session);
|
RealmManager realmManager = new RealmManager(session);
|
||||||
RealmModel realm = getAdminstrationRealm(realmManager);
|
RealmModel realm = getAdminstrationRealm(realmManager);
|
||||||
if (realm == null)
|
if (realm == null)
|
||||||
|
|
|
@ -192,8 +192,8 @@ public class SocialResource {
|
||||||
socialRequestManager.addRequest(requestId, reqDetailsBuilder.build());
|
socialRequestManager.addRequest(requestId, reqDetailsBuilder.build());
|
||||||
boolean secureOnly = !realm.isSslNotRequired();
|
boolean secureOnly = !realm.isSslNotRequired();
|
||||||
String cookiePath = Urls.socialBase(uriInfo.getBaseUri()).build().getPath();
|
String cookiePath = Urls.socialBase(uriInfo.getBaseUri()).build().getPath();
|
||||||
logger.info("creating cookie for social registration - name: " + SocialConstants.SOCIAL_REGISTRATION_COOKIE
|
logger.debug("creating cookie for social registration - name: {0} path: {1}", SocialConstants.SOCIAL_REGISTRATION_COOKIE,
|
||||||
+ " path: " + cookiePath);
|
cookiePath);
|
||||||
NewCookie newCookie = new NewCookie(SocialConstants.SOCIAL_REGISTRATION_COOKIE, requestId,
|
NewCookie newCookie = new NewCookie(SocialConstants.SOCIAL_REGISTRATION_COOKIE, requestId,
|
||||||
cookiePath, null, "Added social cookie", NewCookie.DEFAULT_MAX_AGE, secureOnly);
|
cookiePath, null, "Added social cookie", NewCookie.DEFAULT_MAX_AGE, secureOnly);
|
||||||
response.addNewCookie(newCookie);
|
response.addNewCookie(newCookie);
|
||||||
|
@ -303,7 +303,7 @@ public class SocialResource {
|
||||||
String cookiePath = Urls.socialBase(uriInfo.getBaseUri()).build().getPath();
|
String cookiePath = Urls.socialBase(uriInfo.getBaseUri()).build().getPath();
|
||||||
NewCookie newCookie = new NewCookie(SocialConstants.SOCIAL_REGISTRATION_COOKIE, "", cookiePath, null,
|
NewCookie newCookie = new NewCookie(SocialConstants.SOCIAL_REGISTRATION_COOKIE, "", cookiePath, null,
|
||||||
"Expire social cookie", 0, false);
|
"Expire social cookie", 0, false);
|
||||||
logger.info("Expiring social registration cookie: " + SocialConstants.SOCIAL_REGISTRATION_COOKIE + ", path: " + cookiePath);
|
logger.debug("Expiring social registration cookie: {0}, path: {1}", SocialConstants.SOCIAL_REGISTRATION_COOKIE, cookiePath);
|
||||||
response.addNewCookie(newCookie);
|
response.addNewCookie(newCookie);
|
||||||
socialRequestManager.retrieveData(requestId);
|
socialRequestManager.retrieveData(requestId);
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,7 @@ public class TokenService {
|
||||||
public Response processLogin(@QueryParam("client_id") final String clientId, @QueryParam("scope") final String scopeParam,
|
public Response processLogin(@QueryParam("client_id") final String clientId, @QueryParam("scope") final String scopeParam,
|
||||||
@QueryParam("state") final String state, @QueryParam("redirect_uri") final String redirect,
|
@QueryParam("state") final String state, @QueryParam("redirect_uri") final String redirect,
|
||||||
final MultivaluedMap<String, String> formData) {
|
final MultivaluedMap<String, String> formData) {
|
||||||
logger.info("TokenService.processLogin");
|
logger.debug("TokenService.processLogin");
|
||||||
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
|
OAuthFlows oauth = Flows.oauth(realm, request, uriInfo, authManager, tokenManager);
|
||||||
|
|
||||||
if (!realm.isEnabled()) {
|
if (!realm.isEnabled()) {
|
||||||
|
@ -228,7 +228,7 @@ public class TokenService {
|
||||||
for (RequiredCredentialModel c : realm.getRequiredCredentials()) {
|
for (RequiredCredentialModel c : realm.getRequiredCredentials()) {
|
||||||
if (c.getType().equals(CredentialRepresentation.TOTP) && !user.isTotp()) {
|
if (c.getType().equals(CredentialRepresentation.TOTP) && !user.isTotp()) {
|
||||||
user.addRequiredAction(RequiredAction.CONFIGURE_TOTP);
|
user.addRequiredAction(RequiredAction.CONFIGURE_TOTP);
|
||||||
logger.info("User is required to configure totp");
|
logger.debug("User is required to configure totp");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,7 +236,7 @@ public class TokenService {
|
||||||
private void isEmailVerificationRequired(UserModel user) {
|
private void isEmailVerificationRequired(UserModel user) {
|
||||||
if (realm.isVerifyEmail() && !user.isEmailVerified()) {
|
if (realm.isVerifyEmail() && !user.isEmailVerified()) {
|
||||||
user.addRequiredAction(RequiredAction.VERIFY_EMAIL);
|
user.addRequiredAction(RequiredAction.VERIFY_EMAIL);
|
||||||
logger.info("User is required to verify email");
|
logger.debug("User is required to verify email");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +320,7 @@ public class TokenService {
|
||||||
@POST
|
@POST
|
||||||
@Produces("application/json")
|
@Produces("application/json")
|
||||||
public Response accessCodeToToken(final MultivaluedMap<String, String> formData) {
|
public Response accessCodeToToken(final MultivaluedMap<String, String> formData) {
|
||||||
logger.info("accessRequest <---");
|
logger.debug("accessRequest <---");
|
||||||
if (!realm.isEnabled()) {
|
if (!realm.isEnabled()) {
|
||||||
throw new NotAuthorizedException("Realm not enabled");
|
throw new NotAuthorizedException("Realm not enabled");
|
||||||
}
|
}
|
||||||
|
@ -410,7 +410,7 @@ public class TokenService {
|
||||||
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
|
return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
logger.info("accessRequest SUCCESS");
|
logger.debug("accessRequest SUCCESS");
|
||||||
AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
|
AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
|
||||||
|
|
||||||
return Cors.add(request, Response.ok(res)).allowedOrigins(client.getWebOrigins()).build();
|
return Cors.add(request, Response.ok(res)).allowedOrigins(client.getWebOrigins()).build();
|
||||||
|
@ -476,7 +476,7 @@ public class TokenService {
|
||||||
|
|
||||||
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
|
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
logger.info(user.getLoginName() + " already logged in.");
|
logger.debug(user.getLoginName() + " already logged in.");
|
||||||
return oauth.processAccessCode(scopeParam, state, redirect, client, user);
|
return oauth.processAccessCode(scopeParam, state, redirect, client, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,7 +523,7 @@ public class TokenService {
|
||||||
|
|
||||||
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
|
UserModel user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
logger.info("Logging out: " + user.getLoginName());
|
logger.debug("Logging out: {0}", user.getLoginName());
|
||||||
authManager.expireIdentityCookie(realm, uriInfo);
|
authManager.expireIdentityCookie(realm, uriInfo);
|
||||||
resourceAdminManager.singleLogOut(realm, user.getLoginName());
|
resourceAdminManager.singleLogOut(realm, user.getLoginName());
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,7 @@ import javax.ws.rs.core.Context;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -54,7 +51,7 @@ public class ApplicationResource extends RoleContainerResource {
|
||||||
@PUT
|
@PUT
|
||||||
@Consumes("application/json")
|
@Consumes("application/json")
|
||||||
public void updateCredentials(List<CredentialRepresentation> credentials) {
|
public void updateCredentials(List<CredentialRepresentation> credentials) {
|
||||||
logger.info("updateCredentials");
|
logger.debug("updateCredentials");
|
||||||
if (credentials == null) return;
|
if (credentials == null) return;
|
||||||
|
|
||||||
for (CredentialRepresentation rep : credentials) {
|
for (CredentialRepresentation rep : credentials) {
|
||||||
|
@ -68,5 +65,32 @@ public class ApplicationResource extends RoleContainerResource {
|
||||||
return new ScopeMappedResource(realm, application.getApplicationUser(), session);
|
return new ScopeMappedResource(realm, application.getApplicationUser(), session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Path("allowed-origins")
|
||||||
|
@GET
|
||||||
|
@Produces("application/json")
|
||||||
|
public Set<String> getAllowedOrigins()
|
||||||
|
{
|
||||||
|
return application.getApplicationUser().getWebOrigins();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("allowed-origins")
|
||||||
|
@PUT
|
||||||
|
@Consumes("application/json")
|
||||||
|
public void updateAllowedOrigins(Set<String> allowedOrigins)
|
||||||
|
{
|
||||||
|
application.getApplicationUser().setWebOrigins(allowedOrigins);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Path("allowed-origins")
|
||||||
|
@DELETE
|
||||||
|
@Consumes("application/json")
|
||||||
|
public void deleteAllowedOrigins(Set<String> allowedOrigins)
|
||||||
|
{
|
||||||
|
for (String origin : allowedOrigins) {
|
||||||
|
application.getApplicationUser().removeWebOrigin(origin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ public class OAuthClientResource {
|
||||||
@PUT
|
@PUT
|
||||||
@Consumes("application/json")
|
@Consumes("application/json")
|
||||||
public void updateCredentials(List<CredentialRepresentation> credentials) {
|
public void updateCredentials(List<CredentialRepresentation> credentials) {
|
||||||
logger.info("updateCredentials");
|
logger.debug("updateCredentials");
|
||||||
if (credentials == null) return;
|
if (credentials == null) return;
|
||||||
|
|
||||||
for (CredentialRepresentation rep : credentials) {
|
for (CredentialRepresentation rep : credentials) {
|
||||||
|
|
|
@ -60,7 +60,7 @@ public class RealmAdminResource extends RoleContainerResource {
|
||||||
@PUT
|
@PUT
|
||||||
@Consumes("application/json")
|
@Consumes("application/json")
|
||||||
public void updateRealm(final RealmRepresentation rep) {
|
public void updateRealm(final RealmRepresentation rep) {
|
||||||
logger.info("updating realm: " + realm.getName());
|
logger.debug("updating realm: " + realm.getName());
|
||||||
new RealmManager(session).updateRealm(rep, realm);
|
new RealmManager(session).updateRealm(rep, realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class RealmsAdminResource {
|
||||||
@NoCache
|
@NoCache
|
||||||
@Produces("application/json")
|
@Produces("application/json")
|
||||||
public List<RealmRepresentation> getRealms() {
|
public List<RealmRepresentation> getRealms() {
|
||||||
logger.info(("getRealms()"));
|
logger.debug(("getRealms()"));
|
||||||
RealmManager realmManager = new RealmManager(session);
|
RealmManager realmManager = new RealmManager(session);
|
||||||
List<RealmModel> realms = session.getRealms(admin);
|
List<RealmModel> realms = session.getRealms(admin);
|
||||||
List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
|
List<RealmRepresentation> reps = new ArrayList<RealmRepresentation>();
|
||||||
|
@ -64,11 +64,11 @@ public class RealmsAdminResource {
|
||||||
@POST
|
@POST
|
||||||
@Consumes("application/json")
|
@Consumes("application/json")
|
||||||
public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) {
|
public Response importRealm(@Context final UriInfo uriInfo, final RealmRepresentation rep) {
|
||||||
logger.info("importRealm: " + rep.getRealm());
|
logger.debug("importRealm: {0}", rep.getRealm());
|
||||||
RealmManager realmManager = new RealmManager(session);
|
RealmManager realmManager = new RealmManager(session);
|
||||||
RealmModel realm = realmManager.importRealm(rep, admin);
|
RealmModel realm = realmManager.importRealm(rep, admin);
|
||||||
URI location = realmUrl(uriInfo).build(realm.getId());
|
URI location = realmUrl(uriInfo).build(realm.getId());
|
||||||
logger.info("imported realm success, sending back: " + location.toString());
|
logger.debug("imported realm success, sending back: {0}", location.toString());
|
||||||
return Response.created(location).build();
|
return Response.created(location).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -189,7 +189,7 @@ public class UsersResource {
|
||||||
@POST
|
@POST
|
||||||
@Consumes("application/json")
|
@Consumes("application/json")
|
||||||
public void addRealmRoleMappings(@PathParam("username") String username, List<RoleRepresentation> roles) {
|
public void addRealmRoleMappings(@PathParam("username") String username, List<RoleRepresentation> roles) {
|
||||||
logger.info("** addRealmRoleMappings: " + roles);
|
logger.debug("** addRealmRoleMappings: {0}", roles);
|
||||||
UserModel user = realm.getUser(username);
|
UserModel user = realm.getUser(username);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
|
@ -210,7 +210,7 @@ public class UsersResource {
|
||||||
@DELETE
|
@DELETE
|
||||||
@Consumes("application/json")
|
@Consumes("application/json")
|
||||||
public void deleteRealmRoleMappings(@PathParam("username") String username, List<RoleRepresentation> roles) {
|
public void deleteRealmRoleMappings(@PathParam("username") String username, List<RoleRepresentation> roles) {
|
||||||
logger.info("deleteRealmRoleMappings");
|
logger.debug("deleteRealmRoleMappings");
|
||||||
UserModel user = realm.getUser(username);
|
UserModel user = realm.getUser(username);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
|
@ -238,7 +238,7 @@ public class UsersResource {
|
||||||
@Produces("application/json")
|
@Produces("application/json")
|
||||||
@NoCache
|
@NoCache
|
||||||
public List<RoleRepresentation> getApplicationRoleMappings(@PathParam("username") String username, @PathParam("appId") String appId) {
|
public List<RoleRepresentation> getApplicationRoleMappings(@PathParam("username") String username, @PathParam("appId") String appId) {
|
||||||
logger.info("getApplicationRoleMappings");
|
logger.debug("getApplicationRoleMappings");
|
||||||
|
|
||||||
UserModel user = realm.getUser(username);
|
UserModel user = realm.getUser(username);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
|
@ -256,7 +256,7 @@ public class UsersResource {
|
||||||
for (RoleModel roleModel : mappings) {
|
for (RoleModel roleModel : mappings) {
|
||||||
mapRep.add(RealmManager.toRepresentation(roleModel));
|
mapRep.add(RealmManager.toRepresentation(roleModel));
|
||||||
}
|
}
|
||||||
logger.info("getApplicationRoleMappings.size() = " + mapRep.size());
|
logger.debug("getApplicationRoleMappings.size() = {0}", mapRep.size());
|
||||||
return mapRep;
|
return mapRep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,7 +264,7 @@ public class UsersResource {
|
||||||
@POST
|
@POST
|
||||||
@Consumes("application/json")
|
@Consumes("application/json")
|
||||||
public void addApplicationRoleMapping(@PathParam("username") String username, @PathParam("appId") String appId, List<RoleRepresentation> roles) {
|
public void addApplicationRoleMapping(@PathParam("username") String username, @PathParam("appId") String appId, List<RoleRepresentation> roles) {
|
||||||
logger.info("addApplicationRoleMapping");
|
logger.debug("addApplicationRoleMapping");
|
||||||
UserModel user = realm.getUser(username);
|
UserModel user = realm.getUser(username);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw new NotFoundException();
|
throw new NotFoundException();
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class OAuthFlows {
|
||||||
|
|
||||||
String code = accessCode.getCode();
|
String code = accessCode.getCode();
|
||||||
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", code);
|
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", code);
|
||||||
log.info("redirectAccessCode: state: " + state);
|
log.debug("redirectAccessCode: state: {0}", state);
|
||||||
if (state != null)
|
if (state != null)
|
||||||
redirectUri.queryParam("state", state);
|
redirectUri.queryParam("state", state);
|
||||||
Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
|
Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
|
||||||
|
@ -107,9 +107,9 @@ public class OAuthFlows {
|
||||||
return forwardToSecurityFailure("Login requester not allowed to request login.");
|
return forwardToSecurityFailure("Login requester not allowed to request login.");
|
||||||
}
|
}
|
||||||
AccessCodeEntry accessCode = tokenManager.createAccessCode(scopeParam, state, redirect, realm, client, user);
|
AccessCodeEntry accessCode = tokenManager.createAccessCode(scopeParam, state, redirect, realm, client, user);
|
||||||
log.info("processAccessCode: isResource: " + isResource);
|
log.debug("processAccessCode: isResource: {0}", isResource);
|
||||||
log.info("processAccessCode: go to oauth page?: "
|
log.debug("processAccessCode: go to oauth page?: {0}",
|
||||||
+ (!isResource && (accessCode.getRealmRolesRequested().size() > 0 || accessCode.getResourceRolesRequested()
|
(!isResource && (accessCode.getRealmRolesRequested().size() > 0 || accessCode.getResourceRolesRequested()
|
||||||
.size() > 0)));
|
.size() > 0)));
|
||||||
|
|
||||||
Set<RequiredAction> requiredActions = user.getRequiredActions();
|
Set<RequiredAction> requiredActions = user.getRequiredActions();
|
||||||
|
|
Loading…
Reference in a new issue