KB66 Add editor role.
Change-Id: Ibcf94b6532ccb1602bf169ffb434b75557767598
diff --git a/pom.xml b/pom.xml
index f096d58..8e8c707 100644
--- a/pom.xml
+++ b/pom.xml
@@ -125,6 +125,10 @@
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
+ <artifactId>quarkus-cache</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>io.quarkus</groupId>
<artifactId>quarkus-elytron-security-properties-file</artifactId>
</dependency>
<dependency>
diff --git a/src/main/java/eu/mulk/mulkcms2/benki/accesscontrol/Role.java b/src/main/java/eu/mulk/mulkcms2/benki/accesscontrol/Role.java
index 87b477d..1d66939 100644
--- a/src/main/java/eu/mulk/mulkcms2/benki/accesscontrol/Role.java
+++ b/src/main/java/eu/mulk/mulkcms2/benki/accesscontrol/Role.java
@@ -22,6 +22,8 @@
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
+import org.hibernate.annotations.LazyToOne;
+import org.hibernate.annotations.LazyToOneOption;
@Entity
@Table(name = "roles", schema = "benki")
@@ -68,6 +70,7 @@
public Collection<UserRole> directUsers;
@OneToOne(mappedBy = "ownedRole", fetch = FetchType.LAZY)
+ @LazyToOne(LazyToOneOption.NO_PROXY)
public User owningUsers;
@ManyToMany(mappedBy = "effectiveRoles", fetch = FetchType.LAZY)
diff --git a/src/main/java/eu/mulk/mulkcms2/benki/login/LoginRoles.java b/src/main/java/eu/mulk/mulkcms2/benki/login/LoginRoles.java
new file mode 100644
index 0000000..27c6f5c
--- /dev/null
+++ b/src/main/java/eu/mulk/mulkcms2/benki/login/LoginRoles.java
@@ -0,0 +1,8 @@
+package eu.mulk.mulkcms2.benki.login;
+
+public final class LoginRoles {
+
+ public static final String EDITOR = "EDITOR";
+
+ private LoginRoles() {}
+}
diff --git a/src/main/java/eu/mulk/mulkcms2/benki/login/LoginStatus.java b/src/main/java/eu/mulk/mulkcms2/benki/login/LoginStatus.java
index 06a184c..a217dba 100644
--- a/src/main/java/eu/mulk/mulkcms2/benki/login/LoginStatus.java
+++ b/src/main/java/eu/mulk/mulkcms2/benki/login/LoginStatus.java
@@ -17,6 +17,10 @@
return !identity.isAnonymous();
}
+ public boolean isEditor() {
+ return identity.hasRole(LoginRoles.EDITOR);
+ }
+
public String getUserName() {
return identity.getPrincipal().getName();
}
diff --git a/src/main/java/eu/mulk/mulkcms2/benki/login/RoleAugmentor.java b/src/main/java/eu/mulk/mulkcms2/benki/login/RoleAugmentor.java
new file mode 100644
index 0000000..3aafc0e
--- /dev/null
+++ b/src/main/java/eu/mulk/mulkcms2/benki/login/RoleAugmentor.java
@@ -0,0 +1,59 @@
+package eu.mulk.mulkcms2.benki.login;
+
+import eu.mulk.mulkcms2.benki.accesscontrol.Role;
+import eu.mulk.mulkcms2.benki.users.User;
+import io.quarkus.cache.CacheResult;
+import io.quarkus.security.identity.AuthenticationRequestContext;
+import io.quarkus.security.identity.SecurityIdentity;
+import io.quarkus.security.identity.SecurityIdentityAugmentor;
+import io.quarkus.security.runtime.QuarkusSecurityIdentity;
+import io.smallrye.mutiny.Uni;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.enterprise.context.ApplicationScoped;
+import javax.transaction.Transactional;
+
+@ApplicationScoped
+public class RoleAugmentor implements SecurityIdentityAugmentor {
+
+ private static final String EDITOR_TAG = "editor";
+
+ @Override
+ public Uni<SecurityIdentity> augment(
+ SecurityIdentity identity, AuthenticationRequestContext context) {
+
+ if (identity.isAnonymous()) {
+ return Uni.createFrom().item(identity);
+ }
+
+ return augmentWithRoles(identity, context);
+ }
+
+ @Transactional
+ Uni<SecurityIdentity> augmentWithRoles(
+ SecurityIdentity identity, AuthenticationRequestContext context) {
+ return context.runBlocking(
+ () -> {
+ Set<String> loginRoles = getUserLoginRoles(identity.getPrincipal().getName());
+ return QuarkusSecurityIdentity.builder(identity).addRoles(loginRoles).build();
+ });
+ }
+
+ @CacheResult(cacheName = "login-role-cache")
+ Set<String> getUserLoginRoles(String userNickname) {
+ var user = User.findByNicknameWithRoles(userNickname);
+ return user.effectiveRoles.stream()
+ .flatMap(RoleAugmentor::roleTags)
+ .flatMap(RoleAugmentor::loginRoleOfTag)
+ .collect(Collectors.toSet());
+ }
+
+ private static Stream<String> roleTags(Role role) {
+ return role.tags.stream();
+ }
+
+ private static Stream<String> loginRoleOfTag(String tag) {
+ return tag.equals(EDITOR_TAG) ? Stream.of(LoginRoles.EDITOR) : Stream.empty();
+ }
+}
diff --git a/src/main/java/eu/mulk/mulkcms2/benki/posts/PostResource.java b/src/main/java/eu/mulk/mulkcms2/benki/posts/PostResource.java
index c0d8647..495c780 100644
--- a/src/main/java/eu/mulk/mulkcms2/benki/posts/PostResource.java
+++ b/src/main/java/eu/mulk/mulkcms2/benki/posts/PostResource.java
@@ -14,6 +14,8 @@
import com.rometools.rome.io.WireFeedOutput;
import eu.mulk.mulkcms2.benki.accesscontrol.PageKey;
import eu.mulk.mulkcms2.benki.accesscontrol.Role;
+import eu.mulk.mulkcms2.benki.login.LoginRoles;
+import eu.mulk.mulkcms2.benki.login.LoginStatus;
import eu.mulk.mulkcms2.benki.posts.Post.PostPage;
import eu.mulk.mulkcms2.benki.users.User;
import io.quarkus.qute.Template;
@@ -419,7 +421,7 @@
switch (postFilter) {
case ALL:
case BOOKMARKS_ONLY:
- return !identity.isAnonymous();
+ return identity.hasRole(LoginRoles.EDITOR);
case LAZYCHAT_MESSAGES_ONLY:
return false;
default:
@@ -431,7 +433,7 @@
switch (postFilter) {
case ALL:
case LAZYCHAT_MESSAGES_ONLY:
- return !identity.isAnonymous();
+ return identity.hasRole(LoginRoles.EDITOR);
case BOOKMARKS_ONLY:
return false;
default:
diff --git a/src/main/java/eu/mulk/mulkcms2/benki/users/User.java b/src/main/java/eu/mulk/mulkcms2/benki/users/User.java
index 96feafc..04a5cd4 100644
--- a/src/main/java/eu/mulk/mulkcms2/benki/users/User.java
+++ b/src/main/java/eu/mulk/mulkcms2/benki/users/User.java
@@ -150,6 +150,18 @@
return User.find("from BenkiUser u join u.nicknames n where ?1 = n", nickname).singleResult();
}
+ public static User findByNicknameWithRoles(String nickname) {
+ return User.find(
+ ""
+ + "from BenkiUser u "
+ + "join u.nicknames n "
+ + "left join fetch u.effectiveRoles r "
+ + "left join fetch r.tags "
+ + "where ?1 = n",
+ nickname)
+ .singleResult();
+ }
+
public final boolean canSee(Post message) {
return message.isVisibleTo(this);
}
diff --git a/src/main/resources/db/changeLog-1.8.xml b/src/main/resources/db/changeLog-1.8.xml
index 2359001..05948b0 100644
--- a/src/main/resources/db/changeLog-1.8.xml
+++ b/src/main/resources/db/changeLog-1.8.xml
@@ -55,4 +55,11 @@
</createIndex>
</changeSet>
+ <changeSet id="1.8-4" author="mulk">
+ <sql>
+ ALTER TABLE benki.role_tags DROP CONSTRAINT role_tags_tag_check;
+ ALTER TABLE benki.role_tags ADD CONSTRAINT role_tags_tag_check CHECK (tag = ANY(ARRAY['admin', 'everyone', 'world', 'editor']));
+ </sql>
+ </changeSet>
+
</databaseChangeLog>
diff --git a/src/main/resources/templates/tags/navbar.html b/src/main/resources/templates/tags/navbar.html
index 17a25dd..750d3e1 100644
--- a/src/main/resources/templates/tags/navbar.html
+++ b/src/main/resources/templates/tags/navbar.html
@@ -10,7 +10,7 @@
</ol>
</li>
- {#if inject:LoginStatus.loggedIn}
+ {#if inject:LoginStatus.isEditor}
<li class='{#if siteSection == "Wiki"}this-page{/}' data-site-section="Wiki"><a href="/wiki/Home">Wiki</a></li>
{/if}