From 12978a4343c66f64c341ebeb068768f7052bf034 Mon Sep 17 00:00:00 2001 From: Stian Thorgersen Date: Thu, 6 Mar 2014 11:26:21 +0000 Subject: [PATCH] Added basic command-line example --- .../demo-template/customer-app-cli/pom.xml | 91 +++++++ .../org/keycloak/example/CustomerCli.java | 256 ++++++++++++++++++ examples/demo-template/pom.xml | 1 + 3 files changed, 348 insertions(+) create mode 100755 examples/demo-template/customer-app-cli/pom.xml create mode 100644 examples/demo-template/customer-app-cli/src/main/java/org/keycloak/example/CustomerCli.java diff --git a/examples/demo-template/customer-app-cli/pom.xml b/examples/demo-template/customer-app-cli/pom.xml new file mode 100755 index 0000000000..3eaf498283 --- /dev/null +++ b/examples/demo-template/customer-app-cli/pom.xml @@ -0,0 +1,91 @@ + + + + keycloak-parent + org.keycloak + 1.0-alpha-3-SNAPSHOT + ../../../pom.xml + + 4.0.0 + org.keycloak.example.demo + customer-portal-cli-example + war + Customer Portal CLI + + + + + jboss + jboss repo + http://repository.jboss.org/nexus/content/groups/public/ + + + + + + org.keycloak + keycloak-core + ${project.version} + + + org.keycloak + keycloak-social-core + ${project.version} + + + org.keycloak + keycloak-services + ${project.version} + + + org.json + json + + + net.iharder + base64 + + + org.codehaus.jackson + jackson-core-asl + + + org.codehaus.jackson + jackson-mapper-asl + + + + + customer-portal + + + org.jboss.as.plugins + jboss-as-maven-plugin + 7.4.Final + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + + + + org.codehaus.mojo + exec-maven-plugin + + org.keycloak.example.CustomerCli + + + + + 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 new file mode 100644 index 0000000000..86dfae162f --- /dev/null +++ b/examples/demo-template/customer-app-cli/src/main/java/org/keycloak/example/CustomerCli.java @@ -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 Stian Thorgersen + */ +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; + } + } + +} diff --git a/examples/demo-template/pom.xml b/examples/demo-template/pom.xml index 8185fb422a..20ec866d55 100755 --- a/examples/demo-template/pom.xml +++ b/examples/demo-template/pom.xml @@ -36,6 +36,7 @@ customer-app + customer-app-cli customer-app-js product-app database-service