Started installed application adapter

This commit is contained in:
Stian Thorgersen committed 2014-03-14 17:01:08 +00:00
1 parent cec948ffb4
commit 2ebc32793a
10 files changed
+493 -249

No files matched your search

@@ -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;
}
}
@@ -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;
}
+62
View File
@@ -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>
@@ -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) {
}
}
}
}
+1
View File
@@ -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>