Don't treat the Agent role as a restriction
Previously, the Agent role forced the user to only be able to post metrics. Now, it checks the defaultAuthorizedRoles first and only if the user has none of those roles does it check for agentAuthorizedRoles. A user with roles in both will still have full access Added explanation of the Keystone Authentication/Authorization to the README Change-Id: Ib82a064fd00f25a96c9b5b5294ada301270ab93c
This commit is contained in:
30
README.md
30
README.md
@@ -18,6 +18,36 @@ mvn clean install
|
||||
java -jar target/monasca-api.jar server config-file.yml
|
||||
```
|
||||
|
||||
## Keystone Configuration
|
||||
|
||||
For secure operation of the Monasca API, the API must be configured to use Keystone in the configuration file under the middleware section. Monasca only works with a Keystone v3 server. The important parts of the configuration are explained below:
|
||||
|
||||
* serverVIP - This is the hostname or IP Address of the Keystone server
|
||||
* serverPort - The port for the Keystone server
|
||||
* useHttps - Whether to use https when making requests of the Keystone API
|
||||
* truststore - If useHttps is true and the Keystone server is not using a certificate signed by a public CA recognized by Java, the CA certificate can be placed in a truststore so the Monasca API will trust it, otherwise it will reject the https connection. This must be a JKS truststore
|
||||
* truststorePassword - The password for the above truststore
|
||||
* connSSLClientAuth - If the Keystone server requires the SSL client used by the Monasca server to have a specific client certificate, this should be true, false otherwise
|
||||
* keystore - The keystore holding the SSL Client certificate if connSSLClientAuth is true
|
||||
* keystorePassword - The password for the keystore
|
||||
* defaultAuthorizedRoles - An array of roles that authorize a user to access the complete Monasca API. User must have at least one of these roles. See below
|
||||
* agentAuthorizedRoles - An array of roles that authorize only the posting of metrics. See Keystone Roles below
|
||||
* adminAuthMethod - "password" if the Monasca API should adminUser and adminPassword to login to the Keystone server to check the user's token, "token" if the Monasca API should use adminToken
|
||||
* adminUser - Admin user name
|
||||
* adminPassword - Admin user password
|
||||
* adminToken - A valid admin user token if adminAuthMethod is token
|
||||
* timeToCacheToken - How long the Monasca API should cache the user's token before checking it again
|
||||
|
||||
### Keystone Roles
|
||||
|
||||
The Monasca API has two levels of access:
|
||||
# Full access - user can read/write metrics and Alarm Definitions and Alarms
|
||||
# Agent access - user can only write metrics
|
||||
|
||||
The reason for the "Agent access" level is because the Monasca Agent must be configured to use a Keystone user. Since the user and password are configured onto the all of the systems running the Monasca Agent, this user is most in danger of being compromised. If this user is limited to only writing metrics, then the damage can be limited.
|
||||
|
||||
To configure the user to have full access, the user must have a role that is listed in defaultAuthorizedRoles. To configure a user to have only "Agent access", the user must have a role in agentAuthorizedRoles and none of the roles in defaultAuthorizedRoles.
|
||||
|
||||
## Design Overview
|
||||
|
||||
### Architectural layers
|
||||
|
||||
@@ -78,8 +78,10 @@ public class PostAuthenticationFilter implements Filter {
|
||||
|
||||
Object tenantId = request.getAttribute(X_TENANT_ID_ATTRIBUTE);
|
||||
|
||||
if (tenantId == null)
|
||||
if (tenantId == null) {
|
||||
sendAuthError(res, null, null, null);
|
||||
return;
|
||||
}
|
||||
tenantIdStr = tenantId.toString();
|
||||
|
||||
boolean authenticated = isAuthenticated(req);
|
||||
@@ -120,21 +122,24 @@ public class PostAuthenticationFilter implements Filter {
|
||||
*/
|
||||
private boolean isAuthorized(HttpServletRequest request) {
|
||||
Object rolesFromKeystone = request.getAttribute(X_ROLES_ATTRIBUTE);
|
||||
boolean validUser = false;
|
||||
if (rolesFromKeystone == null)
|
||||
return false;
|
||||
|
||||
boolean agentUser = false;
|
||||
for (String role : rolesFromKeystone.toString().split(",")) {
|
||||
String lowerCaseRole = role.toLowerCase();
|
||||
if ((defaultAuthorizedRoles != null && defaultAuthorizedRoles.contains(lowerCaseRole))
|
||||
|| (agentAuthorizedRoles != null && agentAuthorizedRoles.contains(lowerCaseRole))) {
|
||||
if (agentAuthorizedRoles.contains(lowerCaseRole)) {
|
||||
request.setAttribute(X_MONASCA_AGENT, true);
|
||||
}
|
||||
validUser = true;
|
||||
if ((defaultAuthorizedRoles != null) && defaultAuthorizedRoles.contains(lowerCaseRole)) {
|
||||
return true;
|
||||
}
|
||||
if ((agentAuthorizedRoles != null) && agentAuthorizedRoles.contains(lowerCaseRole)) {
|
||||
agentUser = true;
|
||||
}
|
||||
}
|
||||
return validUser;
|
||||
if (agentUser) {
|
||||
request.setAttribute(X_MONASCA_AGENT, true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,15 +15,22 @@
|
||||
package monasca.api.infrastructure.servlet;
|
||||
|
||||
import monasca.api.resource.exception.Exceptions;
|
||||
import monasca.common.middleware.AuthConstants;
|
||||
|
||||
import com.sun.jersey.spi.container.ContainerRequest;
|
||||
import com.sun.jersey.spi.container.ContainerRequestFilter;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.ws.rs.core.Context;
|
||||
|
||||
import static monasca.api.infrastructure.servlet.PostAuthenticationFilter.X_MONASCA_AGENT;
|
||||
|
||||
public class RoleAuthorizationFilter implements ContainerRequestFilter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger
|
||||
(ContainerRequestFilter.class);
|
||||
@Context
|
||||
private HttpServletRequest httpServletRequest;
|
||||
private static final String VALID_MONASCA_AGENT_PATH = "/v2.0/metrics";
|
||||
@@ -34,11 +41,13 @@ public class RoleAuthorizationFilter implements ContainerRequestFilter {
|
||||
Object isAgent = httpServletRequest.getAttribute(X_MONASCA_AGENT);
|
||||
String pathInfo = httpServletRequest.getPathInfo();
|
||||
|
||||
// X_MONASCA_AGENT is only set if the only valid role for this user is an agent role
|
||||
if (isAgent != null) {
|
||||
if (!pathInfo.equals(VALID_MONASCA_AGENT_PATH)) {
|
||||
throw Exceptions.badRequest("Tenant is missing a required role to perform this request");
|
||||
} else if (pathInfo.equals(VALID_MONASCA_AGENT_PATH) && !method.equals("POST")) {
|
||||
throw Exceptions.badRequest("Tenant is missing a required role to perform this request");
|
||||
if (!pathInfo.equals(VALID_MONASCA_AGENT_PATH) || !method.equals("POST")) {
|
||||
logger.warn("User {} is missing a required role to {} on {}",
|
||||
httpServletRequest.getAttribute(AuthConstants.AUTH_USER_NAME),
|
||||
method, pathInfo);
|
||||
throw Exceptions.badRequest("User is missing a required role to perform this request");
|
||||
}
|
||||
}
|
||||
return containerRequest;
|
||||
|
||||
Reference in New Issue
Block a user