diff --git a/pom.xml b/pom.xml index 8269c270..f4ba567a 100644 --- a/pom.xml +++ b/pom.xml @@ -173,6 +173,20 @@ test + + org.testng + testng + 6.14.3 + test + + + + org.jmockit + jmockit + 1.46 + test + + org.spockframework spock-core diff --git a/src/main/java/com/bullhornsdk/data/api/BullhornRestCredentials.java b/src/main/java/com/bullhornsdk/data/api/BullhornRestCredentials.java index b9127e92..0a674ac3 100644 --- a/src/main/java/com/bullhornsdk/data/api/BullhornRestCredentials.java +++ b/src/main/java/com/bullhornsdk/data/api/BullhornRestCredentials.java @@ -1,176 +1,215 @@ package com.bullhornsdk.data.api; +import org.apache.commons.lang3.StringUtils; + public class BullhornRestCredentials { - private String username; + //set restUrl and bhRestToken for validation of credential-less login + private String restUrl; + + private String bhRestToken; + + private String username; + + private String password; + + private String restTokenUrl; + + private String restClientId; + + private String restClientSecret; + + private String restLoginUrl; + + private String restSessionMinutesToLive; + + private String restAuthorizeUrl; - private String password; + public String getBhRestToken() { + return bhRestToken; + } - private String restTokenUrl; + public void setBhRestToken(String bhRestToken) { + this.bhRestToken = bhRestToken; + } - private String restClientId; - - private String restClientSecret; - - private String restLoginUrl; - - private String restSessionMinutesToLive; - - private String restAuthorizeUrl; - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getRestTokenUrl() { - return restTokenUrl; - } - - public void setRestTokenUrl(String restTokenUrl) { - this.restTokenUrl = restTokenUrl; - } - - public String getRestClientId() { - return restClientId; - } - - public void setRestClientId(String restClientId) { - this.restClientId = restClientId; - } - - public String getRestClientSecret() { - return restClientSecret; - } - - public void setRestClientSecret(String restClientSecret) { - this.restClientSecret = restClientSecret; - } - - public String getRestLoginUrl() { - return restLoginUrl; - } - - public void setRestLoginUrl(String restLoginUrl) { - this.restLoginUrl = restLoginUrl; - } - - public String getRestSessionMinutesToLive() { - return restSessionMinutesToLive; - } - - public void setRestSessionMinutesToLive(String restSessionMinutesToLive) { - this.restSessionMinutesToLive = restSessionMinutesToLive; - } - - public String getRestAuthorizeUrl() { - return restAuthorizeUrl; - } - - public void setRestAuthorizeUrl(String restAuthorizeUrl) { - this.restAuthorizeUrl = restAuthorizeUrl; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((password == null) ? 0 : password.hashCode()); - result = prime * result + ((restAuthorizeUrl == null) ? 0 : restAuthorizeUrl.hashCode()); - result = prime * result + ((restClientId == null) ? 0 : restClientId.hashCode()); - result = prime * result + ((restClientSecret == null) ? 0 : restClientSecret.hashCode()); - result = prime * result + ((restLoginUrl == null) ? 0 : restLoginUrl.hashCode()); - result = prime * result + ((restSessionMinutesToLive == null) ? 0 : restSessionMinutesToLive.hashCode()); - result = prime * result + ((restTokenUrl == null) ? 0 : restTokenUrl.hashCode()); - result = prime * result + ((username == null) ? 0 : username.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - BullhornRestCredentials other = (BullhornRestCredentials) obj; - if (password == null) { - if (other.password != null) - return false; - } else if (!password.equals(other.password)) - return false; - if (restAuthorizeUrl == null) { - if (other.restAuthorizeUrl != null) - return false; - } else if (!restAuthorizeUrl.equals(other.restAuthorizeUrl)) - return false; - if (restClientId == null) { - if (other.restClientId != null) - return false; - } else if (!restClientId.equals(other.restClientId)) - return false; - if (restClientSecret == null) { - if (other.restClientSecret != null) - return false; - } else if (!restClientSecret.equals(other.restClientSecret)) - return false; - if (restLoginUrl == null) { - if (other.restLoginUrl != null) - return false; - } else if (!restLoginUrl.equals(other.restLoginUrl)) - return false; - if (restSessionMinutesToLive == null) { - if (other.restSessionMinutesToLive != null) - return false; - } else if (!restSessionMinutesToLive.equals(other.restSessionMinutesToLive)) - return false; - if (restTokenUrl == null) { - if (other.restTokenUrl != null) - return false; - } else if (!restTokenUrl.equals(other.restTokenUrl)) - return false; - if (username == null) { - if (other.username != null) - return false; - } else if (!username.equals(other.username)) - return false; - return true; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(getClass().getName()); - builder.append(" {\n\tusername: "); - builder.append(username); - builder.append("\n\tpassword: "); - builder.append(password); - builder.append("\n\trestTokenUrl: "); - builder.append(restTokenUrl); - builder.append("\n\trestClientId: "); - builder.append(restClientId); - builder.append("\n\trestClientSecret: "); - builder.append(restClientSecret); - builder.append("\n\trestLoginUrl: "); - builder.append(restLoginUrl); - builder.append("\n\trestSessionMinutesToLive: "); - builder.append(restSessionMinutesToLive); - builder.append("\n\trestAuthorizeUrl: "); - builder.append(restAuthorizeUrl); - builder.append("\n}"); - return builder.toString(); - } + public String getRestUrl() { + return restUrl; + } + + public void setRestUrl(String restUrl) { + this.restUrl = restUrl; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getRestTokenUrl() { + return restTokenUrl; + } + + public void setRestTokenUrl(String restTokenUrl) { + this.restTokenUrl = restTokenUrl; + } + + public String getRestClientId() { + return restClientId; + } + + public void setRestClientId(String restClientId) { + this.restClientId = restClientId; + } + + public String getRestClientSecret() { + return restClientSecret; + } + + public void setRestClientSecret(String restClientSecret) { + this.restClientSecret = restClientSecret; + } + + public String getRestLoginUrl() { + return restLoginUrl; + } + + public void setRestLoginUrl(String restLoginUrl) { + this.restLoginUrl = restLoginUrl; + } + + public String getRestSessionMinutesToLive() { + return restSessionMinutesToLive; + } + + public void setRestSessionMinutesToLive(String restSessionMinutesToLive) { + this.restSessionMinutesToLive = restSessionMinutesToLive; + } + + public String getRestAuthorizeUrl() { + return restAuthorizeUrl; + } + + public void setRestAuthorizeUrl(String restAuthorizeUrl) { + this.restAuthorizeUrl = restAuthorizeUrl; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((bhRestToken == null) ? 0 : bhRestToken.hashCode()); + result = prime * result + ((restUrl == null) ? 0 : restUrl.hashCode()); + result = prime * result + ((password == null) ? 0 : password.hashCode()); + result = prime * result + ((restAuthorizeUrl == null) ? 0 : restAuthorizeUrl.hashCode()); + result = prime * result + ((restClientId == null) ? 0 : restClientId.hashCode()); + result = prime * result + ((restClientSecret == null) ? 0 : restClientSecret.hashCode()); + result = prime * result + ((restLoginUrl == null) ? 0 : restLoginUrl.hashCode()); + result = prime * result + ((restSessionMinutesToLive == null) ? 0 : restSessionMinutesToLive.hashCode()); + result = prime * result + ((restTokenUrl == null) ? 0 : restTokenUrl.hashCode()); + result = prime * result + ((username == null) ? 0 : username.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + BullhornRestCredentials other = (BullhornRestCredentials) obj; + if (bhRestToken == null) { + if (other.bhRestToken != null) + return false; + } else if (!bhRestToken.equals(other.bhRestToken)) + return false; + if (restUrl == null) { + if (other.restUrl != null) + return false; + } else if (!restUrl.equals(other.restUrl)) + return false; + if (password == null) { + if (other.password != null) + return false; + } else if (!password.equals(other.password)) + return false; + if (restAuthorizeUrl == null) { + if (other.restAuthorizeUrl != null) + return false; + } else if (!restAuthorizeUrl.equals(other.restAuthorizeUrl)) + return false; + if (restClientId == null) { + if (other.restClientId != null) + return false; + } else if (!restClientId.equals(other.restClientId)) + return false; + if (restClientSecret == null) { + if (other.restClientSecret != null) + return false; + } else if (!restClientSecret.equals(other.restClientSecret)) + return false; + if (restLoginUrl == null) { + if (other.restLoginUrl != null) + return false; + } else if (!restLoginUrl.equals(other.restLoginUrl)) + return false; + if (restSessionMinutesToLive == null) { + if (other.restSessionMinutesToLive != null) + return false; + } else if (!restSessionMinutesToLive.equals(other.restSessionMinutesToLive)) + return false; + if (restTokenUrl == null) { + if (other.restTokenUrl != null) + return false; + } else if (!restTokenUrl.equals(other.restTokenUrl)) + return false; + if (username == null) { + if (other.username != null) + return false; + } else if (!username.equals(other.username)) + return false; + return true; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(getClass().getName()); + builder.append(" {\n\tusername: "); + builder.append(username); + builder.append("\n\tpassword: "); + builder.append(password); + builder.append("\n\tbhRestToken: "); + builder.append(bhRestToken); + builder.append("\n\trestUrl: "); + builder.append(restUrl); + builder.append("\n\trestTokenUrl: "); + builder.append(restTokenUrl); + builder.append("\n\trestClientId: "); + builder.append(restClientId); + builder.append("\n\trestClientSecret: "); + builder.append(restClientSecret); + builder.append("\n\trestLoginUrl: "); + builder.append(restLoginUrl); + builder.append("\n\trestSessionMinutesToLive: "); + builder.append(restSessionMinutesToLive); + builder.append("\n\trestAuthorizeUrl: "); + builder.append(restAuthorizeUrl); + builder.append("\n}"); + return builder.toString(); + } } diff --git a/src/main/java/com/bullhornsdk/data/api/helper/RestApiSession.java b/src/main/java/com/bullhornsdk/data/api/helper/RestApiSession.java index 902cd6b1..8dc7a221 100644 --- a/src/main/java/com/bullhornsdk/data/api/helper/RestApiSession.java +++ b/src/main/java/com/bullhornsdk/data/api/helper/RestApiSession.java @@ -11,6 +11,7 @@ import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; @@ -26,302 +27,314 @@ /** * Wraps rest api session management. - * + * * @author Yaniv Or-Shahar * @author Magnus Fiore Palm - * */ @JsonIgnoreProperties({"sessionExpired"}) public class RestApiSession { - private static final String AUTH_CODE_ACTION = "Login"; - - private static final String AUTH_CODE_RESPONSE_TYPE = "code"; - - private static final String ACCESS_TOKEN_GRANT_TYPE = "authorization_code"; - - private static final String REFRESH_TOKEN_GRANT_TYPE = "refresh_token"; - - private static Logger log = Logger.getLogger(RestApiSession.class); - - private RestTemplate restTemplate; - - private final BullhornRestCredentials restCredentials; - - private AccessTokenInfo accessTokenInfo; - - private String bhRestToken; - - private String restUrl; - - private String version = "*"; - - private DateTime dateTimeBhRestTokenWillExpire; - - private static int SESSION_RETRY = 3; - - public final static int MAX_TTL = 2880; - - /** - * It is expected that the final members below are not used - * (unlike another constructor that takes RestCredentials) - */ - public RestApiSession() { - this.restCredentials = null; - } - - /** - * This factory method is used when deserializing from JSON. - * It guarantees that "bullhornRestCredentials" property gets assigned first, - * ensuring no NullPointerException when other setters are trying to access it, - * e.g. setBhRestToken->updateDateTimeBhRestTokenWillExpire - */ - @JsonCreator - public static RestApiSession create(@JsonProperty("bullhornRestCredentials") BullhornRestCredentials bullhornRestCredentials) { - return new RestApiSession(bullhornRestCredentials); - } - - public RestApiSession(BullhornRestCredentials bullhornRestCredentials) { - this.restCredentials = bullhornRestCredentials; - this.restTemplate = RestTemplateFactory.getInstance(); - this.dateTimeBhRestTokenWillExpire = getNow(); - createSession(); - } - - /** - * Returns the BhRestToken to be used when making rest api calls. - * - * Wraps all session management, such as renewal etc. - * - * @return - * @throws RestApiException - */ - public String getBhRestToken() throws RestApiException { - - if (isSessionExpired()) { - createSession(); - } - - return bhRestToken; - } - - /** - * Refreshes the BhRestToken, expired or not expired, and returns the brand new BhRestToken to be used when making rest api calls. - * - * Wraps all session management, such as renewal etc. - * - * @return - * @throws RestApiException - */ - public String refreshBhRestToken() throws RestApiException { - - createSession(); - - return bhRestToken; - } - - private void createSession() { - for (int tryNumber = 1; tryNumber <= SESSION_RETRY; tryNumber++) { - try { - String authCode = getAuthorizationCode(); - getAccessToken(authCode); - login(); - break; - } catch (Exception e) { - - if (tryNumber < SESSION_RETRY) { - log.error("Error creating REST session. Try number: " + tryNumber + " out of " + SESSION_RETRY + " trying again.", e); - } else { - log.error("Final error creating REST session. Shutting down.", e); - throw new RestApiException("Failed to create rest session", e); - } - } - } - } - - private String getAuthorizationCode() throws RestApiException { - String authorizeUrl = restCredentials.getRestAuthorizeUrl(); - String clientId = restCredentials.getRestClientId(); - String username = getUserName(); - String password = getPassword(); - String authCode = null; - - String url = authorizeUrl - + "?client_id={clientId}&response_type={responseType}&action={action}&username={username}&password={password}"; - - Map vars = new LinkedHashMap(); - vars.put("clientId", clientId); - vars.put("responseType", AUTH_CODE_RESPONSE_TYPE); - vars.put("action", AUTH_CODE_ACTION); - vars.put("username", username); - vars.put("password", password); - - try { - URI uri = restTemplate.postForLocation(url, null, vars); - - authCode = getAuthCode(uri); - } catch (Exception e) { - log.error("Failed to get authorization code.", e); - throw new RestApiException("Failed to get authorization code.", e); - } - - return authCode; - } - - /** - * restCredentials will only be used in case of multi-tenant app. If not default to username in appSettings. - * - * @return - */ - private String getUserName() { - return restCredentials.getUsername(); - } - - /** - * restCredentials will only be used in case of multi-tenant app. If not default to password in appSettings. - * - * @return - */ - private String getPassword() { - return restCredentials.getPassword(); - } - - // query: code=###&client_id= - private String getAuthCode(URI uri) { - String query = uri.getQuery(); - Map map = Splitter.on("&").trimResults().withKeyValueSeparator('=').split(query); - return map.get("code"); - } - - private void getAccessToken(String authCode) throws RestApiException { - String tokenUrl = restCredentials.getRestTokenUrl(); - String clientId = restCredentials.getRestClientId(); - String clientSecret = restCredentials.getRestClientSecret(); - - String url = tokenUrl + "?grant_type={grantType}&code={authCode}&client_id={clientId}&client_secret={clientSecret}"; - - Map vars = new LinkedHashMap(); - vars.put("grantType", ACCESS_TOKEN_GRANT_TYPE); - vars.put("authCode", authCode); - vars.put("clientId", clientId); - vars.put("clientSecret", clientSecret); - - try { - // String test = restTemplate.postForObject(url, null, String.class, vars); - accessTokenInfo = restTemplate.postForObject(url, null, AccessTokenInfo.class, vars); - } catch (Exception e) { - log.error("Failed to get access token.", e); - throw new RestApiException("Failed to get access token.", e); - } - } - - private void login() { - - JSONObject responseJson = null; - try { - String accessTokenString = URLEncoder.encode(accessTokenInfo.getAccessToken(), "UTF-8"); - String loginUrl = restCredentials.getRestLoginUrl(); - String sessionMinutesToLive = restCredentials.getRestSessionMinutesToLive(); - String url = loginUrl + "?version=" + version + "&access_token=" + accessTokenString + "&ttl=" + sessionMinutesToLive; - GetMethod get = new GetMethod(url); - - HttpClient client = new HttpClient(); - client.executeMethod(get); - - String responseStr = streamToString(get.getResponseBodyAsStream()); - responseJson = new JSONObject(responseStr); - - String localBhRestToken = responseJson.getString("BhRestToken"); - this.setBhRestToken(localBhRestToken); - - restUrl = (String) responseJson.get("restUrl"); - } catch (Exception e) { - log.error("Failed to login. " + responseJson, e); - throw new RestApiException("Failed to login and get BhRestToken: " + responseJson); - - } - } - - private String streamToString(InputStream inputStream) throws IOException { - StringWriter writer = new StringWriter(); - IOUtils.copy(inputStream, writer, "UTF-8"); - return writer.toString(); - - } - - /** - * Check if the DateTime dateTimeBhRestTokenWillExpire in this class is expired. - * - * Pinging every time will decrease performance. - * - * @return - * @throws RestApiException - */ - public boolean isSessionExpired() throws RestApiException { - boolean sessionExpired = false; - - if (bhRestTokenExpired()) { - // sessionExpired = ping(); - sessionExpired = true; - } - - return sessionExpired; - } - - /** - * Uses the DateTime in this class to calculate if the session is expired - * - * @return - */ - - private boolean bhRestTokenExpired() { - if (dateTimeBhRestTokenWillExpire.isBeforeNow()) { - return true; - } - return false; - - } - - public String getRestUrl() { - return restUrl; - } - - private synchronized void setBhRestToken(String bhRestToken) { - this.bhRestToken = bhRestToken; - - updateDateTimeBhRestTokenWillExpire(); - - } - - private void updateDateTimeBhRestTokenWillExpire() { - // set the DateTime the session will expire, subtracting one minute to be on the safe side. - DateTime timeToExpire = getNow(); - int sessionMinutesToLive = Integer.valueOf(restCredentials.getRestSessionMinutesToLive()); - if (sessionMinutesToLive > MAX_TTL) { - sessionMinutesToLive = MAX_TTL; - } - timeToExpire = timeToExpire.plusMinutes(sessionMinutesToLive - 1); - this.dateTimeBhRestTokenWillExpire = timeToExpire; - } - - private DateTime getNow() { - return new DateTime(DateTimeZone.forID("EST5EDT")); - } - - public DateTime getDateTimeBhRestTokenWillExpire() { - return dateTimeBhRestTokenWillExpire; - } - - public void setDateTimeBhRestTokenWillExpire(DateTime dateTimeBhRestTokenWillExpire) { - this.dateTimeBhRestTokenWillExpire = dateTimeBhRestTokenWillExpire; - } - - /** - * Will return the un-encrypted RestCredentials for this RestApiSession. Note that this is only needed for a multi-tenant solution - * - * @return a valid {@link RestCredentials} object if multi-tenant otherwise null - */ - public BullhornRestCredentials getRestCredentials() { - return restCredentials; - } + private static final String AUTH_CODE_ACTION = "Login"; + + private static final String AUTH_CODE_RESPONSE_TYPE = "code"; + + private static final String ACCESS_TOKEN_GRANT_TYPE = "authorization_code"; + + private static final String REFRESH_TOKEN_GRANT_TYPE = "refresh_token"; + + private static Logger log = Logger.getLogger(RestApiSession.class); + + private RestTemplate restTemplate; + + private final BullhornRestCredentials restCredentials; + + private AccessTokenInfo accessTokenInfo; + + private String bhRestToken; + + private String restUrl; + + private String version = "*"; + + private DateTime dateTimeBhRestTokenWillExpire; + + private static int SESSION_RETRY = 3; + + private boolean isSessionProvided; + + public final static int MAX_TTL = 2880; + + /** + * It is expected that the final members below are not used + * (unlike another constructor that takes RestCredentials) + */ + public RestApiSession() { + this.restCredentials = null; + } + + /** + * This factory method is used when deserializing from JSON. + * It guarantees that "bullhornRestCredentials" property gets assigned first, + * ensuring no NullPointerException when other setters are trying to access it, + * e.g. setBhRestToken->updateDateTimeBhRestTokenWillExpire + */ + @JsonCreator + public static RestApiSession create(@JsonProperty("bullhornRestCredentials") BullhornRestCredentials bullhornRestCredentials) { + return new RestApiSession(bullhornRestCredentials); + } + + public RestApiSession(BullhornRestCredentials bullhornRestCredentials) { + this.isSessionProvided = isSessionProvided(bullhornRestCredentials); + this.restCredentials = bullhornRestCredentials; + this.restTemplate = RestTemplateFactory.getInstance(); + this.dateTimeBhRestTokenWillExpire = getNow(); + if (!this.isSessionProvided) { + createSession(); + } else { + this.restUrl = restCredentials.getRestUrl(); + this.bhRestToken = restCredentials.getBhRestToken(); + } + } + + /** + * Returns the BhRestToken to be used when making rest api calls. + *

+ * Wraps all session management, such as renewal etc. + * + * @return + * @throws RestApiException + */ + public String getBhRestToken() throws RestApiException { + + if (isSessionExpired() && !this.isSessionProvided) { + createSession(); + } + + return bhRestToken; + } + + /** + * Refreshes the BhRestToken, expired or not expired, and returns the brand new BhRestToken to be used when making rest api calls. + *

+ * Wraps all session management, such as renewal etc. + * + * @return + * @throws RestApiException + */ + public String refreshBhRestToken() throws RestApiException { + + createSession(); + + return bhRestToken; + } + + private void createSession() { + for (int tryNumber = 1; tryNumber <= SESSION_RETRY; tryNumber++) { + try { + String authCode = getAuthorizationCode(); + getAccessToken(authCode); + login(); + break; + } catch (Exception e) { + + if (tryNumber < SESSION_RETRY) { + log.error("Error creating REST session. Try number: " + tryNumber + " out of " + SESSION_RETRY + " trying again.", e); + } else { + log.error("Final error creating REST session. Shutting down.", e); + throw new RestApiException("Failed to create rest session", e); + } + } + } + } + + private String getAuthorizationCode() throws RestApiException { + String authorizeUrl = restCredentials.getRestAuthorizeUrl(); + String clientId = restCredentials.getRestClientId(); + String username = getUserName(); + String password = getPassword(); + String authCode = null; + + String url = authorizeUrl + + "?client_id={clientId}&response_type={responseType}&action={action}&username={username}&password={password}"; + + Map vars = new LinkedHashMap(); + vars.put("clientId", clientId); + vars.put("responseType", AUTH_CODE_RESPONSE_TYPE); + vars.put("action", AUTH_CODE_ACTION); + vars.put("username", username); + vars.put("password", password); + + try { + URI uri = restTemplate.postForLocation(url, null, vars); + + authCode = getAuthCode(uri); + } catch (Exception e) { + log.error("Failed to get authorization code.", e); + throw new RestApiException("Failed to get authorization code.", e); + } + + return authCode; + } + + /** + * restCredentials will only be used in case of multi-tenant app. If not default to username in appSettings. + * + * @return + */ + private String getUserName() { + return restCredentials.getUsername(); + } + + /** + * restCredentials will only be used in case of multi-tenant app. If not default to password in appSettings. + * + * @return + */ + private String getPassword() { + return restCredentials.getPassword(); + } + + // query: code=###&client_id= + private String getAuthCode(URI uri) { + String query = uri.getQuery(); + Map map = Splitter.on("&").trimResults().withKeyValueSeparator('=').split(query); + return map.get("code"); + } + + private void getAccessToken(String authCode) throws RestApiException { + String tokenUrl = restCredentials.getRestTokenUrl(); + String clientId = restCredentials.getRestClientId(); + String clientSecret = restCredentials.getRestClientSecret(); + + String url = tokenUrl + "?grant_type={grantType}&code={authCode}&client_id={clientId}&client_secret={clientSecret}"; + + Map vars = new LinkedHashMap(); + vars.put("grantType", ACCESS_TOKEN_GRANT_TYPE); + vars.put("authCode", authCode); + vars.put("clientId", clientId); + vars.put("clientSecret", clientSecret); + + try { + // String test = restTemplate.postForObject(url, null, String.class, vars); + accessTokenInfo = restTemplate.postForObject(url, null, AccessTokenInfo.class, vars); + } catch (Exception e) { + log.error("Failed to get access token.", e); + throw new RestApiException("Failed to get access token.", e); + } + } + + private void login() { + + JSONObject responseJson = null; + try { + String accessTokenString = URLEncoder.encode(accessTokenInfo.getAccessToken(), "UTF-8"); + String loginUrl = restCredentials.getRestLoginUrl(); + String sessionMinutesToLive = restCredentials.getRestSessionMinutesToLive(); + String url = loginUrl + "?version=" + version + "&access_token=" + accessTokenString + "&ttl=" + sessionMinutesToLive; + GetMethod get = new GetMethod(url); + + HttpClient client = new HttpClient(); + client.executeMethod(get); + + String responseStr = streamToString(get.getResponseBodyAsStream()); + responseJson = new JSONObject(responseStr); + + String localBhRestToken = responseJson.getString("BhRestToken"); + this.setBhRestToken(localBhRestToken); + + restUrl = (String) responseJson.get("restUrl"); + } catch (Exception e) { + log.error("Failed to login. " + responseJson, e); + throw new RestApiException("Failed to login and get BhRestToken: " + responseJson); + } + } + + private String streamToString(InputStream inputStream) throws IOException { + StringWriter writer = new StringWriter(); + IOUtils.copy(inputStream, writer, "UTF-8"); + return writer.toString(); + + } + + /** + * Check if the DateTime dateTimeBhRestTokenWillExpire in this class is expired. + *

+ * Pinging every time will decrease performance. + * + * @return + * @throws RestApiException + */ + public boolean isSessionExpired() throws RestApiException { + boolean sessionExpired = false; + + if (bhRestTokenExpired()) { + // sessionExpired = ping(); + sessionExpired = true; + } + + return sessionExpired; + } + + /** + * Uses the DateTime in this class to calculate if the session is expired + * + * @return + */ + + private boolean bhRestTokenExpired() { + if (dateTimeBhRestTokenWillExpire.isBeforeNow()) { + return true; + } + return false; + + } + + public String getRestUrl() { + return restUrl; + } + + private synchronized void setBhRestToken(String bhRestToken) { + this.bhRestToken = bhRestToken; + + if (!this.isSessionProvided) { + updateDateTimeBhRestTokenWillExpire(); + } + + } + + private void updateDateTimeBhRestTokenWillExpire() { + // set the DateTime the session will expire, subtracting one minute to be on the safe side. + DateTime timeToExpire = getNow(); + int sessionMinutesToLive = Integer.valueOf(restCredentials.getRestSessionMinutesToLive()); + if (sessionMinutesToLive > MAX_TTL) { + sessionMinutesToLive = MAX_TTL; + } + timeToExpire = timeToExpire.plusMinutes(sessionMinutesToLive - 1); + this.dateTimeBhRestTokenWillExpire = timeToExpire; + } + + private DateTime getNow() { + return new DateTime(DateTimeZone.forID("EST5EDT")); + } + + public DateTime getDateTimeBhRestTokenWillExpire() { + return dateTimeBhRestTokenWillExpire; + } + + public void setDateTimeBhRestTokenWillExpire(DateTime dateTimeBhRestTokenWillExpire) { + this.dateTimeBhRestTokenWillExpire = dateTimeBhRestTokenWillExpire; + } + + public boolean isSessionProvided(BullhornRestCredentials restCredentials) { + return StringUtils.isNotBlank(restCredentials.getRestUrl()) && StringUtils.isNotBlank(restCredentials.getBhRestToken()); + } + + /** + * Will return the un-encrypted RestCredentials for this RestApiSession. Note that this is only needed for a multi-tenant solution + * + * @return a valid {@link RestCredentials} object if multi-tenant otherwise null + */ + public BullhornRestCredentials getRestCredentials() { + return restCredentials; + } } diff --git a/src/test/java/com/bullhornsdk/data/api/helper/TestCredentiallessRestApiSession.java b/src/test/java/com/bullhornsdk/data/api/helper/TestCredentiallessRestApiSession.java new file mode 100644 index 00000000..2289dc7d --- /dev/null +++ b/src/test/java/com/bullhornsdk/data/api/helper/TestCredentiallessRestApiSession.java @@ -0,0 +1,82 @@ +package com.bullhornsdk.data.api.helper; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import com.bullhornsdk.data.BaseTest; +import com.bullhornsdk.data.api.BullhornRestCredentials; + +import static org.junit.Assert.*; + +@Ignore +public class TestCredentiallessRestApiSession extends BaseTest { + + private RestApiSession restApiSession; + + private BullhornRestCredentials bullhornRestCredentials; + + /** + * Add your own rest credentials here to test the connection. + */ + @Before + public void setupTheCredentials() { + BullhornRestCredentials creds = new BullhornRestCredentials(); + + creds.setRestUrl("MY-RESTURL"); + creds.setBhRestToken("MY-BHRESTTOKEN"); + this.bullhornRestCredentials = creds; + this.restApiSession = new RestApiSession(bullhornRestCredentials); + } + + @Test + public void testRestApiSession() { + + RestApiSession restApiSessionManual = new RestApiSession(bullhornRestCredentials); + assertNotNull("RestApiSession is null", restApiSessionManual); + assertNull("Username is not null", bullhornRestCredentials.getUsername()); + assertNull("RestTokenUrl is not null", bullhornRestCredentials.getRestTokenUrl()); + assertNull("RestSessionMinutesToLive is not null", bullhornRestCredentials.getRestSessionMinutesToLive()); + assertNull("RestLoginUrl is not null", bullhornRestCredentials.getRestLoginUrl()); + assertNull("RestClientSecret is not null", bullhornRestCredentials.getRestClientSecret()); + assertNull("RestClientId is not null", bullhornRestCredentials.getRestClientId()); + assertNull("RestAuthorizeUrl is not null", bullhornRestCredentials.getRestAuthorizeUrl()); + } + + @Test + public void testGetBhRestToken() { + + String restToken = restApiSession.getBhRestToken(); + assertNotNull("BhRestToken is null", restToken); + assertNull("Username is not null", bullhornRestCredentials.getUsername()); + assertNull("RestTokenUrl is not null", bullhornRestCredentials.getRestTokenUrl()); + assertNull("RestSessionMinutesToLive is not null", bullhornRestCredentials.getRestSessionMinutesToLive()); + assertNull("RestLoginUrl is not null", bullhornRestCredentials.getRestLoginUrl()); + assertNull("RestClientSecret is not null", bullhornRestCredentials.getRestClientSecret()); + assertNull("RestClientId is not null", bullhornRestCredentials.getRestClientId()); + assertNull("RestAuthorizeUrl is not null", bullhornRestCredentials.getRestAuthorizeUrl()); + } + + @Test + public void testGetRestUrl() { + + String restUrl = restApiSession.getRestUrl(); + assertNotNull("restUrl is null", restUrl); + assertNull("Username is not null", bullhornRestCredentials.getUsername()); + assertNull("RestTokenUrl is not null", bullhornRestCredentials.getRestTokenUrl()); + assertNull("RestSessionMinutesToLive is not null", bullhornRestCredentials.getRestSessionMinutesToLive()); + assertNull("RestLoginUrl is not null", bullhornRestCredentials.getRestLoginUrl()); + assertNull("RestClientSecret is not null", bullhornRestCredentials.getRestClientSecret()); + assertNull("RestClientId is not null", bullhornRestCredentials.getRestClientId()); + assertNull("RestAuthorizeUrl is not null", bullhornRestCredentials.getRestAuthorizeUrl()); + } + + @Test + public void testHasNoSessionProvided() { + + boolean hasNoSession = restApiSession.isSessionProvided(bullhornRestCredentials); + assertTrue(hasNoSession); + + } + +} diff --git a/src/test/java/com/bullhornsdk/data/api/helper/TestRestApiSession.java b/src/test/java/com/bullhornsdk/data/api/helper/TestRestApiSession.java index 30f4e294..501d863f 100644 --- a/src/test/java/com/bullhornsdk/data/api/helper/TestRestApiSession.java +++ b/src/test/java/com/bullhornsdk/data/api/helper/TestRestApiSession.java @@ -1,13 +1,11 @@ package com.bullhornsdk.data.api.helper; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - import java.io.IOException; +import com.bullhornsdk.data.exception.RestApiException; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; +import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -17,132 +15,177 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.joda.JodaModule; +import static org.junit.Assert.*; + +import mockit.Expectations; +import mockit.Injectable; +import mockit.Mocked; +import mockit.Verifications; + @Ignore public class TestRestApiSession extends BaseTest { - private RestApiSession restApiSession; + private RestApiSession restApiSession; + + private BullhornRestCredentials bullhornRestCredentials; + + /** + * Add your own rest credentials here to test the connection. + */ + @Before + public void setupTheCredentials() { + BullhornRestCredentials creds = new BullhornRestCredentials(); + + creds.setRestAuthorizeUrl("https://auth9.bullhornstaffing.com/oauth/authorize"); + creds.setRestClientId("MY-CLIENT-ID"); + creds.setRestClientSecret("MY-CLIENT-SECRET"); + creds.setRestLoginUrl("https://rest9.bullhornstaffing.com/rest-services/login"); + creds.setRestSessionMinutesToLive("1400"); + creds.setRestTokenUrl("https://auth9.bullhornstaffing.com/oauth/token"); + creds.setUsername("MY-USERNAME"); + creds.setPassword("MY-PASSWORD"); + this.bullhornRestCredentials = creds; + this.restApiSession = new RestApiSession(bullhornRestCredentials); + } + + @Test + public void testRestApiSession() { + + RestApiSession restApiSessionManual = new RestApiSession(bullhornRestCredentials); + assertNotNull("RestApiSession is null", restApiSessionManual); + } + + @Test + public void testGetBhRestToken() { + + String restToken = restApiSession.getBhRestToken(); + assertNotNull("BhRestToken is null", restToken); + } + + @Test + public void testGetRestUrl() { + + String restUrl = restApiSession.getRestUrl(); + assertNotNull("restUrl is null", restUrl); + } - private BullhornRestCredentials bullhornRestCredentials; + @Test + public void testSessionExpired_1() throws InterruptedException { - /** - * Add your own rest credentials here to test the connection. - */ - @Before - public void setupTheCredentials() { - BullhornRestCredentials creds = new BullhornRestCredentials(); + bullhornRestCredentials.setRestSessionMinutesToLive("1"); - creds.setRestAuthorizeUrl("https://auth9.bullhornstaffing.com/oauth/authorize"); - creds.setRestClientId("MY-CLIENT-ID"); - creds.setRestClientSecret("MY-CLIENT-SECRET"); - creds.setRestLoginUrl("https://rest9.bullhornstaffing.com/rest-services/login"); - creds.setRestSessionMinutesToLive("1400"); - creds.setRestTokenUrl("https://auth9.bullhornstaffing.com/oauth/token"); - creds.setUsername("MY-USERNAME"); - creds.setPassword("MY-PASSWORD"); - this.bullhornRestCredentials = creds; - this.restApiSession = new RestApiSession(bullhornRestCredentials); - } + RestApiSession restApiSessionManual = new RestApiSession(bullhornRestCredentials); + Thread.sleep(5000); + assertTrue("session should have expired is null", restApiSessionManual.isSessionExpired()); - @Test - public void testRestApiSession() { + String restToken = restApiSessionManual.getBhRestToken(); + assertNotNull("BhRestToken is null", restToken); - RestApiSession restApiSessionManual = new RestApiSession(bullhornRestCredentials); - assertNotNull("RestApiSession is null", restApiSessionManual); - } + String restUrl = restApiSessionManual.getRestUrl(); + assertNotNull("restUrl is null", restUrl); - @Test - public void testGetBhRestToken() { + } - String restToken = restApiSession.getBhRestToken(); - assertNotNull("BhRestToken is null", restToken); - } + @Test + public void testSessionExpired_2() { - @Test - public void testGetRestUrl() { + bullhornRestCredentials.setRestSessionMinutesToLive("5000"); - String restUrl = restApiSession.getRestUrl(); - assertNotNull("restUrl is null", restUrl); - } + RestApiSession restApiSessionManual = new RestApiSession(bullhornRestCredentials); - @Test - public void testSessionExpired_1() throws InterruptedException { + assertFalse("session should not be expired", restApiSessionManual.isSessionExpired()); - bullhornRestCredentials.setRestSessionMinutesToLive("1"); + String restToken = restApiSessionManual.getBhRestToken(); + assertNotNull("BhRestToken is null", restToken); - RestApiSession restApiSessionManual = new RestApiSession(bullhornRestCredentials); - Thread.sleep(5000); - assertTrue("session should have expired is null", restApiSessionManual.isSessionExpired()); + String restUrl = restApiSessionManual.getRestUrl(); + assertNotNull("restUrl is null", restUrl); - String restToken = restApiSessionManual.getBhRestToken(); - assertNotNull("BhRestToken is null", restToken); + DateTime expirationDate = restApiSessionManual.getDateTimeBhRestTokenWillExpire(); + DateTime expirationDateManual = getNow().plusMinutes(RestApiSession.MAX_TTL - 1); + assertTrue(expirationDate.getDayOfYear() == expirationDateManual.getDayOfYear()); + assertTrue(expirationDate.getHourOfDay() == expirationDateManual.getHourOfDay()); + assertTrue(expirationDate.getMinuteOfDay() == expirationDateManual.getMinuteOfDay()); + assertTrue(expirationDate.getSecondOfDay() == expirationDateManual.getSecondOfDay()); - String restUrl = restApiSessionManual.getRestUrl(); - assertNotNull("restUrl is null", restUrl); + } - } + @Test + public void testRefreshBhRestToken() throws InterruptedException { - @Test - public void testSessionExpired_2() { + bullhornRestCredentials.setRestSessionMinutesToLive("1"); - bullhornRestCredentials.setRestSessionMinutesToLive("5000"); + RestApiSession restApiSessionManual = new RestApiSession(bullhornRestCredentials); + String restToken = restApiSessionManual.getBhRestToken(); + assertNotNull("restToken is null", restToken); + Thread.sleep(5000); + assertTrue("session should have expired is null", restApiSessionManual.isSessionExpired()); - RestApiSession restApiSessionManual = new RestApiSession(bullhornRestCredentials); + String newRestToken = restApiSessionManual.refreshBhRestToken(); + assertNotNull("newRestToken is null", newRestToken); - assertFalse("session should not be expired", restApiSessionManual.isSessionExpired()); + assertFalse("new BhRestToken is the same as old BhRestToken", restToken.equals(newRestToken)); - String restToken = restApiSessionManual.getBhRestToken(); - assertNotNull("BhRestToken is null", restToken); + String restUrl = restApiSessionManual.getRestUrl(); + assertNotNull("restUrl is null", restUrl); - String restUrl = restApiSessionManual.getRestUrl(); - assertNotNull("restUrl is null", restUrl); + } - DateTime expirationDate = restApiSessionManual.getDateTimeBhRestTokenWillExpire(); - DateTime expirationDateManual = getNow().plusMinutes(RestApiSession.MAX_TTL - 1); - assertTrue(expirationDate.getDayOfYear() == expirationDateManual.getDayOfYear()); - assertTrue(expirationDate.getHourOfDay() == expirationDateManual.getHourOfDay()); - assertTrue(expirationDate.getMinuteOfDay() == expirationDateManual.getMinuteOfDay()); - assertTrue(expirationDate.getSecondOfDay() == expirationDateManual.getSecondOfDay()); + @Test + public void testSessionSerialization() throws IOException { - } + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new JodaModule()); - @Test - public void testRefreshBhRestToken() throws InterruptedException { + String json = mapper.writeValueAsString(restApiSession); - bullhornRestCredentials.setRestSessionMinutesToLive("1"); + System.out.println(json); - RestApiSession restApiSessionManual = new RestApiSession(bullhornRestCredentials); - String restToken = restApiSessionManual.getBhRestToken(); - assertNotNull("restToken is null", restToken); - Thread.sleep(5000); - assertTrue("session should have expired is null", restApiSessionManual.isSessionExpired()); + final RestApiSession newSession = mapper.readValue(json, RestApiSession.class); + assertNotNull(newSession); - String newRestToken = restApiSessionManual.refreshBhRestToken(); - assertNotNull("newRestToken is null", newRestToken); + } - assertFalse("new BhRestToken is the same as old BhRestToken", restToken.equals(newRestToken)); + @Test + public void testHasNoSessionProvided() { - String restUrl = restApiSessionManual.getRestUrl(); - assertNotNull("restUrl is null", restUrl); + boolean hasNoSession = restApiSession.isSessionProvided(bullhornRestCredentials); + assertFalse(hasNoSession); - } + } - @Test - public void testSessionSerialization() throws IOException { + @Test + public void testSetDateTimeBhRestTokenWillExpire() { + DateTime testDate = getNow(); - ObjectMapper mapper = new ObjectMapper(); - mapper.registerModule(new JodaModule()); + restApiSession.setDateTimeBhRestTokenWillExpire(testDate); - String json = mapper.writeValueAsString(restApiSession); + assertTrue(restApiSession.getDateTimeBhRestTokenWillExpire().equals(testDate)); + } - System.out.println(json); + @Test + public void testCreateSessionWithBadCreds_shouldThrowRestException() throws RestApiException { + BullhornRestCredentials creds = new BullhornRestCredentials(); - final RestApiSession newSession = mapper.readValue(json, RestApiSession.class); - assertNotNull(newSession); + creds.setRestAuthorizeUrl("NO_VALUE"); + creds.setRestClientId("NO_VALUE"); + creds.setRestClientSecret("NO_VALUE"); + creds.setRestLoginUrl("NO_VALUE"); + creds.setRestSessionMinutesToLive("NO_VALUE"); + creds.setRestTokenUrl("NO_VALUE"); + creds.setUsername("NO_VALUE"); + creds.setPassword("NO_VALUE"); - } + try { + new RestApiSession(creds); + Assert.fail("Should have thrown an exception"); + } catch (RestApiException e) { + assertTrue(e.getMessage().equals("Failed to create rest session")); + } + } - private DateTime getNow() { - return new DateTime(DateTimeZone.forID("EST5EDT")); - } + private DateTime getNow() { + return new DateTime(DateTimeZone.forID("EST5EDT")); + } }