Spring Security gives Null authentification when retriving username in Spring Boot - java

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.

Related

How to configure spring security with Office 365 authentication?

I'm new to spring-security. I understood basics of spring-security about authentication-manager and other stuff.
I'm using angularjs as front end, and spring 3.0.5 as backend.
I want to add spring security for role based authorization to my existing project.
I also want to authenticate user using office 365. So, i created application in https://apps.dev.microsoft.com/ and given redirect URI as my localhost action.
Using my code, I'm able to authenticate using office 365 and able to get username in redirected action.
#RequestMapping(value="/getCodeAndProcess", method=RequestMethod.POST)
private ModelAndView getCodeAndProcess(#RequestParam("code") String code, HttpServletRequest request) throws Exception {
HttpSession session = null;
try {
session = request.getSession(false);
session.setMaxInactiveInterval(45*60);
String username = helper.processCodeAndGetUsername(code); //this is I'm getting using office 365.
String userRole = helper.getUserRoleBasedOnUsername(username);
System.out.println("================userRole================="+userRole);
if(username != "") {
session.setAttribute("username", username);
session.setAttribute("userRole", userRole);
}else {
session.invalidate();
throw new Exception("username not found");
}
return new ModelAndView("redirect:/adminDashboard/showDashboard");
}catch(Exception e) {
log.error("Error while processing on users authentication.",e );
session.invalidate();
return new ModelAndView("redirect:/login/loginPage");
}
}
Now, I don't get how to configure username and roles in security-context.xml, so that i can use #PreAuthorize("hasRole('ROLE_USER')") , isAuthenticated(), <sec:authorize in my application. (What to add in security-context.xml? So, that it bind username with role as it doing in form login scenario.)
Can you please help to understand this workflow?

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

How to get the current user authorities/role and do some calculations according to the role in spring security

I am doing a project on library management system in spring boot security.
In order to calculate the fines for the issued books according to the roles i wan the current user role after borrowing a book.
Current user name, role book_id and fine will be stored in other table.
I am able to get the current users username, but not able to get role the current user.
Could someone please help me out!
//Part of Controller class
#RequestMapping("/homepage/borrowBook")
public String addBookings(Bookings bk, HttpServletRequest rqst) {
rqst.setAttribute("mode", "MODE_BORROW");
return "homepage";
}
#PostMapping("/homepage/save-borrow")
public String saveBorrow(Bookings bk, HttpServletRequest rqst, Authentication auth) {
rqst.setAttribute("mode", "MODE_BORROW");
if (BookRepo.exists(bk.getBook_id())) {
bk.setUser(auth.getName());
/////here i want the current user authority to be saved/checked.
bookingsRepo.save(bk);
return "homepage";
} else {
rqst.setAttribute("error", "Book doesn't exist");
return "homepage";
}
}
You can use Authentication.getAuthorities() to get the roles of the currently logged in user.
You can get the authorities using the SecurityContextHolder or through the inject Authentication object at your controller.
Find below through the SecurityContextHolder
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Collection<SimpleGrantedAuthority> list = (Collection<SimpleGrantedAuthority>) auth.getAuthorities();
for (SimpleGrantedAuthority permission : list) {
System.out.println(permission.getAuthority());
}
If you need any other information about the logged in user, you can access the UserDetails as follows
User userDetails = (User) auth.getPrincipal();

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.

Get UserDetails object from Security Context in Spring MVC controller

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.

Categories

Resources