Redirect to another URL and back for Certifcate base Login - spring

Currently i developing an application which have two routes which are in different domain.
Example :
Route 1: https://test.apps.com
Route 2: https://test.cert-apps.com
Users uses Route 1 to access the application. In the Login page there is an option for Certificate based login . But certificate based authentication is only enabled in route 2.
So how do i do the certificate based authentication by redirecting from Route 1 to Route 2 and once client is authenticated redirect to route 1.
Following are the code that i currently using which are not working:
#Controller
#RequestMapping("/login")
public class LoginContr {
#RequestMapping("/certificate")
public String message(HttpServletRequest request, HttpServletResponse response) {
try {
sendGET();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "login";
}
#RequestMapping("/extractcertificate")
private String extractEmailFromCertificate(HttpServletRequest request) {
String email = "";
//Code to extract email from certificate
return email;
}
private static void sendGET() throws IOException {
URL obj = new URL("https://test.cert-apps.com/login/extractcertificate");
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
System.out.println("GET Response Code :: " + responseCode);
if (responseCode == HttpURLConnection.HTTP_OK) { // success
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
// print result
System.out.println(response.toString());
} else {
System.out.println("GET request not worked");
}
}
}
The above code gives the error:
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
sendGet() method sends a request to Route 2 and calls /extractcertificate webservice to do certificate based authentication and once its done it will retrive the email address.
Technology using for app: Java,Spring,Angualar 4, Cloud Foundary
Is there any alternative to do this or any inbuilt implementation , any tips would be great advantage..

Related

meesenger4j how to handle request from diffrent facbook app

I would like to create a rest api that handle user messenger app credential (token,appsecret,verifToken) as parameters instead of define them as env variable.
So that more than one user (facebook app) can subscribe to my rest api throw messenger webhook .
Is that possible?
First, i tried with credential in app.prop and injected the Messenger4j client in Restcontroller constructor and it works like charm (webhook call, conversation...).
Now is it possible to do that for more than one facebook app to communicate with my rest api :
the logic will be:
first connect(accesToken,appSecret) to our backend and save app credential and get response with myBackendApiUrl and generate verifToken.
#RequestMapping(value = "/connect", method = RequestMethod.POST)
public ResponseEntity<String> connect(#RequestParam final String pageAccessToken,
#RequestParam final String appSecret,
) {
logger.debug(" connect ");
try {
logger.debug("********");
//Messenger messenger = Messenger.create(pageAccessToken, appSecret, verifyToken).;
String verifyToken= UUID.randomUUID().toString();
MessengerCredentials msgerCred = new MessengerCredentials(pageAccessToken,appSecret,verifyToken);
messengerCredentialRepo.save(msgerCred);
return ResponseEntity.ok("webhookurl: myurl"+ "verifToken:"+verifyToken);
} catch (Exception e) {
logger.warn("failed to connect", e.getMessage());
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage());
}
}
After that the user should configure messenger app webhook with url and verif token recived in the response body method connect() to avonke the webhook handler and this is how it may be like
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<String> verifyWebhook(#RequestParam(MODE_REQUEST_PARAM_NAME) final String mode,
#RequestParam(CHALLENGE_REQUEST_PARAM_NAME) final String challenge,
#RequestParam(VERIFY_TOKEN_REQUEST_PARAM_NAME) final String verifyToken
) {
logger.debug("Received Webhook verification request - mode: {} | verifyToken: {} | challenge: {}", mode, verifyToken, challenge);
try {
logger.debug("********");
this.messenger.verifyWebhook(mode, verifyToken);
return ResponseEntity.ok(challenge);
} catch (MessengerVerificationException e) {
logger.warn("Webhook verification failed: {}", e.getMessage());
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage());
}
}
Is that possible?!
and how can i deal with post handler to handel users events it my Messenger4j bean not instanciate yet.

sun.security.validator.ValidatorException while invoking graph API

I am getting below exception while invoking the Microsoft graph API by using swagger in the local.
Getting below exception:
feign.RetryableException: sun.security.validator.ValidatorException: PKIX path building failed:
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path
#Override
public int addUser(String token, AddUserRequest request) {
Response response = null;
int status = 0;
try {
long time1 = System.currentTimeMillis();
response = graphAPIFeignClient.addUser("Bearer " + token, request);
log.info("{}:: Time taken to call Graph Api is {}", loggingComponentName,
(System.currentTimeMillis() - time1));
if (response.status() == 200) {
status = response.status();
} else if (response.status() == 404) {
throw new SearchResultNotFoundException("get users not found");
} else {
log.error("{}:: Graph Api failed:: status code {}",
loggingComponentName, 500);
throw new AccessManagementException(HttpStatus.valueOf(500), "Graph Api failed");
}
} catch (FeignException ex) {
log.error("{}:: Graph Api failed:: status code {} & message {}",
loggingComponentName, ex.status(), ex.getMessage());
throw new AccessManagementException(HttpStatus.valueOf(ex.status()), "Graph Api failed");
}
return status;
}
//feign client declaration
#PostMapping(value = "/v1.0/users")
#RequestLine("POST v1.0/users")
//#Headers({"Authorization: {authorization}","Content-Type: application/json"})
Response addUser(#RequestHeader(HttpHeaders.AUTHORIZATION) String authorisation,
#RequestBody AddUserRequest request);
Same is working fine with the postman call.enter image description here

Why OAuth2AccessTokenSupport always send POST request ??

I'm working with a Spring Boot + Spring Security OAuth2 to consume the Restful Oauth2 service.
Our Oauth2 service is always expects HTTP GET But OAuth2AccessTokenSupport always sending HTTP POST.
Result:
resulted in 405 (Method Not Allowed); invoking error handler
protected OAuth2AccessToken retrieveToken(AccessTokenRequest request, OAuth2ProtectedResourceDetails resource,
MultiValueMap<String, String> form, HttpHeaders headers) throws OAuth2AccessDeniedException {
try {
this.authenticationHandler.authenticateTokenRequest(resource, form, headers);
this.tokenRequestEnhancer.enhance(request, resource, form, headers);
AccessTokenRequest copy = request;
ResponseExtractor delegate = getResponseExtractor();
ResponseExtractor extractor = new ResponseExtractor(copy, delegate) {
public OAuth2AccessToken extractData(ClientHttpResponse response) throws IOException {
if (response.getHeaders().containsKey("Set-Cookie")) {
this.val$copy.setCookie(response.getHeaders().getFirst("Set-Cookie"));
}
return ((OAuth2AccessToken) this.val$delegate.extractData(response));
}
};
return ((OAuth2AccessToken) getRestTemplate().execute(getAccessTokenUri(resource, form), getHttpMethod(),
getRequestCallback(resource, form, headers), extractor, form.toSingleValueMap()));
} catch (OAuth2Exception oe) {
throw new OAuth2AccessDeniedException("Access token denied.", resource, oe);
} catch (RestClientException rce) {
throw new OAuth2AccessDeniedException("Error requesting access token.", resource, rce);
}
}
<b>protected HttpMethod getHttpMethod() {
return HttpMethod.POST;
}</b>
protected String getAccessTokenUri(OAuth2ProtectedResourceDetails resource, MultiValueMap<String, String> form) {
String accessTokenUri = resource.getAccessTokenUri();
if (this.logger.isDebugEnabled()) {
this.logger.debug(new StringBuilder().append("Retrieving token from ").append(accessTokenUri).toString());
}
StringBuilder builder = new StringBuilder(accessTokenUri);
String separator;
if (getHttpMethod() == HttpMethod.GET) {
separator = "?";
if (accessTokenUri.contains("?")) {
separator = "&";
}
for (String key : form.keySet()) {
builder.append(separator);
builder.append(new StringBuilder().append(key).append("={").append(key).append("}").toString());
separator = "&";
}
}
return builder.toString();
}
Can Anyone explain me why OAuth2AccessTokenSupport always returns POST and
How to send HTTP GET request
To enable GET requests for the token endpoint, you need to add the following in your AuthorizationServerConfigurerAdapter:
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
}
As for why only POST by default: I think that is due to GET requests potentially sending username and password information as request params (this is certainly the case for password grant). These may well be visible in web server logs, while POST body data is not.
Indeed the RFC for OAuth2 declares that the client must use HTTP POST when requesting an access token (https://www.rfc-editor.org/rfc/rfc6749#section-3.2)

unable to call a REST webservice..Full authentication required

I am currently working on spring application and REST webservices.
I have created a REST webservice in one application and want to access that service from other applications.
Below is the error its showing when trying to access the webservice.
RestClientException : org.springframework.web.client.HttpClientErrorException: 401 Full authentication is required to access this resource
Below is my webservice code:
#RequestMapping(value = MyRequestMapping.GET_ACC_DATA, method = RequestMethod.GET)
#ResponseBody
public MyResponseDTO getSigDataValues(#PathVariable final String acc, final HttpServletResponse response) throws Exception {
MyResponseDTO responseDTO = null;
try {
//logic goes here
//responseDTO = ..
} catch (Exception e) {
LOG.error("Exception" + e);
}
return responseDTO;
}
I am calling above webservice from another application.In the below mentioned method I am calling the webservice and its throwing me the exception org.springframework.web.client.HttpClientErrorException.
public MyResponseDTO getAccData(String acc){
try{
list= (List<String>)restTemplate.postForObject(MyDataURL.GET_ACC_DATA.value(), MyResponseDTO.class, acc);
}
catch (final RestClientException e)
{
LOG.info("RestClientException :" + e);
}
Please suggest, what am I missing.
You would need to authenticate against the REST service. One of the most common ways is Basic Authentication. If this is what the service is using you would need to create an AUTHORIZATION header with Base 64 encoded usernamen + password.
RestTemplate allow to set customer headers before the request gets sent.
The process of creating the Authorization header is relatively straightforward for Basic Authentication, so it can pretty much be done manually with a few lines of code:
private HttpHeaders createHeaders(String username, String password) {
return new HttpHeaders() {
private static final long serialVersionUID = -1704024310885506847L;
{
String auth = username + ":" + password;
byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(Charset.forName("US-ASCII")));
String authHeader = "Basic " + new String(encodedAuth);
set("Authorization", authHeader);
}
};
}
Then, sending a request becomes just as simple:
ResponseEntity<Dados> response = restTemplate.exchange(uriComponents.toUriString(), HttpMethod.GET,
new HttpEntity<Dados>(createHeaders(usuario, senha)), Dados.class);

HttpURLConnnection request failures on Android 6.0 (MarshMallow)

I am using Google's Volley library for my application project , that targets minimum api level 14.So, Volley library uses HttpURLConnection as the NetworkClient.
Therefore , there should not be any issue related to Removal of Apache HTTPClient. However, I have done the configuration required for 6.0 Sdk i.e compileSdkVersion 23, build-tool-version 23.0.1 and build:gradle:1.3.1' and even tried adding useLibrary 'org.apache.http.legacy'. Have updated the same for Volley library project in my application.
Recently ,I tried to run my app on Android 6.0 (MarshMallow), my project compiles and runs. But those requests that require authentication headers are failing on MarshMallow with:
BasicNetwork.performRequest: Unexpected response code 401 com.android.volley.AuthFailureError
However the same is running on all Api level below 23.
I have checked the headers many times.Strangely, those requests that do not require authentication are giving response with 200 OK.
Right now I am totally clueless what is breaking the requests, does anybody have any idea what has changed in new Version that HttpURLConnection request fails for only Api level 23? Is anybody else using Volley and facing similar issue?
Here is my CustomRequest Class
public class CustomRequest extends Request<Void> {
int id, cmd;
Map<String, String> params;
BaseModel model;
public CustomRequest(int method, int cmd, String url, Map<String, String> params, int id, BaseModel model) {
super(method, url, null);
this.id = id;
this.cmd = cmd;
this.params = params;
this.model = model;
if (method == Method.GET) {
setUrl(buildUrlForGetRequest(url));
}
Log.v("Volley", "Making request to: " + getUrl());
}
private String buildUrlForGetRequest(String url) {
if (params == null || params.size() == 0) return url;
StringBuilder newUrl = new StringBuilder(url);
Set<Entry<String, String>> paramPairs = params.entrySet();
Iterator<Entry<String, String>> iter = paramPairs.iterator();
newUrl.append("?");
while (iter.hasNext()) {
Entry<String, String> param = iter.next();
newUrl
.append(param.getKey())
.append("=")
.append(param.getValue());
if (iter.hasNext()) newUrl.append("&");
}
return newUrl.toString();
}
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = new HashMap<String, String>();
headers.put("X-Api-Version", Contract.API_VERSION);
headers.put("X-Client", "android");
String accessToken = APP.getInstance().getToken();
if (!accessToken.equals("")) {
headers.put("Authorization", "Bearer " + accessToken);
}
return headers;
}
#Override
protected Response<Void> parseNetworkResponse(NetworkResponse response) {
Exception ex;
try {
String jsonString = new String(
response.data, HttpHeaderParser.parseCharset(response.headers));
JsonNode json = new ObjectMapper().readTree(jsonString);
if (model != null) model.parse(id, json);
EventBus.getDefault().post(new EventResponse(cmd, true, null));
return Response.success(null, HttpHeaderParser.parseCacheHeaders(response)); //Doesn't return anything. BaseModel.parse() does all the storage work.
} catch (NoMoreDataException e) {
ex = e;
EventBus.getDefault().post(new NoMoreDataModel(cmd, e));
EventBus.getDefault().post(new EventResponse(cmd, false, null));
return Response.success(null, HttpHeaderParser.parseCacheHeaders(response));
} catch (Exception e) {
ex = e;
Log.e("CustomRequest", Log.getStackTraceString(e));
String message = APP.getInstance().getString(R.string.failedRequest);
if (!TextUtils.isEmpty(e.getMessage()))
message = e.getMessage();
EventBus.getDefault().post(new ErrorEventModel(cmd, message, e));
return Response.error(new ParseError(ex));
}
}
#Override
protected Map<String, String> getParams() throws AuthFailureError {
return params;
}
#Override
protected void deliverResponse(Void response) {
Log.v("Volley", "Delivering result: " + getUrl());
}
#Override
public void deliverError(VolleyError error) {
Log.e("CustomRequest", "Delivering error: Request=" + getUrl() + " | Error=" + error.toString());
String message = APP.getInstance().getString(R.string.failedRequest);
EventBus.getDefault().post(new ErrorEventModel(cmd, message, error));
}
}
Only difference I found between Api 23 and others is the HostNameVerifier.
For Api level 23 : com.android.okhttp.internal.tls.OkHostnameVerifier
For Api level <23 : javax.net.ssl.DefaultHostnameVerifier.
After checking the Server side of my application, found the reason behind the issue.
For Android 6.0(MarshMallow) the headers were becoming empty and this was not the case with other versions.
So the fix that worked for me:
Created and Added a new custom header X-Proxy-No-Redirect => 1 and passed along with other headers.
Theory behind it:
There is a API server to which we send request, then the API server redirects the request to corresponding site based on the oAuth token
While redirecting
For the redirection to happen, there are two ways to do that
1 - We just send a response back to the caller stating to redirect to a certain page. Then the caller(Networking library) takes care of redirection
2 - API server will itself makes the redirect request and get the response and then pass to caller
Earlier we were using the Method 1.
On Android 6.0 - The networking lib(Volley) doesn't seem to set all the headers while making the redirection request.
Once this new header is set, Method 2 will come into effective.
P.S This fix was applicable for my application project , maybe not for others.Just providing what was wrong and what helped me.

Resources