I am using custom authentication using credentials and ipaddress, however, I need to display user firstname and lastname on UI. Whereas I am not using UserDetails and I am using UsernamePasswordAuthenticationToken, how can I get access to firstname and lastname, where UserDetails bean saved in Details.
Account account = (Account)accountDao.loadUserByUsername(username);
if(!account.getPassword().equals(password)) {
logger.debug("[USER AUTHENTICATION]Invalid Password:"+password);
return null;
}
logger.warn(String.format("[USER AUTHENTICATION]%s %s",new Object[]{account.getFirstName(),account.getLastName()}));
isAuthenticatedByIP = false;
for(AllowedIPAddress allowedIpAddress:account.getAllowedIPs()){
if(allowedIpAddress.getIpAddress().equals("0.0.0.0")||allowedIpAddress.getIpAddress().equals(userIPAddress)) {
isAuthenticatedByIP = true;
break;
}
}
// Authenticated, the user's IP address matches one in the database
if (isAuthenticatedByIP)
{
logger.debug("[USER AUTHENTICATION]isAuthenticatedByIP is true, IP Addresses match");
UsernamePasswordAuthenticationToken result = null;
result = new UsernamePasswordAuthenticationToken(account.getUsername(), account.getPassword(), account.getAuthorities()) ;
result.setDetails(account);
return result
} else {
logger.warn("[USER AUTHENTICATION]User IP not allowed "+userIPAddress);
}
how to get fields of account in jsp for displaying welcome message for user.
In spring mvc you can make a custom userDetail bean as session scoped bean and set your require values in it after successful login like firstname,lastname etc.Use that value wherever you want.
Related
I want to obtain a HttpSession object by URL Path variable id to get some attributes from it.
Context:
I'm trying to implement a web server that has a register and login sub-systems as a learning exercise.
I'm using JAVA, Springboot and various other spring dependencies like hibernate, jdbc, etc.
I got the behavior I wanted, but as I tested my logic with an Android client application I encountered that the register confirmation link I send, does not work if I access it from another device, because the device-sender has a different session and thus my logic fails.
The flow of my registration is as follows:
User POSTs at /register -> { name, email, password }
Server saves this information in their session and sends confirmation email with /register/confirm/{token}
As the user GETs at /register/confirm/{token} that was send to their email,
the server checks if this token is contained in their session and commits the information from the session to the database.
Of course if I register from the device and try to confirm through another device they'd have different sessions and hence the temp information would not be available to the other device, but this is the same user trying to register and I'm looking for a work around. The way I decided to change my code is to send the user /register/confirm/{sessionId}+{token} to their email, but I can't find my way around obtaining the other HttpSession.
(#ServletComponentScan)
I tried to create a HttpSessionListener and tried to maintain a HashMap of HttpSession's but for some reason the Framework would instantiate the Listener object, but never send createSession events to it thus it's HashMap is always empty, thus {sessionId} is never found.
To provide some extra code for context.
My Listener:
#WebListener
public class SessionLookUpTable implements HttpSessionListener {
static final HashMap<String, HttpSession> sessionHashMap = new HashMap<>();
public SessionLookUpTable() {
super();
System.out.println("-------------- Session Listener Created"); // DEBUG
}
// Always empty for some reason, despite constructor being called
static public Optional<HttpSession> findSessionById(String sessionId) {
if (!sessionHashMap.containsKey(sessionId))
return Optional.empty();
return Optional.of( sessionHashMap.get( sessionId ) );
}
#Override
public void sessionCreated(HttpSessionEvent se) {
HttpSessionListener.super.sessionCreated(se);
HttpSession session = se.getSession();
sessionHashMap.put( session.getId(), session );
}
#Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSessionListener.super.sessionDestroyed(se);
sessionHashMap.remove(se.getSession().getId() );
}
};
The controller entry points
#PostMapping("/register")
public String register(HttpSession session,
#RequestParam("email") String username,
#RequestParam("password") String password,
#RequestParam("password2") String pw2)
{
User user = new User();
user.setUsername(username);
user.setPassword(password);
user.setPrivilegeLevel( Role.USER_PRIVILEGE_NORMAL );
if(session.getAttribute(ATTRIBUTE_USER_ID) != null) {
return "Already registered";
}
if(!userService.isUserDataValid(user)) {
return "Invalid input for registry";
}
if(userService.usernameExists(user.getUsername())) {
return "User already exists";
}
session.setAttribute(ATTRIBUTE_REGISTER_DATA, user);
String token = userService.sendConfirmationEmail( session );
if(token != null) {
session.setAttribute(ATTRIBUTE_USER_ID, 0L );
session.setAttribute(ATTRIBUTE_REGISTER_TOKEN, token);
}
return "A link was sent to your email.";
}
#RequestMapping("/register/confirm/{sessionId}+{token}")
void confirmRegister(HttpSession sessionIn,
#PathVariable("sessionId") String sessionId,
#PathVariable("token") String token) {
Optional<HttpSession> optSession = SessionLookUpTable.findSessionById( sessionId );
if(optSession.isEmpty())
return;
HttpSession session = optSession.get();
// Multiple confirmations guard
Long userId = (Long)session.getAttribute(ATTRIBUTE_USER_ID);
if( userId != null && userId != 0L ){
return;
}
String sessionToken = (String)session.getAttribute(ATTRIBUTE_REGISTER_TOKEN);
if(!sessionToken.equals(token)) {
return;
}
User user = (User)session.getAttribute(ATTRIBUTE_REGISTER_DATA);
user.setDateRegistered( LocalDate.now() );
Long id = userService.register( user );
session.setAttribute(ATTRIBUTE_USER_ID, id);
}
I'm stuck at this stage for quite a while, so any help is appreciated. Thank you.
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?
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();
I am using a (little modified) workaround from this course, to fetch the userId, which is null if the request was sent from an Android client.
/**
* This is an ugly workaround for null userId for Android clients.
*
* #param user A User object injected by the cloud endpoints.
* #return the App Engine userId for the user.
*/
private static String getUserId(User user) {
String userId = user.getUserId();
if (userId == null) {
LOG.info("userId is null, so trying to obtain it from the datastore.");
AppEngineUser appEngineUser = new AppEngineUser(user);
ofy().save().entity(appEngineUser).now();
AppEngineUser savedUser = ofy().load().key(appEngineUser.getKey()).now();
userId = savedUser.getUser().getUserId();
LOG.info("Obtained the userId: " + userId);
}
return userId;
}
Although I am not able to get the userId.
INFO: Obtained the userId: null
This workaround has already worked perfectly in other projects, so the problem must be elsewhere. My endpoints api is annotated with the following scopes, clientIds and audiences:
scopes = {
Constants.EMAIL_SCOPE
},
clientIds = {
Constants.API_EXPLORER_CLIENT_ID,
Constants.WEB_CLIENT_ID,
Constants.ANDROID_CLIENT_ID
},
audiences = {
Constants.ANDROID_AUDIENCE
}
Constants.ANDROID_AUDIENCE and Constants.WEB_CLIENT_ID are the same. I am not using a web client, but Google told me to add a web client id. Does this client id need to have redirect uris and javascript origins specified?
In my Android client I am using the following to specify the audience.
mCredential = GoogleAccountCredential.usingAudience(
EndpointService.this,
"server:client_id:IDIDIDID.apps.googleusercontent.com"
);
Please help me to figure this one out.
I just understood why this workaround works. I need to begin a new objectify session so the cache is not used and the userId can be populated.
Objectify objectify = ofy().factory().begin();
AppEngineUser savedUser = objectify.load();
The question is very simple. I'd like to restrict user access with same login from different machines/browsers: only one live user session is possible.
Apache shiro library is used for user authentification and managment.
Of course this could be done using simple synchornized maps and etc. But the question is: Has Apache Shiro special mechanisms for that or not?
Another variant of this question: how to reveice the list of all subjects who are logged in the system using apache shiro?
UPD:
To clarify my question. My desire is to have some code like this (I known, that there isn't such class exception, but the idea must be more clean):
Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(login, password);
try {
currentUser.login(token);
} catch (AlreadyAuthenticatedException aae) {
errorMsg = "You should logoff on another machine!";
}
The Shiro sessions are stored in SessionDAO with sessionId as keys. Without extra effort you cannot access a session by a principal (user name). However, you could extend DefaultSecurityManager and check all active sessions by SessionDAO.getActiveSessions.
The following codes could be a simple example (suppose you are not using WebSubject):
public class UniquePrincipalSecurityManager extends org.apache.shiro.mgt.DefaultSecurityManager {
#Override
public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
String loginPrincipal = (String) token.getPrincipal();
DefaultSessionManager sm = (DefaultSessionManager) getSessionManager();
for (Session session : sm.getSessionDAO().getActiveSessions()) {
SimplePrincipalCollection p = (SimplePrincipalCollection) session
.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
if (p != null && loginPrincipal.equals(p.getPrimaryPrincipal())) {
throw new AlreadyAuthenticatedException();
}
}
return super.login(subject, token);
}
}