Java tutorial
/** * Copyright 2014 University of Chicago * * 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. * * Author: Daniel Yu <danielyu@uchicago.edu> */ package edu.uchicago.duo.service; import com.duosecurity.client.Http; import edu.uchicago.duo.domain.DuoAllIntegrationKeys; import edu.uchicago.duo.domain.DuoPhone; import edu.uchicago.duo.domain.DuoTablet; import edu.uchicago.duo.domain.DuoToken; import edu.uchicago.duo.web.DuoEnrollController; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.Future; import org.apache.log4j.Logger; import org.json.JSONArray; import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; @Service("duoPhoneService") public class DuoPhoneObjImpl implements DuoObjInterface { //get log4j handler private static final Logger logger = Logger.getLogger(DuoEnrollController.class); private static final String duoPhoneApi = "/admin/v1/phones"; private static final String duoUserApi = "/admin/v1/users"; private static final String duoVerifyApi = "/verify/v1"; private String apiURL; private Http request = null; @Autowired(required = true) private DuoAllIntegrationKeys duoAllIKeys; private JSONObject jResult = null; private JSONArray jResults = null; @Autowired private MessageSource message; @Override public String getObjByParam(String phoneNumber, String landLineExtension, String attribute) { String returnObj = null; request = genHttpRequest("GET", duoPhoneApi, "admin"); request.addParam("number", phoneNumber); if (StringUtils.hasLength(landLineExtension)) { request.addParam("extension", landLineExtension); } request = signHttpRequest("admin"); try { jResults = (JSONArray) request.executeRequest(); switch (attribute) { case "username": JSONArray userproperty = jResults.getJSONObject(0).getJSONArray("users"); returnObj = userproperty.getJSONObject(0).getString("username"); break; } } catch (Exception ex) { logger.debug( "2FA Exception - " + "Phone Not Exist!!!If triggered by Validation is a good thing, not error"); logger.debug("2FA Exception - " + "The Error is: " + ex.toString()); } return returnObj; } @Override public String createObjByParam(String phoneNumber, String device, String deviceOS, String tabletName, String landLineExtension) { String phoneID = null; request = genHttpRequest("POST", duoPhoneApi, "admin"); if (device.equals("mobile")) { request.addParam("number", phoneNumber); request.addParam("type", device); request.addParam("platform", deviceOS); } if (device.equals("tablet")) { request.addParam("type", "mobile"); request.addParam("platform", deviceOS); request.addParam("name", tabletName); } if (device.equals("landline")) { request.addParam("number", phoneNumber); request.addParam("type", "landline"); if (StringUtils.hasLength(landLineExtension)) { request.addParam("extension", landLineExtension); request.addParam("postdelay", "6"); } } request = signHttpRequest("admin"); try { jResult = (JSONObject) request.executeRequest(); phoneID = jResult.getString("phone_id"); logger.debug("2FA Debug - " + "Successfully Created Phone, Type:" + device + "/Number:" + phoneNumber); } catch (Exception ex) { logger.error("2FA Error - " + "Unable to Create Duo Phone Object!!!!, Number:" + phoneNumber); logger.error("2FA Error - " + "The Error is(PhoneObjImp): " + ex.toString()); } return phoneID; } @Override @Async public String getObjStatusById(String phoneId) { String status = "false"; apiURL = new String(); jResult = null; apiURL = duoPhoneApi + '/' + phoneId; request = genHttpRequest("GET", apiURL, "admin"); request = signHttpRequest("admin"); try { jResult = (JSONObject) request.executeRequest(); if (jResult.getBoolean("activated")) { status = "true"; } } catch (Exception ex) { } return status; } @Override public void associateObjs(String userId, String phoneId) { apiURL = new String(); apiURL = duoUserApi + "/" + userId + "/phones"; request = genHttpRequest("POST", apiURL, "admin"); request.addParam("phone_id", phoneId); request = signHttpRequest("admin"); try { request.executeRequest(); logger.debug("2FA Debug - " + "Successfully Linked Phone/Tablet to User account"); } catch (Exception ex) { logger.error("2FA Error - " + "Unable to Link Phone/Tablet to User account!!!!"); logger.error("2FA Error - " + "The Error is(PhoneObjImp): " + ex.toString()); } } @Override public String objActionById(String phoneId, String action) { String actionResult = null; apiURL = new String(); jResult = null; switch (action) { case "qrCode": apiURL = duoPhoneApi + "/" + phoneId + "/activation_url"; break; case "activationSMS": apiURL = duoPhoneApi + "/" + phoneId + "/send_sms_activation"; break; case "installUrlSMS": apiURL = duoPhoneApi + "/" + phoneId + "/send_sms_installation"; break; case "passcodeSMS": apiURL = duoPhoneApi + "/" + phoneId + "/send_sms_passcodes"; break; } request = genHttpRequest("POST", apiURL, "admin"); switch (action) { case "activationSMS": request.addParam("activation_msg", message.getMessage("SMS.Device.Activation", null, Locale.getDefault())); break; case "installUrlSMS": request.addParam("installation_msg", message.getMessage("SMS.Device.Installation", null, Locale.getDefault())); break; } request = signHttpRequest("admin"); try { switch (action) { case "activationSMS": jResult = (JSONObject) request.executeRequest(); actionResult = null; logger.debug("2FA Debug - " + "Activation SMS sent"); break; case "qrCode": jResult = (JSONObject) request.executeRequest(); actionResult = jResult.getString("activation_barcode"); logger.debug("2FA Debug - " + "Activation QR Code generated"); break; case "passcodeSMS": actionResult = (String) request.executeRequest(); logger.debug("2FA Debug - " + "SMS Passcode Sent Successfully"); break; case "installUrlSMS": jResult = (JSONObject) request.executeRequest(); actionResult = null; logger.debug("2FA Debug - " + "Installation SMS sent"); break; } } catch (Exception ex) { logger.error("2FA Error - " + "Object Action Failed for: " + action); logger.error("2FA Error - " + "The Error is(PhoneObjImp): " + ex.toString()); } return actionResult; } /** * Why use UserId instead of UserName?? * * 1)UserId always return SINGLE record, although Username search should * only have one record also... * * 2)The JSON Response code for userID search is either success or User not * found, easier to capture the exception? * * 3)Return a JSON object instead of JSON Array, safe one layer of parsing */ @Override public List<DuoPhone> getAllPhones(String userId) { apiURL = new String(); apiURL = duoUserApi + "/" + userId; request = genHttpRequest("GET", apiURL, "admin"); request = signHttpRequest("admin"); jResults = null; DuoPhone duoPhone; JSONArray jPhones; List<DuoPhone> phones = new ArrayList<>(); String phoneNumber; int counter = 0; try { jResult = (JSONObject) request.executeRequest(); jPhones = jResult.getJSONArray("phones"); for (int p = 0; p < jPhones.length(); p++) { phoneNumber = jPhones.getJSONObject(p).getString("number"); if (phoneNumber != null && !phoneNumber.isEmpty()) { duoPhone = new DuoPhone(); duoPhone.setId(jPhones.getJSONObject(p).getString("phone_id")); duoPhone.setPhoneNumber(jPhones.getJSONObject(p).getString("number")); duoPhone.setPlatform(jPhones.getJSONObject(p).getString("platform")); duoPhone.setType(jPhones.getJSONObject(p).getString("type")); duoPhone.setActivationStatus(jPhones.getJSONObject(p).getBoolean("activated")); duoPhone.setSmsPassCodeSent(jPhones.getJSONObject(p).getBoolean("sms_passcodes_sent")); String capabilities = jPhones.getJSONObject(p).getJSONArray("capabilities").toString(); if (capabilities.toLowerCase().contains("push")) { duoPhone.setCapablePush(true); } if (capabilities.toLowerCase().contains("sms")) { duoPhone.setCapableSMS(true); } if (capabilities.toLowerCase().contains("phone")) { duoPhone.setCapablePhone(true); } phones.add(duoPhone); counter++; } } } catch (Exception ex) { logger.error("2FA Error - " + "Unable to Excute Method 'GetAllPhones'"); logger.error("2FA Error - " + "The Error is(PhoneObjImp): " + ex.toString()); } logger.debug("2FA Debug - " + "Total Number of Phones(DuoPhoneImp) " + userId + " has:" + counter); return phones; } @Override public void deleteObj(String phoneId, String na) { apiURL = new String(); apiURL = duoPhoneApi + "/" + phoneId; request = genHttpRequest("DELETE", apiURL, "admin"); request = signHttpRequest("admin"); try { request.executeRequest(); logger.debug("2FA Debug - " + "Successfully Deleted phone, ID=" + phoneId); } catch (Exception ex) { logger.error("2FA Error - " + "Unable to Delete Phone from Useraccount!!!"); logger.error("2FA Error - " + "The Error is(PhoneObjImp): " + ex.toString()); } } ////////////////////////////////////////////////////////////////////////////////////////////////////////// private Http genHttpRequest(String getOrPost, String apiURL, String apiType) { request = null; try { switch (apiType) { case "admin": request = new Http(getOrPost, duoAllIKeys.getAdminikeys().getHostkey(), apiURL); break; case "verify": request = new Http(getOrPost, duoAllIKeys.getVerifyikeys().getHostkey(), apiURL); break; } } catch (Exception e) { } return request; } private Http signHttpRequest(String apiType) { try { switch (apiType) { case "admin": request.signRequest(duoAllIKeys.getAdminikeys().getIkey(), duoAllIKeys.getAdminikeys().getSkey()); break; case "verify": request.signRequest(duoAllIKeys.getVerifyikeys().getIkey(), duoAllIKeys.getVerifyikeys().getSkey()); break; } } catch (Exception e) { } return request; } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @Override public String getObjById() { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override public List<DuoTablet> getAllTablets(String param1) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override public List<DuoToken> getAllTokens(String param1) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } @Override public void resyncObj(String param1, String param2, String param3, String param4) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @Override @Async public Map<String, Object> verifyObj(String pNumber, String ext, String action) { String txid = null; String pin = null; String info = null; String state = null; jResult = null; Map<String, Object> verifyInfo = new HashMap<>(); apiURL = new String(); apiURL = duoVerifyApi + "/" + action; switch (action) { case "call": request = genHttpRequest("POST", apiURL, "verify"); request.addParam("phone", pNumber); if (StringUtils.hasLength(ext)) { request.addParam("extension", ext); request.addParam("postdelay", "6"); } request.addParam("message", message.getMessage("CALL.Device.Verify", null, Locale.getDefault())); break; case "status": request = genHttpRequest("GET", apiURL, "verify"); request.addParam("txid", pNumber); break; } request = signHttpRequest("verify"); try { jResult = (JSONObject) request.executeRequest(); switch (action) { case "call": txid = jResult.getString("txid"); pin = jResult.getString("pin"); verifyInfo.put("txid", txid); verifyInfo.put("pin", pin); logger.debug("2FA Debug - " + "DuoPhoneService.verifyObj:" + "txid=" + txid + ",Pin=" + pin); break; case "status": info = jResult.getString("info"); state = jResult.getString("state"); verifyInfo.put("info", info); verifyInfo.put("state", state); break; } } catch (Exception ex) { logger.error("2FA Error - " + "Unable to Call Phone!!!"); logger.error("2FA Error - " + "The Error is(PhoneObjImp): " + ex.toString()); } return verifyInfo; } }