How to use email as a username in Spring Security? - java

I have to remove a login field from my User class and use email as a username in SecurityUtils
I've already changed j_username parameter in a frontend, but now the issue remains on a backend
public static String getCurrentUserLogin() {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
String userName = null;
if (authentication != null) {
if (authentication.getPrincipal() instanceof UserDetails) {
UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
userName = springSecurityUser.getUsername();
} else if (authentication.getPrincipal() instanceof String) {
userName = (String) authentication.getPrincipal();
}
}
return userName;
}
and as a result userName is null, becauseUserDetails and Authentication don't have email. How could I set the field email as a 'j_username'? I've tried this
How to login by email instead of username in spring security
solution but it's not enough since I use an anonymousUser
Also, I have an implementation of UserDetailsService but when debugging it's not called when being the anonymousUser
public class DomainUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
public DomainUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public UserDetails loadUserByUsername(final String login) {
String lowercaseLogin = login.toLowerCase(Locale.ENGLISH);
Optional<User> userFromDatabase = userRepository.findOneByLogin(lowercaseLogin);
return userFromDatabase.map(user -> {
if (!user.getActivated()) {
throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated");
}
List<GrantedAuthority> grantedAuthorities = user.getAuthorities().stream()
.map(authority -> new SimpleGrantedAuthority(authority.getName()))
.collect(Collectors.toList());
return new org.springframework.security.core.userdetails.User(lowercaseLogin,
user.getPassword(),
grantedAuthorities);
}).orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the " +
"database"));
}
}

In order to achieve your goal you will have to control anonymous user behavior. I had that issue before and when the user is logged in the queries are working fine. As M. Denim suggested you should search by email here -> Optional<User> userFromDatabase = userRepository.findOneByEmail(lowercaseLogin);
But in case of anonymous user in getCurrentUserLogin() you have to write an if statement to return anonymous#localhost in case the userName = anonymousUser

here i share some code from my Spring Security Configuration class
.formLogin().loginPage("/login")
.usernameParameter("logInId").passwordParameter("password")
here i use 'logInId' parameter for login instead of default parameter....
i think you searching some thing like this .......

Related

LDAP + Spring: how to correctly authenticate?

I realize LDAP authentication by Spring. In my case, I use ActiveDirectoryLdapAuthenticationProvider.
It looks like here:
private Authentication authenticate(String username, String password, HelpDescUser userDetails) {
String url = "ldap://" + ldapHost + ":" + port + "/";
ActiveDirectoryLdapAuthenticationProvider ldapProvider =
new ActiveDirectoryLdapAuthenticationProvider(domain, url, rootDn);
String filterWithName = String.format(filter, username);
ldapProvider.setSearchFilter(filterWithName);
ldapProvider.setContextEnvironmentProperties(createProperties(username, password));
ldapProvider.setConvertSubErrorCodesToExceptions(true);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, password);
Authentication authenticate;
try {
authenticate = ldapProvider.authenticate(authentication);
} catch (Exception e) {
throw new BadCredentialsException("Пользователь не авторизован (сервер LDAP не подтвердил авторизацию).");
}
if (Objects.nonNull(authenticate) && authenticate.isAuthenticated()) {
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
} else {
throw new BadCredentialsException("Пользователь не авторизован (сервер LDAP не подтвердил авторизацию).");
}
}
private Map<String, Object> createProperties(String username, String password) {
Map<String, Object> properties = new HashMap<>();
properties.put(Context.SECURITY_PRINCIPAL, username);
properties.put(Context.SECURITY_CREDENTIALS, password);
return properties;
}
I have a problem.
As I understand authentication schema, when we authenticate by user, we also need to have a technical account. We bind by technical account & than sending user login & password, & after that, we receive answer. But in this schema, we bind with the same user to authenticate, & it's wrong - this user may have no rights to bind.
Please, show me working solution to authenticate with Spring ActiveDirectoryLdapAuthenticationProvider?
When you declare ActiveDirectoryLdapAuthenticationProvider bean, you can use setContextEnvironmentProperties() method.
In example:
#Bean
public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(null, ldapUrls, ldapBase);
setContextEnvironmentProperties(provider);
return provider;
}
private void setContextEnvironmentProperties(ActiveDirectoryLdapAuthenticationProvider provider) {
Map<String, Object> contextEnvironmentProperties = new HashMap<>();
if (StringUtils.isNotEmpty(ldapUsername)) {
contextEnvironmentProperties.put(Context.SECURITY_PRINCIPAL, ldapUsername);
}
if (StringUtils.isNotEmpty(ldapPassword)) {
contextEnvironmentProperties.put(Context.SECURITY_CREDENTIALS, ldapPassword);
}
if (!contextEnvironmentProperties.isEmpty()) {
provider.setContextEnvironmentProperties(contextEnvironmentProperties);
}
}

Refresh token returns a value on console but returns null on ResponseEntity

I got this task as an intern in a company to implement refresh token on their system. I can see that there are some codes that are already made for it (someone already tried to implement it)but it's not working.
I traced the code and found that it creates and prints the refresh token on the console but not on the ResponseEntity (returns null). I'm not used to coding in Java EE, Spring Framework, JWT Tokens or OAuth. I still have a lot of things to learn. I saw some answers that it needs to have an access type that is offline but the codes are all in PHP. I don't know how to implement it on Java with Spring Framework. So here are some of the codes...
For the Login Controller:
public ResponseEntity<String> auth(#RequestBody AuthModel auth) {
String username = auth.getUsername();
String password = auth.getPassword();
UserModel user = authService.authenticate(username, password);
if (user != null) {
final Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
auth.getUsername(),
auth.getPassword()
)
);
SecurityContextHolder.getContext().setAuthentication(authentication); //set current user
final UserDetails userDetails = authService.loadUserByUsername(auth.getUsername());
user.setOrg_id(usrService.setOrgId(user.getCompany_id()));
return new ResponseEntity(new ResponseModel(HttpStatus.OK.value(),jwtService.getToken(userDetails),jwtService.getRefreshToken(userDetails), "Success"), HttpStatus.OK);
}
For the Services:
#SuppressWarnings("static-access")
public String getRefreshToken(UserDetails user)
{
System.out.println("Get Refresh Token: " + createRefreshToken(user));
return createRefreshToken(user);
}
public String createRefreshToken(UserDetails userDetails) {
if (userDetails.getUsername() == null) {
throw new IllegalArgumentException("Cannot create JWT Token without username");
}
Claims claims = Jwts.claims().setSubject(userDetails.getUsername());
claims.put("roles", Arrays.asList(userDetails.getAuthorities()));
Date now = new Date();
String token = Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setId(UUID.randomUUID().toString())
.setIssuedAt(now)
.setExpiration(getRefreshExpirationTime())
.signWith(SignatureAlgorithm.HS512, refreshEncodedSecret)
.compact();
//System.out.println("Refresh Token: " + token);
return token;
}
After a success login, it returns this Response.
ResponseEntity
And for the console...
Console result
I hope you can answer me in details. Thank you in advance!

Errai security with PicketLink

I have this CustomAuthenticator for user with Errai Security:
public CustomAuthenticator extends BaseAuthenticator {
#Override
public void authenticate() {
String userId = loginCredentials.getUserId();
String password = loginCredentials.getPassword();
User user = userDAO.fetchUserByName(userId);
if (!BCrypt.checkpw(password, user.getPasswordHash())) {
setStatus(AuthenticationStatus.FAILURE);
} else {
// Add to IDM
IdentityQuery<UserImpl> query
= partitionManager.createIdentityManager().createIdentityQuery(UserImpl.class);
query.setParameter(UserImpl.LOGIN_NAME, user.getUsername());
List<UserImpl> result = query.getResultList();
org.picketlink.idm.model.basic.Role trial = new org.picketlink.idm.model.basic.Role("TRIAL");
if (result.isEmpty()){
UserImpl account = new UserImpl(user);
partitionManager.createIdentityManager().add(account);
partitionManager.createIdentityManager().updateCredential(account, new Password(password));
partitionManager.createIdentityManager().add(trial);
BasicModel.grantRole(partitionManager.createRelationshipManager(), account, trial);
IdentityQuery<UserImpl> q
= partitionManager.createIdentityManager().createIdentityQuery(UserImpl.class);
q.setParameter(UserImpl.LOGIN_NAME, user.getUsername());
UserImpl u = q.getResultList().iterator().next();
setStatus(AuthenticationStatus.SUCCESS);
setAccount(u);
} else {
setStatus(AuthenticationStatus.SUCCESS);
setAccount(result.iterator().next());
}
userEvent.fire(user);
}
}
Even I check the seAccount Account to be set is ok, I am not sure if the Roles is persisted at list at the Picketlink side; because the response of the call:
Caller<AuthenticationService> authServiceCaller;
The Errai Security User returned although not null, the names is "ANONYMOUS" and role is "NOBODY" I'm not sure what's happening here.
Update:
The login(username, password) method returns the correct User and Role, but getUser() does not. This is the issue.

How to automatically login as a user using Spring Security without knowing their password?

My application uses Spring Security, and my client requires:
users to be able to automatically login after signup.
an admin to login as any user without knowing their password.
So I need to figure out how to login as any user automatically without knowing their password.
How can this be accomplished using Spring Security?
To get this to work, I had to:
Configure a reference to the UserDetailsService (jdbcUserService)
<authentication-manager>
<authentication-provider>
<jdbc-user-service id="jdbcUserService" data-source-ref="dataSource"
users-by-username-query="select username,password, enabled from users where username=?"
authorities-by-username-query="select u.username, ur.authority from users u, user_roles ur where u.user_id = ur.user_id and u.username =? "
/>
</authentication-provider>
</authentication-manager>
Autowire my userDetailsManager in my controller:
#Autowired
#Qualifier("jdbcUserService") // <-- this references the bean id
public UserDetailsManager userDetailsManager;
In the same controller, authenticate my user like so:
#RequestMapping("/automatic/login/test")
public #ResponseBody String automaticLoginTest(HttpServletRequest request)
{
String username = "anyUserName#YourSite.com";
Boolean result = authenticateUserAndInitializeSessionByUsername(username, userDetailsManager, request);
return result.toString();
}
public boolean authenticateUserAndInitializeSessionByUsername(String username, UserDetailsManager userDetailsManager, HttpServletRequest request)
{
boolean result = true;
try
{
// generate session if one doesn't exist
request.getSession();
// Authenticate the user
UserDetails user = userDetailsManager.loadUserByUsername(username);
Authentication auth = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
}
catch (Exception e)
{
System.out.println(e.getMessage());
result = false;
}
return result;
}
Note that a good precursor to just using spring security for your app can be found here.
for second problem
an admin to login as any user without knowing their password.
you should use switch user feature from spring. javadoc and article
This is answer to above question
In Controller:
#RequestMapping(value = "/registerHere", method = RequestMethod.POST)
public ModelAndView registerUser(#ModelAttribute("user") Users user, BindingResult result,
HttpServletRequest request, HttpServletResponse response) {
System.out.println("register 3");
ModelAndView mv = new ModelAndView("/home");
mv.addObject("homePagee", "true");
String uname = user.getUsername();
if (userDAO.getUserByName(uname) == null) {
String passwordFromForm = user.getPassword();
userDAO.saveOrUpdate(user);
try {
authenticateUserAndSetSession(user, passwordFromForm, request);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("register 4");
log.debug("Ending of the method registerUser");
return mv;
}
Further above method in controller is defined as:
`private void authenticateUserAndSetSession(Users user, String passwor`dFromForm, HttpServletRequest request){
String username = user.getUsername();
System.out.println("username: " + username + " password: " + passwordFromForm);
UserDetails userDetails = userDetailsService.loadUserByUsername(user.getUsername());
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, passwordFromForm, userDetails.getAuthorities());
request.getSession();
System.out.println("Line Authentication 1");
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetails(request));
System.out.println("Line Authentication 2");
Authentication authenticatedUser = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
System.out.println("Line Authentication 3");
if (usernamePasswordAuthenticationToken.isAuthenticated()) {
SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
System.out.println("Line Authentication 4");
}
request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, SecurityContextHolder.getContext());// creates context for that session.
System.out.println("Line Authentication 5");
session.setAttribute("username", user.getUsername());
System.out.println("Line Authentication 6");
session.setAttribute("authorities", usernamePasswordAuthenticationToken.getAuthorities());
System.out.println("username: " + user.getUsername() + "password: " + user.getPassword()+"authorities: "+ usernamePasswordAuthenticationToken.getAuthorities());
user = userDAO.validate(user.getUsername(), user.getPassword());
log.debug("You are successfully register");
}
Other answers didnt suggest to put it in try/catch so one does not realize why logic is not working as code runs...and nothing is there neither error or exception on console. So if you wont put it in try catch you wont get exception of bad credentials.

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