Added basic command-line example
This commit is contained in:
parent
b543e22eee
commit
12978a4343
3 changed files with 348 additions and 0 deletions
91
examples/demo-template/customer-app-cli/pom.xml
Executable file
91
examples/demo-template/customer-app-cli/pom.xml
Executable file
|
@ -0,0 +1,91 @@
|
|||
<?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-3-SNAPSHOT</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.keycloak.example.demo</groupId>
|
||||
<artifactId>customer-portal-cli-example</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>Customer Portal CLI</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.keycloak</groupId>
|
||||
<artifactId>keycloak-core</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.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>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<mainClass>org.keycloak.example.CustomerCli</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,256 @@
|
|||
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 java.awt.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
private static String accessToken;
|
||||
private static BufferedReader br;
|
||||
|
||||
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);
|
||||
|
||||
authServerUrl = config.getAuthServerUrl();
|
||||
realm = config.getRealm();
|
||||
clientId = config.getResource();
|
||||
} catch (Throwable t) {
|
||||
System.err.println("Failed to load config:");
|
||||
t.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
br = new BufferedReader(new InputStreamReader(System.in));
|
||||
|
||||
printHelp();
|
||||
|
||||
for (String s = br.readLine(); s != null; s = br.readLine()) {
|
||||
if (s.equals("login")) {
|
||||
login();
|
||||
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void printHelp() {
|
||||
System.out.println("Commands:");
|
||||
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(" 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 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 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 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -36,6 +36,7 @@
|
|||
<modules>
|
||||
<!-- <module>server</module> -->
|
||||
<module>customer-app</module>
|
||||
<module>customer-app-cli</module>
|
||||
<module>customer-app-js</module>
|
||||
<module>product-app</module>
|
||||
<module>database-service</module>
|
||||
|
|
Loading…
Reference in a new issue