/* * Copyright (C) 2015 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package apps.provisioning.server.rest; import java.util.HashMap; import java.util.Set; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.QueryParam; import org.json.JSONException; import org.json.JSONObject; import apps.provisioning.ProvisioningApp; import apps.provisioning.config.ConfigData; import apps.provisioning.server.Action; import apps.provisioning.server.account.UsernameManager; @Path("/rest") public class ProvisioningAction implements Action { private final String[] JSON_FIELDS_CREATE = new String[] {UsernameManager.FIRST_NAME, UsernameManager.LAST_NAME, UsernameManager.USERNAME, UsernameManager.PASSWORD}; private final String[] JSON_FIELDS_SELECT = new String[] {UsernameManager.USERNAME, UsernameManager.SUGGESTIONS}; private final String[] JSON_FIELDS_SUGGEST = new String[] {UsernameManager.FIRST_NAME, UsernameManager.LAST_NAME}; /** * Method exposed as a REST POST service that suggests usernames. * * @param userData Serialized map with the following fields: firstname (String) and lastname * (String). * @return In case of success, it returns a JSON serialized array with suggestions, in case of * error it returns a JSON serialized map with the "errorMessage" index explaining the * error. */ @POST @Path("suggest") public String suggest(String userData) { HashMap<String, String> userDataMap; try { userDataMap = parseAndValidateJSON(userData, JSON_FIELDS_SUGGEST); } catch (Exception e) { return createJSONErrorResponse(e.getMessage()); } try { return JSONObject.valueToString(ProvisioningApp.getInstance().getUsernameManager() .suggest(userDataMap)); } catch (Exception e) { return createJSONErrorResponse(e.getMessage()); } } /** * Method exposed as a REST GET service that suggests usernames. This method doesn't support * custom fields. Use the POST service instead. Exposed for testing only. * * @param firstName The user's first name. * @param lastName The user's last name. * @return In case of success, it returns a JSON serialized array with suggestions, in case of * error it returns a JSON serialized map with the "errorMessage" index explaining the * error. */ @GET @Path("suggest") public String suggestGet(@QueryParam("firstname") String firstName, @QueryParam("lastname") String lastName) { HashMap<String, String> userDataMap = new HashMap<String, String>(); userDataMap.put(UsernameManager.FIRST_NAME, firstName); userDataMap.put(UsernameManager.LAST_NAME, lastName); try { return JSONObject.valueToString(ProvisioningApp.getInstance().getUsernameManager() .suggest(userDataMap)); } catch (Exception e) { return createJSONErrorResponse(e.getMessage()); } } /** * Method exposed as a REST POST service that creates users in Google Apps. * * @param userData Serialized map with the following fields: username (String), firstname * (String), lastname (String) and password (String). * @return In case of success, it returns a JSON serialized map with the "message" index or in * case of failure with the "errorMessage" index. */ @POST @Path("create") public String create(String userData) { HashMap<String, String> userDataMap; try { userDataMap = parseAndValidateJSON(userData, JSON_FIELDS_CREATE); } catch (Exception e) { return createJSONErrorResponse(e.getMessage()); } try { ProvisioningApp.getInstance().getUsernameManager().create(userDataMap); return createJSONSuccessResponse("User created successfully."); } catch (Exception e) { return createJSONErrorResponse(e.getMessage()); } } /** * Method exposed as a REST POST service that unlocks the usernames suggested that were locked * meanwhile user chooses one. * * @param userData Serialized map with username (String) and patterns (String array) keys. * @return In case of success, it returns a JSON serialized map with the "message" index or in * case of failure with the "errorMessage" index. */ @POST @Path("select") public String select(String userData) { HashMap<String, String> userDataMap; try { userDataMap = parseAndValidateJSON(userData, JSON_FIELDS_SELECT); } catch (Exception e) { return createJSONErrorResponse(e.getMessage()); } try { ProvisioningApp.getInstance().getUsernameManager().select(userDataMap); return createJSONSuccessResponse("User selected successfully."); } catch (Exception e) { return createJSONErrorResponse(e.getMessage()); } } /** * Method exposed as a REST POST service to get the server's configuration parameters used by a * client. * * @return A JSON serialized map with the following configuration parameters: * suggestedUsernamesTimeout, numberOfSuggestions and domain. */ @POST @Path("config") public String getServerConfigPost() { return getServerConfig(); } /** * Method exposed as a REST GET service to get the server's configuration parameters used by a * client. * * @return A JSON serialized map with the following configuration parameters: * suggestedUsernamesTimeout, numberOfSuggestions and domain. */ @GET @Path("config") public String getServerConfigGet() { return getServerConfig(); } /** * @return A JSON serialized map with the following configuration parameters: * suggestedUsernamesTimeout, numberOfSuggestions and domain. */ public String getServerConfig() { ConfigData config = ProvisioningApp.getInstance().getContext().getConfig(); long suggestedUsernamesTimeout = config.getSuggestedUsernamesTimeout(); Integer numberOfSuggestions = config.getNumberOfSuggestions(); String domain = config.getDomain(); HashMap<String, String> configMap = new HashMap<String, String>(); configMap.put("suggestedUsernamesTimeout", String.valueOf(suggestedUsernamesTimeout)); configMap.put("numberOfSuggestions", numberOfSuggestions.toString()); configMap.put("domain", domain); return JSONObject.valueToString(configMap); } /** * Parses the incoming JSON text and validates that needed fields are contained. * * @param userData The raw body sent in the HTTP POST payload section. * @param validateFields The fields to be validated after parsing the object. * @return HashMap with the fields as keys containing their values. * @throws Exception */ private HashMap<String, String> parseAndValidateJSON(String userData, String[] validateFields) throws Exception { if (userData == null || userData.isEmpty()) { throw new Exception("No parameters received."); } JSONObject jsonObject; try { jsonObject = new JSONObject(userData); } catch (JSONException e) { throw new Exception("Parse errors in JSON input: " + e.getMessage()); } for (String field : validateFields) { if (!jsonObject.has(field)) { throw new Exception("User data must contain " + field + " field."); } } HashMap<String, String> userDataMap = new HashMap<String, String>(); Set<?> keySet = jsonObject.keySet(); for (Object field : keySet) { String fieldName = (String) field; // The value associated to a key is not always a String, (i.e. it can be a JSONArray in the // select method) userDataMap.put(fieldName, jsonObject.get(fieldName).toString()); } return userDataMap; } private String createJSONSuccessResponse(String message) { return "{\"message\":\"" + message + "\"}"; } private String createJSONErrorResponse(String message) { return "{\"errorMessage\":\"" + message + "\"}"; } }