Skip to content

Commit

Permalink
Merge users for access types
Browse files Browse the repository at this point in the history
  • Loading branch information
cjmalloy committed Apr 13, 2024
1 parent db29974 commit ee7efcc
Show file tree
Hide file tree
Showing 13 changed files with 113 additions and 90 deletions.
19 changes: 17 additions & 2 deletions src/main/java/jasper/component/ConfigCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

import static jasper.domain.proj.HasTags.pub;

@Component
public class ConfigCache {
Expand Down Expand Up @@ -103,12 +107,23 @@ public void clearTemplateCache() {

@Cacheable("user-cache")
@Transactional(readOnly = true)
public UserDto getUser(String tag) {
return userRepository.findOneByQualifiedTag(tag)
public UserDto getUser(String userTag) {
return userRepository.findOneByQualifiedTag(userTag)
.map(dtoMapper::domainToDto)
.orElse(null);
}

@Cacheable("user-cache")
@Transactional(readOnly = true)
public List<UserDto> getUsers(String userTag) {
return Stream.of(
userRepository.findOneByQualifiedTag("+" + pub(userTag)).orElse(null),
userRepository.findOneByQualifiedTag("_" + pub(userTag)).orElse(null))
.filter(Objects::nonNull)
.map(dtoMapper::domainToDto)
.toList();
}

@Cacheable(value = "config-cache", key = "#tag + #origin + '@' + #url")
@Transactional(readOnly = true)
public <T> T getConfig(String url, String origin, String tag, Class<T> toValueType) {
Expand Down
13 changes: 2 additions & 11 deletions src/main/java/jasper/component/ProfileManagerScim.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
import java.util.Arrays;
import java.util.List;

import static jasper.security.AuthoritiesConstants.PRIVATE;

@Profile("scim")
@Component
public class ProfileManagerScim implements ProfileManager {
Expand Down Expand Up @@ -91,16 +89,9 @@ private ProfileDto mapUser(ScimUserResource user) {
result.setActive(user.isActive());
var roles = Arrays.asList(getRoles(user));
for (var role : roles) {
if (!role.equals(PRIVATE)) {
result.setRole(role);
break;
}
}
if (roles.contains(PRIVATE)) {
result.setTag("_user/" + user.getUserName());
} else {
result.setTag("+user/" + user.getUserName());
result.setRole(role);
}
result.setTag("user/" + user.getUserName());
return result;
}

Expand Down
4 changes: 3 additions & 1 deletion src/main/java/jasper/component/channel/Mail.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import jasper.component.ConfigCache;
import jasper.component.delta.Async;
import jasper.domain.Ref;
import jasper.domain.proj.HasTags;
import jasper.domain.proj.RefUrl;
import jasper.repository.ExtRepository;
import jasper.repository.RefRepository;
Expand All @@ -25,6 +26,7 @@
import java.util.stream.Stream;

import static jasper.domain.Ref.removePrefixTags;
import static jasper.domain.proj.HasTags.author;
import static jasper.domain.proj.Tag.localTag;
import static jasper.domain.proj.Tag.tagOrigin;
import static java.util.Arrays.stream;
Expand Down Expand Up @@ -115,7 +117,7 @@ public void run(Ref ref) throws Exception {
}
}).map(URI::getHost).orElse(Stream.of(ref.getOrigin(), configs.root().getEmailHost()).filter(StringUtils::isNotBlank).collect(Collectors.joining(".")));
message.setFrom(ts.stream()
.filter(t -> t.startsWith("+user/") || t.startsWith("+user") || t.startsWith("_user/") || t.startsWith("_user"))
.filter(HasTags::author)
.findFirst()
.map(t -> t + "@" + host)
.orElse("no-reply@" + host)
Expand Down
19 changes: 18 additions & 1 deletion src/main/java/jasper/domain/proj/HasTags.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,30 @@ static String prefix(String prefix, String ...rest) {
}

static String pub(String tag) {
if (isBlank(tag)) return "";
if (tag.startsWith("_") || tag.startsWith("+")) {
return tag.substring(1);
}
return tag;
}

static boolean isPub(String tag) {
return !tag.startsWith("_") && tag.startsWith("+");
return !tag.startsWith("_") && !tag.startsWith("+");
}

static String priv(String tag) {
return "_" + pub(tag);
}

static boolean isPriv(String tag) {
return tag.startsWith("_");
}

static String pro(String tag) {
return "+" + pub(tag);
}

static boolean isPro(String tag) {
return tag.startsWith("+");
}
}
5 changes: 5 additions & 0 deletions src/main/java/jasper/repository/spec/QualifiedTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.List;
import java.util.stream.Collectors;

import static jasper.domain.proj.HasTags.pub;
import static jasper.repository.spec.OriginSpec.isOrigin;
import static jasper.repository.spec.RefSpec.hasTag;
import static jasper.repository.spec.TagSpec.isTag;
Expand Down Expand Up @@ -64,6 +65,10 @@ public boolean matches(QualifiedTag qt) {
return tag.equals(qt.tag) && origin.equals(qt.origin) && not == qt.not;
}

public boolean matchesIgnoringAccess(QualifiedTag qt) {
return pub(tag).equals(pub(qt.tag)) && origin.equals(qt.origin) && not == qt.not;
}

public boolean captures(String capture) {
return captures(selector(capture));
}
Expand Down
49 changes: 24 additions & 25 deletions src/main/java/jasper/security/Auth.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@

import static jasper.config.JacksonConfiguration.dump;
import static jasper.domain.proj.HasOrigin.isSubOrigin;
import static jasper.domain.proj.HasTags.pub;
import static jasper.repository.spec.OriginSpec.isOrigin;
import static jasper.repository.spec.QualifiedTag.qt;
import static jasper.repository.spec.QualifiedTag.qtList;
Expand Down Expand Up @@ -153,7 +154,7 @@ public class Auth {
protected String principal;
protected QualifiedTag userTag;
protected String origin;
protected Optional<UserDto> user;
protected List<UserDto> user;
protected List<QualifiedTag> readAccess;
protected List<QualifiedTag> writeAccess;
protected List<QualifiedTag> tagReadAccess;
Expand Down Expand Up @@ -187,7 +188,7 @@ public void clear(Authentication authentication) {
@PostConstruct
public void log() {
logger.debug("AUTH{} User: {} {} (hasUser: {})",
getOrigin(), getPrincipal(), getAuthoritySet(), getUser().isPresent());
getOrigin(), getPrincipal(), getAuthoritySet(), getUsers().size());
if (logger.isTraceEnabled()) {
logger.trace("Auth Config: {} {}", dump(configs.root()), dump(configs.security(getOrigin())));
}
Expand Down Expand Up @@ -512,7 +513,7 @@ public boolean canWriteTag(String qualifiedTag) {
* Does the user's tag match this tag?
*/
public boolean isUser(QualifiedTag qt) {
return isLoggedIn() && getUserTag().matches(qt);
return isLoggedIn() && getUserTag().matchesIgnoringAccess(qt);
}

public boolean isUser(String qualifiedTag) {
Expand Down Expand Up @@ -736,14 +737,14 @@ public String getPrincipal() {
var authn = getAuthentication();
if (authn == null) return null;
if (authn instanceof JwtAuthentication j) {
principal = j.getPrincipal();
principal = pub(j.getPrincipal());
} else {
if (authn instanceof AnonymousAuthenticationToken) return null;
if (authn.getPrincipal() == null) return null;
if (authn.getPrincipal() instanceof String username) {
principal = username;
principal = pub(username);
} else if (authn.getPrincipal() instanceof UserDetails d) {
principal = d.getUsername();
principal = pub(d.getUsername());
} else {
return null;
}
Expand All @@ -760,14 +761,12 @@ public QualifiedTag getUserTag() {
return userTag;
}

protected Optional<UserDto> getUser() {
protected List<UserDto> getUsers() {
if (user == null) {
var auth = ofNullable(getAuthentication());
user = auth.map(a -> a.getDetails() instanceof UserDto
? (UserDto) a.getDetails()
: null);
if (isLoggedIn() && user.isEmpty()) {
user = ofNullable(configs.getUser(getUserTag().toString()));
if (isLoggedIn()) {
user = configs.getUsers(getUserTag().toString());
} else {
user = List.of();
}
}
return user;
Expand Down Expand Up @@ -813,9 +812,9 @@ public List<QualifiedTag> getReadAccess() {
}
readAccess.addAll(getClaimQualifiedTags(security().getReadAccessClaim()));
if (isLoggedIn()) {
readAccess.addAll(selectors(getSubOrigins(), getUser()
.map(UserDto::getReadAccess)
.orElse(List.of())));
readAccess.addAll(selectors(getSubOrigins(), getUsers().stream()
.flatMap(u -> ofNullable(u.getReadAccess()).orElse(List.of()).stream())
.toList()));
}
}
return readAccess;
Expand All @@ -835,9 +834,9 @@ public List<QualifiedTag> getWriteAccess() {
}
writeAccess.addAll(getClaimQualifiedTags(security().getWriteAccessClaim()));
if (isLoggedIn()) {
writeAccess.addAll(selectors(getSubOrigins(), getUser()
.map(UserDto::getWriteAccess)
.orElse(List.of())));
writeAccess.addAll(selectors(getSubOrigins(), getUsers().stream()
.flatMap(u -> ofNullable(u.getWriteAccess()).orElse(List.of()).stream())
.toList()));
}
}
return writeAccess;
Expand All @@ -857,9 +856,9 @@ public List<QualifiedTag> getTagReadAccess() {
}
tagReadAccess.addAll(getClaimQualifiedTags(security().getTagReadAccessClaim()));
if (isLoggedIn()) {
tagReadAccess.addAll(selectors(getSubOrigins(), getUser()
.map(UserDto::getTagReadAccess)
.orElse(List.of())));
tagReadAccess.addAll(selectors(getSubOrigins(), getUsers().stream()
.flatMap(u -> ofNullable(u.getTagReadAccess()).orElse(List.of()).stream())
.toList()));
}
}
return tagReadAccess;
Expand All @@ -879,9 +878,9 @@ public List<QualifiedTag> getTagWriteAccess() {
}
tagWriteAccess.addAll(getClaimQualifiedTags(security().getTagWriteAccessClaim()));
if (isLoggedIn()) {
tagWriteAccess.addAll(selectors(getSubOrigins(), getUser()
.map(UserDto::getTagWriteAccess)
.orElse(List.of())));
tagWriteAccess.addAll(selectors(getSubOrigins(), getUsers().stream()
.flatMap(u -> ofNullable(u.getTagWriteAccess()).orElse(List.of()).stream())
.toList()));
}
}
return tagWriteAccess;
Expand Down
1 change: 0 additions & 1 deletion src/main/java/jasper/security/AuthoritiesConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ public final class AuthoritiesConstants {
public static final String VIEWER = "ROLE_VIEWER";
public static final String ANONYMOUS = "ROLE_ANONYMOUS";
public static final String BANNED = "ROLE_BANNED";
public static final String PRIVATE = "ROLE_PRIVATE";

private AuthoritiesConstants() {}
}
19 changes: 11 additions & 8 deletions src/main/java/jasper/security/jwt/AbstractTokenProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,22 @@ public abstract class AbstractTokenProvider implements TokenProvider {
this.configs = configs;
}

UserDto getUser(String userTag) {
List<UserDto> getUsers(String userTag) {
if (configs == null) return null;
return configs.getUser(userTag);
return configs.getUsers(userTag);
}

Collection<? extends GrantedAuthority> getAuthorities(UserDto user, String origin) {
Collection<? extends GrantedAuthority> getAuthorities(List<UserDto> user, String origin) {
var auth = getPartialAuthorities(origin);
if (user != null && user.getRole() != null) {
logger.debug("User Roles: {}", user.getRole());
if (User.ROLES.contains(user.getRole().trim())) {
auth.add(new SimpleGrantedAuthority(user.getRole().trim()));
for (var u : user) {
if (isNotBlank(u.getRole())) {
logger.debug("User Roles: {}", u.getRole());
if (User.ROLES.contains(u.getRole().trim())) {
auth.add(new SimpleGrantedAuthority(u.getRole().trim()));
}
}
} else {
}
if (user.isEmpty()) {
logger.debug("No User");
}
return auth;
Expand Down
8 changes: 5 additions & 3 deletions src/main/java/jasper/security/jwt/JwtAuthentication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@

import io.jsonwebtoken.Claims;
import jasper.service.dto.UserDto;
import org.apache.commons.lang3.NotImplementedException;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.util.Assert;

import java.util.Collection;
import java.util.List;

public class JwtAuthentication extends AbstractAuthenticationToken {

private final UserDto user;
private final List<UserDto> user;
private final Claims claims;
private final String principal;

Expand All @@ -22,7 +24,7 @@ public JwtAuthentication(String principal) {
setAuthenticated(false);
}

public JwtAuthentication(String principal, UserDto user, Claims claims, Collection<? extends GrantedAuthority> authorities) {
public JwtAuthentication(String principal, List<UserDto> user, Claims claims, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.user = user;
Expand All @@ -48,7 +50,7 @@ public Object getCredentials() {
}

@Override
public UserDto getDetails() {
public List<UserDto> getDetails() {
return user;
}

Expand Down
Loading

0 comments on commit ee7efcc

Please sign in to comment.