How do I route my login controller - spring-mvc

I am using a homegrown (developers no longer around) web framework that has built in Spring security.
There is a LoginController that every request is redirected to until the user logs in.
The LoginController is mapped to use the context URL, e.g. my-company/login.do
public class LoginController {
public LoginController() {
}
#RequestMapping(
value = {"/login.do"},
method = {RequestMethod.GET}
)
public String showLogin() {
return "login";
}
For my application, I need to change that mapping to my-company/admin/login.do
The LoginController is coming in from a Maven dependency, so I CANNOT MODIFY that class
Is there any way to modify the existing LoginController to route to the extended url?

It seems that if you want it to be located at "my-company/admin/login.do" when it is located at "my-company/login.do", I would start by changing
#RequestMapping(
value = {"/login.do"},
method = {RequestMethod.GET}
)
public String showLogin() {
return "login";
}
to
#RequestMapping(
value = {"/admin/login.do"},
method = {RequestMethod.GET}
)
public String showLogin() {
return "login";
}
However, if you still need the old location too, you might be better of copying the class and making a specific one for your admin login.
Also, this is just where I would start. Odds are that the rest of your application expects this code to be located where it is, so you could easily break the integration with the rest of your code by doing this.

Related

Spring security Authentication parameter in #Controller handler method [duplicate]

I have a Spring MVC web app which uses Spring Security. I want to know the username of the currently logged in user. I'm using the code snippet given below . Is this the accepted way?
I don't like having a call to a static method inside this controller - that defeats the whole purpose of Spring, IMHO. Is there a way to configure the app to have the current SecurityContext, or current Authentication, injected instead?
#RequestMapping(method = RequestMethod.GET)
public ModelAndView showResults(final HttpServletRequest request...) {
final String currentUser = SecurityContextHolder.getContext().getAuthentication().getName();
...
}
If you are using Spring 3, the easiest way is:
#RequestMapping(method = RequestMethod.GET)
public ModelAndView showResults(final HttpServletRequest request, Principal principal) {
final String currentUser = principal.getName();
}
A lot has changed in the Spring world since this question was answered. Spring has simplified getting the current user in a controller. For other beans, Spring has adopted the suggestions of the author and simplified the injection of 'SecurityContextHolder'. More details are in the comments.
This is the solution I've ended up going with. Instead of using SecurityContextHolder in my controller, I want to inject something which uses SecurityContextHolder under the hood but abstracts away that singleton-like class from my code. I've found no way to do this other than rolling my own interface, like so:
public interface SecurityContextFacade {
SecurityContext getContext();
void setContext(SecurityContext securityContext);
}
Now, my controller (or whatever POJO) would look like this:
public class FooController {
private final SecurityContextFacade securityContextFacade;
public FooController(SecurityContextFacade securityContextFacade) {
this.securityContextFacade = securityContextFacade;
}
public void doSomething(){
SecurityContext context = securityContextFacade.getContext();
// do something w/ context
}
}
And, because of the interface being a point of decoupling, unit testing is straightforward. In this example I use Mockito:
public class FooControllerTest {
private FooController controller;
private SecurityContextFacade mockSecurityContextFacade;
private SecurityContext mockSecurityContext;
#Before
public void setUp() throws Exception {
mockSecurityContextFacade = mock(SecurityContextFacade.class);
mockSecurityContext = mock(SecurityContext.class);
stub(mockSecurityContextFacade.getContext()).toReturn(mockSecurityContext);
controller = new FooController(mockSecurityContextFacade);
}
#Test
public void testDoSomething() {
controller.doSomething();
verify(mockSecurityContextFacade).getContext();
}
}
The default implementation of the interface looks like this:
public class SecurityContextHolderFacade implements SecurityContextFacade {
public SecurityContext getContext() {
return SecurityContextHolder.getContext();
}
public void setContext(SecurityContext securityContext) {
SecurityContextHolder.setContext(securityContext);
}
}
And, finally, the production Spring config looks like this:
<bean id="myController" class="com.foo.FooController">
...
<constructor-arg index="1">
<bean class="com.foo.SecurityContextHolderFacade">
</constructor-arg>
</bean>
It seems more than a little silly that Spring, a dependency injection container of all things, has not supplied a way to inject something similar. I understand SecurityContextHolder was inherited from acegi, but still. The thing is, they're so close - if only SecurityContextHolder had a getter to get the underlying SecurityContextHolderStrategy instance (which is an interface), you could inject that. In fact, I even opened a Jira issue to that effect.
One last thing - I've just substantially changed the answer I had here before. Check the history if you're curious but, as a coworker pointed out to me, my previous answer would not work in a multi-threaded environment. The underlying SecurityContextHolderStrategy used by SecurityContextHolder is, by default, an instance of ThreadLocalSecurityContextHolderStrategy, which stores SecurityContexts in a ThreadLocal. Therefore, it is not necessarily a good idea to inject the SecurityContext directly into a bean at initialization time - it may need to be retrieved from the ThreadLocal each time, in a multi-threaded environment, so the correct one is retrieved.
I agree that having to query the SecurityContext for the current user stinks, it seems a very un-Spring way to handle this problem.
I wrote a static "helper" class to deal with this problem; it's dirty in that it's a global and static method, but I figured this way if we change anything related to Security, at least I only have to change the details in one place:
/**
* Returns the domain User object for the currently logged in user, or null
* if no User is logged in.
*
* #return User object for the currently logged in user, or null if no User
* is logged in.
*/
public static User getCurrentUser() {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal()
if (principal instanceof MyUserDetails) return ((MyUserDetails) principal).getUser();
// principal object is either null or represents anonymous user -
// neither of which our domain User object can represent - so return null
return null;
}
/**
* Utility method to determine if the current user is logged in /
* authenticated.
* <p>
* Equivalent of calling:
* <p>
* <code>getCurrentUser() != null</code>
*
* #return if user is logged in
*/
public static boolean isLoggedIn() {
return getCurrentUser() != null;
}
To make it just show up in your JSP pages, you can use the Spring Security Tag Lib:
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/taglibs.html
To use any of the tags, you must have the security taglib declared in your JSP:
<%# taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
Then in a jsp page do something like this:
<security:authorize access="isAuthenticated()">
logged in as <security:authentication property="principal.username" />
</security:authorize>
<security:authorize access="! isAuthenticated()">
not logged in
</security:authorize>
NOTE: As mentioned in the comments by #SBerg413, you'll need to add
use-expressions="true"
to the "http" tag in the security.xml config for this to work.
If you are using Spring Security ver >= 3.2, you can use the #AuthenticationPrincipal annotation:
#RequestMapping(method = RequestMethod.GET)
public ModelAndView showResults(#AuthenticationPrincipal CustomUser currentUser, HttpServletRequest request) {
String currentUsername = currentUser.getUsername();
// ...
}
Here, CustomUser is a custom object that implements UserDetails that is returned by a custom UserDetailsService.
More information can be found in the #AuthenticationPrincipal chapter of the Spring Security reference docs.
I get authenticated user by
HttpServletRequest.getUserPrincipal();
Example:
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.support.RequestContext;
import foo.Form;
#Controller
#RequestMapping(value="/welcome")
public class IndexController {
#RequestMapping(method=RequestMethod.GET)
public String getCreateForm(Model model, HttpServletRequest request) {
if(request.getUserPrincipal() != null) {
String loginName = request.getUserPrincipal().getName();
System.out.println("loginName : " + loginName );
}
model.addAttribute("form", new Form());
return "welcome";
}
}
In Spring 3+ you have have following options.
Option 1 :
#RequestMapping(method = RequestMethod.GET)
public String currentUserNameByPrincipal(Principal principal) {
return principal.getName();
}
Option 2 :
#RequestMapping(method = RequestMethod.GET)
public String currentUserNameByAuthentication(Authentication authentication) {
return authentication.getName();
}
Option 3:
#RequestMapping(method = RequestMethod.GET)
public String currentUserByHTTPRequest(HttpServletRequest request) {
return request.getUserPrincipal().getName();
}
Option 4 : Fancy one : Check this out for more details
public ModelAndView someRequestHandler(#ActiveUser User activeUser) {
...
}
I would just do this:
request.getRemoteUser();
Yes, statics are generally bad - generally, but in this case, the static is the most secure code you can write. Since the security context associates a Principal with the currently running thread, the most secure code would access the static from the thread as directly as possible. Hiding the access behind a wrapper class that is injected provides an attacker with more points to attack. They wouldn't need access to the code (which they would have a hard time changing if the jar was signed), they just need a way to override the configuration, which can be done at runtime or slipping some XML onto the classpath. Even using annotation injection in the signed code would be overridable with external XML. Such XML could inject the running system with a rogue principal. This is probably why Spring is doing something so un-Spring-like in this case.
For the last Spring MVC app I wrote, I didn't inject the SecurityContext holder, but I did have a base controller that I had two utility methods related to this ... isAuthenticated() & getUsername(). Internally they do the static method call you described.
At least then it's only in once place if you need to later refactor.
You could use Spring AOP aproach.
For example if you have some service, that needs to know current principal. You could introduce custom annotation i.e. #Principal , which indicate that this Service should be principal dependent.
public class SomeService {
private String principal;
#Principal
public setPrincipal(String principal){
this.principal=principal;
}
}
Then in your advice, which I think needs to extend MethodBeforeAdvice, check that particular service has #Principal annotation and inject Principal name, or set it to 'ANONYMOUS' instead.
The only problem is that even after authenticating with Spring Security, the user/principal bean doesn't exist in the container, so dependency-injecting it will be difficult. Before we used Spring Security we would create a session-scoped bean that had the current Principal, inject that into an "AuthService" and then inject that Service into most of the other services in the Application. So those Services would simply call authService.getCurrentUser() to get the object. If you have a place in your code where you get a reference to the same Principal in the session, you can simply set it as a property on your session-scoped bean.
The best solution if you are using Spring 3 and need the authenticated principal in your controller is to do something like this:
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
#Controller
public class KnoteController {
#RequestMapping(method = RequestMethod.GET)
public java.lang.String list(Model uiModel, UsernamePasswordAuthenticationToken authToken) {
if (authToken instanceof UsernamePasswordAuthenticationToken) {
user = (User) authToken.getPrincipal();
}
...
}
Try this
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
String userName = authentication.getName();
I am using the #AuthenticationPrincipal annotation in #Controller classes as well as in #ControllerAdvicer annotated ones. Ex.:
#ControllerAdvice
public class ControllerAdvicer
{
private static final Logger LOGGER = LoggerFactory.getLogger(ControllerAdvicer.class);
#ModelAttribute("userActive")
public UserActive currentUser(#AuthenticationPrincipal UserActive currentUser)
{
return currentUser;
}
}
Where UserActive is the class i use for logged users services, and extends from org.springframework.security.core.userdetails.User. Something like:
public class UserActive extends org.springframework.security.core.userdetails.User
{
private final User user;
public UserActive(User user)
{
super(user.getUsername(), user.getPasswordHash(), user.getGrantedAuthorities());
this.user = user;
}
//More functions
}
Really easy.
Define Principal as a dependency in your controller method and spring will inject the current authenticated user in your method at invocation.
I like to share my way of supporting user details on freemarker page.
Everything is very simple and working perfectly!
You just have to place Authentication rerequest on default-target-url (page after form-login)
This is my Controler method for that page:
#RequestMapping(value = "/monitoring", method = RequestMethod.GET)
public ModelAndView getMonitoringPage(Model model, final HttpServletRequest request) {
showRequestLog("monitoring");
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String userName = authentication.getName();
//create a new session
HttpSession session = request.getSession(true);
session.setAttribute("username", userName);
return new ModelAndView(catalogPath + "monitoring");
}
And this is my ftl code:
<#security.authorize ifAnyGranted="ROLE_ADMIN, ROLE_USER">
<p style="padding-right: 20px;">Logged in as ${username!"Anonymous" }</p>
</#security.authorize>
And that's it, username will appear on every page after authorisation.

How to make a method forbidden to direct request but allowed for server requests on Spring MVC?

What I basically want to know is this:
Suppose I have a method annotated with #RequestMapping and the value "/test/ajax". Can I make that specific method accessible only to internal calls but not to the client? If I run an ajax request on that url from within the server it should work normally, but if I run it directly from the browser it should return a 403.
Is that in any way possible?
add the spring annotation #CrossOrigin on controller layer for example
also, follow the given link https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
#CrossOrigin
#RestController
#RequestMapping("/account")
public class AccountController {
#GetMapping("/{id}")
public Account retrieve(#PathVariable Long id) {
// ...
}
#DeleteMapping("/{id}")
public void remove(#PathVariable Long id) {
// ...
}
}
If you allow only a method pass like this
#RestController
#RequestMapping("/account")
public class AccountController {
#CrossOrigin
#GetMapping("/{id}")
public Account retrieve(#PathVariable Long id) {
// ...
}
#DeleteMapping("/{id}")
public void remove(#PathVariable Long id) {
// ...
}
}

Accessing AuthorizationAttribute within Controller

I have a custom AuthorizeAttribute written in MVC. I have it applied to a controller for security. In that AuthorizeAttribute class I have written are several variables I gathered from a web service call I would like to access inside the controller to prevent having to call the web service again. Is this possible?
Your best approach would be to use HttpContext.Current.Items for storing those variables because that data will only be valid for a single http request. Something like this:
public class CustomAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext.User.Identity == null) return false;
if (!httpContext.Request.IsAuthenticated) return false;
var user = new WSUser(); //get this from your webservice
if(user == null) return false;
httpContext.Items.Add("prop", user.Property);
return user.Authorized;
}
}
public class HomeController : Controller
{
[CustomAuthorize]
public ActionResult Index()
{
var property = (string) HttpContext.Items["prop"];
return View();
}
}
You would also want to encapsulate logic for storing and retrieving items from HttpContext.Current into a separate class to keep the code clean and to follow Single responsibility principle
You could save these variables in a static class to store it. But, a elegant solution would be to have a modelbinder object that you call like parameter in your controller and that read the static class and return the properties that you need.
Perhaps, if you are applying security, the best will be that call the webservices each once.
Reference for your custom model binder

Specifying #RequestHeader once for all controllers in Spring Boot app

I have a Spring Boot app with multiple controllers serving various REST methods. Each of the methods require that the same header parameter be defined. Is there a way to specify something like the following one time for all controller methods?
public ResponseEntity get(#RequestHeader(value="NAME", required = true) String name, ...) {
...
}
Thanks.
You can probably achieve this using #ModelAttribute, like this:
public class Something {
private name;
//...
}
#ModelAttribute("something")
public Something addSomething(#RequestHeader(value="NAME", required = true) String name) {
return new Something(name);
}
#RequestMapping("/something")
public ResponseEntity get(#ModelAttribute Something something) {
//...
}
You can implement the #ModelAttribute populating method in a single Controller or in a #ControllerAdvice class, in order to assist multiple controllers. See reference documentation.

Securing ajax calls in a ASP.NET MVC application

I have an ASP.NET MVC based application that allows different levels of access depending on the user. The way it currently works is when a user accesses a page, a check is done against the database to determine the rights that user has. The view is then selected based on the level of access that user has. Some users see more data and have more functionality available to them than do others. Each page also makes a variety of ajax calls to display and update the data displayed on the page.
My question is what is the best way to ensure that a particular ajax call originated from the view and was not crafted manually to return or update data the user does not have access to? I would prefer not to have to go to the database to re-check every time an ajax call is made since that was already done when the user initially loaded the page.
Check out the Authorize Attribute, you can put it on an entire controller or just specific methods within your controller.
Examples:
[Authorize(Roles = "Administrator")]
public class AdminController : Controller
{
//your code here
}
or
public class AdminController : Controller
{
//Available to everyone
public ActionResult Index()
{
return View();
}
//Just available to users in the Administrator role.
[Authorize(Roles = "Administrator")]
public ActionResult AdminOnlyIndex()
{
return View();
}
}
Alternately, you can write a custom Authorize attribute to provide your own logic.
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
IPrincipal user = httpContext.User;
var validRoles = Roles.Split(',');//Roles will be a parameter when you use the Attribute
List<String> userRoles = GetRolesFromDb(user);//This will be a call to your database to get the roles the user is in.
return validRoles.Intersect(userRoles).Any();
}
}
To use:
[CustomAuthorizeAttribute(Roles = "Admin,Superuser")]
public class AdminController : Controller {
}
If iyou are using a post use
[Authorize]
[ValidateAntiForgeryToken]
If iyou are using a get use
[Authorize]
You can also use this custom attribute
public class HttpAjaxRequestAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
if (!controllerContext.HttpContext.Request.IsAjaxRequest())
{
throw new Exception("This action " + methodInfo.Name + " can only be called via an Ajax request");
}
return true;
}
}
Then decorate your action as below
[Authorize]
[HttpAjaxRequest]
public ActionResult FillCity(int State)
{
//code here
}
Remember to "Mark/Tick" if this solve your problem.
It depends on what type of session mechanisam you are using . Are you using default membership provider ? If not than you can pass user's id and sessionid make sure that user session is valid and user has required permission to make that call .
Along with the Authorize attribute, you can also allow only Ajax requests using custom attributes as shown here.
Thanks

Resources