Skip to content

Commit

Permalink
Merge pull request #711 from qbicsoftware/development
Browse files Browse the repository at this point in the history
Release
  • Loading branch information
wow-such-code authored Jul 16, 2024
2 parents 25819b6 + 8efea9d commit a3e5335
Show file tree
Hide file tree
Showing 94 changed files with 2,329 additions and 709 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package life.qbic.identity.api;

import java.util.Optional;
import org.springframework.security.core.Authentication;

/**
* Translates an {@link Authentication} object into an identifier of QBiC
*
* @since 1.2.0
*/
public interface AuthenticationToUserIdTranslator {

/**
* Translates an authentication object to the associated userId
*
* @param authentication
* @return
*/
Optional<String> translateToUserId(Authentication authentication);

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
* @since 1.0.0
*/
public record UserInfo(String id, String fullName, String emailAddress, String platformUserName,
String encryptedPassword,
boolean isActive) implements Serializable {

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,18 @@ public interface UserInformationService {
* @return true, if the username is still available, false if not
* @since 1.0.0
*/
boolean userNameAvailable(String userName);
boolean isUserNameAvailable(String userName);


/**
* Queries if a provided email is already in use by another user
*
* @param email the desired email address
* @return true, if the email is still available, false if not
*/
boolean isEmailAvailable(String email);

Optional<UserInfo> findByOidc(String oidcId, String oidcIssuer);

List<UserInfo> findAllActive(String filter, int offset, int limit, List<SortOrder> sortOrders);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package life.qbic.identity.api;

/**
* An encrypted password belonging to a user
*
* @since 1.1.0
*/
public record UserPassword(String userId, String encryptedPassword) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package life.qbic.identity.api;

import java.util.Optional;

/**
* A service for retrieving encrypted user passwords.
*
* @since 1.2.0
*/
public interface UserPasswordService {

/**
* @param userId the identifier of the user in the datamanager user management
* @return the {@link UserPassword} for a user with the given identifier
*/
Optional<UserPassword> findEncryptedPasswordForUser(String userId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


import java.util.List;
import java.util.Optional;
import life.qbic.identity.domain.model.EmailAddress;
import life.qbic.identity.domain.model.User;
import life.qbic.identity.domain.model.UserId;
Expand Down Expand Up @@ -50,4 +51,6 @@ public interface QbicUserRepo extends JpaRepository<User, UserId> {
User findUserByUserName(String userName);

List<User> findAllByUserNameContainingIgnoreCaseAndActiveTrue(String username, Pageable pageable);

Optional<User> findByOidcIdEqualsAndOidcIssuerEquals(String oidcId, String oidcIssuer);
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,9 @@ public List<User> findByUserNameContainingIgnoreCaseAndActiveTrue(String userNam
Pageable pageable) {
return userRepo.findAllByUserNameContainingIgnoreCaseAndActiveTrue(userName, pageable);
}

@Override
public Optional<User> findByOidcIdEqualsAndOidcIssuerEquals(String oidcId, String oidcIssuer) {
return userRepo.findByOidcIdEqualsAndOidcIssuerEquals(oidcId, oidcIssuer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import life.qbic.application.commons.SortOrder;
import life.qbic.identity.api.UserInfo;
import life.qbic.identity.api.UserInformationService;
import life.qbic.identity.api.UserPassword;
import life.qbic.identity.api.UserPasswordService;
import life.qbic.identity.domain.model.EmailAddress;
import life.qbic.identity.domain.model.EmailAddress.EmailValidationException;
import life.qbic.identity.domain.model.User;
Expand All @@ -26,7 +28,7 @@
*
* @since 1.0.0
*/
public class BasicUserInformationService implements UserInformationService {
public class BasicUserInformationService implements UserInformationService, UserPasswordService {

private static final Logger log = logger(BasicUserInformationService.class);

Expand Down Expand Up @@ -59,10 +61,26 @@ public Optional<UserInfo> findById(String userId) {
}

@Override
public boolean userNameAvailable(String userName) {
public boolean isUserNameAvailable(String userName) {
return userRepository.findByUserName(userName).isEmpty();
}

@Override
public Optional<UserInfo> findByOidc(String oidcId, String oidcIssuer) {
return userRepository.findByOidc(oidcId, oidcIssuer).map(this::convert);
}

@Override
public boolean isEmailAvailable(String email) {
try {
var emailAddress = EmailAddress.from(email);
return userRepository.findByEmail(emailAddress).isEmpty();
} catch (EmailValidationException e) {
log.error("Invalid email address %s".formatted(email), e);
return false;
}
}

@Override
public List<UserInfo> findAllActive(String filter, int offset, int limit,
List<SortOrder> sortOrders) {
Expand All @@ -79,14 +97,21 @@ public List<UserInfo> findAllActive(String filter, int offset, int limit,
filter, new OffsetBasedRequest(offset, limit, Sort.by(orders)))
.stream()
.map(user -> new UserInfo(user.id().get(), user.fullName().get(), user.emailAddress().get(),
user.userName(), user.getEncryptedPassword().get(), user.isActive()))
user.userName(), user.isActive()))
.toList();
}

private UserInfo convert(User user) {
return new UserInfo(user.id().get(), user.fullName().get(), user.emailAddress().get(),
user.userName(),
user.getEncryptedPassword().get(),
user.isActive());
}

@Override
public Optional<UserPassword> findEncryptedPasswordForUser(String userId) {
return userRepository.findById(UserId.from(userId))
.map(user -> user.getEncryptedPassword() != null ? user : null)
.map(user -> new UserPassword(user.id().get(), user.getEncryptedPassword().get()));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,36 @@ public ApplicationResponse registerUser(final String fullName, String userName,
return ApplicationResponse.successResponse();
}

public ApplicationResponse registerOpenIdUser(String fullName, String userName, String email,
String oidcIssuer, String oidcId) {

var validationResponse = validateInputOidcInput(fullName, userName, email, oidcIssuer, oidcId);
if (validationResponse.hasFailures()) {
return validationResponse;
}

var userDomainService = DomainRegistry.instance().userDomainService();
if (userDomainService.isEmpty()) {
throw new RuntimeException("User registration failed.");
}

var userEmail = EmailAddress.from(email);
var userFullName = FullName.from(fullName);

if (userRepository.findByEmail(userEmail).isPresent()) {
return ApplicationResponse.failureResponse(new UserExistsException());
}

if (userRepository.findByUserName(userName).isPresent()) {
return ApplicationResponse.failureResponse(new UserNameNotAvailableException());
}

// Trigger the user creation in the domain service
userDomainService.get().createOidcUser(userFullName, userName, userEmail, oidcIssuer, oidcId);

return ApplicationResponse.successResponse();
}

private ApplicationResponse validateInput(String fullName, String userName, String email,
char[] rawPassword) {
List<RuntimeException> failures = new ArrayList<>();
Expand Down Expand Up @@ -118,6 +148,37 @@ private ApplicationResponse validateInput(String fullName, String userName, Stri
return ApplicationResponse.failureResponse(failures.toArray(RuntimeException[]::new));
}

private ApplicationResponse validateInputOidcInput(String fullName, String userName, String email,
String oidcIssuer, String oidcId) {
List<RuntimeException> failures = new ArrayList<>();

try {
EmailAddress.from(email);
} catch (EmailValidationException e) {
failures.add(e);
}
try {
FullName.from(fullName);
} catch (FullNameValidationException e) {
failures.add(e);
}
if (isNull(userName) || userName.isBlank()) {
failures.add(new EmptyUserNameException());
}
if (isNull(oidcIssuer) || oidcIssuer.isBlank()) {
failures.add(new EmptyOidcIssuerException());
}
if (isNull(oidcId) || oidcId.isBlank()) {
failures.add(new EmptyOidcIdException());
}

if (failures.isEmpty()) {
return ApplicationResponse.successResponse();
}

return ApplicationResponse.failureResponse(failures.toArray(RuntimeException[]::new));
}

/**
* Requests a password reset for a user.
*
Expand Down Expand Up @@ -276,4 +337,12 @@ public static class UserNotActivatedException extends ApplicationException {
super(message);
}
}

public static class EmptyOidcIssuerException extends RuntimeException {

}

public static class EmptyOidcIdException extends RuntimeException {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public EmailConfirmationLinkSupplier(
@Value("${service.host.name}") String host,
@Value("${service.host.port}") int port,
@Value("${server.servlet.context-path}") String contextPath,
@Value("${email-confirmation-endpoint}") String loginEndpoint,
@Value("${email-confirmation-parameter}") String emailConfirmationParameter) {
@Value("${routing.email-confirmation.endpoint}") String loginEndpoint,
@Value("${routing.email-confirmation.confirmation-parameter}") String emailConfirmationParameter) {
this.protocol = protocol;
this.host = host;
this.port = port;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ public PasswordResetLinkSupplier(
@Value("${service.host.name}") String host,
@Value("${service.host.port}") int port,
@Value("${server.servlet.context-path}") String contextPath,
@Value("${password-reset-endpoint}") String resetEndpoint,
@Value("${password-reset-parameter}") String passwordResetParameter) {
@Value("${routing.password-reset.endpoint}") String resetEndpoint,
@Value("${routing.password-reset.reset-parameter}") String passwordResetParameter) {
this.protocol = protocol;
this.host = host;
this.port = port;
Expand Down
Loading

0 comments on commit a3e5335

Please sign in to comment.