Skip to content

Commit aadb3dd

Browse files
authored
Permission setup (#7)
* Added RBAC preliminary support. * Upgraded VueJS and other server side packages. * Bumped the version.
1 parent 0b9cddc commit aadb3dd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1135
-985
lines changed

backend/main/java/com/ideasbucket/tansen/configuration/SecurityConfiguration.java renamed to backend/main/java/com/ideasbucket/tansen/configuration/CorsConfiguration.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,16 @@
88

99
import org.springframework.beans.factory.annotation.Autowired;
1010
import org.springframework.context.annotation.Configuration;
11-
import org.springframework.web.cors.CorsConfiguration;
1211
import org.springframework.web.reactive.config.CorsRegistry;
1312
import org.springframework.web.reactive.config.WebFluxConfigurer;
1413

1514
@Configuration
16-
public class SecurityConfiguration implements WebFluxConfigurer {
15+
public class CorsConfiguration implements WebFluxConfigurer {
1716

1817
private final ApplicationProperties applicationProperties;
1918

2019
@Autowired
21-
public SecurityConfiguration(ApplicationProperties applicationProperties) {
20+
public CorsConfiguration(ApplicationProperties applicationProperties) {
2221
this.applicationProperties = applicationProperties;
2322
}
2423

@@ -31,7 +30,7 @@ public void addCorsMappings(CorsRegistry registry) {
3130
.addMapping("/**")
3231
.allowedOriginPatterns(allowedSources.split(","))
3332
.allowCredentials(true)
34-
.allowedMethods(CorsConfiguration.ALL);
33+
.allowedMethods(org.springframework.web.cors.CorsConfiguration.ALL);
3534
}
3635
}
3736
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* This file is part of the Tansen project.
3+
*
4+
* For the full copyright and license information, please view the LICENSE
5+
* file that was distributed with this source code.
6+
*/
7+
package com.ideasbucket.tansen.configuration;
8+
9+
import jakarta.validation.constraints.NotBlank;
10+
import jakarta.validation.constraints.NotEmpty;
11+
import jakarta.validation.constraints.NotNull;
12+
import java.util.List;
13+
14+
public class Permission {
15+
16+
@NotNull(message = "Resource cannot be null.")
17+
@NotEmpty(message = "Resource cannot be blank.")
18+
private final String resource;
19+
20+
@NotNull(message = "Action cannot be null.")
21+
@NotEmpty(message = "Action cannot be empty.")
22+
private final List<@NotNull(message = "Action cannot be null.") @NotBlank(
23+
message = "Action cannot be blank."
24+
) String> actions;
25+
26+
@NotNull(message = "Value cannot be null.")
27+
@NotEmpty(message = "Value cannot be blank.")
28+
private final String value;
29+
30+
public Permission(String resource, List<String> actions, String value) {
31+
this.resource = resource;
32+
this.actions = actions;
33+
this.value = value;
34+
}
35+
36+
public String getResource() {
37+
return resource;
38+
}
39+
40+
public List<String> getActions() {
41+
return actions;
42+
}
43+
44+
public String getValue() {
45+
return value;
46+
}
47+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* This file is part of the Tansen project.
3+
*
4+
* For the full copyright and license information, please view the LICENSE
5+
* file that was distributed with this source code.
6+
*/
7+
package com.ideasbucket.tansen.configuration;
8+
9+
import com.fasterxml.jackson.annotation.JsonCreator;
10+
import com.fasterxml.jackson.annotation.JsonProperty;
11+
import jakarta.validation.Valid;
12+
import jakarta.validation.constraints.NotEmpty;
13+
import java.util.List;
14+
import org.springframework.boot.context.properties.ConfigurationProperties;
15+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
16+
import org.springframework.context.annotation.PropertySource;
17+
import org.springframework.validation.annotation.Validated;
18+
19+
@PropertySource(value = "classpath:roles.yml", factory = YamlPropertySourceFactory.class)
20+
@ConfigurationProperties(prefix = "rbac")
21+
@EnableConfigurationProperties(RbacProperties.class)
22+
@Validated
23+
public class RbacProperties {
24+
25+
@JsonProperty("roles")
26+
@NotEmpty
27+
private final List<@Valid Role> roles;
28+
29+
@JsonCreator
30+
public RbacProperties(@JsonProperty("roles") List<Role> roles) {
31+
this.roles = roles;
32+
}
33+
34+
public List<Role> getRoles() {
35+
return roles;
36+
}
37+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* This file is part of the Tansen project.
3+
*
4+
* For the full copyright and license information, please view the LICENSE
5+
* file that was distributed with this source code.
6+
*/
7+
package com.ideasbucket.tansen.configuration;
8+
9+
import com.fasterxml.jackson.annotation.JsonCreator;
10+
import com.fasterxml.jackson.annotation.JsonInclude;
11+
import com.fasterxml.jackson.annotation.JsonProperty;
12+
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
13+
import jakarta.validation.Valid;
14+
import jakarta.validation.constraints.NotBlank;
15+
import jakarta.validation.constraints.NotEmpty;
16+
import jakarta.validation.constraints.NotNull;
17+
import java.util.List;
18+
19+
@JsonInclude(JsonInclude.Include.NON_NULL)
20+
@JsonPropertyOrder({ "name", "clusters", "subjects", "permissions" })
21+
public class Role {
22+
23+
@JsonProperty("name")
24+
@NotNull(message = "Role name cannot be null.")
25+
@NotBlank(message = "Role name cannot be blank.")
26+
private final String name;
27+
28+
@JsonProperty("clusters")
29+
@NotNull(message = "Must have at least one cluster.")
30+
@NotEmpty(message = "Must have at least one cluster.")
31+
private final List<@NotNull(message = "Cluster name cannot be null.") @NotBlank(
32+
message = "Cluster name cannot be blank."
33+
) String> clusters;
34+
35+
@JsonProperty("subjects")
36+
@NotEmpty(message = "Must have at least one subject.")
37+
private final List<@Valid Subject> subjects;
38+
39+
@JsonProperty("permissions")
40+
private final List<@Valid Permission> permissions;
41+
42+
@JsonCreator
43+
public Role(
44+
@JsonProperty("name") String name,
45+
@JsonProperty("clusters") List<String> clusters,
46+
@JsonProperty("subjects") List<Subject> subjects,
47+
@JsonProperty("permissions") List<Permission> permissions
48+
) {
49+
this.name = name;
50+
this.clusters = clusters;
51+
this.subjects = subjects;
52+
this.permissions = permissions;
53+
}
54+
55+
public String getName() {
56+
return name;
57+
}
58+
59+
public List<String> getClusters() {
60+
return clusters;
61+
}
62+
63+
public List<Subject> getSubjects() {
64+
return subjects;
65+
}
66+
67+
public List<Permission> getPermissions() {
68+
return permissions;
69+
}
70+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* This file is part of the Tansen project.
3+
*
4+
* For the full copyright and license information, please view the LICENSE
5+
* file that was distributed with this source code.
6+
*/
7+
package com.ideasbucket.tansen.configuration;
8+
9+
import com.fasterxml.jackson.annotation.JsonInclude;
10+
import com.fasterxml.jackson.annotation.JsonProperty;
11+
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
12+
import com.ideasbucket.tansen.validator.FromList;
13+
import jakarta.validation.constraints.NotBlank;
14+
import jakarta.validation.constraints.NotNull;
15+
16+
@JsonInclude(JsonInclude.Include.NON_NULL)
17+
@JsonPropertyOrder({ "provider", "type", "value" })
18+
public class Subject {
19+
20+
@JsonProperty("provider")
21+
@NotNull(message = "Provider cannot be null.")
22+
@NotBlank(message = "Provider cannot be blank.")
23+
@FromList(acceptedValues = { "okta" }, message = "Currently only Okta provider is supported.")
24+
private final String provider;
25+
26+
@JsonProperty("type")
27+
@NotNull(message = "Type cannot be null.")
28+
@NotBlank(message = "Type cannot be blank.")
29+
@FromList(
30+
acceptedValues = { "domain", "user", "organization", "group" },
31+
message = "Type must be either domain, user, organization, group."
32+
)
33+
private final String type;
34+
35+
@JsonProperty("value")
36+
@NotNull(message = "Value cannot be null.")
37+
@NotBlank(message = "Value cannot be blank.")
38+
private final String value;
39+
40+
public Subject(
41+
@JsonProperty("provider") String provider,
42+
@JsonProperty("type") String type,
43+
@JsonProperty("value") String value
44+
) {
45+
this.provider = provider.toLowerCase();
46+
this.type = type.toLowerCase();
47+
this.value = value;
48+
}
49+
50+
public String getProvider() {
51+
return provider;
52+
}
53+
54+
public String getType() {
55+
return type;
56+
}
57+
58+
public String getValue() {
59+
return value;
60+
}
61+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* This file is part of the Tansen project.
3+
*
4+
* For the full copyright and license information, please view the LICENSE
5+
* file that was distributed with this source code.
6+
*/
7+
package com.ideasbucket.tansen.configuration;
8+
9+
import java.io.FileNotFoundException;
10+
import java.io.IOException;
11+
import java.util.Objects;
12+
import java.util.Properties;
13+
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
14+
import org.springframework.core.env.PropertiesPropertySource;
15+
import org.springframework.core.env.PropertySource;
16+
import org.springframework.core.io.support.EncodedResource;
17+
import org.springframework.core.io.support.PropertySourceFactory;
18+
19+
public class YamlPropertySourceFactory implements PropertySourceFactory {
20+
21+
@Override
22+
public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) throws IOException {
23+
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
24+
factory.setResources(encodedResource.getResource());
25+
26+
try {
27+
Properties properties = factory.getObject();
28+
29+
assert properties != null;
30+
return new PropertiesPropertySource(
31+
Objects.requireNonNull(encodedResource.getResource().getFilename()),
32+
properties
33+
);
34+
} catch (Exception exception) {
35+
if (exception.getCause() instanceof FileNotFoundException) {
36+
if (exception.getCause().getMessage().contains("roles.yml")) {
37+
return new PropertiesPropertySource("roles.yml", new Properties());
38+
}
39+
}
40+
41+
throw exception;
42+
}
43+
}
44+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* This file is part of the Tansen project.
3+
*
4+
* For the full copyright and license information, please view the LICENSE
5+
* file that was distributed with this source code.
6+
*/
7+
package com.ideasbucket.tansen.validator;
8+
9+
import static java.lang.annotation.ElementType.FIELD;
10+
import static java.lang.annotation.ElementType.METHOD;
11+
12+
import jakarta.validation.Constraint;
13+
import jakarta.validation.Payload;
14+
import java.lang.annotation.Documented;
15+
import java.lang.annotation.Retention;
16+
import java.lang.annotation.RetentionPolicy;
17+
import java.lang.annotation.Target;
18+
19+
@Documented
20+
@Target({ METHOD, FIELD })
21+
@Retention(RetentionPolicy.RUNTIME)
22+
@Constraint(validatedBy = { FromListValidator.class })
23+
public @interface FromList {
24+
String[] acceptedValues();
25+
26+
String message() default "Invalid value.";
27+
28+
boolean caseSensitive() default false;
29+
30+
Class<?>[] groups() default {};
31+
32+
Class<? extends Payload>[] payload() default {};
33+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* This file is part of the Tansen project.
3+
*
4+
* For the full copyright and license information, please view the LICENSE
5+
* file that was distributed with this source code.
6+
*/
7+
package com.ideasbucket.tansen.validator;
8+
9+
import jakarta.validation.ConstraintValidator;
10+
import jakarta.validation.ConstraintValidatorContext;
11+
import java.util.HashSet;
12+
import java.util.Set;
13+
14+
public class FromListValidator implements ConstraintValidator<FromList, String> {
15+
16+
private final Set<String> valueList = new HashSet<>();
17+
18+
private Boolean isCaseSensitiveComparison;
19+
20+
public void initialize(FromList constraintAnnotation) {
21+
isCaseSensitiveComparison = constraintAnnotation.caseSensitive();
22+
23+
for (String val : constraintAnnotation.acceptedValues()) {
24+
if (isCaseSensitiveComparison) {
25+
valueList.add(val);
26+
} else {
27+
valueList.add(val.toLowerCase());
28+
}
29+
}
30+
}
31+
32+
@Override
33+
public boolean isValid(String value, ConstraintValidatorContext context) {
34+
return (isCaseSensitiveComparison) ? valueList.contains(value) : valueList.contains(value.toLowerCase());
35+
}
36+
}

backend/main/resources/application-prod.properties

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
logging:
2+
pattern:
3+
console: '%d{yyyy-MM-dd HH:mm:ss} - %msg%n'
4+
level:
5+
org:
6+
springframework:
7+
web: INFO
8+
kafka: INFO
9+
root: INFO

backend/main/resources/application-test.properties

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)