Authentication is required to access this resource error - java

I created a registration and login with Spring Boot Security and so far all implementation works fine when I test it with Postman. Right now I want to create also a HTML side of that so user can actually sign up and log in.
There is a problem. I'm getting Full authentication is required to access this resource
In the stack trace there is also a line which points on AcessTokenFilter and that is this:
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
Optional<String> accessToken = parseAccessToken(request);
if(accessToken.isPresent() && jwtHelper.validateAccessToken(accessToken.get())) {
String userId = jwtHelper.getUserIdFromAccessToken(accessToken.get());
User user = userService.findById(userId);
UsernamePasswordAuthenticationToken upat = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
upat.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(upat);
}
} catch (Exception e) {
log.error("cannot set authentication", e);
}
filterChain.doFilter(request, response);
}
I'm getting that error when I try to access to: /api/auth/form
And there is a methods:
#PostMapping("signup")
#Transactional
public ResponseEntity<?> signup(#Valid #RequestBody SignupDTO dto, #ModelAttribute User user, Model model) {
User user1 = new User(dto.getUsername(), dto.getEmail(), passwordEncoder.encode(dto.getPassword()));
model.addAttribute("user", user1);
userRepository.save(user1);
RefreshToken refreshToken = new RefreshToken();
refreshToken.setOwner(user);
refreshTokenRepository.save(refreshToken);
String accessToken = jwtHelper.generateAccessToken(user);
String refreshTokenString = jwtHelper.generateRefreshToken(user, refreshToken);
return ResponseEntity.ok(new TokenDTO(user.getId(), accessToken, refreshTokenString));
}
#GetMapping("/form")
public String showForm(Model model) {
model.addAttribute("user", new User());
return "signup";
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(accessTokenEntryPoint).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(accessTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
And now I saw that on chrome im getting this:
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'GET' not supported
org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'GET' not supported

As far as i understand you want to go to /api/auth/form and you get the error?
I only see this rest mapping here:
#GetMapping("/form")
is the controller annotated with:
#RequestMapping("/api/auth")
?
Another thing: Try to work in reverse to see which part is preventing this from working: Remove spring security and see if you see the website first. Then turn security on again and try to see which lines are exactly preventing you from accessing the resource

Related

#PreAuthorize hasPermission return custom access denied message instead of access denied page

Trying to implement returning the customized denied message for consuming angular clients
*PermissionEvaluator has the implementation to authorize particular fieldName (Lets say user clicks on the button, he has to get the customized message fetched from DB)
Question is :
hasPermission was returning the html page with "Access Denied" Message
Is it possible to return customized message to the client
Message -> { statusCode, message, actionName }
#PreAuthorize("#PermissionEvaluator.hasPermission(authentication, #requestModel, 'updateSync')")
#RequestMapping(value = "/api/updateMarketValueSelected", method = RequestMethod.POST)
public ResponseEntity<List<InputFormModel>> updateAndSaveMarketValueSelected(#RequestBody RequestModel requestModel) throws ParseException {
Tried solving this problem by
#Component
#ControllerAdvice
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{
...
#ExceptionHandler(value = { MyAccessDeniedException.class })
public void commence(HttpServletRequest request, HttpServletResponse response, MyAccessDeniedException ex ) throws IOException {
String json = new ObjectMapper().writeValueAsString(ex.getRequestModel());
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.getWriter().write(json);
response.flushBuffer();
}

bypass CAS to get un/secured health infos from Spring boot app

I have a Spring Boot app using CAS WebSecurity to make sure that all incoming non authenticated requests are redirected to a common login page.
#Configuration
#EnableWebSecurity
public class CASWebSecurityConfig extends WebSecurityConfigurerAdapter {
I want to expose health endpoints through actuator, and added the relevant dependency. I want to bypass the CAS check for these /health URL which are going to be used by monitoring tools, so in the configure method, I have added :
http.authorizeRequests().antMatchers("/health/**").permitAll();
This works, but now I want to tweak it further :
detailed health status (ie "full content" as per the docs) should be accessible only to some specific monitoring user, for which credentials are provided in property file.
if no authentication is provided, then "status only" should be returned.
Following http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-monitoring.html#production-ready-health-access-restrictions, I've configured the properties as below, so that it should work :
management.security.enabled: true
endpoints.health.sensitive: false
But I have a problem with how I configure the credentials... following http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-monitoring.html#production-ready-sensitive-endpoints , I added in my config file :
security.user.name: admin
security.user.password: secret
But it's not working - and when I don't put the properties, I don't see the password generated in logs.
So I'm trying to put some custom properties like
healthcheck.username: healthCheckMonitoring
healthcheck.password: healthPassword
and inject these into my Security config so that configureGlobal method becomes :
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth,
CasAuthenticationProvider authenticationProvider) throws Exception {
auth.inMemoryAuthentication().withUser(healthcheckUsername).password(healthcheckPassword).roles("ADMIN");
auth.authenticationProvider(authenticationProvider);
}
and in the configure method, I change the config for the URL pattern to :
http.authorizeRequests()
.antMatchers("/health/**").hasAnyRole("ADMIN")
.and().httpBasic()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().csrf().disable();
With that config, I get full content when authenticated, but logically, I don't get any status (UP or DOWN) when I'm not authenticated, because the request doesn't even reach the endpoint : it is intercepted and rejected by the security config.
How can I tweak my Spring Security config so that this works properly ? I have the feeling I should somehow chain the configs, with the CAS config first allowing the request to go through purely based on the URL, so that the request then hits a second config that will do basic http authentication if credentials are provided, or let the request hit the endpoint unauthenticated otherwise, so that I get the "status only" result.. But at the same time, I'm thinking Spring Boot can manage this correctly if I configure it properly..
Thanks !
Solution is not great, but so far, that's what works for me :
in my config (only the relevant code):
#Configuration
#EnableWebSecurity
public class CASWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
//disable HTTP Session management
http
.securityContext()
.securityContextRepository(new NullSecurityContextRepository())
.and()
.sessionManagement().disable();
http.requestCache().requestCache(new NullRequestCache());
//no security checks for health checks
http.authorizeRequests().antMatchers("/health/**").permitAll();
http.csrf().disable();
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint());
http // login configuration
.addFilter(authenticationFilter())
.authorizeRequests().anyRequest().authenticated();
}
}
Then I added a specific filter :
#Component
public class HealthcheckSimpleStatusFilter extends GenericFilterBean {
private final String AUTHORIZATION_HEADER_NAME="Authorization";
private final String URL_PATH = "/health";
#Value("${healthcheck.username}")
private String username;
#Value("${healthcheck.password}")
private String password;
private String healthcheckRole="ADMIN";
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = this.getAsHttpRequest(request);
//doing it only for /health endpoint.
if(URL_PATH.equals(httpRequest.getServletPath())) {
String authHeader = httpRequest.getHeader(AUTHORIZATION_HEADER_NAME);
if (authHeader != null && authHeader.startsWith("Basic ")) {
String[] tokens = extractAndDecodeHeader(authHeader);
if (tokens != null && tokens.length == 2 && username.equals(tokens[0]) && password.equals(tokens[1])) {
createUserContext(username, password, healthcheckRole, httpRequest);
} else {
throw new BadCredentialsException("Invalid credentials");
}
}
}
chain.doFilter(request, response);
}
/**
* setting the authenticated user in Spring context so that {#link HealthMvcEndpoint} knows later on that this is an authorized user
* #param username
* #param password
* #param role
* #param httpRequest
*/
private void createUserContext(String username, String password, String role,HttpServletRequest httpRequest) {
List<GrantedAuthority> authoritiesForAnonymous = new ArrayList<>();
authoritiesForAnonymous.add(new SimpleGrantedAuthority("ROLE_" + role));
UserDetails userDetails = new User(username, password, authoritiesForAnonymous);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
private HttpServletRequest getAsHttpRequest(ServletRequest request) throws ServletException {
if (!(request instanceof HttpServletRequest)) {
throw new ServletException("Expecting an HTTP request");
}
return (HttpServletRequest) request;
}
private String[] extractAndDecodeHeader(String header) throws IOException {
byte[] base64Token = header.substring(6).getBytes("UTF-8");
byte[] decoded;
try {
decoded = Base64.decode(base64Token);
} catch (IllegalArgumentException var7) {
throw new BadCredentialsException("Failed to decode basic authentication token",var7);
}
String token = new String(decoded, "UTF-8");
int delim = token.indexOf(":");
if(delim == -1) {
throw new BadCredentialsException("Invalid basic authentication token");
} else {
return new String[]{token.substring(0, delim), token.substring(delim + 1)};
}
}
}

Modify behavior of Spring #RolesAllowed

I'm using Spring #RolesAllowed to secure my APIs (methods), but I'd like to change what happens when a method is called from an unauthorized user. The current behavior is that Spring throws an HTTP 403 error. This is great, but I would just like to add an additional error code in the body of the 403 response to be able to distinguish between access denied errors in different scenarios.
I'm having a hard time figuring out where the implementation of the #RolesAllowed annotation is located. Has anyone come across it? Or attempted to modify its behavior?
The methods in my controller currently look like the following:
#RolesAllowed({"ROLE_DEFENDANT", "ROLE_ADMIN"})
#RequestMapping(method = RequestMethod.POST, value = "/{caseId}/owner")
public ResponseEntity<?> assignOwner(#PathVariable String caseId) {
// method implementation
}
Another way to do this is with an exception handler class and the #ExceptionHandler annotation.
#ControllerAdvice
public class GlobalExceptionHandler {
#ExceptionHandler(AccessDeniedException.class)
public ResponseEntity<?> handleAccessDenied(HttpServletRequest request, AccessDeniedException ex) {
// exception handling logic
if (request.getUserPrincipal() == null) {
// user is not logged in
} else {
// user is logged in but doesn't have permission to the requested resource
}
// return whatever response you'd like
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
}
What you are trying to do, can be done without having to modify the annotation.
In your Spring config, you can specify an AccessDeniedHandler bean which will be called when Spring Security determines that your user is not allowed to perform the action that they've tried to perform.
The access denied handler is really simple:
public class CustomDefaultAccessDeniedHandler implements AccessDeniedHandler {
#Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
An example of an AuthenticationProvider that gives you a bit more information about what failed would be:
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
private UserService userService;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
String username = String.valueOf(auth.getPrincipal().toString());
String password = String.valueOf(auth.getCredentials());
if(username.isEmpty() || password.isEmpty()){
throw new UsernameNotFoundException("You pudding, there is no username or password");
} else {
SystemUser user = userService.findByUsername(username);
if(user == null){
throw new UsernameNotFoundException("No user exists, stop hacking");
}
//Do more stuff here to actually apply roles to the AuthToken etc
return new UsernamePasswordAuthenticationToken(username, null, authorities);
}
}
}

Redirect to desired location after login

I know this question can be found with different solutions. But I am unable to get it working in my project.
We are sending mails to users which has link to perform some action in the application. When user click on url he should be redirect to login page if he is not logged in and after login should be navigated to the targeted URL.
I am trying to fix using CustomLoginSuccessHandler here is the code.:
public class CustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
// public CustomLoginSuccessHandler(String defaultTargetUrl) {
// setDefaultTargetUrl(defaultTargetUrl);
// }
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
HttpSession session = request.getSession(false);
if (session != null) {
String redirectUrl = (String) session.getAttribute("url_prior_login");
if (redirectUrl != null) {
// we do not forget to clean this attribute from session
session.removeAttribute("url_prior_login");
// then we redirect
getRedirectStrategy().sendRedirect(request, response, redirectUrl);
} else {
super.onAuthenticationSuccess(request, response, authentication);
}
} else {
super.onAuthenticationSuccess(request, response, authentication);
}
}
}
Configurations I am using are :
#Bean
public SavedRequestAwareAuthenticationSuccessHandler authenticationSuccessHandler(){
CustomLoginSuccessHandler successHandler = new CustomLoginSuccessHandler();
// SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
// successHandler.setUseReferer(true); getting NULL in the controller every time
// successHandler.setTargetUrlParameter("targetUrl"); this also doesnt work as browser is redirect to /login page and URL parameters are lost
return successHandler;
}
protected void configure(HttpSecurity http) throws Exception {
http
.logout().logoutUrl("/logout").deleteCookies("JSESSIONID").logoutSuccessUrl("/logoutSuccess")
.and()
.authorizeRequests()
.antMatchers("/privacyPolicy", "/faq", "/aboutus", "/termsofuse", "/feedback","/feedbackSubmit", "/contactSsm", "/resources/**", "/userReply", "/userReplySubmit", "/image", "/logoutExternal", "/closeit").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(authenticationSuccessHandler)
.loginPage("/login")
.defaultSuccessUrl("/")
.permitAll();
// .and().exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint());
}
Problem using this configuration is, If i request for url say 'http:localhost:8080/showPage' spring security is navigating to 'http:localhost:8080/login' and I am unable to capture anything from original URL. Same problem occurs when I try to use a custom variable targetUrl and using it in the same CustomLoginSuccessHandler.
Please let me know if am taking a wrong approach or something else is missing
Also tried using Custom EntryPoint but unable to redirect using my entrypoint.
#Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint{
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
request.getSession().setAttribute("targetUrl",request.getRequestURL());
redirectStrategy.sendRedirect(request,response,request.getRequestURL().toString());
}
}
Controller :
#RequestMapping(value="/login")
public ModelAndView loginHandler(HttpServletRequest request) {
ModelAndView mav = new ModelAndView();
String targetUrl = request.getParameter("targetUrl");
if(targetUrl!=null){ // targetUrl is always null as spring security is navigating to /login asd parameters are lost
request.getSession().setAttribute("url_prior_login",targetUrl);
}
mav.setViewName("login");
return mav;
}
To login, page is navigated to a different domain. and I pass a redirect URL to that domain after successful login it redirects the page back to the redirecturl
<a href="https://domain/sso/identity/login?channel=abc&ru=${externalUrl.applicationUrl}login" >Sign In</a>
Spring Security already stores the request using a RequestCache the default implementation HttpSessionRequestCache stores the last request in the HTTP session. You can access it using the SPRING_SECURITY_SAVED_REQUEST attribute name to get it from the session.
Doing something like this in your controller
public ModelAndView login(HttpServletRequest req, HttpSession session) {
ModelAndView mav = new ModelAndView("login");
if (session != null) {
SavedRequest savedRequest = session.getAttribute("SPRING_SECURITY_SAVED_REQUEST");
if (savedRequest != null) {
mav.addObject("redirectUrl", savedRequest.getRedirectUrl());
}
}
return mav;
}
Then in your JSP you can use the redirectUrl to dynamically construct your URL.
http://your.sso/login?url=${redirectUrl}
The final thing you need to do is to make /login accessible for everyone by adding it to the list which is protected by permitAll(). If you don't do this, you will get into a loop or the last request is overwritten and will always point to the login page.
.antMatchers("/privacyPolicy", "/faq", "/aboutus", "/termsofuse", "/feedback","/feedbackSubmit", "/contactSsm", "/resources/**", "/userReply", "/userReplySubmit", "/image", "/logoutExternal", "/closeit", "/login").permitAll()
You don't need any other custom classes like EntryPoints or AuthenticationSuccessHandler implementations.
However as you are using SSO it would be probably best to investigate a proper integration with the SSO solution instead of this hack with a login page.
You will at least have one problem : HttpSession session = request.getSession();.
getSession()
Returns the current session associated with this request, or if the request does not have a session, creates one.
You should use getSession(false) if you want a null return in case there is no session.
In your case you'll never get a null session.
I had the same issue and have solved it by using SavedRequestAwareAuthenticationSuccessHandler as a successHandler to make Spring handle the saved request that was requested before redirecting to login page when user is not logged.
In WebSecurityConfigurerAdapter:
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String LOGIN_PATH = "/login";
#Autowired
MyApplicationAuthenticationSuccessHandler myApplicationAuthenticationSuccessHandler;
#Override
protected void configure(HttpSecurity http) throws Exception {
// Set the default URL when user enters a non internal URL (Like https://my-application.com)
myApplicationAuthenticationSuccessHandler.setDefaultTargetUrl("/myapp/home");
http.authorizeRequests().antMatchers("/resources/**").permitAll().antMatchers(LOGIN_PATH).permitAll().antMatchers("/auto/**").authenticated()
.and().formLogin().loginPage(LOGIN_PATH).permitAll()
.successHandler(myApplicationAuthenticationSuccessHandler).and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl(LOGIN_PATH)
.invalidateHttpSession(true).deleteCookies("JSESSIONID").permitAll().and().sessionManagement().invalidSessionUrl(LOGIN_PATH);
}
}
In custom SavedRequestAwareAuthenticationSuccessHandler:
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
#Component("myApplicationAuthenticationSuccessHandler")
public class MyApplicationAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException {
try {
super.onAuthenticationSuccess(request, response, authentication);
} catch (ServletException e) {
// redirect to default page (home in my case) in case of any possible problem (best solution in my case)
redirectStrategy.sendRedirect(request, response, "/myapp/home");
}
}
}

Manually authenticate use spring security

I am using spring security and it works fine, but now I want to start the security process manually, do to client changes I need to get in my controller the user name and password (the form wont call "j_spring_security_check" directly)
I thought of 2 options with both I have some problems:
After I get the parameters and do something I will send a post request to j_spring_security_check url. My code:
public void test(loginDTO loginDTO) {
MultiValueMap<String, String> body = new LinkedMultiValueMap<String, String>();
HttpHeaders headers = new HttpHeaders();
body.add(
"j_username",
loginDTO.getJ_username());
body.add(
"j_password",
loginDTO.getJ_password());
HttpEntity<?> httpEntity = new HttpEntity<Object>(
body, headers);
headers.add(
"Accept",
MediaType.APPLICATION_JSON_VALUE);
restTemplate.exchange(
"http://localhost:8080/XXX/j_spring_security_check",
HttpMethod.POST,
httpEntity,
HttpServletResponse.class);
}
This doesn't work and I get :500 internal server error why?
second option- I did the following:
public void test2(loginDTO loginDTO, HttpServletRequest request) {
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken(
loginDTO.getJ_username(),
loginDTO.getJ_password());
token.setDetails(new WebAuthenticationDetails(request));
Authentication authentication = this.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
this.sessionRegistry.registerNewSession(
request.getSession().getId(),
authentication.getPrincipal());
}
The problem is that onAuthenticationSuccess is not called. and it feels wrong, that I'm missing the point of using spring security.
What is the correct why?
I typically do the following:
#Controller
public class AuthenticationController
{
#Autowired
AuthenticationManager authenticationManager;
#Autowired
SecurityContextRepository securityContextRepository;
#RequestMapping(method = Array(RequestMethod.POST), value = Array("/authenticate"))
public String authenticate(#RequestParam String username, #RequestParam String password, HttpServletRequest request, HttpServletResponse response)
{
Authentication result = this.authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
SecurityContextHolder.getContext.setAuthentication(result);
this.securityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response);
return "successView";
}
}
The reasons for using this approach is:
Very simple, just a few lines of code if you ignore exception handling and such.
Leverages existing Spring Security components.
Uses Spring Security components configured in the application configuration and allows them to be changed as and when required. For example, the authentication may be done against an RDBMS, LDAP, web service, Active Directory, etc. without the custom code needing to worry about it.
When you want to use as most as possible from the normal Authentication Process, then you could create a mocked HttpServletRequest and HttpServletResponse (org.springframework.mock.web.MockHttpServletRequest and org.springframework.mock.web.MockHttpServletResponse) containing login and password, and then invoke
UsernamePasswordAuthenticationFilter.attemptAuthentication(
HttpServletRequest request,
HttpServletResponse response)`
afterwards you will also need to invoke SessionAuthenticationStrategy.onAuthentication(..) and successfulAuthentication(..)
This is all a bit tricky, because of private fileds, so this is my solution:
public class ExtendedUsernamePasswordAuthenticationFilter
extends UsernamePasswordAuthenticationFilter {
#Override
public void manualAuthentication(String login,
String password,
HttpServletRequest httpServletRequest)
throws IOException, ServletException {
/** I do not mock the request, I use the existing request and
manipulate them*/
AddableHttpRequest addableHttpRequest =
new AddableHttpRequest(httpServletRequest);
addableHttpRequest.addParameter("j_username", login);
addableHttpRequest.addParameter("j_password", password);
MockHttpServletResponse mockServletResponse =
new MockHttpServletResponse();
Authentication authentication = this.attemptAuthentication(
addableHttpRequest,
mockServletResponse);
this.reflectSessionStrategy().onAuthentication(
authentication,
addableHttpRequest,
mockServletResponse);
this.successfulAuthentication(addableHttpRequest,
mockServletResponse,
authentication);
}
private SessionAuthenticationStrategy reflectSessionStrategy() {
Field sessionStrategyField =
ReflectionUtils.findField(
AbstractAuthenticationProcessingFilter.class,
"sessionStrategy",
SessionAuthenticationStrategy.class);
ReflectionUtils.makeAccessible(sessionStrategyField);
return (SessionAuthenticationStrategy)
ReflectionUtils.getField(sessionStrategyField, this);
}
}
AddableHttpRequest is like a mock that is based on an real request
public class AddableHttpRequest extends HttpServletRequestWrapper {
/** The params. */
private HashMap<String, String> params = new HashMap<String, String>();
public AddableHttpRequest(HttpServletRequest request) {
super(request);
}
#Override
public String getMethod() {
return "POST";
}
#Override
public String getParameter(final String name) {
// if we added one, return that one
if (params.get(name) != null) {
return params.get(name);
}
// otherwise return what's in the original request
return super.getParameter(name);
}
public void addParameter(String name, String value) {
params.put(name, value);
}
}
An other way, would be implementing your own, authentication filter. Thats a class that invoke the AuthenticationManager.authenticate(Authentication authentication). But this class is also responsible for invoking all the stuff around authentication (what AbstractAuthenticationProcessingFilter.doFilter does)`
OK so I combined #Ralph and #manish answers and this is what I did:
(twoFactorAuthenticationFilter is an extension of UsernamePasswordAuthenticationFilter)
public void manualAuthentication(loginDTO loginDTO, HttpServletRequest request, HttpServletResponse response) throws IOException,
ServletException {
AddableHttpRequest addableHttpRequest = new AddableHttpRequest(
request);
addableHttpRequest.addParameter(
"j_username",
loginDTO.getJ_username());
addableHttpRequest.addParameter(
"j_password",
loginDTO.getJ_password());
UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) twoFactorAuthenticationFilter.attemptAuthentication(
addableHttpRequest,
response);
if (token.isAuthenticated()) {
twoFactorAuthenticationFilter.successfulAuthentication(
addableHttpRequest,
response,
null,
token);
}
}
It works fine

Categories

Resources