/* * DO NOT REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2014 ForgeRock AS. All rights reserved. * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the License). You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * http://forgerock.org/license/CDDLv1.0.html * See the License for the specific language governing * permission and limitations under the License. * * When distributing Covered Code, include this CDDL * Header Notice in each file and include the License file * at http://forgerock.org/license/CDDLv1.0.html * If applicable, add the following below the CDDL Header, * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" */ package org.forgerock.openicf.connectors.box; import static org.identityconnectors.common.security.SecurityUtil.decrypt; import java.awt.*; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.net.URI; import java.util.HashMap; import java.util.Map; import java.util.Scanner; import org.identityconnectors.common.Assertions; import org.identityconnectors.common.logging.Log; import org.identityconnectors.common.security.GuardedString; import org.identityconnectors.framework.spi.AbstractConfiguration; import org.identityconnectors.framework.spi.ConfigurationProperty; import org.identityconnectors.framework.spi.StatefulConfiguration; import com.box.boxjavalibv2.BoxClient; import com.box.boxjavalibv2.authorization.OAuthWebViewData; import com.box.boxjavalibv2.dao.BoxOAuthToken; import com.box.boxjavalibv2.exceptions.AuthFatalFailureException; /** * Extends the {@link AbstractConfiguration} class to provide all the necessary * parameters to initialize the Box Connector. * */ public class BoxConfiguration extends AbstractConfiguration implements StatefulConfiguration { /** * Setup logging for the {@link BoxConfiguration}. */ private static final Log logger = Log.getLog(BoxConfiguration.class); /** * Client Id of the application registered at Box.com */ private String clientId; /** * Client Secret of the application registered at Box.com */ private GuardedString clientSecret; private GuardedString refreshToken; private BoxClient boxClient; @ConfigurationProperty(order = 1, displayMessageKey = "clientId.display", groupMessageKey = "basic.group", helpMessageKey = "clientId.help", required = true) public String getClientId() { return clientId; } public void setClientId(String clientId) { this.clientId = clientId; } @ConfigurationProperty(order = 2, displayMessageKey = "clientSecret.display", groupMessageKey = "basic.group", helpMessageKey = "clientSecret.help", confidential = true, required = true) public GuardedString getClientSecret() { return clientSecret; } public void setClientSecret(GuardedString secret) { this.clientSecret = secret; } @ConfigurationProperty(order = 3, displayMessageKey = "refreshToken.display", groupMessageKey = "basic.group", helpMessageKey = "refreshToken.help", confidential = true, required = true) public GuardedString getRefreshToken() { return refreshToken; } public void setRefreshToken(GuardedString refreshToken) { this.refreshToken = refreshToken; } /** * {@inheritDoc} */ public void validate() { Assertions.blankCheck(getClientId(), "clientId"); Assertions.nullCheck(getClientSecret(), "clientSecret"); Assertions.nullCheck(getRefreshToken(), "refreshToken"); } // **** THIS MUST BE THREAD SAFE !!! BoxClient getBoxClient() { if (null == this.boxClient) { synchronized (this) { try { boxClient = new BoxClient(getClientId(), decrypt(getClientSecret()), null, null, null); Map<String, Object> map = new HashMap<String, Object>(1); map.put(BoxOAuthToken.FIELD_REFRESH_TOKEN, decrypt(getRefreshToken())); boxClient.getOAuthDataController().setOAuthData(new BoxOAuthToken(map)); boxClient.getOAuthDataController().refresh(); if (boxClient.isAuthenticated()) { logger.info("Client is authenticated"); } else { logger.error("Client is NOT authenticated"); } } catch (AuthFatalFailureException e) { logger.error(e.getMessage(), e); throw new IllegalStateException(e.getMessage(), boxClient .getOAuthDataController().getRefreshFailException()); } catch (final Exception e) { logger.error(e, "Cannot get connection to the box service."); return null; } } } return boxClient; } @Override public void release() { synchronized (this) { if (null != boxClient) { boxClient = null; } } } public static void main(String[] args) throws Exception { if (args.length == 3) { BoxClient client = new BoxClient(args[0], args[1], null, null, null); OAuthWebViewData webView = new OAuthWebViewData(client.getOAuthDataController()); webView.setRedirectUrl(args[2]); browse(webView.buildUrl()); String code; if (true) { code = getCode(); } else { do { System.out.print("Please enter code: "); code = new Scanner(System.in).nextLine(); } while (code.isEmpty()); } BoxOAuthToken oauth = client.getOAuthManager().createOAuth(code, webView.getClientId(), webView.getClientSecret(), webView.getRedirectUrl()); System.out.println(client.getJSONParser().convertBoxObjectToJSONStringQuietly(oauth)); } else { System.err.println("Usage: box [client_id] [client_secret] [redirect_uri]"); } } /** * Open a browser at the given URL using {@link Desktop} if available, or * alternatively output the URL to {@link System#out} for command-line * applications. * * @param uri * URL to browse */ public static void browse(URI uri) { System.out.println("Please open the following address in your browser:"); System.out.println(" " + uri); try { if (Desktop.isDesktopSupported()) { Desktop desktop = Desktop.getDesktop(); if (desktop.isSupported(Desktop.Action.BROWSE)) { System.out .println("Attempting to open that address in the default browser now..."); desktop.browse(uri); } } } catch (IOException e) { logger.warn("Unable to open browser", e); } catch (InternalError e) { logger.warn("Unable to open browser", e); } } private static String getCode() throws IOException { ServerSocket serverSocket = new ServerSocket(8088); Socket socket = serverSocket.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); while (true) { String code = ""; try { BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); out.write("HTTP/1.1 200 OK\r\n"); out.write("Content-Type: text/html\r\n"); out.write("\r\n"); code = in.readLine(); String match = "code"; int loc = code.indexOf(match); if (loc > 0) { int httpstr = code.indexOf("HTTP") - 1; code = code.substring(code.indexOf(match), httpstr); String parts[] = code.split("="); code = parts[1]; out.write(String.format(HTML_PAGE, "", code)); } else { out.write(String.format(HTML_PAGE, "not found in the URL!", "")); } out.close(); return code; } catch (IOException e) { System.exit(1); break; } } return ""; } private static final String HTML_PAGE = "<!DOCTYPE html> <head> <title>OpenICF Box Connector OAuth2 Code | Box</title> <link rel=\"stylesheet\" href=\"https://e1.boxcdn.net/_assets/css/section_templ_login_views_components_center_container-aXC4sq.css\" media=\"screen\"> </head> <body id=\"site_body\"> <div id=\"envelope-background\"> <div class=\"center_container single-width\"> <div class=\"container_body\"> <div class=\"container_header ptl\"> <div class=\"title-logo sprite_signup_login_box_logo\"> </div> <div class=\"title_text\">OAuth2 Code %s</div> <div class=\"title_subtext small pts\"><strong>%s</strong></div> <div class=\"title_subtext small pts\">Now return to command line to see the output of the Box.com Connector Configuration.</div> </div> </div> </div> </div> </body></html>"; }