001package com.pingidentity.developer.pingid; 002 003 004import org.apache.commons.io.IOUtils; 005import org.jose4j.base64url.Base64; 006import org.jose4j.json.internal.json_simple.JSONObject; 007import org.jose4j.json.internal.json_simple.parser.JSONParser; 008import org.jose4j.jws.AlgorithmIdentifiers; 009import org.jose4j.jws.JsonWebSignature; 010import org.jose4j.keys.HmacKey; 011import org.jose4j.lang.JoseException; 012 013import java.io.InputStream; 014import java.io.OutputStreamWriter; 015import java.net.HttpURLConnection; 016import java.net.URL; 017import java.text.SimpleDateFormat; 018import java.util.Date; 019import java.util.HashMap; 020import java.util.Map; 021import java.util.TimeZone; 022 023 024public class Operation { 025 026 private String endpoint; 027 private String requestToken; 028 private String responseToken; 029 private int responseCode; 030 private Boolean wasSuccessful; 031 032 private long errorId; 033 private String errorMsg; 034 private String uniqueMsgId; 035 036 private String idpUrl; 037 private String orgAlias; 038 private String token; 039 private String useBase64Key; 040 041 private String lastSessionId; 042 043 private Map<String, Object> values; 044 045 private String clientData; 046 private User user; 047 048 private final String apiVersion = "4.6"; 049 050 051 public Operation(String orgAlias, String token, String useBase64Key, String pingidUrl) { 052 this.orgAlias = orgAlias; 053 this.token = token; 054 this.useBase64Key = useBase64Key; 055 this.idpUrl = pingidUrl; 056 057 this.values = new HashMap<>(); 058 } 059 060 public Operation(Operation operation) { 061 this(operation.orgAlias, operation.token, operation.useBase64Key, operation.idpUrl); 062 } 063 064 public String getEndpoint() { 065 return endpoint; 066 } 067 068 public String getRequestToken() { 069 return requestToken; 070 } 071 072 public Boolean getWasSuccessful() { 073 return wasSuccessful; 074 } 075 076 public String getErrorMsg() { 077 return responseCode + " - " + errorId + " - " + errorMsg; 078 } 079 080 public User getUser() { 081 return user; 082 } 083 084 public void setTargetUser(String username) { 085 this.user = new User(username); 086 } 087 088 public void setClientData(final String clientData) { 089 this.clientData = clientData; 090 } 091 092 public void startAuthentication(Application application) { 093 this.endpoint = idpUrl + "/rest/4/startauthentication/do"; 094 JSONObject reqBody = new JSONObject(); 095 reqBody.put("spAlias", application.getSpAlias()); 096 reqBody.put("username", this.getUser().getUserName()); 097 reqBody.put("deviceId", null); 098 reqBody.put("sessionId", null); 099 reqBody.put("clientData", null); 100 101 JSONObject formParameters = new JSONObject(); 102 formParameters.put("sp_name", application.getName()); 103 if (application.getLogoUrl() != null && !application.getLogoUrl().isEmpty()) { 104 formParameters.put("sp_logo", application.getLogoUrl()); 105 } 106 107 reqBody.put("formParameters", formParameters); 108 109 this.requestToken = buildRequestToken(reqBody); 110 111 sendRequest(); 112 JSONObject response = parseResponse(); 113 114 if (this.wasSuccessful) { 115 values.clear(); 116 this.lastSessionId = (String) response.get("sessionId"); 117 } 118 } 119 120 public void AuthenticateOnline(Application application, String authType) { 121 this.endpoint = idpUrl + "/rest/4/authonline/do"; 122 JSONObject reqBody = new JSONObject(); 123 reqBody.put("authType", authType); 124 reqBody.put("spAlias", application.getSpAlias()); 125 reqBody.put("userName", this.user.getUserName()); 126 reqBody.put("clientData", this.clientData); 127 128 JSONObject formParameters = new JSONObject(); 129 formParameters.put("sp_name", application.getName()); 130 if (application.getLogoUrl() != null && !application.getLogoUrl().isEmpty()) { 131 formParameters.put("sp_logo", application.getLogoUrl()); 132 } 133 134 reqBody.put("formParameters", formParameters); 135 136 this.requestToken = buildRequestToken(reqBody); 137 138 sendRequest(); 139 JSONObject response = parseResponse(); 140 141 if (this.wasSuccessful) { 142 values.clear(); 143 this.lastSessionId = (String) response.get("sessionId"); 144 } 145 } 146 147 public void AuthenticateOffline(String otp) { 148 this.endpoint = idpUrl + "/rest/4/authoffline/do"; 149 150 JSONObject reqBody = new JSONObject(); 151 reqBody.put("spAlias", "web"); 152 reqBody.put("otp", otp); 153 reqBody.put("userName", this.user.getUserName()); 154 reqBody.put("sessionId", this.lastSessionId); 155 reqBody.put("clientData", this.clientData); 156 157 this.requestToken = buildRequestToken(reqBody); 158 159 sendRequest(); 160 parseResponse(); 161 values.clear(); 162 } 163 164 private String buildRequestToken(JSONObject requestBody) { 165 JSONObject requestHeader = buildRequestHeader(); 166 167 JSONObject payload = new JSONObject(); 168 payload.put("reqHeader", requestHeader); 169 payload.put("reqBody", requestBody); 170 171 JsonWebSignature jws = new JsonWebSignature(); 172 173 jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256); 174 jws.setHeader("org_alias", this.orgAlias); 175 jws.setHeader("token", this.token); 176 177 jws.setPayload(payload.toJSONString()); 178 179 // Set the verification key 180 HmacKey key = new HmacKey(Base64.decode(this.useBase64Key)); 181 jws.setKey(key); 182 183 String jwsCompactSerialization = null; 184 try { 185 jwsCompactSerialization = jws.getCompactSerialization(); 186 } catch (JoseException e) { 187 e.printStackTrace(); 188 } 189 190 this.requestToken = jwsCompactSerialization; 191 192 return jwsCompactSerialization; 193 } 194 195 private JSONObject buildRequestHeader() { 196 JSONObject reqHeader = new JSONObject(); 197 reqHeader.put("locale", "en"); 198 reqHeader.put("orgAlias", this.orgAlias); 199 reqHeader.put("secretKey", this.token); 200 reqHeader.put("timestamp", getCurrentTimeStamp()); 201 reqHeader.put("version", this.apiVersion); 202 203 return reqHeader; 204 } 205 206 static String getCurrentTimeStamp() { 207 Date currentDate = new Date(); 208 SimpleDateFormat PingIDDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 209 PingIDDateFormat.setTimeZone(TimeZone.getTimeZone("America/Denver")); 210 211 return PingIDDateFormat.format(currentDate); 212 } 213 214 private void sendRequest() { 215 try { 216 URL restUrl = new URL(this.getEndpoint()); 217 HttpURLConnection urlConnection = (HttpURLConnection) restUrl.openConnection(); 218 urlConnection.setRequestMethod("POST"); 219 urlConnection.addRequestProperty("Content-Type", "application/json"); 220 urlConnection.addRequestProperty("Accept", "*/*"); 221 222 urlConnection.setDoOutput(true); 223 OutputStreamWriter outputStreamWriter = new OutputStreamWriter(urlConnection.getOutputStream(), "UTF-8"); 224 outputStreamWriter.write(this.getRequestToken()); 225 outputStreamWriter.flush(); 226 outputStreamWriter.close(); 227 228 int responseCode = urlConnection.getResponseCode(); 229 this.responseCode = responseCode; 230 231 if (responseCode == 200) { 232 233 String encoding = urlConnection.getContentEncoding(); 234 InputStream is = urlConnection.getInputStream(); 235 String stringJWS = IOUtils.toString(is, encoding); 236 this.responseToken = stringJWS; 237 this.wasSuccessful = true; 238 239 urlConnection.disconnect(); 240 } else { 241 242 String encoding = urlConnection.getContentEncoding(); 243 InputStream is = urlConnection.getErrorStream(); 244 String stringJWS = IOUtils.toString(is, encoding); 245 this.responseToken = stringJWS; 246 this.wasSuccessful = false; 247 248 urlConnection.disconnect(); 249 } 250 } catch (Exception ex) { 251 this.responseCode = 500; 252 this.wasSuccessful = false; 253 } 254 } 255 256 private JSONObject parseResponse() { 257 JSONParser parser = new JSONParser(); 258 JSONObject responsePayloadJSON = null; 259 260 try { 261 JsonWebSignature responseJWS = new JsonWebSignature(); 262 responseJWS.setCompactSerialization(this.responseToken); 263 HmacKey key = new HmacKey(Base64.decode(this.useBase64Key)); 264 responseJWS.setKey(key); 265 responsePayloadJSON = (JSONObject) parser.parse(responseJWS.getPayload()); 266 267 // workaround for PingID API 4.5 beta 268 if (responsePayloadJSON.containsKey("responseBody")) { 269 responsePayloadJSON = (JSONObject) responsePayloadJSON.get("responseBody"); 270 } 271 272 } catch (Exception e) { 273 e.printStackTrace(); 274 } 275 276 if (responsePayloadJSON != null) { 277 this.errorId = (long) responsePayloadJSON.get("errorId"); 278 this.errorMsg = (String) responsePayloadJSON.get("errorMsg"); 279 this.uniqueMsgId = (String) responsePayloadJSON.get("uniqueMsgId"); 280 this.clientData = (String) responsePayloadJSON.get("clientData"); 281 } else { 282 this.errorId = 501; 283 this.errorMsg = "Could not parse JWS"; 284 this.uniqueMsgId = ""; 285 this.clientData = ""; 286 this.wasSuccessful = false; 287 } 288 289 return responsePayloadJSON; 290 } 291}