update spring security to match url suffix - spring-security

my spring mvc application uses the following url
http://xyz.com/<war name>/springmvc/login
I have updated my web.xml
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/springmvc/*</url-pattern>
</filter-mapping>
I updated spring security xml file as follows
<http access-decision-manager-ref="accessDecisionManager" auto-config="true">
<intercept-url pattern="/springmvc/welcome*" access="ADMIN" />
<form-login login-page="/springmvc/login" default-target-url="/springmvc/welcome"
authentication-failure-url="/springmvc/loginfailed" />
<logout logout-success-url="/springmvc/logout" />
<remember-me data-source-ref="dataSource"/>
</http>
If i type springmvc/login or springmvc/welcome it goes to login page. but when I enter the username and password, I get a 404. The url changes to http://xyz.com/UserInterface/springmvc/j_spring_security_check. I expect to see hello.jsp as per the controller below
my login controller is as follows
#RequestMapping(value="/welcome", method = RequestMethod.GET)
public String printWelcome(ModelMap model) {
User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = user.getUsername();
model.addAttribute("username", name);
model.addAttribute("message", "Spring Security login + database example");
//logical view name
return "hello";
}

The default login-processing-url property value for form-login is /j_spring_security_check.
i.e. the login form will be posted to this url.
If you context root is UserInterface the default url would be http://xyz.com/UserInterface/j_spring_security_check, but you are creating the url as http://xyz.com/UserInterface/springmvc/j_spring_security_check which spring-security is not able to understand.
You have two options
Change you springSecurityFilterChain url pattern to /* from
/springmvc/*, and make sure that your custom-login form has action
as //j_spring_security_check
Add custom login-processing-url path in form-login

Related

Spring Security: Getting error "The server understood the request but refuses to authorize it"

While running the application using Spring Security, I am getting below error on all browsers:
"The server understood the request but refuses to authorize it"
I tried by changing Roles from "ROLE_ADMIN" to "ROLE_USER" in "spring-security.xml" file.
Below is "spring-security.xml"
<http auto-config="true">
<intercept-url pattern ="/admin" access = "hasRole('ROLE-USER')"/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name = "abc" password = "xyz" authorities="hasRole('ROLE-USER')" />
</user-service>
</authentication-provider>
</authentication-manager>
Below is SpringController Class:
#Controller
public class SpringController {
#RequestMapping(value = "/")
public String homePage() {
return "HomePage";
}
#RequestMapping(value="/admin", method=RequestMethod.GET)
public String loginPage() {
return "login";
}
HomePage.jsp and login.jsp pages are loaded property but after passing credentials on login.jsp getting error:
HTTP Status 403 – Forbidden
Type: Status Report
Message: Access is denied
Description: The server understood the request but refuses to
authorize it.
Apache Tomcat/7.0.90
403 is a very generic error code. I was facing the same issue but after making some changes I am able to make it work. Still not sure if the problem was with password encryption or configuration of form-login tag.
<security:http auto-config="true" >
<security:intercept-url pattern="/login*" access="isAnonymous()" />
<security:intercept-url pattern="/**" access="isAuthenticated()"/>
<security:form-login login-page="/login" login-processing-url="/login-user" authentication-failure-url="/login?error=true" />
<security:csrf disabled="true" />
<security:logout logout-success-url="/" />
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="admin" password="{noop}admin" authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider >
</security:authentication-manager>
Ignore the security: prefix in the tags.
{noop} in front of the password ensures that I am not using any encryption for the password.
Controller to show login JSP
#Controller
#RequestMapping("/login")
public class LoginController {
#RequestMapping(value = { "/", "" }, method = { RequestMethod.GET})
public String login(HttpServletRequest request) {
System.out.println("LoginController.login() "+request.getRequestURI());
return "login";
}
}
Form action
<form name='loginForm' action="login-user" method='POST'>
I got this issue but not while using spring. We were hosting two instances of our own in house application on the same server but using two different ports. Login to one instance was okay, however login to the other one from the same browser (another tab) caused the error above to be thrown from tomcat, preceded with this message "CSRF nonce validation failed".
The workaround I did is to login to the other instance from different browser. I know that this is not a fix but it may help if you have a situation similar to mine
This happens because you use normal <form> tags with spring security, while it checks for CSRF attacks.
The solution is:
Add CSRF hidden field with each <form> tag
<form action="..." method="POST">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
Or use spring MVC <form:form> tags which include this hidden field automtically (Recommended)
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<form:form action="..." method="POST">
</form:form>
This also happened with me when I accidentally launched two instances of my application on different tomcat servers. I resolved it by removing the working directories of the application in my webapps and work folders, and restarting the server.
use <form:form> tags when you're dealing with spring security, instead of manually adding the CSRF token for each forms as below
<form:form action="", method="">
</form:form>

Spring Security, programmatic login for json restful web service

I am using spring 4.2.1 with spring security 4.0.2
On login, I need to return a json object tree to the client, containing the cached data it requires for the session.
So I've added a the following method:
#RequestMapping(value = "/login", method = RequestMethod.POST)
public #ResponseBody ServerResponse<?> login(#RequestBody LoginRequest loginRequest, HttpServletRequest request, HttpServletResponse response) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword());
Authentication result = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(result);
Object data = null; // Do stuff here
return new ServerResponse<>(data);
}
My spring security config:
<ss:http auto-config="false" use-expressions="true" entry-point-ref="authenticationEntryPoint">
<ss:anonymous enabled="false" />
<!-- this is enabled by default in spring 4 -->
<ss:csrf disabled="true" />
<ss:custom-filter position="FORM_LOGIN_FILTER" ref="myAuthFilter" />
<ss:session-management session-authentication-strategy-ref="sas" />
<ss:port-mappings>
<ss:port-mapping http="8080" https="8443" />
</ss:port-mappings>
<ss:intercept-url pattern="/app/logi**" access="permitAll()" />
<ss:intercept-url pattern="/app/logou**" access="permitAll()" />
<ss:intercept-url pattern="/app/**" access="hasAuthority('user')" />
<ss:intercept-url pattern="/www/**" access="hasAuthority('user')" />
</ss:http>
All the pages I find regarding a programmatic login confirm that what I am doing is fine.
However, when I try and call another web service method later, I get 403 as the client is not logged in.
I read some vague references to having to use a spring filter, but I am not sure how I would get the filter to return the json tree to the client after successful login.
Any suggestions or links to an example on how to do this would be much appreciated.
Thanks
Sooo it turns out the problem was that I was doing Cross Origin Resource Sharing and the browser was not sending the cookie across with the next request.
Basically I was calling the server from html on the file system (with origin file://)
I was handling options calls, but I was not sending back
Access-Control-Allow-Credentials true
headers in the responses and I had to configure angular to send the cookie by passing the flag
withCredentials: true
in the config object to $http.post

#PreAuthorize and intercept-url priority

I have
<security:http use-expressions="true">
<security:intercept-url pattern="/**/*" access="hasRole('ROLE_USER')"/>
in the Spring Security context configuration file and
#PreAuthorize("permitAll")
#RequestMapping("/public")
public String aMethod() {
// ...
}
in a controller.
What I want is that all the URLs to require authentication except public. Is this possible?
<intercept-url> in XML takes precedence over annotations. <intercept-url> works at URL level and annotations at method level.
If you are going to use spring security and spring <form-login /> then the approach below would serve you better.
<intercept-url pattern="/public/**"
access="permitAll" />
<intercept-url pattern="/restricted/**"
access="hasAnyRole('ROLE_USER', 'ROLE_ADMIN', 'ROLE_SOME')
#PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_SOME')")
#RequestMapping("/restricted/aMethod")
public String aMethod() {
// ...
}
Anything under restricted can be accessed by three different roles. But specific path restricted/aMethod can be accessed by #PreAuthorize("ROLE_ADMIN") and #PreAuthorize("ROLE_SOME") but NOT by #PreAuthorize("ROLE_USER"). By default all three roles can access but when you mark some path with #PreAuthorize("ROLE_ADMIN") then user with ROLE_ADMIN can access that path.
If you think about it, #PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_SOME')") act as narrowed or filtered access from a large set of ROLES to single(or set of roles) ROLE.
As you would notice, none of /restricted paths are accessible by permitAll. Its preferred to have /static/*.css and others under permitAll.
HTH

Spring-security not working, need help understanding why

I'm trying to understand Spring-security but my pages can be accessed without loggin in and I don't understand why.
The "secure" page is located in WEB-INF/pages/secure and is accessed using http://localhost:8080/secret. This should not allow access, but currently does.
/secure maps here
#Controller
public class HelloWorld {
...
#RequestMapping("/secret")
public String showSecret(ModelMap model) {
return "secure/secretPage";
}
}
web.xml
...
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext-security.xml
/WEB-INF/springmvc-config.xml
</param-value>
</context-param>
...
applicationContext-security.xml
<http auto-config="true">
<form-login login-processing-url="/j_spring_security_check"
login-page="/login"
authentication-failure-url="/login?login_error=t"/>
<logout logout-url="/j_spring_security_logout"/>
<intercept-url pattern="/pages/secure/**" access="IS_AUTHENTICATED_FULLY" requires-channel="https"/>
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userAccountDetailsService"/>
</authentication-manager>
userAccountDetailsService
#Service("userAccountDetailsService") // enables component to be found to <component-scan/>
public class UserAccountDetailsService implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
throw new UsernameNotFoundException("Could not find user");
}
}
The /login page does not currently exist. There are no users anyway. I just want this to disallow access for now.
The URL you are hitting is /secure, not /pages/secure and yet in your Spring Security configuration you are protecting /pages/secure/** instead of /secure/**. Change the intercept URL from /pages/secure/** to /secure/** and try again.

How to handle 404 with Spring Security?

I found only related topic for c# please don't blame me if I missed the resource.
It looks something like
/project/blablaentered and content with 404.
Effectively I just want to specify my own page when 404 page is thrown.
My security xml:
<security:http auto-config="true" use-expressions="true" >
<security:form-login login-processing-url="/static/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t" default-target-url="/home"/>
<security:intercept-url pattern="/home" access="isAuthenticated()" />
<security:intercept-url pattern="/home/try" access="hasRole('ROLE_EDITOR')"/>
<security:access-denied-handler error-page="/accessDenied"/>
</security:http>
UPDATE: Please follow for solution: Custom 404 using Spring DispatcherServlet
The simplest way is probably enable an error-page element inside web.xml as long as you don't mind it being a plain JSP (ie, no controller). This way, URLs outside your DispatcherServlet which will generate a 404 from your servlet container will follow the same path as any URL that Spring is unable to map to a controller based on your configuration.
If this isn't good enough, you can define a #Exception method for a particular controller, or use a HandlerExceptionResolver.
You need add class:
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
// Do nothing
}

Resources