-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #342 from sanger/selfcreate
x1145 Let sanger users create a Stan enduser account without approval
- Loading branch information
Showing
12 changed files
with
582 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
src/main/java/uk/ac/sanger/sccp/stan/service/AuthService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package uk.ac.sanger.sccp.stan.service; | ||
|
||
import uk.ac.sanger.sccp.stan.model.User; | ||
import uk.ac.sanger.sccp.stan.request.LoginResult; | ||
|
||
/** | ||
* Service dealing with user authentication | ||
*/ | ||
public interface AuthService { | ||
/** | ||
* Logs in | ||
* @param username the username to log in | ||
* @param password the password to authenticate the user | ||
* @return a login result describing the result of the login | ||
*/ | ||
LoginResult logIn(String username, String password); | ||
|
||
/** | ||
* Logs out the current logged in user, if any | ||
* @return a description of the result of logging out | ||
*/ | ||
String logOut(); | ||
|
||
/** | ||
* Creates a Stan user authenticated with the given credentials | ||
* @param username the username to create | ||
* @param password the password to authenticate the user | ||
* @param role the role to create the user with | ||
* @return the result of attempting to log in with the given credentials | ||
*/ | ||
LoginResult selfRegister(String username, String password, User.Role role); | ||
} |
133 changes: 133 additions & 0 deletions
133
src/main/java/uk/ac/sanger/sccp/stan/service/AuthServiceImp.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package uk.ac.sanger.sccp.stan.service; | ||
|
||
import org.jetbrains.annotations.Nullable; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.stereotype.Service; | ||
import uk.ac.sanger.sccp.stan.AuthenticationComponent; | ||
import uk.ac.sanger.sccp.stan.config.SessionConfig; | ||
import uk.ac.sanger.sccp.stan.model.User; | ||
import uk.ac.sanger.sccp.stan.repo.UserRepo; | ||
import uk.ac.sanger.sccp.stan.request.LoginResult; | ||
|
||
import java.util.*; | ||
|
||
import static uk.ac.sanger.sccp.utils.BasicUtils.repr; | ||
|
||
/** | ||
* @author dr6 | ||
*/ | ||
@Service | ||
public class AuthServiceImp implements AuthService { | ||
Logger log = LoggerFactory.getLogger(AuthServiceImp.class); | ||
private final SessionConfig sessionConfig; | ||
private final UserRepo userRepo; | ||
private final AuthenticationComponent authComp; | ||
private final LDAPService ldapService; | ||
private final EmailService emailService; | ||
private final UserAdminService userAdminService; | ||
|
||
@Autowired | ||
public AuthServiceImp(SessionConfig sessionConfig, | ||
UserRepo userRepo, AuthenticationComponent authComp, | ||
LDAPService ldapService, EmailService emailService, UserAdminService userAdminService) { | ||
this.sessionConfig = sessionConfig; | ||
this.userRepo = userRepo; | ||
this.authComp = authComp; | ||
this.ldapService = ldapService; | ||
this.emailService = emailService; | ||
this.userAdminService = userAdminService; | ||
} | ||
|
||
/** | ||
* Gets the username of the logged in user, if any | ||
* @return the logged in username, or null | ||
*/ | ||
@Nullable | ||
public String loggedInUsername() { | ||
var auth = authComp.getAuthentication(); | ||
if (auth != null) { | ||
var princ = auth.getPrincipal(); | ||
if (princ instanceof User) { | ||
return ((User) princ).getUsername(); | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
@Override | ||
public LoginResult logIn(String username, String password) { | ||
if (log.isInfoEnabled()) { | ||
log.info("Login attempt by {}", repr(username)); | ||
} | ||
Optional<User> optUser = userRepo.findByUsername(username); | ||
if (optUser.isEmpty()) { | ||
return new LoginResult("Username not in database.", null); | ||
} | ||
User user = optUser.get(); | ||
if (user.getRole()==User.Role.disabled) { | ||
return new LoginResult("Username is disabled.", null); | ||
} | ||
if (!ldapService.verifyCredentials(username, password)) { | ||
return new LoginResult("Login failed.", null); | ||
} | ||
Authentication authentication = new UsernamePasswordAuthenticationToken(user, password, new ArrayList<>()); | ||
authComp.setAuthentication(authentication, sessionConfig.getMaxInactiveMinutes()); | ||
log.info("Login succeeded for user {}", user); | ||
return new LoginResult("OK", user); | ||
} | ||
|
||
@Override | ||
public String logOut() { | ||
if (log.isInfoEnabled()) { | ||
log.info("Logout requested by {}", repr(loggedInUsername())); | ||
} | ||
authComp.setAuthentication(null, 0); | ||
return "OK"; | ||
} | ||
|
||
@Override | ||
public LoginResult selfRegister(String username, String password, User.Role role) { | ||
if (log.isInfoEnabled()) { | ||
log.info("selfRegister attempt by {}", repr(username)); | ||
} | ||
username = userAdminService.validateUsername(username); | ||
if (!ldapService.verifyCredentials(username, password)) { | ||
return new LoginResult("Authentication failed.", null); | ||
} | ||
Optional<User> optUser = userRepo.findByUsername(username); | ||
User user; | ||
if (optUser.isEmpty()) { | ||
user = userAdminService.addUser(username, role); | ||
log.info("Login succeeded as new user {}", user); | ||
sendNewUserEmail(user); | ||
} else { | ||
user = optUser.get(); | ||
if (user.getRole()== User.Role.disabled) { | ||
return new LoginResult("Username is disabled.", null); | ||
} | ||
log.info("Login succeeded for existing user {}", user); | ||
} | ||
|
||
Authentication authentication = new UsernamePasswordAuthenticationToken(user, password, new ArrayList<>()); | ||
authComp.setAuthentication(authentication, sessionConfig.getMaxInactiveMinutes()); | ||
return new LoginResult("OK", user); | ||
} | ||
|
||
/** | ||
* Tries to send an email to admin users about the new user being created. | ||
* @param user the new user | ||
*/ | ||
public void sendNewUserEmail(User user) { | ||
List<User> admins = userRepo.findAllByRole(User.Role.admin); | ||
if (admins.isEmpty()) { | ||
return; | ||
} | ||
List<String> usernames = admins.stream().map(User::getUsername).toList(); | ||
String body = "User "+user.getUsername()+" has registered themself as "+user.getRole()+" on %service."; | ||
emailService.tryEmail(usernames, "New user created on %service", body); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.