Return Http Status (eg. 401) or redirect Spring Security - spring

Hi I use this configuration to Spring Security:
<http auto-config="true" use-expressions="true">
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
<form-login login-page="/login" login-processing-url="/resources/j_spring_security_check" authentication-failure-url="/login?login_error=t"/>
<logout logout-url="/resources/j_spring_security_logout"/>
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
</http>
I need to return an Http Error Code like 401 if the Content-Type in my header's request is: application/json; otherwise I want to redirect to Login Page.
But with this configuration, regardless of request content type I'm being redirected to login url with a 302 response code..
Is there a way to do this??
EDIT:
I want use only one servlet to handler the html and json so I try this:
#Component
public class CustomEntryPoint extends LoginUrlAuthenticationEntryPoint {
private final Logger log = LoggerFactory.getLogger(CustomEntryPoint.class);
public CustomEntryPoint(String loginFormUrl) {
super(loginFormUrl);
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
if(request.getContentType() != null && request.getContentType().equals("application/json")) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied");
}else {
super.commence(request, response, authException);
}
}
}
And this is my new Security Configuration:
<http auto-config="true" use-expressions="true" entry-point-ref="customEntryPoint">
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
<form-login login-page="/login" login-processing-url="/resources/j_spring_security_check" authentication-failure-url="/login?login_error=t"/>
<logout logout-url="/resources/j_spring_security_logout"/>
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
</http>
<beans:bean id="customEntryPoint" class="x.x.CustomEntryPoint">
<beans:constructor-arg value="/login"/>
</beans:bean>
What do you think about that? It is a correct way to do it, or do you know a better way?
Thank you

I solved in this way:
public class CustomEntryPoint extends LoginUrlAuthenticationEntryPoint {
private static final String XML_HTTP_REQUEST = "XMLHttpRequest";
private static final String X_REQUESTED_WITH = "X-Requested-With";
public CustomEntryPoint(String loginFormUrl) {
super(loginFormUrl);
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException {
if (XML_HTTP_REQUEST.equals(request.getHeader(X_REQUESTED_WITH))) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
} else {
super.commence(request, response, exception);
}
}
}
And Security configuration is:
<http auto-config="true" use-expressions="true" entry-point-ref="customEntryPoint">
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
<form-login login-page="/login" login-processing-url="/resources/j_spring_security_check" authentication-failure-url="/login?login_error=t"/>
<logout logout-url="/resources/j_spring_security_logout"/>
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/**" access="isAuthenticated()" />
</http>
<beans:bean id="customEntryPoint" class="x.x.CustomEntryPoint">
<beans:constructor-arg value="/login"/>
</beans:bean>

Related

BasicAuthenticationFilter onUnsuccessfulAuthentication call twice

in beans:
<http auto-config="false" disable-url-rewriting="false">
<intercept-url pattern="/server/**" access="permitAll"/>
<intercept-url pattern="/includes/**" access="permitAll"/>
<intercept-url pattern="/favicon.ico" access="permitAll"/>
<intercept-url pattern="/" access="permitAll"/>
<intercept-url pattern="/index.html" access="permitAll"/>
<intercept-url pattern="/help/**/*" access="permitAll"/>
<intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
<custom-filter ref="unsuccessfulBasicAuthenticationFilter" position="BASIC_AUTH_FILTER"/>
</http>
Call twice:
public class UnsuccessfulBasicAuthenticationFilter extends BasicAuthenticationFilter {
#Override
protected void onUnsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException {
if (failed instanceof BadCredentialsException) {
failedLogonAttemptsHandler.onFailedLogonAttempt();
}
super.onUnsuccessfulAuthentication(request, response, failed);
}
}
But method onUnsuccessfulAuthentication call twice.

Unable to use access="permitAll"

I am using spring 4 and hibernate 5.
Below is the xml config for my spring security.
I have this line:
<intercept-url pattern="/android/download" access="permitAll" />
When i tried access from SOAPUI, all i get is
Authentication request failed: com.test.common.JwtTokenMissingException: No token found in request headers. Please login again!
com.test.common.JwtTokenMissingException: No token found in request headers. Please login again!
Is there something wrong with my config file? I do not wish to set to security="none" as i want it to go through spring security.
Could it be the order in which the authenication is done in my CustomAuthenticationFilter class?
XML file for spring security:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<sec:http auto-config="false" create-session="stateless" entry-point-ref="customEntryPoint" use-expressions="true">
<intercept-url pattern="/admin/**" access="hasRole('ADMIN') or hasRole('MANAGER') or hasRole('SUPERVISOR')" />
<intercept-url pattern="/agent/**" access="isFullyAuthenticated()" />
<intercept-url pattern="/analysis/**" access="hasRole('ADMIN') or hasRole('MANAGER') or hasRole('SUPERVISOR') or hasRole('IC') or hasRole('OPS')" />
<intercept-url pattern="/android/download" access="permitAll" />
<intercept-url pattern="/android/**" access="hasRole('ADMIN') or hasRole('SNF_AGENT')" />
<intercept-url pattern="/audit/**" access="hasRole('ADMIN')" />
<intercept-url pattern="/auth/logout" access="isFullyAuthenticated()" />
<intercept-url pattern="/external/**" access="hasRole('ADMIN') or hasRole('MANAGER') or hasRole('SUPERVISOR') or hasRole('SV_IC') or hasRole('IC') " />
<intercept-url pattern="/index.xhtml" access="hasRole('ADMIN') or hasRole('MANAGER') or hasRole('SUPERVISOR')" />
<intercept-url pattern="/misc/**" access="isFullyAuthenticated()" />
<intercept-url pattern="/mission/missions/search" access="isFullyAuthenticated()" />
<intercept-url pattern="/mission/**" access="hasRole('ADMIN') or hasRole('MANAGER') or hasRole('SUPERVISOR') or hasRole('SV_IC')" />
<intercept-url pattern="/report/**" access="hasRole('ADMIN') or hasRole('MANAGER') or hasRole('SUPERVISOR')" />
<intercept-url pattern="/request/**" access="hasRole('ADMIN') or hasRole('MANAGER') or hasRole('SUPERVISOR') or hasRole('IC') or hasRole('OPS')" />
<intercept-url pattern="/target/**" access="hasRole('ADMIN') or hasRole('MANAGER') or hasRole('SUPERVISOR') or hasRole('IC')" />
<intercept-url pattern="/trawling/**" access="hasRole('ADMIN') or hasRole('MANAGER') or hasRole('SUPERVISOR')" />
<intercept-url pattern="/**" access="denyAll" />
<sec:custom-filter ref="customAuthenticationFilter"
before="PRE_AUTH_FILTER" />
<sec:csrf disabled="true" />
</sec:http>
<sec:authentication-manager alias="authenticationManager">
<authentication-provider ref="customAuthenticationProvider" />
</sec:authentication-manager>
<beans:bean id="customAuthenticationFilter"
class="com.test.common.CustomAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="authenticationSuccessHandler"
ref="customSuccessHandler" />
</beans:bean>
<beans:bean id="customSuccessHandler" class="com.test.common.CustomSuccessHandler" />
</beans:beans>
/**EDITED **/
I missed out this portion of code for CustomAuthenticationFilter class:
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
{
String header = request.getHeader(this.tokenHeader);
if (request.getServletPath().contains(".xhtml"))
{
header = (String) request.getSession().getAttribute("token");
}
if (header == null || !header.startsWith(PropertiesUtil.TOKEN_HEADER))
{
throw new JwtTokenMissingException(msgProperty.getProperty(MessageUtil.ERR_AUTH_NO_TOKEN));
}
String authToken = header.substring(PropertiesUtil.TOKEN_HEADER.length());
JwtAuthenticationToken authRequest = new JwtAuthenticationToken(authToken);
return getAuthenticationManager().authenticate(authRequest);
}
permitAll means that any authentication, even AnonymousAuthenticationToken is allowed, however your request never makes it that far. You have a custom filter, I assume it is derived from AbstractAuthenticationProcessingFilter, and since the filter throws an exception when the header is missing, you request never makes it to the AuthenticationManager!
There are several ways to solve this, here are two.
Create another filterchain <sec:http...> for endpoints that do not require a token, and use AnonymousAuthenticationFilter for this filter chain.
Return AnonymousAuthenticationToken from your filter if the JWT header is missing.
Hope this helps.

Spring redirect view is not working

I am using Spring Controllers to show my jsp views and Spring security.
In security context, all users can access to /login (login.jsp) but only authenticated users can access to /home (home.jsp).
When i remove the session id from browser cookies, the next request in the app should redirect to login page.
My method to show login page in controller is:
#RequestMapping(value = {"/login","/login.do"})
public ModelAndView showLoginForm() {
String username = getUsername();
if(!username.equals("anonymousUser")){
return new ModelAndView("redirect:/home");
}
return new ModelAndView("login");
}
My url is on /home but when i try to redirect to login using this function return new ModelAndView("login") the browsers stay with the same url.
My spring security config
<http entry-point-ref="loginEntryPoint"
use-expressions="true" create-session="always">
<session-management
session-authentication-strategy-ref="sas" />
<intercept-url pattern="/" access="permitAll" />
<intercept-url pattern="/login.do" access="permitAll" />
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/accessDenied.do" access="permitAll" />
<intercept-url pattern="/app/**" access="permitAll" />
<intercept-url pattern="/signup/createuser" access="permitAll" />
<intercept-url pattern="/changepassword/changefirstpassword" access="permitAll" />
<intercept-url pattern="/recoverpassword/recoverPasswordRequest" access="permitAll" />
<intercept-url pattern="/resources/**" access="permitAll"/>
<intercept-url pattern="/**" access="authenticated" />
<access-denied-handler error-page="/accessDenied.do" />
<custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<custom-filter position="FORM_LOGIN_FILTER" ref="domainFormLoginFilter" />
<logout success-handler-ref="myLogoutSuccessHandler" />
</http>
Why my browser doesnt redirect to login page? tks
First remove your controller and add the following to your security configuration.
<sec:intercept-url pattern="/home" access="isAuthenticated()" />
<sec:intercept-url pattern="/login" access="permitAll()" />
Work with the framework not against or around it...

spring security roles issues

I want to have to types os users (admin and user)
This is my security xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http auto-config="true" use-expressions="true" access-denied-page="/jsp/static/deniedpage.jsp">
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/jsp/static/**" access="isAuthenticated()" />
<intercept-url pattern="/jsp/users/**" access="hasRole('ROLE_USER')" />
<intercept-url pattern="/jsp/admin/**" access="hasRole('ROLE_ADMIN')" />
<logout invalidate-session="true" logout-success-url="/login" logout-url="/logout" />
<form-login login-page="/login" default-target-url="/index" authentication-failure-url="/login?error=true" />
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="select username,password, enabled from Users where USERNAME=?"
authorities-by-username-query="select u.username, ur.authority from USERS u, USER_ROLES ur where u.user_id= ur.user_id and u.username=?" />
</authentication-provider>
</authentication-manager>
<global-method-security secured-annotations="enabled" />
And this is my LoginController
#Controller
public class LoginController {
#RequestMapping(value = "/index", method = RequestMethod.GET)
public String accessUserPage(Model model) {
model.addAttribute("message",
"This page is publicly accessible. No authentication is required to view.");
return "/users/menu";
}
#RequestMapping("/admin/menuAdmin")
public String accessSecuredPage(Model model) {
model.addAttribute("message",
"Only you are authenticated and authorized to view this page.");
return "/admin/menuAdmin";
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(ModelMap model) {
return "login";
}
#RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginerror(ModelMap model) {
model.addAttribute("error", "true");
return "login";
}
#RequestMapping(value = "/logout", method = RequestMethod.GET)
public String logout(ModelMap model) {
return "login";
}
Now everytime i'm making the login he goes to that path /jsp/users/menu even if it is the Role_Admin
As you can see i have differents paths
<intercept-url pattern="/jsp/static/**" access="isAuthenticated()" />
<intercept-url pattern="/jsp/users/**" access="hasRole('ROLE_USER')" />
<intercept-url pattern="/jsp/admin/**" access="hasRole('ROLE_ADMIN')" />
What's wrong with my code? The login works but not the way i want
Thanks
Your intercept-URL are wrong.
The pattern should not match the paths to the jsp file , but your URL path. You should write something like this .
<intercept-url pattern="/index" access="hasRole('ROLE_USER')">
<intercept-url pattern="/admin/menuAdmin" access="hasRole('ROLE_ADMIN')">

Spring Auto Login Intercept URL issue

I'm able to use the below to store a user in the SecurityContext and I get a valid Authentcation object (says im authenticated and has user_role attached) but then I still get routed to my /auth/login.html page. I stepped the code below and it is returning the "/registered/home.html" to JSF but for some reason when Spring applies the intercept rule to /registered/* it must see it as being an unauthenticated request. Any ideas?
#Named
#Scope("request")
public class SignUpDetail extends BaseAction{
#Inject
private SignUpDetailBean signUpDetailBean;
#Inject
private UserManager userManager;
#Inject #Named("am")
protected AuthenticationManager authenticationManager;
public String login(){
if(signUpDetailBean.getEmail() != null){
Users currentUser = userManager.getUser(signUpDetailBean.getEmail());
authenticateUserAndSetSession(currentUser, (HttpServletRequest) FacesUtils.getExternalContext().getRequest());
return "/registered/home.html";
}else{
return "/auth/login.html";
}
}
private void authenticateUserAndSetSession(Users user,
HttpServletRequest request)
{
UserDetails details = userManager.loadUserByUsername(user.getUsername());
UsernamePasswordAuthenticationToken usernameAndPassword =
new UsernamePasswordAuthenticationToken(
user.getUsername(), "pwd", details.getAuthorities());
// Authenticate, just to be sure
Authentication auth = authenticationManager.authenticate(usernameAndPassword);
// Place the new Authentication object in the security context.
SecurityContextHolder.getContext().setAuthentication(auth);
}
<context:annotation-config />
<context:component-scan base-package="dc" />
<global-method-security />
<http security="none" pattern="/javax.faces.resource/**" />
<http security="none" pattern="/services/rest-api/1.0/**" />
<http security="none" pattern="/preregistered/*" />
<http access-denied-page="/auth/denied.html">
<intercept-url
pattern="/**/*.xhtml"
access="ROLE_NONE_GETS_ACCESS" />
<intercept-url
pattern="/auth/**"
access="ROLE_ANONYMOUS,ROLE_USER" />
<intercept-url
pattern="/auth/*"
access="ROLE_ANONYMOUS" />
<intercept-url
pattern="/registered/*"
access="ROLE_USER" />
<intercept-url
pattern="/*"
access="ROLE_ANONYMOUS" />
<form-login
login-processing-url="/j_spring_security_check.html"
login-page="/auth/login.html"
default-target-url="/registered/home.html"
authentication-failure-url="/auth/login.html" />
<logout invalidate-session="true"
logout-success-url="/"
logout-url="/auth/logout.html"/>
<anonymous username="guest" granted-authority="ROLE_ANONYMOUS"/>
<remember-me user-service-ref="userManager" key="dfdf"/>
</http>
<!-- Configure the authentication provider -->
<authentication-manager alias="am">
<authentication-provider user-service-ref="userManager">
<password-encoder ref="passwordEncoder" />
</authentication-provider>
</authentication-manager>
Store the context object in session since you have set that particular url http security to none
...
HttpSession session = request.getSession();
...
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(auth);
session.setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, context);

Resources