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 089 public void startAuthentication(Application application) { 090 this.endpoint = idpUrl + "/rest/4/startauthentication/do"; 091 JSONObject reqBody = new JSONObject(); 092 reqBody.put("spAlias", application.getSpAlias()); 093 reqBody.put("username", this.getUser().getUserName()); 094 reqBody.put("deviceId", null); 095 reqBody.put("sessionId", null); 096 reqBody.put("clientData", null); 097 098 JSONObject formParameters = new JSONObject(); 099 formParameters.put("sp_name", application.getName()); 100 if (application.getLogoUrl() != null && !application.getLogoUrl().isEmpty()) { 101 formParameters.put("sp_logo", application.getLogoUrl()); 102 } 103 104 reqBody.put("formParameters", formParameters); 105 106 this.requestToken = buildRequestToken(reqBody); 107 108 sendRequest(); 109 JSONObject response = parseResponse(); 110 111 if (this.wasSuccessful) { 112 values.clear(); 113 this.lastSessionId = (String) response.get("sessionId"); 114 } 115 } 116 117 public void AuthenticateOnline(Application application, String authType) { 118 this.endpoint = idpUrl + "/rest/4/authonline/do"; 119 JSONObject reqBody = new JSONObject(); 120 reqBody.put("authType", authType); 121 reqBody.put("spAlias", application.getSpAlias()); 122 reqBody.put("userName", this.user.getUserName()); 123 reqBody.put("clientData", this.clientData); 124 125 JSONObject formParameters = new JSONObject(); 126 formParameters.put("sp_name", application.getName()); 127 if (application.getLogoUrl() != null && !application.getLogoUrl().isEmpty()) { 128 formParameters.put("sp_logo", application.getLogoUrl()); 129 } 130 131 reqBody.put("formParameters", formParameters); 132 133 this.requestToken = buildRequestToken(reqBody); 134 135 sendRequest(); 136 JSONObject response = parseResponse(); 137 138 if (this.wasSuccessful) { 139 values.clear(); 140 this.lastSessionId = (String) response.get("sessionId"); 141 } 142 } 143 144 public void AuthenticateOffline(String otp) { 145 this.endpoint = idpUrl + "/rest/4/authoffline/do"; 146 147 JSONObject reqBody = new JSONObject(); 148 reqBody.put("spAlias", "web"); 149 reqBody.put("otp", otp); 150 reqBody.put("userName", this.user.getUserName()); 151 reqBody.put("sessionId", this.lastSessionId); 152 reqBody.put("clientData", this.clientData); 153 154 this.requestToken = buildRequestToken(reqBody); 155 156 sendRequest(); 157 parseResponse(); 158 values.clear(); 159 } 160 161 private String buildRequestToken(JSONObject requestBody) { 162 JSONObject requestHeader = buildRequestHeader(); 163 164 JSONObject payload = new JSONObject(); 165 payload.put("reqHeader", requestHeader); 166 payload.put("reqBody", requestBody); 167 168 JsonWebSignature jws = new JsonWebSignature(); 169 170 jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256); 171 jws.setHeader("org_alias", this.orgAlias); 172 jws.setHeader("token", this.token); 173 174 jws.setPayload(payload.toJSONString()); 175 176 // Set the verification key 177 HmacKey key = new HmacKey(Base64.decode(this.useBase64Key)); 178 jws.setKey(key); 179 180 String jwsCompactSerialization = null; 181 try { 182 jwsCompactSerialization = jws.getCompactSerialization(); 183 } catch (JoseException e) { 184 e.printStackTrace(); 185 } 186 187 this.requestToken = jwsCompactSerialization; 188 189 return jwsCompactSerialization; 190 } 191 192 private JSONObject buildRequestHeader() { 193 JSONObject reqHeader = new JSONObject(); 194 reqHeader.put("locale", "en"); 195 reqHeader.put("orgAlias", this.orgAlias); 196 reqHeader.put("secretKey", this.token); 197 reqHeader.put("timestamp", getCurrentTimeStamp()); 198 reqHeader.put("version", this.apiVersion); 199 200 return reqHeader; 201 } 202 203 static String getCurrentTimeStamp() { 204 Date currentDate = new Date(); 205 SimpleDateFormat PingIDDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 206 PingIDDateFormat.setTimeZone(TimeZone.getTimeZone("America/Denver")); 207 208 return PingIDDateFormat.format(currentDate); 209 } 210 211 private void sendRequest() { 212 try { 213 URL restUrl = new URL(this.getEndpoint()); 214 HttpURLConnection urlConnection = (HttpURLConnection) restUrl.openConnection(); 215 urlConnection.setRequestMethod("POST"); 216 urlConnection.addRequestProperty("Content-Type", "application/json"); 217 urlConnection.addRequestProperty("Accept", "*/*"); 218 219 urlConnection.setDoOutput(true); 220 OutputStreamWriter outputStreamWriter = new OutputStreamWriter(urlConnection.getOutputStream(), "UTF-8"); 221 outputStreamWriter.write(this.getRequestToken()); 222 outputStreamWriter.flush(); 223 outputStreamWriter.close(); 224 225 int responseCode = urlConnection.getResponseCode(); 226 this.responseCode = responseCode; 227 228 if (responseCode == 200) { 229 230 String encoding = urlConnection.getContentEncoding(); 231 InputStream is = urlConnection.getInputStream(); 232 String stringJWS = IOUtils.toString(is, encoding); 233 this.responseToken = stringJWS; 234 this.wasSuccessful = true; 235 236 urlConnection.disconnect(); 237 } else { 238 239 String encoding = urlConnection.getContentEncoding(); 240 InputStream is = urlConnection.getErrorStream(); 241 String stringJWS = IOUtils.toString(is, encoding); 242 this.responseToken = stringJWS; 243 this.wasSuccessful = false; 244 245 urlConnection.disconnect(); 246 } 247 } catch (Exception ex) { 248 this.responseCode = 500; 249 this.wasSuccessful = false; 250 } 251 } 252 253 private JSONObject parseResponse() { 254 JSONParser parser = new JSONParser(); 255 JSONObject responsePayloadJSON = null; 256 257 try { 258 JsonWebSignature responseJWS = new JsonWebSignature(); 259 responseJWS.setCompactSerialization(this.responseToken); 260 HmacKey key = new HmacKey(Base64.decode(this.useBase64Key)); 261 responseJWS.setKey(key); 262 responsePayloadJSON = (JSONObject) parser.parse(responseJWS.getPayload()); 263 264 // workaround for PingID API 4.5 beta 265 if (responsePayloadJSON.containsKey("responseBody")) { 266 responsePayloadJSON = (JSONObject) responsePayloadJSON.get("responseBody"); 267 } 268 269 } catch (Exception e) { 270 e.printStackTrace(); 271 } 272 273 if (responsePayloadJSON != null) { 274 this.errorId = (long) responsePayloadJSON.get("errorId"); 275 this.errorMsg = (String) responsePayloadJSON.get("errorMsg"); 276 this.uniqueMsgId = (String) responsePayloadJSON.get("uniqueMsgId"); 277 this.clientData = (String) responsePayloadJSON.get("clientData"); 278 } else { 279 this.errorId = 501; 280 this.errorMsg = "Could not parse JWS"; 281 this.uniqueMsgId = ""; 282 this.clientData = ""; 283 this.wasSuccessful = false; 284 } 285 286 return responsePayloadJSON; 287 } 288}