keycloak-uncached
Changes
examples/as7-eap-demo/third-party/pom.xml 61(+61 -0)
examples/as7-eap-demo/third-party/src/main/java/org/jboss/resteasy/example/oauth/Bootstrap.java 69(+69 -0)
examples/as7-eap-demo/third-party/src/main/java/org/jboss/resteasy/example/oauth/ProductDatabaseClient.java 69(+69 -0)
examples/pom.xml 1(+1 -0)
Details
diff --git a/core/src/main/java/org/keycloak/AbstractOAuthClient.java b/core/src/main/java/org/keycloak/AbstractOAuthClient.java
index bf40101..955f9df 100755
--- a/core/src/main/java/org/keycloak/AbstractOAuthClient.java
+++ b/core/src/main/java/org/keycloak/AbstractOAuthClient.java
@@ -28,6 +28,7 @@ public class AbstractOAuthClient {
protected String codeUrl;
protected String stateCookieName = "OAuth_Token_Request_State";
protected Client client;
+ protected boolean isSecure;
protected final AtomicLong counter = new AtomicLong();
protected String getStateCode() {
@@ -109,6 +110,8 @@ public class AbstractOAuthClient {
Form codeForm = new Form()
.param("grant_type", "authorization_code")
.param("code", code)
+ .param("client_id", clientId)
+ .param("Password", password)
.param("redirect_uri", redirectUri);
Response res = client.target(codeUrl).request().header(HttpHeaders.AUTHORIZATION, authHeader).post(Entity.form(codeForm));
try {
diff --git a/core/src/main/java/org/keycloak/servlet/ServletOAuthClient.java b/core/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
index 3ba7224..27693b4 100755
--- a/core/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
+++ b/core/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
@@ -55,7 +55,7 @@ public class ServletOAuthClient extends AbstractOAuthClient {
if (cookiePath.equals("")) cookiePath = "/";
Cookie cookie = new Cookie(stateCookieName, state);
- cookie.setSecure(true);
+ cookie.setSecure(isSecure);
cookie.setPath(cookiePath);
response.addCookie(cookie);
response.sendRedirect(url.toString());
diff --git a/examples/as7-eap-demo/server/src/main/webapp/loginForm.jsp b/examples/as7-eap-demo/server/src/main/webapp/loginForm.jsp
index b3ee74a..0e1b963 100755
--- a/examples/as7-eap-demo/server/src/main/webapp/loginForm.jsp
+++ b/examples/as7-eap-demo/server/src/main/webapp/loginForm.jsp
@@ -9,7 +9,7 @@
<head>
<meta charset="utf-8">
- <title>Keycloak</title>
+ <title>Keycloak Realm Login Page</title>
<link rel="shortcut icon" type="image/x-icon" href="<%=application.getContextPath()%>/img/favicon.ico">
diff --git a/examples/as7-eap-demo/server/src/main/webapp/META-INF/testrealm.json b/examples/as7-eap-demo/server/src/main/webapp/META-INF/testrealm.json
index dc9375a..b81aad6 100755
--- a/examples/as7-eap-demo/server/src/main/webapp/META-INF/testrealm.json
+++ b/examples/as7-eap-demo/server/src/main/webapp/META-INF/testrealm.json
@@ -25,16 +25,34 @@
{ "type" : "Password",
"value" : "password" }
]
+ },
+ {
+ "username" : "third-party",
+ "enabled" : true,
+ "credentials" : [
+ { "type" : "Password",
+ "value" : "password" }
+ ]
}
],
"roles" : [
- { "name" : "user", "description" : "User privileges" },
- { "name" : "admin", "description" : "Administrator privileges" }
+ { "name" : "user", "description" : "Have User privileges" },
+ { "name" : "admin", "description" : "Have Administrator privileges" }
],
"roleMappings" : [
{
"username" : "bburke@redhat.com",
"roles" : ["user"]
+ },
+ {
+ "username" : "third-party",
+ "roles" : ["KEYCLOAK_IDENTITY_REQUESTER"]
+ }
+ ],
+ "scopeMappings" : [
+ {
+ "username" : "third-party",
+ "roles" : ["user"]
}
],
"resources" : [
diff --git a/examples/as7-eap-demo/server/src/main/webapp/oauthGrantForm.jsp b/examples/as7-eap-demo/server/src/main/webapp/oauthGrantForm.jsp
new file mode 100755
index 0000000..07c1d7e
--- /dev/null
+++ b/examples/as7-eap-demo/server/src/main/webapp/oauthGrantForm.jsp
@@ -0,0 +1,82 @@
+<%@ page import="org.picketlink.idm.model.*,org.keycloak.services.models.*,org.keycloak.services.resources.*,javax.ws.rs.core.*,java.util.*" language="java" contentType="text/html; charset=ISO-8859-1"
+ pageEncoding="ISO-8859-1"%>
+<%
+ RealmModel realm = (RealmModel)request.getAttribute(RealmModel.class.getName());
+ String username = (String)request.getAttribute("username");
+%>
+<!doctype html>
+<html lang="en">
+
+<head>
+ <meta charset="utf-8">
+ <title>Keycloak</title>
+
+ <link rel="shortcut icon" type="image/x-icon" href="<%=application.getContextPath()%>/img/favicon.ico">
+
+ <link href="<%=application.getContextPath()%>/lib/bootstrap/css/bootstrap.css" rel="stylesheet">
+ <link href="<%=application.getContextPath()%>/lib/font-awesome/css/font-awesome.css" rel="stylesheet">
+ <link href="<%=application.getContextPath()%>/css/reset.css" rel="stylesheet">
+ <link href="<%=application.getContextPath()%>/css/base.css" rel="stylesheet">
+</head>
+
+<body>
+
+<%
+ User client = (User)request.getAttribute("client");
+ List<Role> realmRolesRequested = (List<Role>)request.getAttribute("realmRolesRequested");
+ MultivaluedMap<String, Role> resourceRolesRequested = (MultivaluedMap<String, Role>)request.getAttribute("resourceRolesRequested");
+%>
+
+ <h1>Grant request for: <%=client.getLoginName()%></h1>
+<div class="modal-body">
+
+
+ <p>This app would like to:</p>
+ <hr/>
+ <%
+ if (realmRolesRequested.size() > 0) {
+ %> <ul> <%
+ for (Role role : realmRolesRequested) {
+ String desc = "Have " + role.getName() + " privileges.";
+ Attribute roleDesc = role.getAttribute("description");
+ if (roleDesc != null) {
+ desc = (String)roleDesc.getValue();
+ }
+ %>
+ <li><%=desc%></li>
+ <%
+ }
+ %> </ul> <%
+ }
+ for (String resource : resourceRolesRequested.keySet()) {
+ List<Role> roles = resourceRolesRequested.get(resource);
+ out.println("<i>For application " + resource + ":</i> ");
+ out.println("<ul>");
+ for (Role role : roles) {
+ String desc = "Have " + role.getName() + " privileges.";
+ Attribute roleDesc = role.getAttribute("description");
+ if (roleDesc != null) {
+ desc = (String)roleDesc.getValue();
+ }
+ out.println("<li>" + desc + "</li>");
+ }
+ out.println("</ul>");
+ }
+ %>
+ <hr/>
+
+
+ <form class="form-horizontal" name="oauthGrant" action="<%=request.getAttribute("action")%>" method="POST">
+ <input type="hidden" name="code" value="<%=request.getAttribute("code")%>">
+ <div class="control-group">
+ <div class="controls">
+ <input type="submit" name="accept" class="btn btn-primary" value="Accept">
+ <input type="submit" name="cancel" class="btn btn-primary" value="Cancel">
+ </div>
+ </div>
+ </form>
+</div>
+<footer>
+ <p>Powered By Keycloak</p>
+</body>
+</html>
examples/as7-eap-demo/third-party/pom.xml 61(+61 -0)
diff --git a/examples/as7-eap-demo/third-party/pom.xml b/examples/as7-eap-demo/third-party/pom.xml
new file mode 100755
index 0000000..eedb752
--- /dev/null
+++ b/examples/as7-eap-demo/third-party/pom.xml
@@ -0,0 +1,61 @@
+<?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>oauth-client-example</artifactId>
+ <packaging>war</packaging>
+ <name>Simple OAuth Client</name>
+ <description/>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.spec.javax.servlet</groupId>
+ <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+ <version>1.0.1.Final</version>
+ <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>
+ </dependencies>
+
+ <build>
+ <finalName>oauth-client</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>
diff --git a/examples/as7-eap-demo/third-party/src/main/java/org/jboss/resteasy/example/oauth/Bootstrap.java b/examples/as7-eap-demo/third-party/src/main/java/org/jboss/resteasy/example/oauth/Bootstrap.java
new file mode 100755
index 0000000..717cd3e
--- /dev/null
+++ b/examples/as7-eap-demo/third-party/src/main/java/org/jboss/resteasy/example/oauth/Bootstrap.java
@@ -0,0 +1,69 @@
+package org.jboss.resteasy.example.oauth;
+
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import org.keycloak.servlet.ServletOAuthClient;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.KeyStore;
+
+/**
+ * Stupid init code to load up the truststore so we can make appropriate SSL connections
+ * You really should use a better way of initializing this stuff.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class Bootstrap implements ServletContextListener {
+
+ private ServletOAuthClient client;
+
+ private static KeyStore loadKeyStore(String filename, String password) throws Exception {
+ KeyStore trustStore = KeyStore.getInstance(KeyStore
+ .getDefaultType());
+ File truststoreFile = new File(filename);
+ FileInputStream trustStream = new FileInputStream(truststoreFile);
+ trustStore.load(trustStream, password.toCharArray());
+ trustStream.close();
+ return trustStore;
+ }
+
+ @Override
+ public void contextInitialized(ServletContextEvent sce) {
+ client = new ServletOAuthClient();
+/*
+ // hardcoded, WARNING, you should really have a better way of doing this
+ // configuration. Either use something like Spring or CDI, or even pull
+ // config vales from context-params
+ String truststorePath = "${jboss.server.config.dir}/client-truststore.ts";
+ String truststorePassword = "password";
+ truststorePath = EnvUtil.replace(truststorePath);
+ KeyStore truststore = null;
+ try
+ {
+ truststore = loadKeyStore(truststorePath, truststorePassword);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ client.setTruststore(truststore);
+ */
+ client.setClientId("third-party");
+ client.setPassword("password");
+ client.setAuthUrl("http://localhost:8080/auth-server/rest/realms/demo/tokens/login");
+ client.setCodeUrl("http://localhost:8080/auth-server/rest/realms/demo/tokens/access/codes");
+ client.setClient(new ResteasyClientBuilder().build());
+ client.start();
+ sce.getServletContext().setAttribute(ServletOAuthClient.class.getName(), client);
+
+
+ }
+
+ @Override
+ public void contextDestroyed(ServletContextEvent sce) {
+ client.stop();
+ }
+}
diff --git a/examples/as7-eap-demo/third-party/src/main/java/org/jboss/resteasy/example/oauth/ProductDatabaseClient.java b/examples/as7-eap-demo/third-party/src/main/java/org/jboss/resteasy/example/oauth/ProductDatabaseClient.java
new file mode 100755
index 0000000..d21c823
--- /dev/null
+++ b/examples/as7-eap-demo/third-party/src/main/java/org/jboss/resteasy/example/oauth/ProductDatabaseClient.java
@@ -0,0 +1,69 @@
+package org.jboss.resteasy.example.oauth;
+
+import org.jboss.resteasy.client.jaxrs.ResteasyClient;
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import org.keycloak.servlet.ServletOAuthClient;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ProductDatabaseClient {
+ public static void redirect(HttpServletRequest request, HttpServletResponse response) {
+ // This is really the worst code ever. The ServletOAuthClient is obtained by getting a context attribute
+ // that is set in the Bootstrap context listenr in this project.
+ // You really should come up with a better way to initialize
+ // and obtain the ServletOAuthClient. I actually suggest downloading the ServletOAuthClient code
+ // and take a look how it works.
+ ServletOAuthClient oAuthClient = (ServletOAuthClient) request.getServletContext().getAttribute(ServletOAuthClient.class.getName());
+ try {
+ oAuthClient.redirectRelative("pull_data.jsp", request, response);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static List<String> getProducts(HttpServletRequest request) {
+ // This is really the worst code ever. The ServletOAuthClient is obtained by getting a context attribute
+ // that is set in the Bootstrap context listenr in this project.
+ // You really should come up with a better way to initialize
+ // and obtain the ServletOAuthClient. I actually suggest downloading the ServletOAuthClient code
+ // and take a look how it works.
+ ServletOAuthClient oAuthClient = (ServletOAuthClient) request.getServletContext().getAttribute(ServletOAuthClient.class.getName());
+ String token = oAuthClient.getBearerToken(request);
+ ResteasyClient client = new ResteasyClientBuilder()
+ .trustStore(oAuthClient.getTruststore())
+ .hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY).build();
+ try {
+ // invoke without the Authorization header
+ Response response = client.target("http://localhost:8080/database/products").request().get();
+ response.close();
+ if (response.getStatus() != 401) {
+ response.close();
+ client.close();
+ throw new RuntimeException("Expecting an auth status code: " + response.getStatus());
+ }
+ } finally {
+ }
+ try {
+ Response response = client.target("http://localhost:8080/database/products").request()
+ .header(HttpHeaders.AUTHORIZATION, "Bearer " + token).get();
+ if (response.getStatus() != 200) {
+ response.close();
+ throw new RuntimeException("Failed to access!: " + response.getStatus());
+ }
+ return response.readEntity(new GenericType<List<String>>() {
+ });
+ } finally {
+ client.close();
+ }
+ }
+}
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/index.html b/examples/as7-eap-demo/third-party/src/main/webapp/index.html
new file mode 100644
index 0000000..dbd7d7a
--- /dev/null
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/index.html
@@ -0,0 +1,6 @@
+<html>
+<body>
+<h1>Third Party App That Pulls Data Using OAuth</h1>
+<a href="redirect.jsp">Pull Data</a>
+</body>
+</html>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/pull_data.jsp b/examples/as7-eap-demo/third-party/src/main/webapp/pull_data.jsp
new file mode 100644
index 0000000..63ad9d9
--- /dev/null
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/pull_data.jsp
@@ -0,0 +1,21 @@
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+ pageEncoding="ISO-8859-1"%>
+<html>
+<head>
+ <title>Pull Page</title>
+</head>
+<body>
+<h2>Pulled Product Listing</h2>
+<%
+java.util.List<String> list = org.jboss.resteasy.example.oauth.ProductDatabaseClient.getProducts(request);
+for (String prod : list)
+{
+ out.print("<p>");
+ out.print(prod);
+ out.println("</p>");
+
+}
+%>
+<br><br>
+</body>
+</html>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/redirect.jsp b/examples/as7-eap-demo/third-party/src/main/webapp/redirect.jsp
new file mode 100644
index 0000000..35ff870
--- /dev/null
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/redirect.jsp
@@ -0,0 +1,3 @@
+<%
+ org.jboss.resteasy.example.oauth.ProductDatabaseClient.redirect(request, response);
+%>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
new file mode 100755
index 0000000..74f5dff
--- /dev/null
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -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.jboss.resteasy.resteasy-jaxrs" services="import"/>
+ <module name="org.jboss.resteasy.resteasy-jackson-provider" services="import"/>
+ </dependencies>
+ </deployment>
+</jboss-deployment-structure>
\ No newline at end of file
diff --git a/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/web.xml b/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000..9273212
--- /dev/null
+++ b/examples/as7-eap-demo/third-party/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,20 @@
+<?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">
+ <listener>
+ <listener-class>org.jboss.resteasy.example.oauth.Bootstrap</listener-class>
+ </listener>
+ <!--
+ <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>
+ -->
+
+</web-app>
examples/pom.xml 1(+1 -0)
diff --git a/examples/pom.xml b/examples/pom.xml
index 1fb476f..73c83a9 100755
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -38,5 +38,6 @@
<module>as7-eap-demo/customer-app</module>
<module>as7-eap-demo/product-app</module>
<module>as7-eap-demo/database-service</module>
+ <module>as7-eap-demo/third-party</module>
</modules>
</project>
diff --git a/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java b/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java
index 63032d7..bbffedf 100755
--- a/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java
+++ b/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java
@@ -17,6 +17,9 @@ import java.util.UUID;
public class AccessCodeEntry {
protected String id = UUID.randomUUID().toString() + System.currentTimeMillis();
protected String code;
+ protected String state;
+ protected String redirectUri;
+
protected long expiration;
protected SkeletonKeyToken token;
protected User user;
@@ -79,4 +82,20 @@ public class AccessCodeEntry {
public MultivaluedMap<String, Role> getResourceRolesRequested() {
return resourceRolesRequested;
}
+
+ public String getState() {
+ return state;
+ }
+
+ public void setState(String state) {
+ this.state = state;
+ }
+
+ public String getRedirectUri() {
+ return redirectUri;
+ }
+
+ public void setRedirectUri(String redirectUri) {
+ this.redirectUri = redirectUri;
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index 9f5e8c8..d2a512e 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -41,7 +41,7 @@ import java.util.concurrent.atomic.AtomicLong;
public class RealmManager {
private static AtomicLong counter = new AtomicLong(1);
public static final String RESOURCE_ROLE = "KEYCLOAK_RESOURCE";
- public static final String OAUTH_CLIENT_ROLE = "KEYCLOAK_OAUTH_CLIENT";
+ public static final String IDENTITY_REQUESTER_ROLE = "KEYCLOAK_IDENTITY_REQUESTER";
public static final String WILDCARD_ROLE = "*";
public static String generateId() {
@@ -78,6 +78,7 @@ public class RealmManager {
RealmModel realm = new RealmModel(newRealm, identitySession);
idm.add(new SimpleRole(WILDCARD_ROLE));
idm.add(new SimpleRole(RESOURCE_ROLE));
+ idm.add(new SimpleRole(IDENTITY_REQUESTER_ROLE));
return realm;
}
diff --git a/services/src/main/java/org/keycloak/services/managers/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
index 1c4bb00..a50fbff 100755
--- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
@@ -54,7 +54,7 @@ public class TokenManager {
return cookie;
}
- public AccessCodeEntry createAccessCode(String scopeParam, RealmModel realm, User client, User user) {
+ public AccessCodeEntry createAccessCode(String scopeParam, String state, String redirect, RealmModel realm, User client, User user) {
AccessCodeEntry code = new AccessCodeEntry();
SkeletonKeyScope scopeMap = null;
if (scopeParam != null) scopeMap = decodeScope(scopeParam);
@@ -105,6 +105,8 @@ public class TokenManager {
code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
code.setClient(client);
code.setUser(user);
+ code.setState(state);
+ code.setRedirectUri(redirect);
accessCodeMap.put(code.getId(), code);
String accessCode = null;
try {
diff --git a/services/src/main/java/org/keycloak/services/resources/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java
index f450491..8fc87af 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -7,9 +7,7 @@ import org.jboss.resteasy.jwt.JsonSerialization;
import org.jboss.resteasy.logging.Logger;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
-import org.keycloak.TokenIdGenerator;
import org.keycloak.representations.AccessTokenResponse;
-import org.keycloak.representations.SkeletonKeyScope;
import org.keycloak.representations.SkeletonKeyToken;
import org.keycloak.services.JspRequestParameters;
import org.keycloak.services.managers.AccessCodeEntry;
@@ -18,7 +16,6 @@ import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.managers.ResourceAdminManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.models.RealmModel;
-import org.keycloak.services.models.ResourceModel;
import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.model.Role;
import org.picketlink.idm.model.User;
@@ -31,24 +28,17 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
-import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Providers;
-import java.net.URI;
import java.security.PrivateKey;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
-import java.util.Set;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -77,7 +67,7 @@ public class TokenService {
protected String securityFailurePath = "/securityFailure.jsp";
protected String loginFormPath = "/loginForm.jsp";
- protected String oauthFormPath = "/oauthForm.jsp";
+ protected String oauthFormPath = "/oauthGrantForm.jsp";
protected RealmModel realm;
protected TokenManager tokenManager;
@@ -228,17 +218,18 @@ public class TokenService {
protected Response processAccessCode(String scopeParam, String state, String redirect, User client, User user) {
Role resourceRole = realm.getIdm().getRole(RealmManager.RESOURCE_ROLE);
- Role oauthClientRole = realm.getIdm().getRole(RealmManager.OAUTH_CLIENT_ROLE);
+ Role identityRequestRole = realm.getIdm().getRole(RealmManager.IDENTITY_REQUESTER_ROLE);
boolean isResource = realm.getIdm().hasRole(client, resourceRole);
- if (!isResource && !realm.getIdm().hasRole(client, oauthClientRole)) {
+ if (!isResource && !realm.getIdm().hasRole(client, identityRequestRole)) {
securityFailureForward("Login requester not allowed to request login.");
identitySession.close();
return null;
}
- AccessCodeEntry accessCode = tokenManager.createAccessCode(scopeParam, realm, client, user);
-
- if (!isResource && accessCode.getRealmRolesRequested().size() > 0 && accessCode.getResourceRolesRequested().size() > 0) {
- oauthGrantPage(accessCode, client, state, redirect);
+ AccessCodeEntry accessCode = tokenManager.createAccessCode(scopeParam, state, redirect, realm, client, user);
+ logger.info("processAccessCode: isResource: " + isResource);
+ logger.info("processAccessCode: go to oauth page?: " + (!isResource && (accessCode.getRealmRolesRequested().size() > 0 || accessCode.getResourceRolesRequested().size() > 0)));
+ if (!isResource && (accessCode.getRealmRolesRequested().size() > 0 || accessCode.getResourceRolesRequested().size() > 0)) {
+ oauthGrantPage(accessCode, client);
identitySession.close();
return null;
}
@@ -248,6 +239,7 @@ public class TokenService {
protected Response redirectAccessCode(AccessCodeEntry accessCode, String state, String redirect) {
String code = accessCode.getCode();
UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", code);
+ logger.info("redirectAccessCode: state: " + state);
if (state != null) redirectUri.queryParam("state", state);
Response.ResponseBuilder location = Response.status(302).location(redirectUri.build());
if (realm.isCookieLoginAllowed()) {
@@ -422,10 +414,11 @@ public class TokenService {
identitySession.close();
return null;
}
+
Role resourceRole = realm.getIdm().getRole(RealmManager.RESOURCE_ROLE);
- Role oauthClientRole = realm.getIdm().getRole(RealmManager.OAUTH_CLIENT_ROLE);
+ Role identityRequestRole = realm.getIdm().getRole(RealmManager.IDENTITY_REQUESTER_ROLE);
boolean isResource = realm.getIdm().hasRole(client, resourceRole);
- if (!isResource && !realm.getIdm().hasRole(client, oauthClientRole)) {
+ if (!isResource && !realm.getIdm().hasRole(client, identityRequestRole)) {
securityFailureForward("Login requester not allowed to request login.");
identitySession.close();
return null;
@@ -433,6 +426,7 @@ public class TokenService {
User user = authManager.authenticateIdentityCookie(realm, uriInfo, headers);
if (user != null) {
+ logger.info(user.getLoginName() + " already logged in.");
return processAccessCode(scopeParam, state, redirect, client, user);
}
@@ -459,13 +453,7 @@ public class TokenService {
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response processOAuth(MultivaluedMap<String, String> formData) {
- String redirect = formData.getFirst("redirect_uri");
- String state = formData.getFirst("state");
- if (formData.containsKey("cancel")) {
- return redirectAccessDenied(redirect, state);
- }
String code = formData.getFirst("code");
-
JWSInput input = new JWSInput(code, providers);
boolean verifiedCode = false;
try {
@@ -474,13 +462,25 @@ public class TokenService {
logger.debug("Failed to verify signature", ignored);
}
if (!verifiedCode) {
- return redirectAccessDenied(redirect, state);
+ securityFailureForward("Illegal access code.");
+ identitySession.close();
+ return null;
}
String key = input.readContent(String.class);
AccessCodeEntry accessCodeEntry = tokenManager.getAccessCode(key);
if (accessCodeEntry == null) {
+ securityFailureForward("Unknown access code.");
+ identitySession.close();
+ return null;
+ }
+
+ String redirect = accessCodeEntry.getRedirectUri();
+ String state = accessCodeEntry.getState();
+
+ if (formData.containsKey("cancel")) {
return redirectAccessDenied(redirect, state);
}
+
return redirectAccessCode(accessCodeEntry, state, redirect);
}
@@ -491,14 +491,12 @@ public class TokenService {
return location.build();
}
- protected void oauthGrantPage(AccessCodeEntry accessCode, User client, String state, String redirect_uri) {
+ protected void oauthGrantPage(AccessCodeEntry accessCode, User client) {
request.setAttribute("realmRolesRequested", accessCode.getRealmRolesRequested());
request.setAttribute("resourceRolesRequested", accessCode.getResourceRolesRequested());
- request.setAttribute("state", state);
- request.setAttribute("redirect_uri", redirect_uri);
request.setAttribute("client", client);
- request.setAttribute("action", processOAuthUrl(uriInfo));
- request.setAttribute("accessCode", accessCode.getCode());
+ request.setAttribute("action", processOAuthUrl(uriInfo).build(realm.getId()).toString());
+ request.setAttribute("code", accessCode.getCode());
request.forward(oauthFormPath);
}
diff --git a/services/src/test/java/org/keycloak/test/AdapterTest.java b/services/src/test/java/org/keycloak/test/AdapterTest.java
index 36b3d6b..1bcbca6 100755
--- a/services/src/test/java/org/keycloak/test/AdapterTest.java
+++ b/services/src/test/java/org/keycloak/test/AdapterTest.java
@@ -166,7 +166,7 @@ public class AdapterTest {
idm.add(new SimpleRole("admin"));
idm.add(new SimpleRole("user"));
List<Role> roles = realmModel.getRoles();
- Assert.assertEquals(4, roles.size());
+ Assert.assertEquals(5, roles.size());
SimpleUser user = new SimpleUser("bburke");
idm.add(user);
Role role = idm.getRole("user");