Disable jsession id from filter in spring - spring

I have written a filter that extends AbstractAuthenticationProcessingFilter.
The following is the overridden method:
#Override
public Authentication attemptAuthentication(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse)
throws AuthenticationException, IOException, ServletException {
if (StringUtils.isNoneBlank(cookie)) {
return authenticationProvider.authenticate(token);
//Here I want to return jsession id and establish a session.
} else {
return handleInSomeOtherWay(httpServletRequest);
//Here I DONT want to return jsessionid
}
}
How can I achieve returning jsession id in one path and not in another path? I tried to set allowSessionCreation = false, but that did not help.

Related

How do it set username to security context

I am using Spring boot.
I am using my own authentication server to authenticate my users.
So after calling my auth server, with my result which is a json of UserInfo class.
How am I able to set it in security context?
I see my class as a different class type of user from org.springframework.security.core.userdetails.User and org.springframework.security.core.userdetails.UserDetails.
This is my JwtAuthenticationFilter class.
#Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
#Autowired
private AuthenticationService authenticationService;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
getJwtFromRequest(request, response, filterChain);
}
private void getJwtFromRequest(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String bearerToken = request.getHeader("Authorization");
if (!StringUtils.hasText(bearerToken) || !bearerToken.startsWith("Bearer ")) {
throw new AccessTokenMissingException("No access token found in request headers");
}
// Call auth server to validate token
try {
ResponseEntity<String> result = authenticationService.getUserInfo(bearerToken.substring(7));
UserInfo user = new ObjectMapper().readValue(result.getBody(), UserInfo.class);
System.out.println(user.toString());
// Invalid access token
if (!result.getStatusCode().is2xxSuccessful()) {
throw new InvalidAccessTokenException("Invalid access token");
}
} catch (HttpClientErrorException.Unauthorized | IOException e) {
throw new InvalidAccessTokenException("Invalid access token");
}
//add to security context
filterChain.doFilter(request, response);
}
}
This is my UserInfo class.
#Getter
#Setter
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class UserInfo implements Serializable {
private List<String> role = new ArrayList<>();
private String username
private String email;
}
From the Spring Security Reference documentation
All you need to do is write a filter (or equivalent) that reads the
third-party user information from a location, build a Spring
Security-specific Authentication object, and put it into the
SecurityContextHolder. In this case you also need to think about
things which are normally taken care of automatically by the built-in
authentication infrastructure. For example, you might need to
pre-emptively create an HTTP session to cache the context between
requests, before you write the response to the client
An example for creating a simple Authentication object is also provided
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#what-is-authentication-in-spring-security
SecurityContextHolder.getContext().setAuthentication(anAuthentication);
Here anAuthentication is an Authentication object to be set to the SecurityContext.
Update :
Authentication

Spring Security - Adding a custom filter for Authorization

we are implementing some api.
The authentification is done in the Front, and it send us a Bearer in the authorization Header.
We have created a method with validates the token (it calls some rest services xxx ) and another method with returns a list of roles that the user has .
Is it possible to create a filter that will do this verification ??
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
#Override
protected void doFilter(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain) throws IOException, ServletException {
System.out.println("IN FILTER");
String header = req.getHeader("Authorization");
if (header == null || !header.startsWith("Bearer")) {
chain.doFilter(req, res);
return;
}
String token = request.getHeader(HEADER_STRING);
if (validateMyToken(token)) {
List<String> mygroups = getMyGroups(token);
} else {
throw new InvalidTokenException("Token is not Ok :(");
}
#HOW DO I PUT MY GROUPS, SOMEWHERE FOR VERIFICATION ???
}
}
And use it in my controller :
#RestController
#RequestMapping(value = "/applications/")
public class TestController {
#PreAuthorize("hasRole('ROLE_ADMIN')")
#GetMapping(value = "/test")
public String getContacts() {
System.out.println("IN CONTROLLER");
return "toto";
}
}
I know I have to do something in WebSecurity, but don't know how
You need to create a custom UserDetails implementation https://docs.spring.io/spring-security/site/docs/4.2.6.RELEASE/apidocs/org/springframework/security/core/userdetails/UserDetails.html . After that create a proper Authorities collection according to your List<String> mygroups = getMyGroups(token);. If you want to secure methods with roles just mark them with #Secured / #RolesAllowed or just like you wrote with #PreAuthorize("hasRole('ROLE_ADMIN')")

using servlet filter with session variable

I have created a Java web application using JSF 2.
When a user login to my application, I store his identifier in the session, so:
FacesContext context = FacesContext.getCurrentInstance();
context.getExternalContext().getSessionMap().put("userid", myBean.getUserId());
Then I created my filter:
public class PageFilter implements Filter {
private FilterConfig filterconfig;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterconfig = filterconfig;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httprequest =(HttpServletRequest) request;
HttpServletResponse httpresponse =(HttpServletResponse) response;
HttpSession session = ((HttpServletRequest) request).getSession();
String userid = (String) session.getAttribute("userid");
String pageRequested = httprequest.getRequestURI();
try {
if( userid != null && pageRequested.contains("index.xhtml") ) {
System.out.printf("User authenticated with " + httprequest.getRemoteUser() + " username conected.");
httprequest.getRequestDispatcher("/service/home.xhtml").forward(request, response);
} else {
chain.doFilter(request, response);
}
}catch(IOException | ServletException e){
//do something
}
}
#Override
public void destroy() {
System.out.print("Existing from loginFilter");
}
}
My scope is to manage the refresh button of the browser so if user is already logged then user is redirected to /service/home.xhtml. Also, the url in my web application is always:
localhost:8080/myapplication
So if user browses the site among all the pages, the url is always that (the action is hidden).
The problem is that if user clicks on the url in the browser, the request is for index.xhtml and my session is null (I cannot get user identifier by session.getAttribute("userid");).
Where is my fault?
The index.xhtml is defined as welcome-file-list in my web.xml:
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
Thanks.

Modify request URI in spring mvc

I have a spring mvc based application. I want to modify the request URI before it reaches controller. For example, RequestMapping for controller is "abc/xyz" but the request coming is "abc/1/xyz". I want to modify incoming request to map it to controller.
Solution1: Implement interceptor and modify incoming request URI. But the problem here is that as there is no controller matching the URI pattern "abc/1/xyz", it does not even goes to interceptor.(I might be missing something to enable it if its there)
Get around for it could be to have both of URI as request mapping for controller.
What other solutions could be there? Is there a way to handle this request even before it comes to spring. As in handle it at filter in web.xml, i am just making it up.
You could write a servlet Filter which wraps the HttpServletRequest and returns a different value for the method getRequestURI. Something like that:
public class RequestURIOverriderServletFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request) {
#Override
public String getRequestURI() {
// return what you want
}
}, response);
}
// ...
}
The servlet filter configuration must be added into the web.xml.
But sincerly, there is probably other way to solve your problems and you should not do this unless you have very good reasons.
in order to achieve this you should replace every place that affected when you calling uri.
the place that not mentioned is INCLUDE_SERVLET_PATH_ATTRIBUTE which is internally is accessed when going deeper.
public class AuthFilter implements Filter {
private final Logger logger = LoggerFactory.getLogger(AuthFilter.class);
private final String API_PREFIX = "/api";
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String requestURI = httpRequest.getRequestURI();
if (requestURI.startsWith(API_PREFIX)) {
String redirectURI = requestURI.substring(API_PREFIX.length());
StringBuffer redirectURL = new StringBuffer(((HttpServletRequest) request).getRequestURL().toString().replaceFirst(API_PREFIX, ""));
filterChain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request) {
#Override
public String getRequestURI() {
return redirectURI;
}
#Override
public StringBuffer getRequestURL() {
return redirectURL;
}
#Override
public Object getAttribute(String name) {
if(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE.equals(name))
return redirectURI;
return super.getAttribute(name);
}
}, response);
} else {
filterChain.doFilter(request, response);
}
}
}
You can use a URL Re-Write which are specifically meant for this purpose i.e. transform one request URI to another URI based on some regex.

Spring Security authentication via URL

I have a Spring MVC app that uses Spring Security and form based login for authorization/authentication.
Now I want to add a special URL that includes a token that should be accessible without additional information because the token is unique to a user:
http://myserver.com/special/5f6be0c0-87d7-11e2-9e96-0800200c9a66/text.pdf
How do I need to configure Spring Security to use that token for user authentication?
You need to define your custom pre auth filter.
In security app context within http tag:
<custom-filter position="PRE_AUTH_FILTER" ref="preAuthTokenFilter" />
Then define your filter bean (and its properties approprietly):
<beans:bean class="com.yourcompany.PreAuthTokenFilter"
id="preAuthTokenFilter">
<beans:property name="authenticationDetailsSource" ref="authenticationDetailsSource" />
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
</beans:bean>
Create your custom filter extended from GenericFilterBean
public class PreAuthTokenFilter extends GenericFilterBean {
private AuthenticationEntryPoint authenticationEntryPoint;
private AuthenticationManager authenticationManager;
private AuthenticationDetailsSource authenticationDetailsSource = new WebAuthenticationDetailsSource();
#Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String token = getTokenFromHeader(request);//your method
if (StringUtils.isNotEmpty(token)) {
/* get user entity from DB by token, retrieve its username and password*/
if (isUserTokenValid(/* some args */)) {
try {
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
Authentication authResult = this.authenticationManager.authenticate(authRequest);
SecurityContextHolder.getContext().setAuthentication(authResult);
} catch (AuthenticationException e) {
}
}
}
chain.doFilter(request, response);
}
/*
other methods
*/
If you don't want or cannot retrieve a password, you need to create your own AbstractAuthenticationToken which will receive only username as param (principal) and use it instead of UsernamePasswordAuthenticationToken:
public class PreAuthToken extends AbstractAuthenticationToken {
private final Object principal;
public PreAuthToken(Object principal) {
super(null);
super.setAuthenticated(true);
this.principal = principal;
}
#Override
public Object getCredentials() {
return "";
}
#Override
public Object getPrincipal() {
return principal;
}
}
You can provide a custom PreAuthenticatedProcessingFilter and PreAuthenticatedAuthenticationProvider. See Pre-Authentication Scenarios chapter for details.
I ran into this problem, and solved it using a custom implementation of the Spring Security RembereMe Service infrastructure. Here is what you need to do.
Define your own Authentication object
public class LinkAuthentication extends AbstractAuthenticationToken
{
#Override
public Object getCredentials()
{
return null;
}
#Override
public Object getPrincipal()
{
return the prncipal that that is passed in via the constructor
}
}
Define
public class LinkRememberMeService implements RememberMeServices, LogoutHandler
{
/**
* It might appear that once this method is called and returns an authentication object, that authentication should be finished and the
* request should proceed. However, spring security does not work that way.
*
* Once this method returns a non null authentication object, spring security still wants to run it through its authentication provider
* which, is totally brain dead on the part of Spring this, is why there is also a
* LinkAuthenticationProvider
*
*/
#Override
public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response)
{
String accessUrl = ServletUtils.getApplicationUrl(request, "/special/");
String requestUrl = request.getRequestURL().toString();
if (requestUrl.startsWith(accessUrl))
{
// take appart the url extract the token, find the user details object
// and return it.
LinkAuthentication linkAuthentication = new LinkAuthentication(userDetailsInstance);
return linkAuthentication;
} else
{
return null;
}
}
#Override
public void loginFail(HttpServletRequest request, HttpServletResponse response)
{
}
#Override
public void loginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication)
{
}
#Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
{
}
}
public class LinkAuthenticationProvider implements AuthenticationProvider
{
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException
{
// Spring Security is totally brain dead and over engineered
return authentication;
}
#Override
public boolean supports(Class<?> authentication)
{
return LinkAuthentication.class.isAssignableFrom(authentication);
}
}
Hack up the rest rest of your spring security xml to define a custom authentication provider, and the custom remember me service.
P.S. if you do base64 encoding of the GUID in your URL it will be a few characters shorter. You can use the Apache commons codec base64 binary encoder / decoder to do safer url links.
public static String toBase64Url(UUID uuid)
{
return Base64.encodeBase64URLSafeString(toBytes(uuid));
}

Resources