Get UserDetails object from Security Context in Spring MVC controller - java

I'm using Spring Security 3 and Spring MVC 3.05.
I would like to print username of currently logged in user,how can I fetch UserDetails in my Controller?
#RequestMapping(value="/index.html", method=RequestMethod.GET)
public ModelAndView indexView(){
UserDetails user = ?
mv.addObject("username", user.getUsername());
ModelAndView mv = new ModelAndView("index");
return mv;
}

If you already know for sure that the user is logged in (in your example if /index.html is protected):
UserDetails userDetails =
(UserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
To first check if the user is logged in, check that the current Authentication is not a AnonymousAuthenticationToken.
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!(auth instanceof AnonymousAuthenticationToken)) {
// userDetails = auth.getPrincipal()
}

Let Spring 3 injection take care of this.
Thanks to tsunade21 the easiest way is:
#RequestMapping(method = RequestMethod.GET)
public ModelAndView anyMethodNameGoesHere(Principal principal) {
final String loggedInUserName = principal.getName();
}

If you just want to print user name on the pages, maybe you'll like this solution. It's free from object castings and works without Spring Security too:
#RequestMapping(value = "/index.html", method = RequestMethod.GET)
public ModelAndView indexView(HttpServletRequest request) {
ModelAndView mv = new ModelAndView("index");
String userName = "not logged in"; // Any default user name
Principal principal = request.getUserPrincipal();
if (principal != null) {
userName = principal.getName();
}
mv.addObject("username", userName);
// By adding a little code (same way) you can check if user has any
// roles you need, for example:
boolean fAdmin = request.isUserInRole("ROLE_ADMIN");
mv.addObject("isAdmin", fAdmin);
return mv;
}
Note "HttpServletRequest request" parameter added.
Works fine because Spring injects it's own objects (wrappers) for HttpServletRequest, Principal etc., so you can use standard java methods to retrieve user information.

That's another solution (Spring Security 3):
public String getLoggedUser() throws Exception {
String name = SecurityContextHolder.getContext().getAuthentication().getName();
return (!name.equals("anonymousUser")) ? name : null;
}

if you are using spring security then you can get the current logged in user by
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String name = auth.getName(); //get logged in username

You can use below code to find out principal (user email who logged in)
org.opensaml.saml2.core.impl.NameIDImpl principal =
(NameIDImpl) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String email = principal.getValue();
This code is written on top of SAML.

Related

How can i use SecurityContext in Jax-RS to get Token of a specified user?

Can i do this? I am using SecurityContext of Jax-rs to get current Student
#GET
#Secured
#Path("/books")
#Produces("application/json")
public List<Book> getBooks(#Context SecurityContext securityContext){
Student s = (Student)securityContext.getUserPrincipal();
TypedQuery<Book> query = em.createQuery("SELECT s.books from Student s where s.token = :token", Book.class);
query.setParameter("token", s.getToken());
List<Book> resultList = query.getResultList();
return resultList;
I'm not sure if yours is working. I have implemented the security handling with spring security and it works fine like this. It's similar but not the same.
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
User loggedinUser = null;
if (authentication != null) {
Object principal = authentication.getPrincipal();
loggedinUser = principal instanceof SpringSecurityUser ? ((SpringSecurityUser)principal).getUser() : null;
}
In this example you can access a token or password or whatever now with
String token = loggedinUser.getToken();

Setting authentication true with Spring Security + Spring Session

I have a Spring Security + Spring Session + Spring Boot project and a Controller with a custom login POST method. I have my own means to verify the credentials of the customer. Once the verification is successful, what's the best practice to access the session and set the identification to true?
I've tried this with no results:
#PostMapping("/login")
public ResponseEntity loginSubmit(#RequestBody LoginForm form) {
Errors errors = authenticationService.validateLoginForm(form);
if (!errors.hasErrors()) {
CustomerDTO result = authenticationService.findCustomerByEmailAndPassword(form);
boolean success = (result != null && result.getId() != null);
SecurityContextHolder.getContext().getAuthentication().setAuthenticated(success);
return new ResponseEntity(result, HttpStatus.OK);
} else {
return new ResponseEntity(errors.getAllErrors(), HttpStatus.OK);
}
}
How should I be doing this instead?
Instead of writing your own endpoint I would suggest to integrate in Spring Security framework by implementing your own org.springframework.security.authentication.AuthenticationProvider
Or simply do this
public void login(HttpServletRequest req, String user, String pass) {
UsernamePasswordAuthenticationToken authReqz = new UsernamePasswordAuthenticationToken(user, pass);
Authentication auth = authManager.authenticate(authReq);
SecurityContext sc = SecurityContextHolder.getContext();
sc.setAuthentication(auth);
HttpSession session = req.getSession(true);
session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, sc);
}
Detailed explanation can be found here

Spring Security gives Null authentification when retriving username in Spring Boot

I try to get user's name like this:
public static String getUsername() {
SecurityContext context = SecurityContextHolder.getContext();
UserDetails userDetails = (UserDetails) context.getAuthentication().getPrincipal();
return userDetails.getUsername();
}
It works fine when just loggined, but when go to a different page context becomes org.springframework.security.core.context.SecurityContextImpl#ffffffff: Null authentication with authentification = null.
How do I retrieve logged in user with Spring Security in Spring Boot correctly?
Spring Boot version is 2.0.3.RELEASE.
UPD:
To clarify: After navigating to another page SecurityContextHolder.getContext() gives a context with authentification = null. So context.getAuthentication().getPrincipal() throws NullPointerException because context.getAuthentication() is null.
Don't know what is wrong, but I found a workaround - I save username in session.
Since I use Vaadin - I use VaadinSession, but I believe HttpSession can be used as well.
public static String getUsername() {
VaadinSession session = VaadinSession.getCurrent();
if(session.getAttribute("username") == null) {
SecurityContext context = SecurityContextHolder.getContext();
UserDetails userDetails = (UserDetails) context.getAuthentication().getPrincipal();
session.setAttribute("username", userDetails.getUsername());
}
return (String) session.getAttribute("username");
}
The only thing - this code works only in Components, so you must make sure to use it from autowired classes.

How to find out the currently logged-in user in Spring Boot?

In this Spring Boot application there is a web service, which returns some data for a logged-in user:
#RequestMapping("/resource")
public Map<String, Object> home() {
Map<String, Object> model = new HashMap<String, Object>();
model.put("id", UUID.randomUUID().toString());
model.put("content", "Hello World");
return model;
}
Imagine, the return value of the method depends on what user is currently logged in.
How can I find out, which user is logged in in that method?
As per request:
Spring Boot which uses Spring Security internally provides a SecurityContextHolder class which allows the lookup of the currently authenticated user via:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
The authentication instance now provides the following methods:
Get the username of the logged in user: getPrincipal()
Get the password of the authenticated user: getCredentials()
Get the assigned roles of the authenticated user: getAuthorities()
Get further details of the authenticated user: getDetails()
Since Spring Security 3.2 you can get currently logged in user (your implementation of UserDetails) by adding a parameter inside your controller method:
import org.springframework.security.web.bind.annotation.AuthenticationPrincipal;
#RequestMapping("/resource")
public Map<String, Object> home(#AuthenticationPrincipal User user) {
..
}
Replace User with the name of your class which implements UserDetails interface.
Edit:
Since Spring Security 4.0 annotation was moved to a different package:
import org.springframework.security.core.annotation.AuthenticationPrincipal;
Addendum:
This will work even in WebFlux reactive environment versus the SecurityContextHolder.getContext().getAuthentication() which won't work because of paradigm shift from thread per request model to multiple requests per thread.
You can simply use HttpServletRequest also to get user principle,
using HttpServletRequest request,
String user=request.getUserPrincipal().getName();
One way is to add java.security.Principal as a parameter as follows:
#RequestMapping("/resource")
public Map<String, Object> home(Principal principal) {
Map<String, Object> model = new HashMap<String, Object>();
model.put("id", UUID.randomUUID().toString());
model.put("content", "Hello " + principal.getName());
return model;
}
Since version 5.2 you can use CurrentSecurityContext annotation:
#GetMapping("/hello")
public String hello(#CurrentSecurityContext(expression="authentication?.name")
String username) {
return "Hello, " + username + "!";
}
In Spring boot v2.1.9.RELEASE if you are trying to get the name, email, given_name you can get those details from Pricipal.
Note: I am using spring security with google oauth2.
Map<String , Object> userDetails = ((DefaultOidcUser)SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getAttributes();
System.out.println(userDetails.get("name"));
System.out.println(userDetails.get("email"));
System.out.println(userDetails.get("given_name"));
Recently using Keycloak authentication server and accessing currently logged-in user data is accessible like this
String userID;
KeycloakPrincipal kcPrincipal = getPrincipal();
KeycloakSecurityContext ksContext = kcPrincipal.getKeycloakSecurityContext();
IDToken idToken = ksContext.getToken();
userID = idToken.getName();
Im using spring boot 2.0 with OAuth so I'm doing it like this
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Object pricipal = auth.getPrincipal();
String user="";
if (pricipal instanceof DefaultOidcUser) {
user = ((DefaultOidcUser) pricipal).getName();
}
You can find the currently logged in user name without using any spring Security features.
All you need is a jdk 1.8
Do the following :
#RequestMapping("/login")
#Override
public ModelAndView AuthChecker(#RequestParam("email") String email, #RequestParam("password") String password, Customers cust) {
ModelAndView mv = new ModelAndView("index");
if((repo.findByEmail(email)!=null) && (repo.findByPassword(password)!=null)) {
List<Customers> l= repo.findAll();
cust = (Customers) l.stream()
.filter(x -> email.equals(x.getEmail()))
.findAny()
.orElse(null);
mv.addObject("user",cust.getName());
mv.setViewName("DashBoardRedirect");
return mv;
Once name fetched successfully, you can use the same in any jsp/thymeleaf view.

Spring ModelAttribute show old value after logout

I am developing an application using Spring. I have a trouble about login and logout. I logged in application using a login credentials(e.g. userName:john, pass: doe) and go to Admin page and than I logged out from application. But this time I used different login credentials(e.g. userName: jack, pass: white) for login. When I go to Admin page and debug my application #ModelAttribute(value = "myUser") User loggedInUser at AdminController shows old user value. I couldn't understand why this occurs. Anyone can help?
My source codes are below:
#Controller
#RequestMapping("/LoginController")
#SessionAttributes({"myUser"})
public class LoginController
{
private static String LOGIN_URL = "login/login_";
private static String INDEX_URL = "main/index";
#Autowired
private IUserService userService = null;
#RequestMapping("/login")
public ModelAndView login(#RequestParam(value="userName", required=false) String argUserName, #RequestParam(value="password", required=false) String argPassword, HttpServletRequest req)
{
ModelAndView modelAndView = new ModelAndView();
// Assume argUserName and argPassword not null
User loginUser = this.userService.getUser(argUserName, argPassword);
HttpSession ses = req.getSession();
// Assume loginUser not null
ses.setAttribute("myUser", loginUser);
modelAndView.setViewName(LoginController.INDEX_URL);
return modelAndView;
}
#RequestMapping("/logout")
public String logout(HttpServletRequest argReq, HttpServletResponse argResp) throws ServletException, IOException
{
HttpSession session = argReq.getSession(false);
Enumeration<?> attributeNames = session.getAttributeNames();
while(attributeNames.hasMoreElements())
{
String attrName = (String)attributeNames.nextElement();
if(session.getAttribute(attrName) != null)
{
session.setAttribute(attrName,null);
//session.removeAttribute(attrName);
attributeNames = session.getAttributeNames();
}
}
// close session
session.invalidate();
return LoginController.LOGIN_URL;
}
}
AdminController
#Controller
#RequestMapping("/AdminController")
#SessionAttributes({"myUser"})
public class AdminController
{
private static String SETTINGS_PAGE = "settings/index";
#RequestMapping("/index")
public ModelAndView index(#ModelAttribute(value = "myUser") User loggedInUser, HttpSession ses)
{
ModelAndView modelAndView = new ModelAndView();
Map<String, Object> map = new HashMap<String, Object>();
map.put("loggedInUserId", loggedInUser.getUserID());
map.put("userName", loggedInUser.getUserName());
modelAndView.addAllObjects(map);
modelAndView.setViewName(AdminController.SETTINGS_PAGE);
return modelAndView;
}
}
Remove this annotation
#SessionAttributes({"myUser"})
For starters #SessionAttributes isn't designed to store data in the session between different controllers. Its intended use is only to store data for the same controller in between requests. If you want to store items in the session between requests store them in the session yourself and don't rely on #SessionAttributes. This is also mentioned in the javadoc of the annotation (although a bit cryptic maybe).
If you want to remove object cached by #SessionAttributes you cannot simply clear the session but you would have to use the SessionStatus object (which you can add as an argument) to mark the use of these objects complete.
Your logout method is way to verbose, simply calling session.invalidate() should be enough, but I guess this was one of your attempts to fix things. Also when you are on a Servlet 3.0 container simply calling request.logout() could be enough (or call it in conjunction with session.invalidate())
My final advice would be to use Spring Security instead of trying to develop your own security solution.

Categories

Resources