Spring - Saml2 - Customize the request built by Saml2WebSsoAuthenticationRequestFilter - spring

The actual implementation of the filter Saml2WebSsoAuthenticationRequestFilter (which responds to saml2/authentication/{regitstrationId}) has this method to create the redirect URL:
private void sendRedirect(HttpServletRequest request, HttpServletResponse response, Saml2RedirectAuthenticationRequest authenticationRequest) throws IOException {
this.authenticationRequestRepository.saveAuthenticationRequest(authenticationRequest, request, response);
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromUriString(authenticationRequest.getAuthenticationRequestUri());
this.addParameter("SAMLRequest", authenticationRequest.getSamlRequest(), uriBuilder);
this.addParameter("RelayState", authenticationRequest.getRelayState(), uriBuilder);
this.addParameter("SigAlg", authenticationRequest.getSigAlg(), uriBuilder);
this.addParameter("Signature", authenticationRequest.getSignature(), uriBuilder);
String redirectUrl = uriBuilder.build(true).toUriString();
response.sendRedirect(redirectUrl);
}
I need to add another parameter to this request so that the request built by the filter contains (beside SAMLRequest, RelayState, SigAlg and Signature) another query param (in my case it will be a "FIDP", a paramater to preselect a federate IdP)
Thanks!

Related

Add custom rest header in api is not working

I need to call a third party api via my own api. The third party api required custom headers for authentication, which i do not want exposed to client side. So what i did is add custom header and call the third party api in my api. But it is not working.
#GetMapping(value = "/downloadCompletedDocument/{id}", produces = MediaType.APPLICATION_PDF_VALUE)
public ResponseEntity<byte[]> download(#PathVariable("id") String id, #RequestHeader Map header)
{
HttpHeaders headers = new HttpHeaders();
headers.set("userloginname", "testUser");
headers.set("organizationkey", "testOrganization");
HttpEntity<String> requestEntity = new HttpEntity<>(headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<byte[]> responseObj = restTemplate
.exchange(url + id, HttpMethod.GET, requestEntity,
byte[].class);
return responseObj;
}
But when i use the tool by passing the header, it could work successfully. This is what i am not understand.
PS: I have tried filter, but same result.
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(req);
Enumeration<String> a = req.getHeaderNames();
mutableRequest.putHeader("userloginname", "testUser");
mutableRequest.putHeader("organizationkey", "testOrganization");
Enumeration<String> b = mutableRequest.getHeaderNames();
chain.doFilter(mutableRequest, response);
}
I have solved the issue by changing the third party api url from http to https. Not sure why this does not affect the rest client tool.

How to reject the request and send custom message if extra params present in Spring boot REST Api

#PostMapping()
public ResponseEntity<ApiResponse> createContact(
#RequestBody ContactRequest contactRequest) throws IOException {
}
How to reject the API request, if extra params present in the request, by default spring boot ignoring extra parameters.
I believe you can add an HttpServletRequest as a parameter to the controller method (createContact in this case). Then you'll get access to all the parameters that come with the requests (query params, headers, etc.):
#PostMapping
public ResponseEntity<ApiResponse> createContact(HttpServletRequest request,
#RequestBody ContactRequest contactRequest) throws IOException {
boolean isValid = ...// validate for extra parameters
if(!isValid) {
// "reject the request" as you call it...
}
}
First add an additional parameter to the method. This gives you access to information about the request. If Spring sees this parameter then it provides it.
#PostMapping()
public ResponseEntity<ApiResponse> createContact(
#RequestBody ContactRequest contactRequest,
WebRequest webRequest) throws IOException {
if (reportUnknownParameters(webRequest) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
}
I do something like this to get the bad request into the log.
private boolean reportUnknownParameters(WebRequest webRequest) {
LongAdder unknownCount = new LongAdder();
webRequest.getParameterMap().keySet().stream()
.filter(key -> !knownParameters.contains(key))
.forEach(key -> {
unknownCount.increment();
log.trace("unknown request parameter \"{}\"=\"{}\"", key, webRequest.getParameter(key));});
return unknownCount.longValue() > 0;
}
add #RequestParam annotation in your methods parameter list and add it as a map, then you can access for it's key list and check if it contains anything else other than your required params.
public ResponseEntity<ApiResponse> createContact(#RequestParam Map<String,String> requestParams, #RequestBody ContactRequest contactRequest) throws IOException {
//Check for requestParams maps keyList and then pass accordingly.
}

Spring boot: Add request parameter in interceptor

I need to add a parameter when a request is made:
Currently, I'm adding headers using interceptors. However, I'm running against how to add a parameter to the current request:
#Override
public ClientHttpResponse intercept(
HttpRequest request,
byte[] body,
ClientHttpRequestExecution execution
) throws IOException {
//Adding headers
request
.getHeaders()
.set(
HttpHeaders.AUTHORIZATION,
this.jwtService.getBearer()
);
//HOW TO ADD REQUEST PARAMETER HERE???
return execution.execute(request, body);
}
Any ideas?

Spring 3.2 REST API add cookie to the response outside controller

I'm using Spring 3.2.4 and Spring Security 3.2.3 to handle RESTful API call to "get security token" request that returns the token (which would be used to secure subsequent requests to the service). This is a POST request which has a body with username and password and is processed in the controller:
#RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public SessionTokenResponse getSessionToken(#RequestBody Credentials credentials, ModelAndView interceptorModel) throws AccessException {
final String token = webGate.getSessionTokenForUser(credentials.getUsername(), credentials.getPassword());
LOGGER.debug("Logged in user : " + credentials.getUsername());
interceptorModel.addObject(SessionConstants.INTERCEPTOR_MODEL_TOKEN_KEY, token); // Used by post-processing in interceptors, e.g. add Cookie
return new SessionTokenResponse(ResponseMessages.SUCCESS, token);
}
After the controller has successfully finished processing the request I would like to add a cookie with the token to the response.
I tried HandlerInterceptorAdapter implementation, but I cannot find the way to the the 'token' from the response or ModelAndView:
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView interceptorModel) throws Exception {
final String token = (String) interceptorModel.getModel().get(SessionConstants.INTERCEPTOR_MODEL_TOKEN_KEY);
if (token != null) {
final Cookie obsso = new Cookie(cookieName, token);
obsso.setPath(cookiePathUri);
obsso.setDomain(cookieDomain);
obsso.setMaxAge(cookieMaxAge);
response.addCookie(obsso);
}
}
The interceptorModel is null .
It seems that Spring MVC doesn't provide it to the postHandle since the #ResponseBody has been already resolved and there is no need for the ModelAndView anymore (this is just my assumption based on the debugging).
What is the correct way of achieving that (add cookie to the response) outside the controller in the interceptor or maybe listener?
To retrieve the token you can use the request object
request.setAttribute(SessionConstants.INTERCEPTOR_MODEL_TOKEN_KEY, token);
and then in the postHandle
String token = ( String ) request.getAttribute(SessionConstants.INTERCEPTOR_MODEL_TOKEN_KEY);
However I don't think you can add a cookie to the response object in postHandle as the response is already committed.
Perhaps you could store the token information on the servlet context instead.
In your controller, add the token information to the servlet context.
Then implement preHandle, so that every api call can check if token for that user exists on servlet context, if so you can add cookie to the response.

How to get request attributes in authentication-success-handler

I am trying to do few things in authentication-success-handler and I need to access few values which was part of initial request data being posted to Spring security.
I am posting following information when user trying to do login
j_username
j_password
storeCode
Spring security is able to authenticate user successfully and is calling "authentication-success-handler".
public class WebshopAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler
{
public WebshopAuthenticationSuccessHandler() {
}
#Override
public void onAuthenticationSuccess(final HttpServletRequest request,
final HttpServletResponse response, final Authentication authentication)
throws IOException, ServletException {
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
request.getAttribute( "storeCode" );
attr.getRequest().getAttribute( "storeCode" );
}
}
But in all way, I am not able to get value of storeCode and its coming as null.
Not sure what I am doing wrong.
I am assuming that Spring is creating a new instance of Request and response while calling onAuthenticationSuccess, but how can I pass/ retrieve values which passed passed from the login page?
If the data is from an HTTP POST request, you should be using getParameter, not getAttribute. Attributes are server-side state only, not submitted by the client.

Resources