Spring cloudFeignClient send header programmatically in RequestInterceptor - spring-boot

i'm working on a spring boot project where i should call a rest api using Feign via Spring Cloud, i can call the rest api using feignClient without any problem,
now the rest api that i call needs a JWT to let me consume it, to send a JWT from my code i used RequestInterceptor and this my code :
class AuthInterceptor implements RequestInterceptor {
#Override
public void apply(RequestTemplate template) {
template.header("Authorization", "Bearer eyJraWQiOiJOcTVZWmUwNF8tazZfR3RySDZkenBWbHhkY1uV_1wSxWPGZui-t1Zf2BkbqZ_h44RkjVtQquIe0Yz9efWS6QZQ");
}
}
i put manually the JWT in the code and this work fine ...
my issue is : the JWT expire after 30 min and i should call manually another rest api that generate a JWT then i hardcode it in my code...
my question is : there any solution to call programmatically the api that generate JWT then inject this JWT in the Interceptor?
Thanks in advance.
Best Regards.

Get the Token from the current HttpServletRequest header.
public void apply(RequestTemplate template) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
.getRequest();
String jwtToken = request.getHeader(HttpHeaders.AUTHORIZATION);
if (jwtToken != null) {
template.header(HttpHeaders.AUTHORIZATION, jwtToken);
}
}

Related

Spring authentication scheme using the authentication header

I am using a spring boot application and I have a web security config adapter set up to authenticate each request using the jwt.
I want to expand my service to allow a different api end point to be authenticated using the header. One of the services I am integrating with sends a web hook and all it sends is the request with the custom header I set it up to include. How can I set up a specific endpoint to only authenticate using a custom header?
You could use a OncePerRequestFilter to filter the requests to that endpoint and return a 401 if they are do not contain your header with the right value.
You would define your filter:
public class HeaderSecurityFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
String value = request.getHeader("Token");
if(value == null || !value.equals("Secret")) {
response.sendError(401);
return;
}
chain.doFilter(request, response);
}
}
And then register it:
#Configuration
public class HeaderSecurityConfiguration {
#Bean
FilterRegistrationBean<HeaderSecurityFilter> filterRegistration() {
FilterRegistrationBean<HeaderSecurityFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new HeaderSecurityFilter());
registration.addUrlPatterns("/some/path/*");
return registration;
}
}
Which would require the header of Token be present with a value of Secret for anything under /some/path/*.
You would also need to ensure through your oauth configuration that you open up access to /some/path/*.

Spring Boot Security , Form based login to invoke a custom API for authentication

So wondering if it's possible or not. I'm trying to authenticate my rest API's in spring boot with a post API which is already present which validate the user.
I'm using fromLogin based authentication and trying to invoke that Rest Controller and use that login API by passing the post parameter. There I'm creating the spring security context
I'm trying to invoke the POST API of login on login submit. Authentication is not working.
Can we achieve this using form login? Let me know if my understanding very new to spring boot security
My code somewhat looks like this
Controller
#RestController
#RequestMapping("/somemapping")
public class AuthController {
#RequestMapping(value = "/login", method = RequestMethod.POST)
public UserData authenticateUser(#RequestBody(required = true) UserInfo userInfo, HttpServletRequest request) {
// get user data goes here
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userdata.getUsername(), userdata.getPassword(), new ArrayList < > ());
authentication.setDetails(userdata);
SecurityContextHolder.getContext().setAuthentication(authentication);
send the info to caller
return userdata;
}
//Security Adapter
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/somemapping/**", "/login*", ).permitAll()
.anyRequest().authenticated().and()
.formLogin().loginPage("/")
.and().authenticationEntryPoint(authenticationPoint);
}

Convert SAML 2.0 to JWT while redirecting from /saml/sso

I have a requirement to create a service provider form ADFS IDP. IDP is sending a SAML 2.0 token and in service side I am receiving it.
I have used spring security same extension plugin in service provider.
My code’s flow is mentioned below
/saml/login ——> will make a call to ADFS(IDP)———>redirect to saml/sso (with SAML token)
Now from this same/sso redirection to Front end (client will happen, which requested the token). I want to send back JWT instead of SAML to send back to browser.
What will be the best way to do it. How can I make /saml/sso to covert SAML to JWT in successRedirectHandler.
Sample handler
#Bean
public SavedRequestAwareAuthenticationSuccessHandler successRedirectHandler() {
SavedRequestAwareAuthenticationSuccessHandler successRedirectHandler =
new SavedRequestAwareAuthenticationSuccessHandler();
successRedirectHandler.setDefaultTargetUrl("/landing");
return successRedirectHandler;
}
Please note that I am using Nimbus JSON JWT jar for SAML to JWT conversion. I would prefer not to create a separate controller to convert SAML to JWT. Any help and pointers will be helpful.
Basically, after the authentication on the IDP side, you'll receive the assertions in response. You'll extract the attributes and perform some validation on the service side. You'll create JWT token with desired attributes. After that, you can redirect to target url with the token. Below is a snippet of code.
public class SAMLLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
public SAMLLoginSuccessHandler() {}
#Override
public void onAuthenticationSuccess(final HttpServletRequest request,
final HttpServletResponse response, final Authentication authentication)
throws IOException, ServletException {
if (authentication.getPrincipal() instanceof UserDetails
|| authentication.getDetails() instanceof UserDetails) {
UserDetails details;
String failureRedirectUrl = Constants.REDIRECTION_WEB;
if (authentication.getPrincipal() instanceof UserDetails) {
details = (UserDetails) authentication.getPrincipal();
} else {
details = (UserDetails) authentication.getDetails();
}
String username = details.getUsername();
SAMLCredential credential = (SAMLCredential) authentication.getCredentials();
List<Attribute> attributes = credential.getAttributes();
// validate user related information coming in assertions from IDP
// TODO:JWT Token generation code
// eventually you want to send that code to client therefore append the token
// in the url to which you want to redirect
String redirectUri; // set the redirect uri
response.sendRedirect(redirectUri);
}
super.onAuthenticationSuccess(request, response, authentication);
}
}

Spring Cloud RestTemplate add auth token

How to correctly implement restTemplate with authorisation token?
I have a Zuul gateway which passes a JWT downstream to other services correctly, assuming I don't want to do anything on the gateway first, using a config like:
zuul:
sensitive-headers:
routes:
instance-service:
path: /instances/**
strip-prefix: false
And using a token relay filter:
#Component
public class TokenRelayFilter extends ZuulFilter {
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
Set<String> headers = (Set<String>) ctx.get("ignoredHeaders");
headers.remove("authorization");
return null;
}
#Override
public boolean shouldFilter() {
return true;
}
#Override
public String filterType() {
return "pre";
}
#Override
public int filterOrder() {
return 10000;
}
}
Which just forwards everything to the instance-service, works a treat.
However if I remove the routes config from the config.yml file because I want to handle some things on the gateway before manually calling the service I loose the access token and get a 401 back from the downstream services
#ApiOperation(value = "List all instances and their properties.")
#GetMapping("/instances")
public ResponseEntity<String> instances() {
ParameterizedTypeReference<String> reference = new ParameterizedTypeReference<String>() {
};
return restTemplate.exchange("http://instance-service", HttpMethod.GET, null, reference);
}
My RestTemplate is just wired up generically
#Configuration
public class MyConfiguration {
#LoadBalanced
#Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
}
How do I correctly get the JWT back into the new RestTemplate without having to manually create and add a header in each request?
Am I supposed to be using OAuth2RestTemplate?
After some discussion, it seems like you have two options:
Implement and endpoint and dig the Auth header out via #RequestParam on request. From there, you can add it back on for the subsequent outbound request via RestTemplate to your downstream service.
Use Zuul to proxy your request (Auth header included, make sure its excluded from the sensitive-headers config) and implement a pre filter to include any additional logic you might need.
If I had to pick, it sounds like something Zuul should be doing since it's likely acting as your gateway for both your queue and other services, and it looks like you are trying to implement a proxy request, which Zuul can already do, but it's tough to say without knowing the full scope of the architecture.

Passing a new header in Spring Interceptor

I want to add authentication logic to interceptor. When service is called, interceptor will authenticate. Once authenticated, I want to put a new header in the request say 'header-user': 'john-doe'. But in interceptor, I am unable to do that, when I add to response.setHeader(), nothing happens.
I want to use this new header in actual REST service.
public class AuthInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// Authenticate
// Add header
response.setHeader("header-user", "john-doe"); // not working
return true;
}
...
}
If I add Filter, filter is called before Interceptor.
I figured out from Using Spring Interceptor that I can use setAttribute
request.setAttribute("user", "john-doe");
In controller side use,
public String testService(#RequestAttribute("user") String user){

Resources