Summary Table

Categories Total Count
PII 0
URL 0
DNS 0
EKL 0
IP 0
PORT 0
VsID 0
CF 0
AI 0
VPD 0
PL 0
Other 0

File Content

package gov.va.vamf.scheduling.varutility.clientapi;

import com.agilex.healthcare.utility.NullChecker;
import com.gargoylesoftware.htmlunit.BrowserVersion;
import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.*;
import org.apache.log4j.Logger;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.common.AuthenticationScheme;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestTemplate;

import javax.ws.rs.core.UriBuilder;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.StringTokenizer;

import static org.junit.Assert.*;

public class OauthClient {

private static final Logger LOGGER = Logger.getLogger(OauthClient.class);
private static final String CLIENT_SECRET = "client_secret";
private static final String AUTH_CODE = "code";
private static final String GRANT_TYPE = "grant_type";
private static final String SCOPE = "scope";
private static final String REDIRECT_URI = "redirect_uri";
private static final String CLIENT_ID = "client_id";
private static final String STATE = "state";
private static final String RESPONSE_TYPE = "response_type";
private String redirectionUri = "http://anywhere";

public String authenticate(AuthenticationInfo authenticationInfo, WebClient userAgent) throws Exception {
AuthorizationResult authorizationResult = authorize(authenticationInfo, userAgent);
OAuth2AccessToken accessToken = getAccessToken(authenticationInfo, authorizationResult);
return accessToken.getValue();
}

public AuthorizationResult authorize(AuthenticationInfo authenticationInfo, WebClient userAgent) throws IOException, MalformedURLException, URISyntaxException {
String stateId = "stateId";

if (userAgent == null)
userAgent = new WebClient(BrowserVersion.CHROME);

userAgent.getOptions().setThrowExceptionOnScriptError(false);

userAgent.getOptions().setRedirectEnabled(false);

String mhpAuthorizeUrl = authenticationInfo.getAuthorizeUrl();
UriBuilder authorizeUrlBuilder = UriBuilder.fromPath(mhpAuthorizeUrl);

URI uri = authorizeUrlBuilder.queryParam(RESPONSE_TYPE, AUTH_CODE).queryParam(STATE, stateId).queryParam(CLIENT_ID, authenticationInfo.getClientId()).queryParam(REDIRECT_URI, redirectionUri).queryParam(SCOPE, "read").build();

String authenticationRedirectUri = null;
HtmlPage confirmationPage = null;
try {
confirmationPage = userAgent.getPage(uri.toString());
} catch (FailingHttpStatusCodeException e) {
authenticationRedirectUri = e.getResponse().getResponseHeaderValue("Location");
if (e.getResponse().getStatusCode() == 404 && authenticationRedirectUri == null)
throw new IllegalStateException("404 Error (is the service running?): " + e.getMessage());
}

boolean denied = false;

if (NullChecker.isNotNullish(authenticationRedirectUri)) {
HtmlPage loginPage = userAgent.getPage(authenticationRedirectUri);
// should be directed to the login screen...
HtmlForm loginForm = loginPage.getFormByName("logonForm");
((HtmlPasswordInput) loginForm.getInputByName("j_username")).setValueAttribute(authenticationInfo.getUsername());
((HtmlPasswordInput) loginForm.getInputByName("j_password")).setValueAttribute(authenticationInfo.getPassword());

HtmlHiddenInput facilityName = null;
HtmlHiddenInput facilityCode = null;
String errorMsg = null;
try {
facilityName = (HtmlHiddenInput) loginPage.getHtmlElementById("facilityName");
facilityCode = (HtmlHiddenInput) loginPage.getHtmlElementById("facilityCode");

if (facilityName != null){
facilityName.setValueAttribute(authenticationInfo.getFacilityName());
}
if (facilityCode != null){
facilityCode.setValueAttribute(authenticationInfo.getFacilityCode());
}
} catch (Exception e) {
// Intentionally ignored as vistaLocation is not available on Veteran Login page
LOGGER.error("loginForm element error : " + e.getMessage());
errorMsg = e.getMessage();
}

try {
HtmlElement button = (HtmlElement)loginPage.createElement("button");
button.setAttribute("type", "submit");

loginForm.appendChild(button);
button.click();

throw new IllegalStateException("should have been redirected to the authorization endpoint. " + errorMsg);
} catch (FailingHttpStatusCodeException e) {
String authorizationRedirectUri = e.getResponse().getResponseHeaderValue("Location");

if (authorizationRedirectUri != null && authorizationRedirectUri.contains("denied"))
denied = true;

try {
confirmationPage = userAgent.getPage(authorizationRedirectUri);

// dev mode (confirmation page)
HtmlForm okForm = confirmationPage.getFormByName("confirmationForm");
((HtmlSubmitInput) okForm.getInputByName("authorize")).click();
} catch (FailingHttpStatusCodeException fe) {
// other modes (no confirmation page)
authenticationRedirectUri = fe.getResponse().getResponseHeaderValue("Location");
if (fe.getResponse().getStatusCode() == 404 && authenticationRedirectUri == null)
throw new IllegalStateException("404 Error (possible cause was access was denied for that user): " + fe.getMessage());
} catch (ElementNotFoundException exc) {
if (denied == true)
throw new IllegalStateException("Access was denied for that user.");
else
throw exc;
}
}
}

if (authenticationRedirectUri == null) {
if (denied == true)
throw new IllegalStateException("No Redirect URI was returned after the User was denied access");
else
throw new IllegalStateException("No Redirect URI was returned after login completed");
}
URI redirection = new URI(authenticationRedirectUri); //authenticationRedirectUriBuilder.build();

String code = null;
String state = null;
for (StringTokenizer queryTokens = new StringTokenizer(redirection.getQuery(), "&="); queryTokens.hasMoreTokens();) {
String token = queryTokens.nextToken();
if (AUTH_CODE.equals(token)) {
if (code != null) {
fail("shouldn't have returned more than one code.");
}

code = queryTokens.nextToken();
} else if (STATE.equals(token)) {
state = queryTokens.nextToken();
}
}

assertEquals(stateId, state);
assertNotNull(code);

AuthorizationResult authorizationResult = new AuthorizationResult(code, state);
return authorizationResult;
}

public OAuth2AccessToken getAccessToken(AuthenticationInfo authenticationInfo, AuthorizationResult authorizationResult) {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>();
formData.add(GRANT_TYPE, "authorization_code");
formData.add(CLIENT_ID, authenticationInfo.getClientId());
formData.add(SCOPE, "read");
formData.add(REDIRECT_URI, redirectionUri);
formData.add(AUTH_CODE, authorizationResult.getCode());
formData.add(CLIENT_SECRET, authenticationInfo.getClientSecret());

AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails();

resource.setAccessTokenUri(authenticationInfo.getTokenUrl());
resource.setClientId(authenticationInfo.getClientId());
resource.setScope(Arrays.asList("read"));
resource.setClientSecret(authenticationInfo.getClientSecret());
resource.setClientAuthenticationScheme(AuthenticationScheme.query);

AccessTokenRequest request = new DefaultAccessTokenRequest();
request.setAuthorizationCode(authorizationResult.getCode());
request.setPreservedState(new Object());
request.setAll(formData.toSingleValueMap());

OAuth2RestTemplate template = new OAuth2RestTemplate(resource, new DefaultOAuth2ClientContext(request));
OAuth2AccessToken accessToken = template.getAccessToken();

return accessToken ;
}

public RestTemplate getRestTemplate() {
RestTemplate client = new RestTemplate();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
client.setRequestFactory(requestFactory);
client.setErrorHandler(new ResponseErrorHandler() {
public boolean hasError(ClientHttpResponse response) throws IOException {
return false;
}

public void handleError(ClientHttpResponse response) throws IOException {
}
});
return client;
}

public HttpStatus getStatusCode(String path, final HttpHeaders headers) {
RequestCallback requestCallback = createRequestCallback(headers);

return execute(path, HttpMethod.GET, requestCallback);
}

private RequestCallback createRequestCallback(final HttpHeaders headers) {
RequestCallback requestCallback = new NullRequestCallback();
if (headers != null) {
requestCallback = new RequestCallback() {
public void doWithRequest(ClientHttpRequest request) throws IOException {
request.getHeaders().putAll(headers);
}
};
}
return requestCallback;
}

public HttpStatus deleteToken(String path, OAuth2AccessToken accessToken) {
final HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, accessToken.getValue()));
RequestCallback requestCallback = createRequestCallback(headers);

return execute(path, HttpMethod.DELETE, requestCallback);
}

private HttpStatus execute(String path, HttpMethod method, RequestCallback requestCallback) {
HttpStatus statusCode = getRestTemplate().execute(path, method, requestCallback, new ResponseExtractor<ResponseEntity<String>>() {
public ResponseEntity<String> extractData(ClientHttpResponse response) throws IOException {
return new ResponseEntity<String>(response.getStatusCode());
}
}).getStatusCode();

return statusCode;
}


public HttpStatus getStatusCode(String path) {
return getStatusCode(path, null);
}

private static final class NullRequestCallback implements RequestCallback {
public void doWithRequest(ClientHttpRequest request) throws IOException {
}
}
}