Skip to content

Commit

Permalink
WIP configure auth clients using a Map so configs can be merged from …
Browse files Browse the repository at this point in the history
…different property sources
  • Loading branch information
groldan committed May 14, 2023
1 parent b994fdc commit b4da8f1
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 129 deletions.
49 changes: 25 additions & 24 deletions docker-compose-acl-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,30 +12,31 @@ jndi:
connection-timeout: 3000
idle-timeout: 60000

acl:
db:
jndiName: java:comp/env/jdbc/acl
hbm2ddl.auto: update
schema: acl
security:
headers:
enabled: true
user-header: sec-username
roles-header: sec-roles
admin-roles: ["ROLE_ADMINISTRATOR"]
internal:
enabled: true
users:
- name: ${acl.admin.name:admin}
admin: true
enabled: ${acl.admin.enabled:true}
# password is the bcrypt encoded value for s3cr3t
password: ${acl.admin.password:"{bcrypt}$2a$10$eMyaZRLZBAZdor8nOX.qwuwOyWazXjR2hddGLCT6f6c382WiwdQGG"}
- name: user
admin: false
enabled: false
# password is the bcrypt encoded value for s3cr3t
password: "{bcrypt}$2a$10$eMyaZRLZBAZdor8nOX.qwuwOyWazXjR2hddGLCT6f6c382WiwdQGG"
acl.db.jndiName: java:comp/env/jdbc/acl
acl.db.schema: acl
acl.db.hbm2ddl.auto: update

geoserver:
acl:
security:
headers:
enabled: true
user-header: sec-username
roles-header: sec-roles
admin-roles: ["ROLE_ADMINISTRATOR"]
internal:
enabled: true
users:
- name: ${acl.admin.name:admin}
admin: true
enabled: ${acl.admin.enabled:true}
# password is the bcrypt encoded value for s3cr3t
password: ${acl.admin.password:"{bcrypt}$2a$10$eMyaZRLZBAZdor8nOX.qwuwOyWazXjR2hddGLCT6f6c382WiwdQGG"}
- name: user
admin: false
enabled: false
# password is the bcrypt encoded value for s3cr3t
password: "{bcrypt}$2a$10$eMyaZRLZBAZdor8nOX.qwuwOyWazXjR2hddGLCT6f6c382WiwdQGG"

logging:
level:
Expand Down
39 changes: 0 additions & 39 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,42 +35,3 @@ access rules. So if you're familiar with GeoFence, it'll be easy to reason
about GeoServer ACL.


## Dependency graph

```mermaid
flowchart LR
subgraph domain
adminrule-management --> object-model & rule-management
authorization --> adminrule-management & rule-management
rule-management --> object-model
end
subgraph openapi-codegen
openapi-server --> openapi-model
openapi-client --> openapi-model
end
subgraph integration
subgraph persistence-jpa
jpa-integration --> jpa-persistence
end
subgraph spring-integration
domain-spring-integration -. optional> .-> rule-management & adminrule-management & authorization
end
subgraph openapi-integration
api-model-mapper --> object-model & openapi-model
api-impl --> api-model-mapper & openapi-server & domain-spring-integration & rule-management & adminrule-management
api-client --> api-model-mapper & openapi-client
end
subgraph spring-boot-integration
spring-boot-autoconfiguration --> domain-spring-integration & api-impl & jpa-integration
end
end
subgraph geoserver-plugin
plugin-webui --> plugin-accessmanager
plugin-rest --> plugin-accessmanager & api-impl
plugin --> plugin-accessmanager & plugin-rest & plugin-webui
end
subgraph application
rest-app --> spring-boot-autoconfiguration
end
```

15 changes: 13 additions & 2 deletions src/artifacts/api/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ FROM eclipse-temurin:17-jre
LABEL maintainer="GeoServer PSC <[email protected]>"

WORKDIR /opt/app/bin
ENV JAVA_TOOL_OPTS="\
ENV DEF_JAVA_TOOL_OPTS="\
--add-exports=java.desktop/sun.awt.image=ALL-UNNAMED \
--add-opens=java.base/java.lang=ALL-UNNAMED \
--add-opens=java.base/java.util=ALL-UNNAMED \
Expand All @@ -22,6 +22,9 @@ ENV JAVA_TOOL_OPTS="\
--add-opens=java.naming/com.sun.jndi.ldap=ALL-UNNAMED \
-Djava.awt.headless=true"
ENV JAVA_OPTS="-XX:MaxRAMPercentage=80 -XshowSettings:system"

ENV JAVA_TOOL_OPTS="$DEF_JAVA_TOOL_OPTS $JAVA_OPTS"

EXPOSE 8080

COPY --from=builder dependencies/ ./
Expand All @@ -36,4 +39,12 @@ HEALTHCHECK \
--retries=5 \
CMD curl -f -s -o /dev/null localhost:8080/actuator/health || exit 1

CMD exec java $JAVA_OPTS $JAVA_TOOL_OPTS org.springframework.boot.loader.JarLauncher
#CMD exec java $JAVA_OPTS $JAVA_TOOL_OPTS org.springframework.boot.loader.JarLauncher

ARG APP_ARGS=""
#ENTRYPOINT exec java $JAVA_OPTS $JAVA_TOOL_OPTS org.springframework.boot.loader.JarLauncher
#ENTRYPOINT ["java", "$JAVA_TOOL_OPTS", "org.springframework.boot.loader.JarLauncher"]

ENTRYPOINT [ "/bin/bash", "-c", "exec java $JAVA_TOOL_OPTS org.springframework.boot.loader.JarLauncher \"${@}\"", "--" ]

CMD ["${APP_ARGS}"]
4 changes: 2 additions & 2 deletions src/artifacts/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ With the application running at [http://localhost:8080/api](http://localhost:808
mvn clean install
```

will create a single-jar executable at `target/gs-cloud-acl-service-<version>-bin.jar`.
will create a single-jar executable at `target/gs-acl-service-<version>-bin.jar`.

## Run

Expand All @@ -27,7 +27,7 @@ Run in development mode with an in-memory H2 database, either with

or

java -jar target/gs-cloud-acl-service-1.0-SNAPSHOT-bin.jar --spring.profiles.active=dev
java -jar target/gs-acl-service-1.0-SNAPSHOT-bin.jar --spring.profiles.active=dev


## Dependency graph
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,41 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.Arrays;
import java.util.List;

@SpringBootApplication
public class AccesControlListApplication {

private static final String ENCODEPASSWORD = "encodepassword";

public static void main(String... args) {
List<String> arglist = Arrays.asList(args);

if (arglist.contains(ENCODEPASSWORD)) {
System.exit(encodePassword(arglist));
}

try {
SpringApplication.run(AccesControlListApplication.class, args);
} catch (RuntimeException e) {
System.exit(-1);
}
}

private static int encodePassword(List<String> arglist) {
int pwdIndex = 1 + arglist.indexOf(ENCODEPASSWORD);
if (arglist.size() < pwdIndex) {
System.err.println("Usage: encodepassword <password>");
return -1;
}
String pwd = arglist.get(pwdIndex);
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
String encoded = encoder.encode(pwd);
System.out.println(encoded);
return 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ public SecurityFilterChain securityFilterChain(
log.info("Pre-authentication headers disabled");
} else {
log.info(
"Pre-authentication headers enabled for {}/{}",
"Pre-authentication headers enabled for {}/{}. Admin roles: {}",
config.getHeaders().getUserHeader(),
config.getHeaders().getRolesHeader());
config.getHeaders().getRolesHeader(),
config.getHeaders().getAdminRoles());
http.addFilterAfter(preAuthFilter, RequestHeaderAuthenticationFilter.class);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.Map;

@AutoConfiguration
@ConditionalOnInternalAuthenticationEnabled
Expand Down Expand Up @@ -53,37 +53,46 @@ AuthenticationProvider internalAuthenticationProvider(
@Bean("internalUserDetailsService")
public UserDetailsService internalUserDetailsService(SecurityConfigProperties config) {

List<SecurityConfigProperties.Internal.User> users = config.getInternal().getUsers();
Collection<UserDetails> authUsers =
users.stream()
.peek(this::validate)
.peek(
u ->
log.info(
"Loading internal user {}, admin: {}",
u.getName(),
u.isAdmin()))
.map(this::toUserDetails)
.collect(Collectors.toList());
Map<String, SecurityConfigProperties.Internal.UserInfo> users =
config.getInternal().getUsers();
Collection<UserDetails> authUsers = new ArrayList<>();
users.forEach(
(username, userinfo) -> {
validate(username, userinfo);
log.info(
"Loading internal user {}, admin: {}, enabled: {}",
username,
userinfo.isAdmin(),
userinfo.isEnabled());
UserDetails user = toUserDetails(username, userinfo);
authUsers.add(user);
});

long enabledUsers = authUsers.stream().filter(UserDetails::isEnabled).count();
if (0L == enabledUsers) {
log.warn(
"No API users are enabled for HTTP Basic Auth. Loaded user names: {}",
users.keySet());
}

return new InMemoryUserDetailsManager(authUsers);
}

private UserDetails toUserDetails(SecurityConfigProperties.Internal.User u) {
private UserDetails toUserDetails(
String username, SecurityConfigProperties.Internal.UserInfo u) {
return User.builder()
.username(u.getName())
.username(username)
.password(u.getPassword())
.authorities(u.authorities())
.disabled(!u.isEnabled())
.build();
}

private void validate(SecurityConfigProperties.Internal.User user) {
if (user.isEnabled()) {
if (!hasText(user.getName()))
throw new IllegalArgumentException("User has no name: " + user);
if (!hasText(user.getPassword()))
throw new IllegalArgumentException("User has no password: " + user);
private void validate(final String name, SecurityConfigProperties.Internal.UserInfo info) {
if (info.isEnabled()) {
if (!hasText(name)) throw new IllegalArgumentException("User has no name: " + info);
if (!hasText(info.getPassword()))
throw new IllegalArgumentException("User has no password " + name + ": " + info);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand All @@ -29,11 +30,10 @@ public boolean enabled() {

public static @Data class Internal {
private boolean enabled;
private List<User> users = List.of();
private Map<String, UserInfo> users = Map.of();

@ToString(exclude = "password")
public static @Data class User {
private String name;
public static @Data class UserInfo {
private String password;
private boolean admin;
private boolean enabled = true;
Expand Down
66 changes: 31 additions & 35 deletions src/artifacts/api/src/main/resources/acl-service.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,23 @@ geoserver.acl:
hbm2ddl.auto: ${acl.db.hbm2ddl.auto:validate}
security:
headers:
enabled: true
enabled: false
user-header: sec-username
roles-header: sec-roles
admin-roles: ["ROLE_ADMINISTRATOR"]
internal:
enabled: true
users:
- name: admin
admin: true
enabled: true
# password is the bcrypt encoded value for s3cr3t
password: "{bcrypt}$2a$10$eMyaZRLZBAZdor8nOX.qwuwOyWazXjR2hddGLCT6f6c382WiwdQGG"
- name: user
admin: false
enabled: true
# password is the bcrypt encoded value for s3cr3t
password: "{bcrypt}$2a$10$eMyaZRLZBAZdor8nOX.qwuwOyWazXjR2hddGLCT6f6c382WiwdQGG"
admin:
admin: true
enabled: true
# password is the bcrypt encoded value for s3cr3t
password: "{bcrypt}$2a$10$eMyaZRLZBAZdor8nOX.qwuwOyWazXjR2hddGLCT6f6c382WiwdQGG"
user:
admin: false
enabled: true
# password is the bcrypt encoded value for s3cr3t
password: "{bcrypt}$2a$10$eMyaZRLZBAZdor8nOX.qwuwOyWazXjR2hddGLCT6f6c382WiwdQGG"

---
spring.config.activate.on-profile: local
Expand All @@ -54,35 +54,31 @@ jndi:
connection-timeout: 3000
idle-timeout: 60000

acl:
db:
jndiName: java:comp/env/jdbc/acl
hbm2ddl.auto: update
schema: acl
acl.db.jndiName: java:comp/env/jdbc/acl
acl.db.schema: acl
acl.db.hbm2ddl.auto: create

---
spring.config.activate.on-profile: dev

geoserver.acl:
security:
internal:
enabled: true
users:
- name: admin
enabled: true
- name: user
geoserver:
acl:
security:
headers.enabled: true
internal:
enabled: true

datasource:
url: jdbc:h2:mem:geoserver-acl;DB_CLOSE_DELAY=-1
hikari:
minimum-idle: 1
maximum-pool-size: 20
jpa:
show-sql: true
properties:
hibernate:
hbm2ddl.auto: create
users:
admin.enabled: true
user.enabled: true
datasource:
url: jdbc:h2:mem:geoserver-acl;DB_CLOSE_DELAY=-1
hikari:
minimum-idle: 1
maximum-pool-size: 20
jpa:
show-sql: true
properties:
hibernate.hbm2ddl.auto: create

management:
endpoints:
Expand Down

0 comments on commit b4da8f1

Please sign in to comment.