From 2117e6ccd5fe883226d163ac65065017dbd31a41 Mon Sep 17 00:00:00 2001 From: "witold.brzozowski" Date: Thu, 15 Feb 2024 13:18:40 +0100 Subject: [PATCH] Add account name to user model and use it for auth --- .../fingo/urlopia/config/ad/Attribute.java | 56 +++++++++---------- .../authentication/oauth/AccessToken.java | 15 +---- .../authentication/oauth/JwtFilter.java | 4 +- .../oauth/JwtTokenAuthoritiesProvider.java | 9 +-- .../config/authentication/oauth/JwtUtils.java | 21 +------ .../oauth/OAuthUserIdInterceptor.java | 10 +--- .../team/ActiveDirectoryTeamMapper.java | 12 ++-- .../user/ActiveDirectoryUserMapper.java | 35 ++++-------- .../urlopia/user/NoSuchUserException.java | 4 ++ .../java/info/fingo/urlopia/user/User.java | 11 ++++ .../fingo/urlopia/user/UserRepository.java | 2 + .../info/fingo/urlopia/user/UserService.java | 26 ++------- .../U3_3_0_1__add_user_account_name.sql | 1 + .../V3_3_0_1__add_user_account_name.sql | 1 + view.react/.env | 6 +- view.react/.gitignore | 51 ++++++++--------- 16 files changed, 110 insertions(+), 154 deletions(-) create mode 100644 src/main/resources/scripts/U3_3_0_1__add_user_account_name.sql create mode 100644 src/main/resources/scripts/V3_3_0_1__add_user_account_name.sql diff --git a/src/main/java/info/fingo/urlopia/config/ad/Attribute.java b/src/main/java/info/fingo/urlopia/config/ad/Attribute.java index 06991e1a..e885c1db 100644 --- a/src/main/java/info/fingo/urlopia/config/ad/Attribute.java +++ b/src/main/java/info/fingo/urlopia/config/ad/Attribute.java @@ -1,28 +1,28 @@ -package info.fingo.urlopia.config.ad; - -public enum Attribute { - PRINCIPAL_NAME("userPrincipalName"), - MAIL("mail"), - FIRST_NAME("givenname"), - LAST_NAME("sn"), - MEMBER("member"), - MEMBER_OF("memberOf"), - MANAGED_OBJECTS("managedObjects"), - MANAGED_BY("managedBy"), - NAME("name"), - DISTINGUISHED_NAME("distinguishedName"), - CREATED_TIME("whenCreated"), - CHANGED_TIME("whenChanged"), - USER_ACCOUNT_CONTROL("userAccountControl"); - - - private String key; - - Attribute(String key) { - this.key = key; - } - - public String getKey() { - return key; - } -} +package info.fingo.urlopia.config.ad; + +public enum Attribute { + PRINCIPAL_NAME("userPrincipalName"), + MAIL("mail"), + FIRST_NAME("givenname"), + LAST_NAME("sn"), + MEMBER("member"), + MEMBER_OF("memberOf"), + MANAGED_OBJECTS("managedObjects"), + MANAGED_BY("managedBy"), + NAME("name"), + DISTINGUISHED_NAME("distinguishedName"), + CREATED_TIME("whenCreated"), + CHANGED_TIME("whenChanged"), + USER_ACCOUNT_CONTROL("userAccountControl"), + ACCOUNT_NAME("sAMAccountName"); + + private String key; + + Attribute(String key) { + this.key = key; + } + + public String getKey() { + return key; + } +} diff --git a/src/main/java/info/fingo/urlopia/config/authentication/oauth/AccessToken.java b/src/main/java/info/fingo/urlopia/config/authentication/oauth/AccessToken.java index 3e986227..84628aeb 100644 --- a/src/main/java/info/fingo/urlopia/config/authentication/oauth/AccessToken.java +++ b/src/main/java/info/fingo/urlopia/config/authentication/oauth/AccessToken.java @@ -15,20 +15,9 @@ public class AccessToken { private final String value; private final JwtTokenAuthoritiesProvider jwtTokenAuthoritiesProvider; - - public String getPrincipal() { - var decodedToken = decodeToken(value); - return JwtUtils.getPrincipalNameFromDecodedToken(decodedToken); - } - - public String getFirstName() { - var decodedToken = decodeToken(value); - return JwtUtils.getFirstNameFromDecodedToken(decodedToken); - } - - public String getLastName() { + public String getAccountName() { var decodedToken = decodeToken(value); - return JwtUtils.getLastNameFromDecodedToken(decodedToken); + return JwtUtils.getAccountNameFromDecodedToken(decodedToken); } public Set getAuthorities() { diff --git a/src/main/java/info/fingo/urlopia/config/authentication/oauth/JwtFilter.java b/src/main/java/info/fingo/urlopia/config/authentication/oauth/JwtFilter.java index dc43b0d7..2959a9f9 100644 --- a/src/main/java/info/fingo/urlopia/config/authentication/oauth/JwtFilter.java +++ b/src/main/java/info/fingo/urlopia/config/authentication/oauth/JwtFilter.java @@ -42,9 +42,9 @@ private Authentication getAuthenticationByToken(String header, HttpServletResponse response) { try{ var accessToken = jwtTokenValidator.validateAuthorizationHeader(header); - var principal = accessToken.getFirstName() + ";" + accessToken.getLastName(); + var accountName = accessToken.getAccountName(); var authorities = accessToken.getAuthorities(); - return new UsernamePasswordAuthenticationToken(principal, null, authorities); + return new UsernamePasswordAuthenticationToken(accountName, null, authorities); }catch (InvalidTokenException | NoSuchUserException exception){ response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return null; diff --git a/src/main/java/info/fingo/urlopia/config/authentication/oauth/JwtTokenAuthoritiesProvider.java b/src/main/java/info/fingo/urlopia/config/authentication/oauth/JwtTokenAuthoritiesProvider.java index 0b49ddb9..e86ec1c0 100644 --- a/src/main/java/info/fingo/urlopia/config/authentication/oauth/JwtTokenAuthoritiesProvider.java +++ b/src/main/java/info/fingo/urlopia/config/authentication/oauth/JwtTokenAuthoritiesProvider.java @@ -16,13 +16,8 @@ public class JwtTokenAuthoritiesProvider { private final UserAuthoritiesProvider userAuthoritiesProvider; public Set getAuthoritiesFromJWT(DecodedJWT decodedToken){ -// var principal = JwtUtils.getPrincipalNameFromDecodedToken(decodedToken); TODO: go back to checking @ / sth else than name and surname -// var user = userService.getByPrincipal(principal); - - var firstName = JwtUtils.getFirstNameFromDecodedToken(decodedToken); - var lastName = JwtUtils.getLastNameFromDecodedToken(decodedToken); - var user = userService.getByFirstNameAndLastName(firstName, lastName); - + var accountName = JwtUtils.getAccountNameFromDecodedToken(decodedToken); + var user = userService.getFirstByAccountName(accountName); return userAuthoritiesProvider.getAuthoritiesFromUser(user); } } diff --git a/src/main/java/info/fingo/urlopia/config/authentication/oauth/JwtUtils.java b/src/main/java/info/fingo/urlopia/config/authentication/oauth/JwtUtils.java index ed513010..5c53fb43 100644 --- a/src/main/java/info/fingo/urlopia/config/authentication/oauth/JwtUtils.java +++ b/src/main/java/info/fingo/urlopia/config/authentication/oauth/JwtUtils.java @@ -12,16 +12,7 @@ @Component @RequiredArgsConstructor public class JwtUtils { - private static final String PRINCIPAL_KEY = "unique_name"; - private static final String FIRST_NAME_KEY = "given_name"; - private static final String LAST_NAME_KEY = "family_name"; - - - public static String getPrincipalNameFromDecodedToken(DecodedJWT decodedToken){ - var payloadAsJson = decodeTokenPayloadToJsonObject(decodedToken); - return payloadAsJson.getAsJsonPrimitive(PRINCIPAL_KEY).getAsString(); - } public static JsonObject decodeTokenPayloadToJsonObject(DecodedJWT decodedJWT) { try { @@ -34,15 +25,9 @@ public static JsonObject decodeTokenPayloadToJsonObject(DecodedJWT decodedJWT) { } } - //TEMPORARY FIX - - public static String getFirstNameFromDecodedToken(DecodedJWT decodedToken){ - var payloadAsJson = decodeTokenPayloadToJsonObject(decodedToken); - return payloadAsJson.getAsJsonPrimitive(FIRST_NAME_KEY).getAsString(); - } - - public static String getLastNameFromDecodedToken(DecodedJWT decodedToken){ + public static String getAccountNameFromDecodedToken(DecodedJWT decodedToken) { var payloadAsJson = decodeTokenPayloadToJsonObject(decodedToken); - return payloadAsJson.getAsJsonPrimitive(LAST_NAME_KEY).getAsString(); + var principal = payloadAsJson.getAsJsonPrimitive(PRINCIPAL_KEY).getAsString(); + return principal.substring(0, principal.indexOf("@")); } } diff --git a/src/main/java/info/fingo/urlopia/config/authentication/oauth/OAuthUserIdInterceptor.java b/src/main/java/info/fingo/urlopia/config/authentication/oauth/OAuthUserIdInterceptor.java index 9a244e16..5a39da7c 100644 --- a/src/main/java/info/fingo/urlopia/config/authentication/oauth/OAuthUserIdInterceptor.java +++ b/src/main/java/info/fingo/urlopia/config/authentication/oauth/OAuthUserIdInterceptor.java @@ -27,14 +27,10 @@ public boolean preHandle(HttpServletRequest request, var token = request.getHeader("Authorization"); try{ var accessToken = jwtTokenValidator.validateAuthorizationHeader(token); -// var principal = accessToken.getPrincipal(); TODO: go back to checking @ / sth else than name and surname -// var user = userService.getByPrincipal(principal); - - var firstName = accessToken.getFirstName(); - var lastName = accessToken.getLastName(); - var user = userService.getByFirstNameAndLastName(firstName, lastName); + var user = userService.getFirstByAccountName(accessToken.getAccountName()); request.setAttribute(USER_ID_ATTRIBUTE, user.getId()); - } catch (RuntimeException ignored){ + } catch (RuntimeException ignored) { + // Ignored } return true; } diff --git a/src/main/java/info/fingo/urlopia/team/ActiveDirectoryTeamMapper.java b/src/main/java/info/fingo/urlopia/team/ActiveDirectoryTeamMapper.java index 0046ab58..9f40261c 100644 --- a/src/main/java/info/fingo/urlopia/team/ActiveDirectoryTeamMapper.java +++ b/src/main/java/info/fingo/urlopia/team/ActiveDirectoryTeamMapper.java @@ -28,14 +28,10 @@ Team mapToTeam(SearchResult adTeam) { return this.mapToTeam(adTeam, new Team()); } - Team mapToTeam(SearchResult adTeam, - Team team) { - team.setAdName( - ActiveDirectoryUtils.pickAttribute(adTeam, Attribute.DISTINGUISHED_NAME)); - team.setName( - normalizeName(ActiveDirectoryUtils.pickAttribute(adTeam, Attribute.NAME))); - team.setLeader( - findUser(ActiveDirectoryUtils.pickAttribute(adTeam, Attribute.MANAGED_BY))); + Team mapToTeam(SearchResult adTeam, Team team) { + team.setAdName(ActiveDirectoryUtils.pickAttribute(adTeam, Attribute.DISTINGUISHED_NAME)); + team.setName(normalizeName(ActiveDirectoryUtils.pickAttribute(adTeam, Attribute.NAME))); + team.setLeader(findUser(ActiveDirectoryUtils.pickAttribute(adTeam, Attribute.MANAGED_BY))); return team; } diff --git a/src/main/java/info/fingo/urlopia/user/ActiveDirectoryUserMapper.java b/src/main/java/info/fingo/urlopia/user/ActiveDirectoryUserMapper.java index f22d85cf..67c250e4 100644 --- a/src/main/java/info/fingo/urlopia/user/ActiveDirectoryUserMapper.java +++ b/src/main/java/info/fingo/urlopia/user/ActiveDirectoryUserMapper.java @@ -20,29 +20,18 @@ public class ActiveDirectoryUserMapper { @Value("${ad.groups.admin}") private String adminGroup; - public User mapToUser(SearchResult searchResult, - User user) { - user.setPrincipalName( - ActiveDirectoryUtils.pickAttribute(searchResult, Attribute.PRINCIPAL_NAME)); - user.setAdName( - ActiveDirectoryUtils.pickAttribute(searchResult, Attribute.DISTINGUISHED_NAME)); - user.setMail( - ActiveDirectoryUtils.pickAttribute(searchResult, Attribute.MAIL)); - user.setFirstName( - ActiveDirectoryUtils.pickAttribute(searchResult, Attribute.FIRST_NAME)); - user.setLastName( - ActiveDirectoryUtils.pickAttribute(searchResult, Attribute.LAST_NAME)); - user.setLeader( - isLeader(searchResult)); - user.setB2b( - isB2B(searchResult)); - user.setEc( - isEC(searchResult)); - user.setActive( - !ActiveDirectoryUtils.isDisabled(searchResult)); - user.setAdmin( - isAdmin(searchResult)); - + public User mapToUser(SearchResult searchResult, User user) { + user.setAccountName(ActiveDirectoryUtils.pickAttribute(searchResult, Attribute.ACCOUNT_NAME)); + user.setPrincipalName(ActiveDirectoryUtils.pickAttribute(searchResult, Attribute.PRINCIPAL_NAME)); + user.setAdName(ActiveDirectoryUtils.pickAttribute(searchResult, Attribute.DISTINGUISHED_NAME)); + user.setMail(ActiveDirectoryUtils.pickAttribute(searchResult, Attribute.MAIL)); + user.setFirstName(ActiveDirectoryUtils.pickAttribute(searchResult, Attribute.FIRST_NAME)); + user.setLastName(ActiveDirectoryUtils.pickAttribute(searchResult, Attribute.LAST_NAME)); + user.setLeader(isLeader(searchResult)); + user.setB2b(isB2B(searchResult)); + user.setEc(isEC(searchResult)); + user.setActive(!ActiveDirectoryUtils.isDisabled(searchResult)); + user.setAdmin(isAdmin(searchResult)); return user; } diff --git a/src/main/java/info/fingo/urlopia/user/NoSuchUserException.java b/src/main/java/info/fingo/urlopia/user/NoSuchUserException.java index 320c8606..4799f68f 100644 --- a/src/main/java/info/fingo/urlopia/user/NoSuchUserException.java +++ b/src/main/java/info/fingo/urlopia/user/NoSuchUserException.java @@ -26,6 +26,10 @@ public static NoSuchUserException invalidEmail() { return new NoSuchUserException(ERROR_MESSAGE.formatted("email")); } + public static NoSuchUserException accountName() { + return new NoSuchUserException(ERROR_MESSAGE.formatted("account name")); + } + public static NoSuchUserException inactiveAccount(String mail) { return new NoSuchUserException(INACTIVE_ACCOUNT_MESSAGE.formatted(mail)); } diff --git a/src/main/java/info/fingo/urlopia/user/User.java b/src/main/java/info/fingo/urlopia/user/User.java index 3325a365..75012bae 100644 --- a/src/main/java/info/fingo/urlopia/user/User.java +++ b/src/main/java/info/fingo/urlopia/user/User.java @@ -16,6 +16,9 @@ public class User { @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "users_id_seq") private Long id; + @Column(nullable = false, unique = true) + private String accountName; + @Column(nullable = false, unique = true) private String principalName; @@ -109,6 +112,10 @@ public void setMail(String mail) { this.mail = mail; } + public void setAccountName(String accountName) { + this.accountName = accountName; + } + public void setPrincipalName(String principalName) { this.principalName = principalName; } @@ -149,6 +156,10 @@ public void setWorkTime(Float workTime) { this.workTime = workTime; } + public String getAccountName() { + return accountName; + } + public String getPrincipalName() { return principalName; } diff --git a/src/main/java/info/fingo/urlopia/user/UserRepository.java b/src/main/java/info/fingo/urlopia/user/UserRepository.java index f9a87ab3..3e080cfb 100644 --- a/src/main/java/info/fingo/urlopia/user/UserRepository.java +++ b/src/main/java/info/fingo/urlopia/user/UserRepository.java @@ -13,6 +13,8 @@ public interface UserRepository extends BaseRepository, JpaRepository findFirstByPrincipalName(String principalName); + Optional findFirstByAccountName(String accountName); + Optional findFirstByAdName(String adName); Optional findFirstByFirstNameAndLastName(String firstName, String lastName); diff --git a/src/main/java/info/fingo/urlopia/user/UserService.java b/src/main/java/info/fingo/urlopia/user/UserService.java index 2c243c27..5c8a0ad0 100644 --- a/src/main/java/info/fingo/urlopia/user/UserService.java +++ b/src/main/java/info/fingo/urlopia/user/UserService.java @@ -72,21 +72,12 @@ public User get(String userMail) { }); } - public User getByPrincipal(String principal) { + public User getFirstByAccountName(String accountName) { return userRepository - .findFirstByPrincipalName(principal) + .findFirstByAccountName(accountName) .orElseThrow(() -> { - log.error("There is no user with principal: {}", Anonymizer.anonymizeMail(principal)); - return NoSuchUserException.invalidEmail(); - }); - } - public User getByFirstNameAndLastName(String firstName, - String lastName) { - return userRepository - .findFirstByFirstNameAndLastName(firstName, lastName) - .orElseThrow(() -> { - log.error("There is no user with firstName: {} lastName: {}", firstName, lastName); - return NoSuchUserException.invalidEmail(); + log.error("There is no user with account name: {}", accountName); + return NoSuchUserException.accountName(); }); } @@ -161,14 +152,9 @@ public Set getLeaders(Long userId) { } public Long getCurrentUserId(){ - var principal = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - - // Temporary fix while domain migration is on - var split = principal.split(";"); - var firstName = split[0]; - var lastName = split.length > 1 ? split[1] : ""; + var accountName = (String) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); - var user = userRepository.findFirstByFirstNameAndLastName(firstName, lastName); + var user = userRepository.findFirstByAccountName(accountName); if (user.isPresent()){ return user.get().getId(); } diff --git a/src/main/resources/scripts/U3_3_0_1__add_user_account_name.sql b/src/main/resources/scripts/U3_3_0_1__add_user_account_name.sql new file mode 100644 index 00000000..d8a009e2 --- /dev/null +++ b/src/main/resources/scripts/U3_3_0_1__add_user_account_name.sql @@ -0,0 +1 @@ +ALTER TABLE users DROP COLUMN account_name; \ No newline at end of file diff --git a/src/main/resources/scripts/V3_3_0_1__add_user_account_name.sql b/src/main/resources/scripts/V3_3_0_1__add_user_account_name.sql new file mode 100644 index 00000000..8d5881fc --- /dev/null +++ b/src/main/resources/scripts/V3_3_0_1__add_user_account_name.sql @@ -0,0 +1 @@ +ALTER TABLE users ADD COLUMN account_name VARCHAR(63) NOT NULL UNIQUE; \ No newline at end of file diff --git a/view.react/.env b/view.react/.env index 29de7379..20cfaed9 100644 --- a/view.react/.env +++ b/view.react/.env @@ -1,3 +1,3 @@ -VITE_OAUTH_CLIENT_ID= -VITE_OAUTH_TENANT_ID= -VITE_AUTH_MODE=AUTH +VITE_OAUTH_CLIENT_ID= +VITE_OAUTH_TENANT_ID= +VITE_AUTH_MODE=AUTH diff --git a/view.react/.gitignore b/view.react/.gitignore index 53a04680..8af0f7e0 100644 --- a/view.react/.gitignore +++ b/view.react/.gitignore @@ -1,25 +1,26 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -.vscode +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +.vscode +