grants = grantedAuthorityMapper.getAuthorities(xroadRoles);
return new UsernamePasswordAuthenticationToken(user.getUserName(), authentication.getCredentials(), grants);
} catch (PAMException e) {
diff --git a/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/auth/PamAuthenticationProviderConfig.java b/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/auth/PamAuthenticationProviderConfig.java
index afc043601e..c5a7ebaa8f 100644
--- a/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/auth/PamAuthenticationProviderConfig.java
+++ b/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/auth/PamAuthenticationProviderConfig.java
@@ -24,10 +24,11 @@
*/
package org.niis.xroad.restapi.auth;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.niis.xroad.restapi.config.UserRoleConfig;
import org.niis.xroad.restapi.config.audit.AuditEventLoggingFacade;
import org.niis.xroad.restapi.config.audit.RestApiAuditEvent;
-import org.niis.xroad.restapi.util.SecurityHelper;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -45,6 +46,7 @@
@Slf4j
@Configuration
@Profile("!devtools-test-auth")
+@RequiredArgsConstructor
public class PamAuthenticationProviderConfig {
public static final String KEY_MANAGEMENT_PAM_AUTHENTICATION = "keyManagementPam";
@@ -56,17 +58,7 @@ public class PamAuthenticationProviderConfig {
private final GrantedAuthorityMapper grantedAuthorityMapper;
private final AuditEventLoggingFacade auditEventLoggingFacade;
- private final SecurityHelper securityHelper;
-
- /**
- * constructor
- */
- public PamAuthenticationProviderConfig(GrantedAuthorityMapper grantedAuthorityMapper,
- AuditEventLoggingFacade auditEventLoggingFacade, SecurityHelper securityHelper) {
- this.grantedAuthorityMapper = grantedAuthorityMapper;
- this.auditEventLoggingFacade = auditEventLoggingFacade;
- this.securityHelper = securityHelper;
- }
+ private final UserRoleConfig userRoleConfig;
/**
* PAM authentication for form login, with corresponding IP whitelist
@@ -76,8 +68,9 @@ public PamAuthenticationProviderConfig(GrantedAuthorityMapper grantedAuthorityMa
public PamAuthenticationProvider formLoginPamAuthentication() {
AuthenticationIpWhitelist formLoginWhitelist = new AuthenticationIpWhitelist();
formLoginWhitelist.setWhitelistEntries(FORM_LOGIN_IP_WHITELIST);
- return new PamAuthenticationProvider(formLoginWhitelist, grantedAuthorityMapper, RestApiAuditEvent.FORM_LOGIN,
- auditEventLoggingFacade, securityHelper);
+ return new PamAuthenticationProvider(
+ formLoginWhitelist, grantedAuthorityMapper, userRoleConfig.getUserRoleMappings(), RestApiAuditEvent.FORM_LOGIN,
+ auditEventLoggingFacade);
}
/**
@@ -87,8 +80,8 @@ public PamAuthenticationProvider formLoginPamAuthentication() {
@Bean(KEY_MANAGEMENT_PAM_AUTHENTICATION)
public PamAuthenticationProvider keyManagementWhitelist(
@Qualifier(KEY_MANAGEMENT_API_WHITELIST) AuthenticationIpWhitelist keyManagementWhitelist) {
- return new PamAuthenticationProvider(keyManagementWhitelist, grantedAuthorityMapper,
- RestApiAuditEvent.KEY_MANAGEMENT_PAM_LOGIN, auditEventLoggingFacade, securityHelper);
+ return new PamAuthenticationProvider(keyManagementWhitelist, grantedAuthorityMapper, userRoleConfig.getUserRoleMappings(),
+ RestApiAuditEvent.KEY_MANAGEMENT_PAM_LOGIN, auditEventLoggingFacade);
}
}
diff --git a/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/config/UserRoleConfig.java b/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/config/UserRoleConfig.java
new file mode 100644
index 0000000000..873d1709df
--- /dev/null
+++ b/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/config/UserRoleConfig.java
@@ -0,0 +1,40 @@
+/**
+ * The MIT License
+ * Copyright (c) 2019- Nordic Institute for Interoperability Solutions (NIIS)
+ * Copyright (c) 2018 Estonian Information System Authority (RIA),
+ * Nordic Institute for Interoperability Solutions (NIIS), Population Register Centre (VRK)
+ * Copyright (c) 2015-2017 Estonian Information System Authority (RIA), Population Register Centre (VRK)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package org.niis.xroad.restapi.config;
+
+import org.niis.xroad.restapi.domain.Role;
+
+import java.util.EnumMap;
+import java.util.List;
+
+public interface UserRoleConfig {
+
+ /**
+ * Configures UNIX groups mapped to X-Road user roles.
+ */
+ EnumMap> getUserRoleMappings();
+
+}
diff --git a/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/domain/InvalidRoleNameException.java b/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/domain/InvalidRoleNameException.java
index 56e121dc11..c1ea8ab487 100644
--- a/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/domain/InvalidRoleNameException.java
+++ b/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/domain/InvalidRoleNameException.java
@@ -32,4 +32,8 @@ public class InvalidRoleNameException extends Exception {
public InvalidRoleNameException(String s) {
super(s);
}
+
+ public InvalidRoleNameException(String s, Throwable cause) {
+ super(s, cause);
+ }
}
diff --git a/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/domain/Role.java b/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/domain/Role.java
index cad838d03d..6e9febc7a7 100644
--- a/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/domain/Role.java
+++ b/src/common/common-admin-api/src/main/java/org/niis/xroad/restapi/domain/Role.java
@@ -25,13 +25,10 @@
*/
package org.niis.xroad.restapi.domain;
-import com.google.common.collect.MoreCollectors;
import lombok.Getter;
-import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
-import java.util.Optional;
import java.util.Set;
/**
@@ -39,58 +36,12 @@
*/
@Getter
public enum Role {
- XROAD_SECURITY_OFFICER(1, "xroad-security-officer"),
- XROAD_REGISTRATION_OFFICER(2, "xroad-registration-officer"),
- XROAD_SERVICE_ADMINISTRATOR(3, "xroad-service-administrator"),
- XROAD_SYSTEM_ADMINISTRATOR(4, "xroad-system-administrator"),
- XROAD_SECURITYSERVER_OBSERVER(5, "xroad-securityserver-observer"),
- //management service does not exist as a linux group
- XROAD_MANAGEMENT_SERVICE(6, null);
-
- /**
- * Some unfortunate extra boilerplate, since role names in e.g. @RolesAllowed
- * annotations need to be constants. Keep this in sync with the actual
- * enum values.
- * Alternative is to use approach like https://stackoverflow.com/a/54289956/1469083
- * and non-standard annotations
- */
- public final class Names {
- public static final String XROAD_SECURITY_OFFICER = "XROAD_SECURITY_OFFICER";
- public static final String XROAD_REGISTRATION_OFFICER = "XROAD_REGISTRATION_OFFICER";
- public static final String XROAD_SERVICE_ADMINISTRATOR = "XROAD_SERVICE_ADMINISTRATOR";
- public static final String XROAD_SYSTEM_ADMINISTRATOR = "XROAD_SYSTEM_ADMINISTRATOR";
- public static final String XROAD_SECURITYSERVER_OBSERVER = "XROAD_SECURITYSERVER_OBSERVER";
- private Names() {
- }
- }
-
- private final String linuxGroupName;
- // primary key in db
- private final int key;
-
- Role(int key, String linuxGroupName) {
- this.key = key;
- this.linuxGroupName = linuxGroupName;
- }
-
- /**
- * get key
- * @return
- */
- public int getKey() {
- return key;
- }
-
- /**
- * return Role matching given key
- * @param key
- * @return
- */
- public static Role getForKey(int key) {
- return Arrays.stream(values())
- .filter(role -> role.getKey() == key)
- .collect(MoreCollectors.onlyElement());
- }
+ XROAD_SECURITY_OFFICER,
+ XROAD_REGISTRATION_OFFICER,
+ XROAD_SERVICE_ADMINISTRATOR,
+ XROAD_SYSTEM_ADMINISTRATOR,
+ XROAD_SECURITYSERVER_OBSERVER,
+ XROAD_MANAGEMENT_SERVICE;
/**
* @return name which follows the "ROLE_" + name convention
@@ -99,45 +50,22 @@ public String getGrantedAuthorityName() {
return "ROLE_" + name();
}
- /**
- * return Role matching given linuxGroupName, if any
- * @param linuxGroupName
- * @return
- */
- public static Optional getForGroupName(String linuxGroupName) {
- return Arrays.stream(values())
- .filter(role -> role.linuxGroupName.equals(linuxGroupName))
- .findFirst();
- }
-
/**
* Return Roles matching the given role names. Throws InvalidRoleNameException
* if matching Role for some name does not exist.
* @param names
- * @return
+ * @return set of matching roles
*/
public static Set getForNames(Collection names) throws InvalidRoleNameException {
Set roles = EnumSet.noneOf(Role.class);
for (String name: names) {
- if (!Role.contains(name)) {
- throw new InvalidRoleNameException("invalid role " + name);
+ try {
+ Role.valueOf(name);
+ } catch (IllegalArgumentException e) {
+ throw new InvalidRoleNameException("Invalid role: " + name, e);
}
roles.add(Role.valueOf(name));
}
return roles;
}
-
- /**
- * Tells if parameter string is one of Role names
- * @param name
- * @return
- */
- public static boolean contains(String name) {
- for (Role role: Role.values()) {
- if (role.name().equals(name)) {
- return true;
- }
- }
- return false;
- }
}
diff --git a/src/common/common-admin-api/src/test/java/org/niis/xroad/restapi/auth/RoleTest.java b/src/common/common-admin-api/src/test/java/org/niis/xroad/restapi/auth/RoleTest.java
index 8ec0de030f..b5d591083e 100644
--- a/src/common/common-admin-api/src/test/java/org/niis/xroad/restapi/auth/RoleTest.java
+++ b/src/common/common-admin-api/src/test/java/org/niis/xroad/restapi/auth/RoleTest.java
@@ -26,25 +26,30 @@
package org.niis.xroad.restapi.auth;
import org.junit.jupiter.api.Test;
+import org.niis.xroad.restapi.domain.InvalidRoleNameException;
import org.niis.xroad.restapi.domain.Role;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.fail;
+import java.util.Set;
-/**
- * test role
- */
-public class RoleTest {
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.niis.xroad.restapi.domain.Role.XROAD_SERVICE_ADMINISTRATOR;
+
+class RoleTest {
+
+ @Test
+ void getGrantedAuthorityName() {
+ String result = XROAD_SERVICE_ADMINISTRATOR.getGrantedAuthorityName();
+ assertThat(result).isEqualTo("ROLE_" + XROAD_SERVICE_ADMINISTRATOR.name());
+ }
@Test
- public void test() {
- Role role = Role.getForKey(3);
- assertEquals("XROAD_SERVICE_ADMINISTRATOR", role.name());
+ void getForNames() throws InvalidRoleNameException {
+ Set result = Role.getForNames(Set.of(XROAD_SERVICE_ADMINISTRATOR.name()));
+ assertThat(result).containsOnly(XROAD_SERVICE_ADMINISTRATOR);
- try {
- role = Role.getForKey(10);
- fail("should throw exception");
- } catch (Exception expected) {
- }
+ assertThatThrownBy(() -> Role.getForNames(Set.of("INVALID_ROLE")))
+ .isInstanceOf(InvalidRoleNameException.class)
+ .hasMessage("Invalid role: INVALID_ROLE");
}
}
diff --git a/src/common/common-admin-api/src/test/java/org/niis/xroad/restapi/controller/ApiKeysControllerTest.java b/src/common/common-admin-api/src/test/java/org/niis/xroad/restapi/controller/ApiKeysControllerTest.java
index d75e9c6949..1fc911dc37 100644
--- a/src/common/common-admin-api/src/test/java/org/niis/xroad/restapi/controller/ApiKeysControllerTest.java
+++ b/src/common/common-admin-api/src/test/java/org/niis/xroad/restapi/controller/ApiKeysControllerTest.java
@@ -29,6 +29,7 @@
import org.junit.jupiter.api.Test;
import org.niis.xroad.restapi.config.AllowedHostnamesConfig;
+import org.niis.xroad.restapi.config.UserRoleConfig;
import org.niis.xroad.restapi.converter.PublicApiKeyDataConverter;
import org.niis.xroad.restapi.domain.InvalidRoleNameException;
import org.niis.xroad.restapi.domain.PersistentApiKeyType;
@@ -64,6 +65,8 @@ class ApiKeysControllerTest extends AbstractSpringMvcTest {
public PublicApiKeyDataConverter publicApiKeyDataConverter;
@MockBean
private AllowedHostnamesConfig allowedHostnamesConfig;
+ @MockBean
+ private UserRoleConfig userRoleConfig;
private static final String AUTHORITY_WRONG = "AUTHORITY_WRONG";
private static final String AUTHORITY_CREATE_API_KEY = "CREATE_API_KEY";
diff --git a/src/security-server/admin-service/application/src/main/java/org/niis/xroad/securityserver/restapi/config/AdminServiceProperties.java b/src/security-server/admin-service/application/src/main/java/org/niis/xroad/securityserver/restapi/config/AdminServiceProperties.java
index 131302307a..68a2ee19a0 100644
--- a/src/security-server/admin-service/application/src/main/java/org/niis/xroad/securityserver/restapi/config/AdminServiceProperties.java
+++ b/src/security-server/admin-service/application/src/main/java/org/niis/xroad/securityserver/restapi/config/AdminServiceProperties.java
@@ -33,11 +33,22 @@
import org.niis.xroad.restapi.config.ApiCachingConfiguration;
import org.niis.xroad.restapi.config.IdentifierValidationConfiguration;
import org.niis.xroad.restapi.config.LimitRequestSizesFilter;
+import org.niis.xroad.restapi.config.UserRoleConfig;
+import org.niis.xroad.restapi.domain.Role;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.unit.DataSize;
+import java.util.EnumMap;
import java.util.List;
+import java.util.stream.Stream;
+
+import static java.util.stream.Collectors.toList;
+import static org.niis.xroad.restapi.domain.Role.XROAD_REGISTRATION_OFFICER;
+import static org.niis.xroad.restapi.domain.Role.XROAD_SECURITYSERVER_OBSERVER;
+import static org.niis.xroad.restapi.domain.Role.XROAD_SECURITY_OFFICER;
+import static org.niis.xroad.restapi.domain.Role.XROAD_SERVICE_ADMINISTRATOR;
+import static org.niis.xroad.restapi.domain.Role.XROAD_SYSTEM_ADMINISTRATOR;
/**
* Admin service configuration properties.
@@ -51,7 +62,8 @@ public class AdminServiceProperties implements IpThrottlingFilterConfig,
AllowedHostnamesConfig,
ApiCachingConfiguration.Config,
LimitRequestSizesFilter.Config,
- IdentifierValidationConfiguration.Config {
+ IdentifierValidationConfiguration.Config,
+ UserRoleConfig {
/**
* Controls how many requests from an IP address are allowed per minute.
@@ -108,5 +120,27 @@ public class AdminServiceProperties implements IpThrottlingFilterConfig,
/** Configures Api file upload request size limit. */
private DataSize requestSizeLimitBinaryUpload;
+
+ /**
+ * Configures additional UNIX groups mapped to X-Road user roles.
+ */
+ private EnumMap> complementaryUserRoleMappings;
+
+ @Override
+ public EnumMap> getUserRoleMappings() {
+ EnumMap> userRoleMappings = new EnumMap<>(Role.class);
+ userRoleMappings.put(XROAD_SECURITY_OFFICER, List.of("xroad-security-officer"));
+ userRoleMappings.put(XROAD_REGISTRATION_OFFICER, List.of("xroad-registration-officer"));
+ userRoleMappings.put(XROAD_SERVICE_ADMINISTRATOR, List.of("xroad-service-administrator"));
+ userRoleMappings.put(XROAD_SYSTEM_ADMINISTRATOR, List.of("xroad-system-administrator"));
+ userRoleMappings.put(XROAD_SECURITYSERVER_OBSERVER, List.of("xroad-securityserver-observer"));
+
+ if (complementaryUserRoleMappings != null) {
+ complementaryUserRoleMappings.forEach((role, groups) -> userRoleMappings.merge(role, groups,
+ (a, b) -> Stream.concat(a.stream(), b.stream()).collect(toList())));
+ }
+
+ return userRoleMappings;
+ }
}