keycloak-aplcache
Changes
examples/demo-template/customer-app-cli/src/main/java/org/keycloak/example/CustomerCli.java 299(+90 -209)
integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java 8(+4 -4)
integration/installed/pom.xml 62(+62 -0)
integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java 312(+312 -0)
integration/pom.xml 1(+1 -0)
Details
diff --git a/core/src/main/java/org/keycloak/OAuthErrorException.java b/core/src/main/java/org/keycloak/OAuthErrorException.java
index 3cddba2..4eff35f 100755
--- a/core/src/main/java/org/keycloak/OAuthErrorException.java
+++ b/core/src/main/java/org/keycloak/OAuthErrorException.java
@@ -19,6 +19,8 @@ public class OAuthErrorException extends Exception {
}
public OAuthErrorException(String error, String description, String message) {
super(message);
+ this.error = error;
+ this.description = description;
}
public OAuthErrorException(String error, String description) {
super(description);
diff --git a/core/src/main/java/org/keycloak/ServiceUrlConstants.java b/core/src/main/java/org/keycloak/ServiceUrlConstants.java
index f40d83e..b392ca6 100755
--- a/core/src/main/java/org/keycloak/ServiceUrlConstants.java
+++ b/core/src/main/java/org/keycloak/ServiceUrlConstants.java
@@ -9,4 +9,7 @@ public interface ServiceUrlConstants {
public static final String TOKEN_SERVICE_LOGIN_PATH = "/rest/realms/{realm-name}/tokens/login";
public static final String TOKEN_SERVICE_ACCESS_CODE_PATH = "/rest/realms/{realm-name}/tokens/access/codes";
public static final String TOKEN_SERVICE_REFRESH_PATH = "/rest/realms/{realm-name}/tokens/refresh";
+ public static final String TOKEN_SERVICE_LOGOUT_PATH = "/rest/realms/{realm-name}/tokens/logout";
+ public static final String ACCOUNT_SERVICE_PATH = "/rest/realms/{realm-name}/account";
+
}
diff --git a/examples/demo-template/customer-app-cli/pom.xml b/examples/demo-template/customer-app-cli/pom.xml
index 777bfd5..2abf670 100755
--- a/examples/demo-template/customer-app-cli/pom.xml
+++ b/examples/demo-template/customer-app-cli/pom.xml
@@ -25,49 +25,14 @@
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
- <artifactId>keycloak-core</artifactId>
+ <artifactId>keycloak-installed</artifactId>
<version>${project.version}</version>
</dependency>
- <dependency>
- <groupId>org.keycloak</groupId>
- <artifactId>keycloak-social-core</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.keycloak</groupId>
- <artifactId>keycloak-services</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.json</groupId>
- <artifactId>json</artifactId>
- </dependency>
- <dependency>
- <groupId>net.iharder</groupId>
- <artifactId>base64</artifactId>
- </dependency>
- <dependency>
- <groupId>org.codehaus.jackson</groupId>
- <artifactId>jackson-core-asl</artifactId>
- </dependency>
- <dependency>
- <groupId>org.codehaus.jackson</groupId>
- <artifactId>jackson-mapper-asl</artifactId>
- </dependency>
</dependencies>
<build>
- <finalName>customer-portal</finalName>
<plugins>
<plugin>
- <groupId>org.jboss.as.plugins</groupId>
- <artifactId>jboss-as-maven-plugin</artifactId>
- <version>7.1.1.Final</version>
- <configuration>
- <skip>true</skip>
- </configuration>
- </plugin>
- <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
diff --git a/examples/demo-template/customer-app-cli/src/main/java/org/keycloak/example/CustomerCli.java b/examples/demo-template/customer-app-cli/src/main/java/org/keycloak/example/CustomerCli.java
index 86dfae1..f04a283 100644
--- a/examples/demo-template/customer-app-cli/src/main/java/org/keycloak/example/CustomerCli.java
+++ b/examples/demo-template/customer-app-cli/src/main/java/org/keycloak/example/CustomerCli.java
@@ -1,72 +1,84 @@
package org.keycloak.example;
-import org.json.JSONObject;
-import org.keycloak.jose.jws.JWSInput;
-import org.keycloak.services.managers.ApplicationManager;
-import org.keycloak.social.utils.SimpleHttp;
-import org.keycloak.util.JsonSerialization;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializationConfig;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.keycloak.adapters.ServerRequest;
+import org.keycloak.adapters.installed.KeycloakInstalled;
-import java.awt.*;
import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.net.ServerSocket;
-import java.net.Socket;
-import java.net.URI;
-import java.net.URLEncoder;
-import java.util.UUID;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class CustomerCli {
- private static String authServerUrl;
- private static String realm;
- private static String clientId;
+ public static final ObjectMapper mapper = new ObjectMapper();
- private static String accessToken;
- private static BufferedReader br;
+ static {
+ mapper.enable(SerializationConfig.Feature.INDENT_OUTPUT);
+ mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
+ }
- public static void main(String[] args) throws Exception {
- try {
- String f = args.length > 0 ? args[0] : "keycloak.json";
- ApplicationManager.InstallationAdapterConfig config = JsonSerialization.readValue(new FileInputStream(new File(f)), ApplicationManager.InstallationAdapterConfig.class);
+ private static BufferedReader br;
- authServerUrl = config.getAuthServerUrl();
- realm = config.getRealm();
- clientId = config.getResource();
- } catch (Throwable t) {
- System.err.println("Failed to load config:");
- t.printStackTrace();
- System.exit(1);
- }
+ private static KeycloakInstalled keycloak;
+ public static void main(String[] args) throws Exception {
+ keycloak = new KeycloakInstalled();
br = new BufferedReader(new InputStreamReader(System.in));
printHelp();
+ printDivider();
+ System.out.print("$ ");
for (String s = br.readLine(); s != null; s = br.readLine()) {
- if (s.equals("login")) {
- login();
+ printDivider();
- } else if (s.equals("login-desktop")) {
- loginDesktop();
- } else if (s.equals("login-manual")) {
- loginManual();
- } else if (s.equals("profile")) {
- profile();
- } else if (s.equals("token")) {
- token();
- } else if (s.equals("exit")) {
- System.exit(0);
- } else {
- printHelp();
+ try {
+ if (s.equals("login")) {
+ keycloak.login(System.out, br);
+ System.out.println("Logged in: " + keycloak.getToken().getSubject());
+ } else if (s.equals("logout")) {
+ keycloak.logout();
+ System.out.println("Logged out");
+ } else if (s.equals("login-desktop")) {
+ keycloak.loginDesktop();
+ System.out.println("Logged in: " + keycloak.getToken().getSubject());
+ } else if (s.equals("login-manual")) {
+ keycloak.loginManual(System.out, br);
+ System.out.println("Logged in: " + keycloak.getToken().getSubject());
+ } else if (s.equals("profile")) {
+ profile();
+ } else if (s.equals("customers")) {
+ customers();
+ } else if (s.equals("token")) {
+ System.out.println(mapper.writeValueAsString(keycloak.getToken()));
+ } else if (s.equals("id-token")) {
+ System.out.println(mapper.writeValueAsString(keycloak.getIdToken()));
+ } else if (s.equals("refresh")) {
+ keycloak.refreshToken();
+ System.out.println("Token refreshed: expires at " + new Date(keycloak.getToken().getExpiration() * 1000));
+ } else if (s.equals("exit")) {
+ System.exit(0);
+ } else {
+ printHelp();
+ }
+ } catch (ServerRequest.HttpFailure t) {
+ System.out.println(t.getError());
+ }catch (Throwable t) {
+ System.out.println(t.getMessage() != null ? t.getMessage() : t.getClass().toString());
}
+ printDivider();
+
+ System.out.print("$ ");
}
}
@@ -75,181 +87,50 @@ public class CustomerCli {
System.out.println(" login - login with desktop browser if available, otherwise do manual login");
System.out.println(" login-manual - manual login");
System.out.println(" login-desktop - desktop login");
- System.out.println(" profile - retrieve user profile");
System.out.println(" token - show token details");
+ System.out.println(" id-token - show ID token details");
+ System.out.println(" profile - retrieve user profile");
+ System.out.println(" customers - retrieve customers listing");
+ System.out.println(" refresh - refresh token");
System.out.println(" exit - exit");
-
}
- public static void login() {
- try {
- if (Desktop.isDesktopSupported()) {
- loginDesktop();
- } else {
- loginManual();
- }
-
- } catch (Throwable e) {
- System.err.println("Failed to log in user: " + e.getMessage());
- }
+ public static void printDivider() {
+ System.out.println("");
}
- public static void loginDesktop() {
- try {
- CallbackListener callback = new CallbackListener();
- callback.start();
-
- String redirectUri = URLEncoder.encode("http://localhost:" + callback.getPort(), "utf-8");
- String state = UUID.randomUUID().toString();
-
- String loginUrl = authServerUrl + "/rest/realms/" + realm + "/tokens/login?" +
- "client_id=" + clientId +
- "&redirect_uri=" + redirectUri +
- "&state=" + state;
-
- Desktop.getDesktop().browse(new URI(loginUrl));
-
- callback.join();
-
- if (!state.equals(callback.getStateParam())) {
- System.err.println("Invalid state received");
- return;
- }
-
- if (callback.getError() != null) {
- System.err.println("Failed to login: " + callback.getError());
- return;
- }
-
- System.out.println("User logged in");
-
- String tokenUrl = authServerUrl + "/rest/realms/" + realm + "/tokens/access/codes";
- JSONObject response = SimpleHttp.doPost(tokenUrl).param("client_id", clientId).param("code", callback.getCode()).asJson();
- accessToken = response.getString("access_token");
- System.out.println("Access token received");
-
- return;
- } catch (Throwable e) {
- System.err.println("Failed to log in user: " + e.getMessage());
+ public static void profile() throws Exception {
+ String accountUrl = keycloak.getDeployment().getAccountUrl();
+ HttpGet get = new HttpGet(accountUrl);
+ get.setHeader("Accept", "application/json");
+ get.setHeader("Authorization", "Bearer " + keycloak.getTokenString(10, TimeUnit.SECONDS));
+
+ HttpResponse response = keycloak.getDeployment().getClient().execute(get);
+ if (response.getStatusLine().getStatusCode() == 200) {
+ print(response.getEntity().getContent());
+ } else {
+ System.out.println(response.getStatusLine().toString());
}
}
- public static void loginManual() {
- try {
- CallbackListener callback = new CallbackListener();
- callback.start();
-
- String redirectUri = URLEncoder.encode("urn:ietf:wg:oauth:2.0:oob", "utf-8");
-
- String loginUrl = authServerUrl + "/rest/realms/" + realm + "/tokens/login?" +
- "client_id=" + clientId +
- "&redirect_uri=" + redirectUri;
-
- System.out.println("Open the following URL in a browser and paste the code back:");
- System.out.println(loginUrl);
- System.out.print("code: ");
-
- String code = br.readLine().trim();
-
- String tokenUrl = authServerUrl + "/rest/realms/" + realm + "/tokens/access/codes";
- JSONObject response = SimpleHttp.doPost(tokenUrl).param("client_id", clientId).param("code", code).asJson();
- accessToken = response.getString("access_token");
- System.out.println("Access token received");
-
- return;
- } catch (Throwable e) {
- System.err.println("Failed to log in user: " + e.getMessage());
+ public static void customers() throws Exception {
+ String customersUrl = "http://localhost:8080/database/customers";
+ HttpGet get = new HttpGet(customersUrl);
+ get.setHeader("Accept", "application/json");
+ get.setHeader("Authorization", "Bearer " + keycloak.getTokenString(10, TimeUnit.SECONDS));
+
+ HttpResponse response = keycloak.getDeployment().getClient().execute(get);
+ if (response.getStatusLine().getStatusCode() == 200) {
+ print(response.getEntity().getContent());
+ } else {
+ System.out.println(response.getStatusLine().toString());
}
}
- public static void profile() {
- try {
- String profileUrl = authServerUrl + "/rest/realms/" + realm + "/account";
- JSONObject profile = SimpleHttp.doGet(profileUrl).header("Accept", "application/json").header("Authorization", "Bearer " + accessToken).asJson();
- System.out.println(profile.toString(2));
- } catch (Throwable e) {
- System.err.println("Failed: " + e.getMessage());
- }
- }
-
- public static void token() {
- try {
- JWSInput jws = new JWSInput(accessToken);
- System.out.println(new JSONObject(new String(jws.getContent())).toString(2));
- } catch (Throwable e) {
- System.err.println("Failed to log in user: " + e.getMessage());
- }
- }
-
- public static class CallbackListener extends Thread {
-
- private String code;
-
- private String error;
-
- private String state;
- private final ServerSocket server;
-
- public CallbackListener() throws IOException {
- server = new ServerSocket(0);
- }
-
- public int getPort() {
- return server.getLocalPort();
- }
-
- @Override
- public void run() {
- try {
- Socket socket = server.accept();
-
- System.out.println("Request received");
-
- BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- String request = br.readLine();
-
- System.out.println(request);
-
- String[] params = request.split(" ")[1].substring(2).split("&");
- System.out.println(params.length);
-
- for (String param : params) {
- String[] p = param.split("=");
- System.out.println(p[0]);
- if (p[0].equals("code")) {
- code = p[1];
- } else if (p[0].equals("error")) {
- error = p[1];
- } else if (p[0].equals("state")) {
- state = p[1];
- }
- }
-
- PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
- pw.println("Please close and return to application");
- pw.flush();
-
- socket.close();
- } catch (IOException e) {
- error = "Local error: " + e.getMessage();
- }
-
- try {
- server.close();
- } catch (IOException e) {
- }
- }
-
- public String getCode() throws InterruptedException {
- return code;
- }
-
- public String getError() {
- return error;
- }
-
- public String getStateParam() {
- return state;
+ private static void print(InputStream is) throws IOException {
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ for (String l = br.readLine(); l != null; l = br.readLine()) {
+ System.out.println(l);
}
}
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
index ba969bd..bd2eabc 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
@@ -17,6 +17,8 @@ public class KeycloakDeployment {
protected KeycloakUriBuilder authUrl;
protected String codeUrl;
protected String refreshUrl;
+ protected KeycloakUriBuilder logoutUrl;
+ protected String accountUrl;
protected String resourceName;
protected boolean bearerOnly;
@@ -194,4 +196,20 @@ public class KeycloakDeployment {
public void setNotBefore(int notBefore) {
this.notBefore = notBefore;
}
+
+ public KeycloakUriBuilder getLogoutUrl() {
+ return logoutUrl;
+ }
+
+ public void setLogoutUrl(KeycloakUriBuilder logoutUrl) {
+ this.logoutUrl = logoutUrl;
+ }
+
+ public String getAccountUrl() {
+ return accountUrl;
+ }
+
+ public void setAccountUrl(String accountUrl) {
+ this.accountUrl = accountUrl;
+ }
}
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
index d497c0d..3f5a4a4 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
@@ -63,14 +63,14 @@ public class KeycloakDeploymentBuilder {
String authUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGIN_PATH).build(adapterConfig.getRealm()).toString();
String tokenUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_ACCESS_CODE_PATH).build(adapterConfig.getRealm()).toString();
String refreshUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_REFRESH_PATH).build(adapterConfig.getRealm()).toString();
-
-
+ String logoutUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH).build(adapterConfig.getRealm()).toString();
+ String accountUrl = serverBuilder.clone().path(ServiceUrlConstants.ACCOUNT_SERVICE_PATH).build(adapterConfig.getRealm()).toString();
deployment.setAuthUrl(KeycloakUriBuilder.fromUri(authUrl).queryParam("client_id", deployment.getResourceName()));
deployment.setCodeUrl(tokenUrl);
deployment.setRefreshUrl(refreshUrl);
-
-
+ deployment.setLogoutUrl(KeycloakUriBuilder.fromUri(logoutUrl));
+ deployment.setAccountUrl(accountUrl);
return deployment;
}
integration/installed/pom.xml 62(+62 -0)
diff --git a/integration/installed/pom.xml b/integration/installed/pom.xml
new file mode 100755
index 0000000..78860ce
--- /dev/null
+++ b/integration/installed/pom.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<project>
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.0-beta-1-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-installed</artifactId>
+ <name>Keycloak Installed Application</name>
+ <description/>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk16</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>${keycloak.apache.httpcomponents.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.iharder</groupId>
+ <artifactId>base64</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <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/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java b/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
new file mode 100644
index 0000000..c0f7c27
--- /dev/null
+++ b/integration/installed/src/main/java/org/keycloak/adapters/installed/KeycloakInstalled.java
@@ -0,0 +1,312 @@
+package org.keycloak.adapters.installed;
+
+import org.keycloak.OAuthErrorException;
+import org.keycloak.RSATokenVerifier;
+import org.keycloak.VerificationException;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.KeycloakDeploymentBuilder;
+import org.keycloak.adapters.ServerRequest;
+import org.keycloak.jose.jws.JWSInput;
+import org.keycloak.representations.AccessToken;
+import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.IDToken;
+
+import java.awt.*;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class KeycloakInstalled {
+
+ private static final String KEYCLOAK_JSON = "META-INF/keycloak.json";
+
+ private KeycloakDeployment deployment;
+
+ private enum Status {
+ LOGGED_MANUAL, LOGGED_DESKTOP
+ }
+
+ private String tokenString;
+ private String idTokenString;
+ private IDToken idToken;
+ private AccessToken token;
+ private String refreshToken;
+ private Status status;
+
+ public KeycloakInstalled() {
+ InputStream config = Thread.currentThread().getContextClassLoader().getResourceAsStream(KEYCLOAK_JSON);
+ deployment = KeycloakDeploymentBuilder.build(config);
+ }
+
+ public KeycloakInstalled(InputStream config) {
+ deployment = KeycloakDeploymentBuilder.build(config);
+ }
+
+ public void login() throws IOException, ServerRequest.HttpFailure, VerificationException, InterruptedException, OAuthErrorException, URISyntaxException {
+ if (isDesktopSupported()) {
+ loginDesktop();
+ } else {
+ loginManual();
+ }
+ }
+
+ public void login(PrintStream printer, Reader reader) throws IOException, ServerRequest.HttpFailure, VerificationException, InterruptedException, OAuthErrorException, URISyntaxException {
+ if (isDesktopSupported()) {
+ loginDesktop();
+ } else {
+ loginManual(printer, reader);
+ }
+ }
+
+ public void logout() throws IOException, InterruptedException, URISyntaxException {
+ if (status == Status.LOGGED_DESKTOP) {
+ logoutDesktop();
+ }
+
+ tokenString = null;
+ token = null;
+
+ idTokenString = null;
+ idToken = null;
+
+ refreshToken = null;
+
+ status = null;
+ }
+
+ public void loginDesktop() throws IOException, VerificationException, OAuthErrorException, URISyntaxException, ServerRequest.HttpFailure, InterruptedException {
+ CallbackListener callback = new CallbackListener();
+ callback.start();
+
+ String redirectUri = "http://localhost:" + callback.server.getLocalPort();
+ String state = UUID.randomUUID().toString();
+
+ String authUrl = deployment.getAuthUrl().clone()
+ .queryParam("client_id", deployment.getResourceName())
+ .queryParam("redirect_uri", redirectUri)
+ .queryParam("state", state)
+ .queryParam("login", "true")
+ .build().toString();
+
+ Desktop.getDesktop().browse(new URI(authUrl));
+
+ callback.join();
+
+ if (!state.equals(callback.state)) {
+ throw new VerificationException("Invalid state");
+ }
+
+ if (callback.error != null) {
+ throw new OAuthErrorException(callback.error, callback.errorDescription);
+ }
+
+ if (callback.errorException != null) {
+ throw callback.errorException;
+ }
+
+ processCode(callback.code, redirectUri);
+
+ status = Status.LOGGED_DESKTOP;
+ }
+
+ private void logoutDesktop() throws IOException, URISyntaxException, InterruptedException {
+ CallbackListener callback = new CallbackListener();
+ callback.start();
+
+ String redirectUri = "http://localhost:" + callback.server.getLocalPort();
+
+ String logoutUrl = deployment.getLogoutUrl()
+ .queryParam("redirect_uri", redirectUri)
+ .build().toString();
+
+ Desktop.getDesktop().browse(new URI(logoutUrl));
+
+ callback.join();
+
+ if (callback.errorException != null) {
+ throw callback.errorException;
+ }
+ }
+
+ public void loginManual() throws IOException, ServerRequest.HttpFailure, VerificationException {
+ loginManual(System.out, new InputStreamReader(System.in));
+ }
+
+ public void loginManual(PrintStream printer, Reader reader) throws IOException, ServerRequest.HttpFailure, VerificationException {
+ CallbackListener callback = new CallbackListener();
+ callback.start();
+
+ String redirectUri = "urn:ietf:wg:oauth:2.0:oob";
+
+ String authUrl = deployment.getAuthUrl().clone()
+ .queryParam("client_id", deployment.getResourceName())
+ .queryParam("redirect_uri", redirectUri)
+ .queryParam("login", "true")
+ .build().toString();
+
+ printer.println("Open the following URL in a browser. After login copy/paste the code back and press <enter>");
+ printer.println(authUrl);
+ printer.println();
+ printer.print("Code: ");
+
+ String code = readCode(reader);
+ processCode(code, redirectUri);
+
+ status = Status.LOGGED_MANUAL;
+ }
+
+ public String getTokenString() throws VerificationException, IOException, ServerRequest.HttpFailure {
+ return tokenString;
+ }
+
+ public String getTokenString(long minValidity, TimeUnit unit) throws VerificationException, IOException, ServerRequest.HttpFailure {
+ long expires = token.getExpiration() * 1000 - unit.toMillis(minValidity);
+ if (expires < System.currentTimeMillis()) {
+ refreshToken();
+ }
+
+ return tokenString;
+ }
+
+ public void refreshToken() throws IOException, ServerRequest.HttpFailure, VerificationException {
+ AccessTokenResponse tokenResponse = ServerRequest.invokeRefresh(deployment, refreshToken);
+ parseAccessToken(tokenResponse);
+ }
+
+ private void parseAccessToken(AccessTokenResponse tokenResponse) throws VerificationException {
+ tokenString = tokenResponse.getToken();
+ refreshToken = tokenResponse.getRefreshToken();
+ idTokenString = tokenResponse.getIdToken();
+
+ token = RSATokenVerifier.verifyToken(tokenString, deployment.getRealmKey(), deployment.getRealm());
+ if (idTokenString != null) {
+ JWSInput input = new JWSInput(idTokenString);
+ try {
+ idToken = input.readJsonContent(IDToken.class);
+ } catch (IOException e) {
+ throw new VerificationException();
+ }
+ }
+ }
+
+ public AccessToken getToken() {
+ return token;
+ }
+
+ public IDToken getIdToken() {
+ return idToken;
+ }
+
+ public String getIdTokenString() {
+ return idTokenString;
+ }
+
+ public String getRefreshToken() {
+ return refreshToken;
+ }
+
+ public boolean isDesktopSupported() {
+ return Desktop.isDesktopSupported();
+ }
+
+ public KeycloakDeployment getDeployment() {
+ return deployment;
+ }
+
+ private void processCode(String code, String redirectUri) throws IOException, ServerRequest.HttpFailure, VerificationException {
+ AccessTokenResponse tokenResponse = ServerRequest.invokeAccessCodeToToken(deployment, code, redirectUri);
+ parseAccessToken(tokenResponse);
+ }
+
+ private String readCode(Reader reader) throws IOException {
+ StringBuilder sb = new StringBuilder();
+
+ char cb[] = new char[1];
+ while (reader.read(cb) != -1) {
+ char c = cb[0];
+ if ((c == ' ') || (c == '\n') || (c == '\r')) {
+ break;
+ } else {
+ sb.append(c);
+ }
+ }
+
+ return sb.toString();
+ }
+
+ public class CallbackListener extends Thread {
+
+ private ServerSocket server;
+
+ private String code;
+
+ private String error;
+
+ private String errorDescription;
+
+ private IOException errorException;
+
+ private String state;
+
+ public CallbackListener() throws IOException {
+ server = new ServerSocket(0);
+ }
+
+ @Override
+ public void run() {
+ try {
+ Socket socket = server.accept();
+
+ BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ String request = br.readLine();
+
+ String url = request.split(" ")[1];
+ if (url.indexOf('?') >= 0) {
+ url = url.split("\\?")[1];
+ String[] params = url.split("&");
+
+ for (String param : params) {
+ String[] p = param.split("=");
+ if (p[0].equals("code")) {
+ code = p[1];
+ } else if (p[0].equals("error")) {
+ error = p[1];
+ } else if (p[0].equals("error-description")) {
+ errorDescription = p[1];
+ } else if (p[0].equals("state")) {
+ state = p[1];
+ }
+ }
+ }
+
+ PrintWriter pw = new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
+ pw.println("Please close window and return to application");
+ pw.flush();
+
+ socket.close();
+ } catch (IOException e) {
+ errorException = e;
+ }
+
+ try {
+ server.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+}
integration/pom.xml 1(+1 -0)
diff --git a/integration/pom.xml b/integration/pom.xml
index 1295151..5904823 100755
--- a/integration/pom.xml
+++ b/integration/pom.xml
@@ -25,6 +25,7 @@
<module>wildfly-subsystem</module>
<module>as7-eap-subsystem</module>
<module>js</module>
+ <module>installed</module>
<!-- <module>as7-eap6/jboss-modules</module> -->
</modules>
</project>