Skip to content

Commit

Permalink
feat(sandside): #198 implement password generator and checker for ano…
Browse files Browse the repository at this point in the history
…nymous
  • Loading branch information
Marthym committed Jan 13, 2024
1 parent 3990714 commit a6c259b
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
package fr.ght1pc9kc.baywatch.security.api;

import fr.ght1pc9kc.baywatch.security.api.model.PasswordEvaluation;
import fr.ght1pc9kc.baywatch.security.api.model.User;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public interface PasswordService {
/**
* Check the password strength and return an evaluation
* <p>Check the password strength and return an evaluation</p>
* <p>The current authenticated user is used to populate the password evaluation context</p>
*
* @param password The new password
* @return {@code Void} when the password is changed
* @throws IllegalArgumentException When password strength is not enough
* @return A password evaluation
* @throws fr.ght1pc9kc.baywatch.common.api.exceptions.UnauthorizedException When no user was authenticated
*/
Mono<PasswordEvaluation> checkPasswordStrength(String password);

Mono<String> generateSecurePassword();
/**
* Check the password strength and return a {@link PasswordEvaluation}
*
* @param user The user owner of the password as the context
* @return A password evaluation
*/
Mono<PasswordEvaluation> checkPasswordStrength(User user);

Flux<String> generateSecurePassword(int number);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@
import fr.ght1pc9kc.baywatch.security.api.AuthenticationFacade;
import fr.ght1pc9kc.baywatch.security.api.PasswordService;
import fr.ght1pc9kc.baywatch.security.api.model.PasswordEvaluation;
import fr.ght1pc9kc.baywatch.security.api.model.User;
import fr.ght1pc9kc.baywatch.security.domain.ports.PasswordStrengthChecker;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuples;

import java.util.List;
import java.util.stream.LongStream;

@Slf4j
@RequiredArgsConstructor
public class PasswordServiceImpl implements PasswordService {

Expand All @@ -33,7 +38,19 @@ public Mono<PasswordEvaluation> checkPasswordStrength(String password) {
}

@Override
public Mono<String> generateSecurePassword() {
return null;
public Mono<PasswordEvaluation> checkPasswordStrength(User user) {
return localeFacade.getLocale()
.map(locale -> passwordChecker.estimate(user.password, locale, List.of(user.name, user.login, user.mail)))
}

@Override
public Flux<String> generateSecurePassword(int number) {
return Flux.<String>create(sink ->
sink.onRequest(n ->
LongStream.range(1, n)
.mapToObj(ignore -> passwordChecker.generate())
.forEach(sink::next)))
.take(Integer.valueOf(number).longValue())
.doOnComplete(() -> log.atDebug().log("Password generation complete"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,6 @@ public interface PasswordStrengthChecker {
default PasswordEvaluation estimate(String password, Locale locale) {
return estimate(password, locale, Collections.emptyList());
}

String generate();
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import me.gosimple.nbvcxz.resources.ConfigurationBuilder;
import me.gosimple.nbvcxz.resources.Dictionary;
import me.gosimple.nbvcxz.resources.DictionaryBuilder;
import me.gosimple.nbvcxz.resources.Generator;
import me.gosimple.nbvcxz.scoring.Result;
import me.gosimple.nbvcxz.scoring.TimeEstimate;
import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -55,4 +56,9 @@ public PasswordEvaluation estimate(String password, Locale locale, Collection<St
message
);
}

@Override
public String generate() {
return Generator.generateRandomPassword(Generator.CharacterTypes.ALPHANUMERIC, 16);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import fr.ght1pc9kc.baywatch.security.api.model.Permission;
import fr.ght1pc9kc.baywatch.security.api.model.UpdatableUser;
import fr.ght1pc9kc.baywatch.security.api.model.User;
import fr.ght1pc9kc.baywatch.security.infra.model.UserForm;
import org.jooq.Record;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
Expand All @@ -30,6 +31,8 @@ public interface UserMapper {

UpdatableUser getUpdatableUser(Map<String, Object> userForm);

User getUser(UserForm userForm);

@SuppressWarnings({"OptionalAssignedToNull", "java:S2789", "java:S3655"})
default UsersRecord updatableUserToRecord(UpdatableUser user) {
var r = new UsersRecord();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,37 @@

import fr.ght1pc9kc.baywatch.security.api.PasswordService;
import fr.ght1pc9kc.baywatch.security.api.model.PasswordEvaluation;
import fr.ght1pc9kc.baywatch.security.infra.adapters.UserMapper;
import fr.ght1pc9kc.baywatch.security.infra.model.UserForm;
import lombok.RequiredArgsConstructor;
import org.springframework.graphql.data.method.annotation.Argument;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Controller
@RequiredArgsConstructor
@PreAuthorize("isAuthenticated()")
public class PasswordController {
private final PasswordService passwordService;
private final UserMapper userMapper;

@QueryMapping
public Mono<PasswordEvaluation> checkPasswordStrength(@Argument("password") String password) {
return passwordService.checkPasswordStrength(password);
}

@QueryMapping
@PreAuthorize("isAnonymous()")
public Mono<PasswordEvaluation> checkAnonymousPassword(@Argument("user") UserForm user) {
return passwordService.checkPasswordStrength(userMapper.getUser(user));
}

@QueryMapping
@PreAuthorize("isAnonymous()")
public Flux<String> generatePasswords(@Argument("number") int number) {
return passwordService.generateSecurePassword(number);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ type PasswordEvaluation {

extend type Query {
checkPasswordStrength(password: String): PasswordEvaluation
}
checkAnonymousPassword(user: UserForm): PasswordEvaluation
generatePasswords(number: Int): [String]
}

0 comments on commit a6c259b

Please sign in to comment.