You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by bb...@apache.org on 2017/11/08 16:14:00 UTC
nifi-registry git commit: NIFIREG-46 Add authorizedActions field to
Bucket API model object
Repository: nifi-registry
Updated Branches:
refs/heads/master 90f36dd22 -> 9b41af80b
NIFIREG-46 Add authorizedActions field to Bucket API model object
This closes #30.
Signed-off-by: Bryan Bende <bb...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/nifi-registry/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi-registry/commit/9b41af80
Tree: http://git-wip-us.apache.org/repos/asf/nifi-registry/tree/9b41af80
Diff: http://git-wip-us.apache.org/repos/asf/nifi-registry/diff/9b41af80
Branch: refs/heads/master
Commit: 9b41af80b855d82ffa4163c3d1e074d45376437f
Parents: 90f36dd
Author: Kevin Doran <kd...@gmail.com>
Authored: Wed Nov 1 15:02:19 2017 -0400
Committer: Bryan Bende <bb...@apache.org>
Committed: Wed Nov 8 11:13:45 2017 -0500
----------------------------------------------------------------------
.../org/apache/nifi/registry/bucket/Bucket.java | 24 ++-
.../registry/model/authorization/Tenant.java | 27 +++
.../nifi/registry/model/authorization/User.java | 22 ---
.../registry/model/authorization/UserGroup.java | 23 ---
.../registry/service/AuthorizationService.java | 122 ++++++-------
.../nifi/registry/web/api/AccessResource.java | 106 ++---------
.../api/AuthorizableApplicationResource.java | 4 +-
.../nifi/registry/web/api/BucketResource.java | 71 ++++++--
.../nifi/registry/web/api/ItemResource.java | 10 +-
.../nifi/registry/web/api/ResourceResource.java | 15 +-
.../web/mapper/NiFiRegistryJsonProvider.java | 48 +++++
.../web/mapper/ObjectMapperContextResolver.java | 44 -----
.../security/NiFiRegistrySecurityConfig.java | 6 +-
.../apache/nifi/registry/web/api/BucketsIT.java | 8 +-
.../registry/web/api/IntegrationTestBase.java | 29 ++-
.../nifi/registry/web/api/SecureLdapIT.java | 175 +++++++++++++++++--
16 files changed, 448 insertions(+), 286 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java
----------------------------------------------------------------------
diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java
index 314598e..3ba9b22 100644
--- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java
+++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/bucket/Bucket.java
@@ -18,13 +18,14 @@ package org.apache.nifi.registry.bucket;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
-import org.apache.nifi.registry.link.LinkableEntity;
import org.apache.nifi.registry.flow.VersionedFlow;
+import org.apache.nifi.registry.link.LinkableEntity;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.xml.bind.annotation.XmlRootElement;
+import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
@@ -43,10 +44,11 @@ public class Bucket extends LinkableEntity {
private String description;
+ private Set<String> authorizedActions;
+
@Valid
private Set<VersionedFlow> versionedFlows;
-
@ApiModelProperty("An ID to uniquely identify this object.")
public String getIdentifier() {
return identifier;
@@ -83,6 +85,24 @@ public class Bucket extends LinkableEntity {
this.description = description;
}
+ @ApiModelProperty("A list of actions the client is authorized to perform for this bucket.")
+ public Set<String> getAuthorizedActions() {
+ return authorizedActions;
+ }
+
+ public void setAuthorizedActions(Set<String> authorizedActions) {
+ this.authorizedActions = authorizedActions;
+ }
+
+ public void addAuthorizedAction(String action) {
+ if (action != null) {
+ if (this.authorizedActions == null) {
+ this.authorizedActions = new HashSet<>();
+ }
+ authorizedActions.add(action);
+ }
+ }
+
@ApiModelProperty(value = "The versioned flows in the bucket.", readOnly = true)
public Set<VersionedFlow> getVersionedFlows() {
return versionedFlows;
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Tenant.java
----------------------------------------------------------------------
diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Tenant.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Tenant.java
index 662e3bf..87f1242 100644
--- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Tenant.java
+++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/Tenant.java
@@ -19,6 +19,10 @@ package org.apache.nifi.registry.model.authorization;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* A tenant of this NiFi Registry
*/
@@ -27,6 +31,7 @@ public class Tenant {
private String identifier;
private String identity;
+ private Set<AccessPolicySummary> accessPolicies;
public Tenant() {}
@@ -58,4 +63,26 @@ public class Tenant {
public void setIdentity(String identity) {
this.identity = identity;
}
+
+ @ApiModelProperty(
+ value = "The access policies granted to this tenant. This field is read only",
+ readOnly = true
+ )
+ public Set<AccessPolicySummary> getAccessPolicies() {
+ return accessPolicies;
+ }
+
+ public void setAccessPolicies(Set<AccessPolicySummary> accessPolicies) {
+ this.accessPolicies = accessPolicies;
+ }
+
+ public void addAccessPolicies(Collection<AccessPolicySummary> accessPolicies) {
+ if (accessPolicies != null) {
+ if (this.accessPolicies == null) {
+ this.accessPolicies = new HashSet<>();
+ }
+ this.accessPolicies.addAll(accessPolicies);
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/User.java
----------------------------------------------------------------------
diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/User.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/User.java
index 76ed867..449a274 100644
--- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/User.java
+++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/User.java
@@ -27,7 +27,6 @@ import java.util.Set;
public class User extends Tenant {
private Set<Tenant> userGroups;
- private Set<AccessPolicySummary> accessPolicies;
public User() {}
@@ -56,25 +55,4 @@ public class User extends Tenant {
}
}
- @ApiModelProperty(
- value = "The access policies granted to this user. This field is read only",
- readOnly = true
- )
- public Set<AccessPolicySummary> getAccessPolicies() {
- return accessPolicies;
- }
-
- public void setAccessPolicies(Set<AccessPolicySummary> accessPolicies) {
- this.accessPolicies = accessPolicies;
- }
-
- public void addAccessPolicies(Collection<? extends AccessPolicySummary> accessPolicies) {
- if (accessPolicies != null) {
- if (this.accessPolicies == null) {
- this.accessPolicies = new HashSet<>();
- }
- this.accessPolicies.addAll(accessPolicies);
- }
- }
-
}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/UserGroup.java
----------------------------------------------------------------------
diff --git a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/UserGroup.java b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/UserGroup.java
index 51b1297..4b14a20 100644
--- a/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/UserGroup.java
+++ b/nifi-registry-data-model/src/main/java/org/apache/nifi/registry/model/authorization/UserGroup.java
@@ -59,27 +59,4 @@ public class UserGroup extends Tenant {
}
}
- /**
- * @return The access policies set for this user group
- */
- @ApiModelProperty(
- value = "The access policies granted to this user group.",
- readOnly = true
- )
- public Set<AccessPolicySummary> getAccessPolicies() {
- return accessPolicies;
- }
-
- public void setAccessPolicies(Set<AccessPolicySummary> accessPolicies) {
- this.accessPolicies = accessPolicies;
- }
-
- public void addAccessPolicies(Collection<? extends AccessPolicySummary> accessPolicies) {
- if (accessPolicies != null) {
- if (this.accessPolicies == null) {
- this.accessPolicies = new HashSet<>();
- }
- this.accessPolicies.addAll(accessPolicies);
- }
- }
}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/AuthorizationService.java
----------------------------------------------------------------------
diff --git a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/AuthorizationService.java b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/AuthorizationService.java
index 2567b55..ead73cd 100644
--- a/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/AuthorizationService.java
+++ b/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/AuthorizationService.java
@@ -16,6 +16,13 @@
*/
package org.apache.nifi.registry.service;
+import org.apache.nifi.registry.bucket.Bucket;
+import org.apache.nifi.registry.model.authorization.AccessPolicy;
+import org.apache.nifi.registry.model.authorization.AccessPolicySummary;
+import org.apache.nifi.registry.model.authorization.Resource;
+import org.apache.nifi.registry.model.authorization.Tenant;
+import org.apache.nifi.registry.model.authorization.User;
+import org.apache.nifi.registry.model.authorization.UserGroup;
import org.apache.nifi.registry.security.authorization.AccessPolicyProvider;
import org.apache.nifi.registry.security.authorization.AccessPolicyProviderInitializationContext;
import org.apache.nifi.registry.security.authorization.AuthorizableLookup;
@@ -38,13 +45,6 @@ import org.apache.nifi.registry.security.authorization.exception.AuthorizerDestr
import org.apache.nifi.registry.security.authorization.resource.ResourceFactory;
import org.apache.nifi.registry.security.authorization.resource.ResourceType;
import org.apache.nifi.registry.security.authorization.user.NiFiUserUtils;
-import org.apache.nifi.registry.bucket.Bucket;
-import org.apache.nifi.registry.model.authorization.AccessPolicy;
-import org.apache.nifi.registry.model.authorization.AccessPolicySummary;
-import org.apache.nifi.registry.model.authorization.Resource;
-import org.apache.nifi.registry.model.authorization.Tenant;
-import org.apache.nifi.registry.model.authorization.User;
-import org.apache.nifi.registry.model.authorization.UserGroup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -150,6 +150,15 @@ public class AuthorizationService {
}
}
+ public User getUserByIdentity(String identity) {
+ this.readLock.lock();
+ try {
+ return userToDTO(userGroupProvider.getUserByIdentity(identity));
+ } finally {
+ this.readLock.unlock();
+ }
+ }
+
public User updateUser(User user) {
verifyUserGroupProviderIsConfigurable();
this.writeLock.lock();
@@ -198,19 +207,6 @@ public class AuthorizationService {
}
}
-// private List<UserGroup> getUserGroupsForUser(String userIdentifier) {
-// this.readLock.lock();
-// try {
-// return userGroupProvider.getGroups()
-// .stream()
-// .filter(group -> group.getUsers().contains(userIdentifier))
-// .map(this::userGroupToDTO)
-// .collect(Collectors.toList());
-// } finally {
-// this.readLock.unlock();
-// }
-// }
-
public UserGroup getUserGroup(String identifier) {
this.readLock.lock();
try {
@@ -295,18 +291,6 @@ public class AuthorizationService {
}
}
- public List<AccessPolicy> getAccessPoliciesForUser(String userIdentifier) {
- readLock.lock();
- try {
- return accessPolicyProvider.getAccessPolicies().stream()
- .filter(accessPolicy -> accessPolicy.getUsers().contains(userIdentifier))
- .map(this::accessPolicyToDTO)
- .collect(Collectors.toList());
- } finally {
- readLock.unlock();
- }
- }
-
private List<AccessPolicySummary> getAccessPolicySummariesForUser(String userIdentifier) {
readLock.lock();
try {
@@ -364,26 +348,33 @@ public class AuthorizationService {
// ---------------------- Resource Lookup methods --------------------------------------
+ public List<Resource> getResources() {
+ final List<Resource> dtoResources =
+ getAuthorizableResources()
+ .stream()
+ .map(AuthorizationService::resourceToDTO)
+ .collect(Collectors.toList());
+ return dtoResources;
+ }
+
+ public List<Resource> getAuthorizedResources(RequestAction actionType) {
+ return getAuthorizedResources(actionType, null);
+ }
+
public List<Resource> getAuthorizedResources(RequestAction actionType, ResourceType resourceType) {
final List<Resource> authorizedResources =
- getAllAuthorizableResources()
+ getAuthorizableResources(resourceType)
.stream()
.filter(resource -> {
String resourceId = resource.getIdentifier();
- if (resourceType != null) {
- if (!resourceId.startsWith(resourceType.getValue())) {
- return false;
- }
- }
try {
authorizableLookup
.getAuthorizableByResource(resource.getIdentifier())
.authorize(authorizer, actionType, NiFiUserUtils.getNiFiUser());
+ return true;
} catch (AccessDeniedException e) {
return false;
}
- return true;
-
})
.map(AuthorizationService::resourceToDTO)
.collect(Collectors.toList());
@@ -391,20 +382,6 @@ public class AuthorizationService {
return authorizedResources;
}
- public List<Resource> getAuthorizedResources(RequestAction actionType) {
- return getAuthorizedResources(actionType, null);
- }
-
- public List<Resource> getResources() {
- final List<Resource> dtoResources =
- getAllAuthorizableResources()
- .stream()
- .map(AuthorizationService::resourceToDTO)
- .collect(Collectors.toList());
- return dtoResources;
- }
-
-
// ---------------------- Private Helper methods --------------------------------------
private void verifyUserGroupProviderIsConfigurable() {
@@ -419,17 +396,32 @@ public class AuthorizationService {
}
}
- private List<org.apache.nifi.registry.security.authorization.Resource> getAllAuthorizableResources() {
+ private List<org.apache.nifi.registry.security.authorization.Resource> getAuthorizableResources() {
+ return getAuthorizableResources(null);
+ }
+
+ private List<org.apache.nifi.registry.security.authorization.Resource> getAuthorizableResources(ResourceType includeFilter) {
+
final List<org.apache.nifi.registry.security.authorization.Resource> resources = new ArrayList<>();
- resources.add(ResourceFactory.getPoliciesResource());
- resources.add(ResourceFactory.getTenantResource());
- resources.add(ResourceFactory.getProxyResource());
- resources.add(ResourceFactory.getResourceResource());
- // add all buckets
- resources.add(ResourceFactory.getBucketsResource());
- for (final Bucket bucket : registryService.getBuckets()) {
- resources.add(ResourceFactory.getChildResource(ResourceType.Bucket, bucket.getIdentifier(), bucket.getName()));
+ if (includeFilter == null || includeFilter.equals(ResourceType.Policy)) {
+ resources.add(ResourceFactory.getPoliciesResource());
+ }
+ if (includeFilter == null || includeFilter.equals(ResourceType.Tenant)) {
+ resources.add(ResourceFactory.getTenantResource());
+ }
+ if (includeFilter == null || includeFilter.equals(ResourceType.Proxy)) {
+ resources.add(ResourceFactory.getProxyResource());
+ }
+ if (includeFilter == null || includeFilter.equals(ResourceType.Resource)) {
+ resources.add(ResourceFactory.getResourceResource());
+ }
+ if (includeFilter == null || includeFilter.equals(ResourceType.Bucket)) {
+ resources.add(ResourceFactory.getBucketsResource());
+ // add all buckets
+ for (final Bucket bucket : registryService.getBuckets()) {
+ resources.add(ResourceFactory.getChildResource(ResourceType.Bucket, bucket.getIdentifier(), bucket.getName()));
+ }
}
return resources;
@@ -533,7 +525,7 @@ public class AuthorizationService {
private static org.apache.nifi.registry.model.authorization.User userToDTO(
final org.apache.nifi.registry.security.authorization.User user,
final Collection<? extends Tenant> userGroups,
- final Collection<? extends AccessPolicySummary> accessPolicies) {
+ final Collection<AccessPolicySummary> accessPolicies) {
if (user == null) {
return null;
@@ -562,7 +554,7 @@ public class AuthorizationService {
private static org.apache.nifi.registry.model.authorization.UserGroup userGroupToDTO(
final org.apache.nifi.registry.security.authorization.Group userGroup,
final Collection<? extends Tenant> users,
- final Collection<? extends AccessPolicySummary> accessPolicies) {
+ final Collection<AccessPolicySummary> accessPolicies) {
if (userGroup == null) {
return null;
}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java
index ad923c4..2732d5a 100644
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AccessResource.java
@@ -16,39 +16,26 @@
*/
package org.apache.nifi.registry.web.api;
-import io.jsonwebtoken.JwtException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.registry.exception.AdministrationException;
+import org.apache.nifi.registry.model.authorization.AccessStatus;
import org.apache.nifi.registry.security.authentication.AuthenticationResponse;
import org.apache.nifi.registry.security.authentication.LoginCredentials;
import org.apache.nifi.registry.security.authentication.LoginIdentityProvider;
import org.apache.nifi.registry.security.authentication.exception.IdentityAccessException;
import org.apache.nifi.registry.security.authentication.exception.InvalidLoginCredentialsException;
-import org.apache.nifi.registry.security.authorization.exception.AccessDeniedException;
import org.apache.nifi.registry.security.authorization.user.NiFiUser;
-import org.apache.nifi.registry.security.authorization.user.NiFiUserDetails;
-import org.apache.nifi.registry.exception.AdministrationException;
-import org.apache.nifi.registry.model.authorization.AccessStatus;
-import org.apache.nifi.registry.web.security.authentication.exception.InvalidAuthenticationException;
-import org.apache.nifi.registry.web.security.authentication.ProxiedEntitiesUtils;
-import org.apache.nifi.registry.web.security.authentication.exception.UntrustedProxyException;
-import org.apache.nifi.registry.web.security.authentication.jwt.JwtAuthenticationFilter;
-import org.apache.nifi.registry.web.security.authentication.jwt.JwtAuthenticationProvider;
-import org.apache.nifi.registry.web.security.authentication.jwt.JwtAuthenticationRequestToken;
+import org.apache.nifi.registry.security.authorization.user.NiFiUserUtils;
+import org.apache.nifi.registry.service.AuthorizationService;
import org.apache.nifi.registry.web.security.authentication.jwt.JwtService;
import org.apache.nifi.registry.web.security.authentication.token.LoginAuthenticationToken;
-import org.apache.nifi.registry.web.security.authentication.token.NiFiAuthenticationToken;
-import org.apache.nifi.registry.web.security.authentication.x509.X509AuthenticationProvider;
-import org.apache.nifi.registry.web.security.authentication.x509.X509AuthenticationRequestToken;
-import org.apache.nifi.registry.web.security.authentication.x509.X509CertificateExtractor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.security.authentication.AuthenticationServiceException;
-import org.springframework.security.web.authentication.preauth.x509.X509PrincipalExtractor;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@@ -62,7 +49,6 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.net.URI;
-import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
@Component
@@ -75,27 +61,16 @@ public class AccessResource extends ApplicationResource {
private static final Logger logger = LoggerFactory.getLogger(AccessResource.class);
- private X509CertificateExtractor certificateExtractor;
- private X509AuthenticationProvider x509AuthenticationProvider;
- private X509PrincipalExtractor x509principalExtractor;
private LoginIdentityProvider loginIdentityProvider;
- private JwtAuthenticationProvider jwtAuthenticationProvider;
private JwtService jwtService;
@Autowired
- public AccessResource(X509CertificateExtractor certificateExtractor,
- X509AuthenticationProvider x509AuthenticationProvider,
- X509PrincipalExtractor x509principalExtractor,
- LoginIdentityProvider loginIdentityProvider,
- JwtAuthenticationProvider jwtAuthenticationProvider,
- JwtService jwtService
- ) {
- this.certificateExtractor = certificateExtractor;
- this.x509AuthenticationProvider = x509AuthenticationProvider;
- this.x509principalExtractor = x509principalExtractor;
- this.loginIdentityProvider = loginIdentityProvider;
- this.jwtAuthenticationProvider = jwtAuthenticationProvider;
+ public AccessResource(
+ AuthorizationService authorizationService,
+ JwtService jwtService,
+ LoginIdentityProvider loginIdentityProvider) {
this.jwtService = jwtService;
+ this.loginIdentityProvider = loginIdentityProvider;
}
/**
@@ -124,60 +99,15 @@ public class AccessResource extends ApplicationResource {
final AccessStatus accessStatus = new AccessStatus();
- try {
- final X509Certificate[] certificates = certificateExtractor.extractClientCertificate(httpServletRequest);
-
- // if there is not certificate, consider a token
- if (certificates == null) {
-
- // look for an authorization token
- final String authorization = httpServletRequest.getHeader(JwtAuthenticationFilter.AUTHORIZATION);
-
- // if there is no authorization header, we don't know the user
- if (authorization == null) {
- accessStatus.setStatus(AccessStatus.Status.UNKNOWN.name());
- accessStatus.setMessage("No credentials supplied, unknown user.");
- } else {
- try {
- // Extract the Base64 encoded token from the Authorization header
- final String token = StringUtils.substringAfterLast(authorization, " ");
-
- final JwtAuthenticationRequestToken jwtRequest = new JwtAuthenticationRequestToken(token, httpServletRequest.getRemoteAddr());
- final NiFiAuthenticationToken authenticationResponse = (NiFiAuthenticationToken) jwtAuthenticationProvider.authenticate(jwtRequest);
- final NiFiUser nifiUser = ((NiFiUserDetails) authenticationResponse.getDetails()).getNiFiUser();
-
- // set the user identity
- accessStatus.setIdentity(nifiUser.getIdentity());
-
- // attempt authorize to /flow
- accessStatus.setStatus(AccessStatus.Status.ACTIVE.name());
- accessStatus.setMessage("You are already logged in.");
- } catch (JwtException e) {
- throw new InvalidAuthenticationException(e.getMessage(), e);
- }
- }
- } else {
- try {
- final X509AuthenticationRequestToken x509Request = new X509AuthenticationRequestToken(
- httpServletRequest.getHeader(ProxiedEntitiesUtils.PROXY_ENTITIES_CHAIN), x509principalExtractor, certificates, httpServletRequest.getRemoteAddr());
-
- final NiFiAuthenticationToken authenticationResponse = (NiFiAuthenticationToken) x509AuthenticationProvider.authenticate(x509Request);
- final NiFiUser nifiUser = ((NiFiUserDetails) authenticationResponse.getDetails()).getNiFiUser();
-
- // set the user identity
- accessStatus.setIdentity(nifiUser.getIdentity());
-
- // attempt authorize to /flow
- accessStatus.setStatus(AccessStatus.Status.ACTIVE.name());
- accessStatus.setMessage("You are already logged in.");
- } catch (final IllegalArgumentException iae) {
- throw new InvalidAuthenticationException(iae.getMessage(), iae);
- }
- }
- } catch (final UntrustedProxyException upe) {
- throw new AccessDeniedException(upe.getMessage(), upe);
- } catch (final AuthenticationServiceException ase) {
- throw new AdministrationException(ase.getMessage(), ase);
+ NiFiUser currentUser = NiFiUserUtils.getNiFiUser();
+ if (currentUser == null || currentUser.getIdentity() == null || currentUser.isAnonymous()) {
+ accessStatus.setStatus(AccessStatus.Status.UNKNOWN.name());
+ accessStatus.setMessage("No credentials supplied, unknown user.");
+ } else {
+ final String identity = currentUser.getIdentity();
+ accessStatus.setIdentity(identity);
+ accessStatus.setStatus(AccessStatus.Status.ACTIVE.name());
+ accessStatus.setMessage("You are logged in.");
}
return generateOkResponse(accessStatus).build();
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AuthorizableApplicationResource.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AuthorizableApplicationResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AuthorizableApplicationResource.java
index 58ee742..1e6602e 100644
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AuthorizableApplicationResource.java
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/AuthorizableApplicationResource.java
@@ -56,9 +56,9 @@ public class AuthorizableApplicationResource extends ApplicationResource {
authorizeBucketAccess(actionType, bucketItem.getBucketIdentifier());
}
- protected Set<String> getAuthorizedBucketIds() {
+ protected Set<String> getAuthorizedBucketIds(RequestAction actionType) {
return authorizationService
- .getAuthorizedResources(RequestAction.READ, ResourceType.Bucket)
+ .getAuthorizedResources(actionType, ResourceType.Bucket)
.stream()
.map(AuthorizableApplicationResource::extractBucketIdFromResource)
.filter(Objects::nonNull)
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java
index 5835ea0..19ae7f2 100644
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/BucketResource.java
@@ -22,19 +22,19 @@ import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.registry.bucket.Bucket;
+import org.apache.nifi.registry.bucket.BucketItem;
+import org.apache.nifi.registry.field.Fields;
+import org.apache.nifi.registry.params.SortParameter;
import org.apache.nifi.registry.security.authorization.Authorizer;
import org.apache.nifi.registry.security.authorization.RequestAction;
+import org.apache.nifi.registry.security.authorization.exception.AccessDeniedException;
import org.apache.nifi.registry.security.authorization.resource.Authorizable;
import org.apache.nifi.registry.security.authorization.user.NiFiUserUtils;
-import org.apache.nifi.registry.bucket.Bucket;
-import org.apache.nifi.registry.bucket.BucketItem;
import org.apache.nifi.registry.service.AuthorizationService;
-import org.apache.nifi.registry.service.RegistryService;
import org.apache.nifi.registry.service.QueryParameters;
-import org.apache.nifi.registry.params.SortParameter;
+import org.apache.nifi.registry.service.RegistryService;
import org.apache.nifi.registry.web.link.LinkService;
-import org.apache.nifi.registry.field.Fields;
-import org.apache.nifi.registry.bucket.Bucket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -55,6 +55,9 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.EnumSet;
import java.util.List;
import java.util.Set;
@@ -101,6 +104,7 @@ public class BucketResource extends AuthorizableApplicationResource {
public Response createBucket(final Bucket bucket) {
authorizeAccess(RequestAction.WRITE);
final Bucket createdBucket = registryService.createBucket(bucket);
+ populateBucketAuthorizedActions(createdBucket, RequestAction.WRITE);
linkService.populateBucketLinks(createdBucket);
return Response.status(Response.Status.OK).entity(createdBucket).build();
}
@@ -122,9 +126,7 @@ public class BucketResource extends AuthorizableApplicationResource {
@ApiParam(value = SortParameter.API_PARAM_DESCRIPTION, format = "field:order", allowMultiple = true, example = "name:ASC")
@QueryParam("sort")
final List<String> sortParameters) {
- authorizeAccess(RequestAction.READ);
-
- final Set<String> authorizedBucketIds = getAuthorizedBucketIds();
+ final Set<String> authorizedBucketIds = getAuthorizedBucketIds(RequestAction.READ);
if (authorizedBucketIds == null || authorizedBucketIds.isEmpty()) {
// not authorized for any bucket, return empty list of items
@@ -137,6 +139,7 @@ public class BucketResource extends AuthorizableApplicationResource {
}
final List<Bucket> buckets = registryService.getBuckets(paramsBuilder.build(), authorizedBucketIds);
+ populateBucketAuthorizedActions(buckets, RequestAction.READ);
linkService.populateBucketLinks(buckets);
return Response.status(Response.Status.OK).entity(buckets).build();
@@ -161,6 +164,7 @@ public class BucketResource extends AuthorizableApplicationResource {
authorizeBucketAccess(RequestAction.READ, bucketId);
final Bucket bucket = registryService.getBucket(bucketId);
+ populateBucketAuthorizedActions(bucket, RequestAction.READ);
linkService.populateBucketLinks(bucket);
if (bucket.getVersionedFlows() != null) {
@@ -206,6 +210,7 @@ public class BucketResource extends AuthorizableApplicationResource {
authorizeBucketAccess(RequestAction.WRITE, bucketId);
final Bucket updatedBucket = registryService.updateBucket(bucket);
+ populateBucketAuthorizedActions(updatedBucket, RequestAction.WRITE);
linkService.populateBucketLinks(updatedBucket);
return Response.status(Response.Status.OK).entity(updatedBucket).build();
}
@@ -250,11 +255,57 @@ public class BucketResource extends AuthorizableApplicationResource {
return Response.status(Response.Status.OK).entity(fields).build();
}
- private void authorizeAccess(RequestAction actionType) {
+ private void authorizeAccess(RequestAction actionType) throws AccessDeniedException {
authorizationService.authorizeAccess(lookup -> {
final Authorizable bucketsAuthorizable = lookup.getBucketsAuthorizable();
bucketsAuthorizable.authorize(authorizer, actionType, NiFiUserUtils.getNiFiUser());
});
}
+ private void populateBucketAuthorizedActions(Collection<Bucket> buckets, RequestAction... knownAuthorizedActions) {
+
+ EnumSet<RequestAction> knownActions = EnumSet.noneOf(RequestAction.class);
+ knownActions.addAll(Arrays.asList(knownAuthorizedActions));
+
+ EnumSet<RequestAction> unknownActions = EnumSet.allOf(RequestAction.class);
+ unknownActions.removeAll(knownActions);
+
+ // if the user has an authorized action on the top-level /buckets resource, that applies to all buckets
+ for (RequestAction action : unknownActions) {
+ try {
+ authorizeAccess(action);
+ knownActions.add(action);
+ } catch (AccessDeniedException e) {
+ // not authorized, do nothing
+ }
+ }
+
+ // now for each bucket, add the known actions and check if the user has additional authorized actions for that bucket
+ for (Bucket bucket : buckets) {
+ populateBucketAuthorizedActions(bucket, knownAuthorizedActions);
+ }
+ }
+
+ private void populateBucketAuthorizedActions(Bucket bucket, RequestAction... knownAuthorizedActions) {
+
+ EnumSet<RequestAction> knownActions = EnumSet.noneOf(RequestAction.class);
+ knownActions.addAll(Arrays.asList(knownAuthorizedActions));
+
+ EnumSet<RequestAction> unknownActions = EnumSet.allOf(RequestAction.class);
+ unknownActions.removeAll(knownActions);
+
+ for (RequestAction action : knownAuthorizedActions) {
+ bucket.addAuthorizedAction(action.toString());
+ }
+
+ for (RequestAction action : unknownActions) {
+ try {
+ authorizeBucketAccess(action, bucket.getIdentifier());
+ bucket.addAuthorizedAction(action.toString());
+ } catch (AccessDeniedException e) {
+ // not authorized, do nothing
+ }
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java
index 8b8a3ed..5702540 100644
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ItemResource.java
@@ -19,15 +19,15 @@ package org.apache.nifi.registry.web.api;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
+import org.apache.nifi.registry.bucket.BucketItem;
+import org.apache.nifi.registry.field.Fields;
+import org.apache.nifi.registry.params.SortParameter;
import org.apache.nifi.registry.security.authorization.Authorizer;
import org.apache.nifi.registry.security.authorization.RequestAction;
-import org.apache.nifi.registry.bucket.BucketItem;
import org.apache.nifi.registry.service.AuthorizationService;
-import org.apache.nifi.registry.service.RegistryService;
import org.apache.nifi.registry.service.QueryParameters;
-import org.apache.nifi.registry.params.SortParameter;
+import org.apache.nifi.registry.service.RegistryService;
import org.apache.nifi.registry.web.link.LinkService;
-import org.apache.nifi.registry.field.Fields;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -89,7 +89,7 @@ public class ItemResource extends AuthorizableApplicationResource {
@QueryParam("sort")
final List<String> sortParameters) {
- Set<String> authorizedBucketIds = getAuthorizedBucketIds();
+ Set<String> authorizedBucketIds = getAuthorizedBucketIds(RequestAction.READ);
if (authorizedBucketIds == null || authorizedBucketIds.isEmpty()) {
// not authorized for any bucket, return empty list of items
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ResourceResource.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ResourceResource.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ResourceResource.java
index d0cb879..119b71f 100644
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ResourceResource.java
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/api/ResourceResource.java
@@ -20,12 +20,12 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
+import org.apache.nifi.registry.model.authorization.Resource;
import org.apache.nifi.registry.security.authorization.Authorizer;
import org.apache.nifi.registry.security.authorization.RequestAction;
import org.apache.nifi.registry.security.authorization.resource.Authorizable;
import org.apache.nifi.registry.security.authorization.user.NiFiUserUtils;
import org.apache.nifi.registry.service.AuthorizationService;
-import org.apache.nifi.registry.model.authorization.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -57,13 +57,6 @@ public class ResourceResource extends AuthorizableApplicationResource {
super(authorizer, authorizationService);
}
- private void authorizeResource() {
- authorizationService.authorizeAccess(lookup -> {
- final Authorizable resource = lookup.getResourcesAuthorizable();
- resource.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
- });
- }
-
/**
* Gets the available resources that support access/authorization policies.
*
@@ -88,4 +81,10 @@ public class ResourceResource extends AuthorizableApplicationResource {
return generateOkResponse(resources).build();
}
+ private void authorizeResource() {
+ authorizationService.authorizeAccess(lookup -> {
+ final Authorizable resource = lookup.getResourcesAuthorizable();
+ resource.authorize(authorizer, RequestAction.READ, NiFiUserUtils.getNiFiUser());
+ });
+ }
}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/NiFiRegistryJsonProvider.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/NiFiRegistryJsonProvider.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/NiFiRegistryJsonProvider.java
new file mode 100644
index 0000000..3d2e4a1
--- /dev/null
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/NiFiRegistryJsonProvider.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.nifi.registry.web.mapper;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
+import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
+import org.springframework.stereotype.Component;
+
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.ext.Provider;
+
+@Component
+@Provider
+@Produces(MediaType.APPLICATION_JSON)
+public class NiFiRegistryJsonProvider extends JacksonJaxbJsonProvider {
+
+ private static final ObjectMapper mapper = new ObjectMapper();
+
+ static {
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ mapper.setPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL));
+ mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(mapper.getTypeFactory()));
+ mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ }
+
+ public NiFiRegistryJsonProvider() {
+ super();
+ setMapper(mapper);
+ }
+}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/ObjectMapperContextResolver.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/ObjectMapperContextResolver.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/ObjectMapperContextResolver.java
deleted file mode 100644
index f5f3ff8..0000000
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/mapper/ObjectMapperContextResolver.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.registry.web.mapper;
-
-import com.fasterxml.jackson.annotation.JsonInclude.Include;
-import com.fasterxml.jackson.annotation.JsonInclude.Value;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
-import org.springframework.stereotype.Component;
-
-import javax.ws.rs.ext.ContextResolver;
-import javax.ws.rs.ext.Provider;
-
-@Component
-@Provider
-public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {
-
- private final ObjectMapper mapper;
-
- public ObjectMapperContextResolver() throws Exception {
- mapper = new ObjectMapper();
- mapper.setPropertyInclusion(Value.construct(Include.NON_NULL, Include.NON_NULL));
- mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(mapper.getTypeFactory()));
- }
-
- @Override
- public ObjectMapper getContext(Class<?> objectType) {
- return mapper;
- }
-}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java
index e0eddba..ce81ee2 100644
--- a/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java
+++ b/nifi-registry-web-api/src/main/java/org/apache/nifi/registry/web/security/NiFiRegistrySecurityConfig.java
@@ -50,8 +50,8 @@ public class NiFiRegistrySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired private NiFiRegistryProperties properties;
- @Autowired X509CertificateExtractor certificateExtractor;
- @Autowired X509PrincipalExtractor principalExtractor;
+ @Autowired private X509CertificateExtractor certificateExtractor;
+ @Autowired private X509PrincipalExtractor principalExtractor;
@Autowired private X509AuthenticationProvider x509AuthenticationProvider;
private X509AuthenticationFilter x509AuthenticationFilter;
@@ -74,7 +74,7 @@ public class NiFiRegistrySecurityConfig extends WebSecurityConfigurerAdapter {
// the /access/download-token endpoints)
webSecurity
.ignoring()
- .antMatchers("/access", "/access/config", "/access/token");
+ .antMatchers( "/access/token");
}
@Override
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java
index 15477f9..40ca558 100644
--- a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java
+++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/BucketsIT.java
@@ -59,16 +59,19 @@ public class BucketsIT extends UnsecuredITBase {
"\"name\":\"Bucket 1\"," +
"\"createdTimestamp\":1505091060000," +
"\"description\":\"This is test bucket 1\"," +
+ "\"authorizedActions\":[\"read\",\"write\",\"delete\"]," +
"\"link\":{\"params\":{\"rel\":\"self\"},\"href\":\"buckets/1\"}}," +
"{\"identifier\":\"2\"," +
"\"name\":\"Bucket 2\"," +
"\"createdTimestamp\":1505091120000," +
"\"description\":\"This is test bucket 2\"," +
+ "\"authorizedActions\":[\"read\",\"write\",\"delete\"]," +
"\"link\":{\"params\":{\"rel\":\"self\"},\"href\":\"buckets/2\"}}," +
"{\"identifier\":\"3\"," +
"\"name\":\"Bucket 3\"," +
"\"createdTimestamp\":1505091180000," +
"\"description\":\"This is test bucket 3\"," +
+ "\"authorizedActions\":[\"read\",\"write\",\"delete\"]," +
"\"link\":{\"params\":{\"rel\":\"self\"},\"href\":\"buckets/3\"}}" +
"]";
@@ -82,6 +85,7 @@ public class BucketsIT extends UnsecuredITBase {
// Then: the pre-populated list of buckets is returned
JSONAssert.assertEquals(expected, bucketsJson, false);
+ assertTrue(!bucketsJson.contains("null")); // JSON serialization from the server should not include null fields, such as "versionedFlows": null
}
@Test
@@ -202,7 +206,8 @@ public class BucketsIT extends UnsecuredITBase {
// Then: the body of the server response matches the bucket that was deleted
// and: the bucket is no longer accessible (resource not found)
- createdBucket.setLink(null); // self URI will not be present in deletedBucket
+ createdBucket.setAuthorizedActions(null); // authorizedActions will not be present in deletedBucket
+ createdBucket.setLink(null); // links will not be present in deletedBucket
assertBucketsEqual(createdBucket, deletedBucket, true);
final Response response = client
@@ -239,6 +244,7 @@ public class BucketsIT extends UnsecuredITBase {
if (checkServerSetFields) {
assertEquals(expected.getIdentifier(), actual.getIdentifier());
assertEquals(expected.getCreatedTimestamp(), actual.getCreatedTimestamp());
+ assertEquals(expected.getAuthorizedActions(), actual.getAuthorizedActions());
assertEquals(expected.getLink(), actual.getLink());
}
}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/IntegrationTestBase.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/IntegrationTestBase.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/IntegrationTestBase.java
index 5b12074..e1d396e 100644
--- a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/IntegrationTestBase.java
+++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/IntegrationTestBase.java
@@ -16,8 +16,14 @@
*/
package org.apache.nifi.registry.web.api;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
+import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
import org.apache.nifi.registry.client.NiFiRegistryClientConfig;
import org.apache.nifi.registry.properties.NiFiRegistryProperties;
+import org.glassfish.jersey.client.ClientConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.embedded.LocalServerPort;
@@ -151,13 +157,17 @@ public abstract class IntegrationTestBase {
private static Client createClientFromConfig(NiFiRegistryClientConfig registryClientConfig) {
- final SSLContext sslContext = registryClientConfig.getSslContext();
- final HostnameVerifier hostnameVerifier = registryClientConfig.getHostnameVerifier();
+ final ClientConfig clientConfig = new ClientConfig();
+ clientConfig.register(jacksonJaxbJsonProvider());
+
+ final ClientBuilder clientBuilder = ClientBuilder.newBuilder().withConfig(clientConfig);
- final ClientBuilder clientBuilder = ClientBuilder.newBuilder();
+ final SSLContext sslContext = registryClientConfig.getSslContext();
if (sslContext != null) {
clientBuilder.sslContext(sslContext);
}
+
+ final HostnameVerifier hostnameVerifier = registryClientConfig.getHostnameVerifier();
if (hostnameVerifier != null) {
clientBuilder.hostnameVerifier(hostnameVerifier);
}
@@ -165,4 +175,17 @@ public abstract class IntegrationTestBase {
return clientBuilder.build();
}
+ private static JacksonJaxbJsonProvider jacksonJaxbJsonProvider() {
+ JacksonJaxbJsonProvider jacksonJaxbJsonProvider = new JacksonJaxbJsonProvider();
+
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setPropertyInclusion(JsonInclude.Value.construct(JsonInclude.Include.NON_NULL, JsonInclude.Include.NON_NULL));
+ mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(mapper.getTypeFactory()));
+ // Ignore unknown properties so that deployed client remain compatible with future versions of NiFi Registry that add new fields
+ mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+ jacksonJaxbJsonProvider.setMapper(mapper);
+ return jacksonJaxbJsonProvider;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/9b41af80/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java
----------------------------------------------------------------------
diff --git a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java
index 5f5af59..d6b94c2 100644
--- a/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java
+++ b/nifi-registry-web-api/src/test/java/org/apache/nifi/registry/web/api/SecureLdapIT.java
@@ -18,7 +18,9 @@ package org.apache.nifi.registry.web.api;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.registry.SecureLdapTestApiApplication;
+import org.apache.nifi.registry.bucket.Bucket;
import org.apache.nifi.registry.extension.ExtensionManager;
+import org.apache.nifi.registry.model.authorization.AccessPolicy;
import org.apache.nifi.registry.model.authorization.Tenant;
import org.apache.nifi.registry.properties.NiFiRegistryProperties;
import org.apache.nifi.registry.security.authorization.Authorizer;
@@ -43,8 +45,13 @@ import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Stream;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
@@ -82,7 +89,7 @@ public class SecureLdapIT extends IntegrationTestBase {
}
- private String authToken;
+ private String adminAuthToken;
@Before
public void generateAuthToken() {
@@ -93,11 +100,11 @@ public class SecureLdapIT extends IntegrationTestBase {
.target(createURL("access/token"))
.request()
.post(Entity.form(form), String.class);
- authToken = token;
+ adminAuthToken = token;
}
@Test
- public void testTokenGeneration() throws Exception {
+ public void testTokenGenerationAndAccessStatus() throws Exception {
// Note: this test intentionally does not use the token generated
// for nifiadmin by the @Before method
@@ -170,7 +177,7 @@ public class SecureLdapIT extends IntegrationTestBase {
final String usersJson = client
.target(createURL("tenants/users"))
.request()
- .header("Authorization", "Bearer " + authToken)
+ .header("Authorization", "Bearer " + adminAuthToken)
.get(String.class);
// Then: the server returns a list of all users (see test-ldap-data.ldif)
@@ -191,14 +198,14 @@ public class SecureLdapIT extends IntegrationTestBase {
final String groupsJson = client
.target(createURL("tenants/user-groups"))
.request()
- .header("Authorization", "Bearer " + authToken)
+ .header("Authorization", "Bearer " + adminAuthToken)
.get(String.class);
// Then: the server returns a list of all users (see test-ldap-data.ldif)
JSONAssert.assertEquals(expectedJson, groupsJson, false);
}
-
+ @Test
public void testCreateTenantFails() throws Exception {
// Given: the server has been configured with the LdapUserGroupProvider, which is non-configurable,
@@ -210,21 +217,169 @@ public class SecureLdapIT extends IntegrationTestBase {
final Response createUserResponse = client
.target(createURL("tenants/users"))
.request()
- .header("Authorization", "Bearer " + authToken)
+ .header("Authorization", "Bearer " + adminAuthToken)
.post(Entity.entity(tenant, MediaType.APPLICATION_JSON_TYPE), Response.class);
// Then: an error is returned
- assertEquals(405, createUserResponse.getStatus());
+ assertEquals(409, createUserResponse.getStatus());
// When: the POST /tenants/users endpoint is accessed
final Response createUserGroupResponse = client
.target(createURL("tenants/user-groups"))
.request()
- .header("Authorization", "Bearer " + authToken)
+ .header("Authorization", "Bearer " + adminAuthToken)
.post(Entity.entity(tenant, MediaType.APPLICATION_JSON_TYPE), Response.class);
// Then: an error is returned because the UserGroupProvider is non-configurable
- assertEquals(405, createUserGroupResponse.getStatus());
+ assertEquals(409, createUserGroupResponse.getStatus());
+ }
+
+ @Test
+ public void testAccessPolicyCreation() throws Exception {
+
+ // Given: the server has been configured with an initial admin "nifiadmin" and a user with no accessPolicies "nobel"
+ String nobelId = getTenantIdentifierByIdentity("nobel");
+ String chemistsId = getTenantIdentifierByIdentity("chemists"); // a group containing user "nobel"
+ final Form form = new Form()
+ .param("username", "nobel")
+ .param("password", "password");
+ final String nobelAuthToken = client
+ .target(createURL("access/token"))
+ .request()
+ .post(Entity.form(form), String.class);
+
+
+ // When: nifiadmin creates a bucket
+ final Bucket bucket = new Bucket();
+ bucket.setName("Integration Test Bucket");
+ bucket.setDescription("A bucket created by an integration test.");
+ Response adminCreatesBucketResponse = client
+ .target(createURL("buckets"))
+ .request()
+ .header("Authorization", "Bearer " + adminAuthToken)
+ .post(Entity.entity(bucket, MediaType.APPLICATION_JSON), Response.class);
+
+ // Then: the server returns a 200 OK
+ assertEquals(200, adminCreatesBucketResponse.getStatus());
+ Bucket createdBucket = adminCreatesBucketResponse.readEntity(Bucket.class);
+
+
+ // When: user nobel initial queries /buckets
+ final Bucket[] buckets1 = client
+ .target(createURL("buckets"))
+ .request()
+ .header("Authorization", "Bearer " + nobelAuthToken)
+ .get(Bucket[].class);
+
+ // Then: an empty list is returned (nobel has no read access yet)
+ assertNotNull(buckets1);
+ assertEquals(0, buckets1.length);
+
+
+ // When: nifiadmin grants read access on createdBucket to 'chemists' a group containing nobel
+ Set<String> policiesToCleanup = new HashSet<>();
+ AccessPolicy readPolicy = new AccessPolicy();
+ readPolicy.setResource("/buckets/" + createdBucket.getIdentifier());
+ readPolicy.setAction("read");
+ readPolicy.addUserGroups(Arrays.asList(new Tenant(chemistsId, "chemists")));
+ Response adminGrantsReadAccessResponse = client
+ .target(createURL("policies"))
+ .request()
+ .header("Authorization", "Bearer " + adminAuthToken)
+ .post(Entity.entity(readPolicy, MediaType.APPLICATION_JSON), Response.class);
+
+ // Then: the server returns a 201 Created
+ assertEquals(201, adminGrantsReadAccessResponse.getStatus());
+ policiesToCleanup.add(adminGrantsReadAccessResponse.readEntity(AccessPolicy.class).getIdentifier());
+
+ try {
+
+ // When: user nobel re-queries /buckets
+ final Bucket[] buckets2 = client
+ .target(createURL("buckets"))
+ .request()
+ .header("Authorization", "Bearer " + nobelAuthToken)
+ .get(Bucket[].class);
+
+ // Then: the created bucket is now present
+ assertNotNull(buckets2);
+ assertEquals(1, buckets2.length);
+ assertEquals(createdBucket.getIdentifier(), buckets2[0].getIdentifier());
+ assertEquals(1, buckets2[0].getAuthorizedActions().size());
+ assertTrue(buckets2[0].getAuthorizedActions().contains("read"));
+
+
+ // When: nifiadmin grants write access on createdBucket to user 'nobel'
+ AccessPolicy writePolicy = new AccessPolicy();
+ writePolicy.setResource("/buckets/" + createdBucket.getIdentifier());
+ writePolicy.setAction("write");
+ writePolicy.addUsers(Arrays.asList(new Tenant(nobelId, "nobel")));
+ Response adminGrantsWriteAccessResponse = client
+ .target(createURL("policies"))
+ .request()
+ .header("Authorization", "Bearer " + adminAuthToken)
+ .post(Entity.entity(writePolicy, MediaType.APPLICATION_JSON), Response.class);
+
+ // Then: the server returns a 201 Created
+ assertEquals(201, adminGrantsWriteAccessResponse.getStatus());
+ policiesToCleanup.add(adminGrantsWriteAccessResponse.readEntity(AccessPolicy.class).getIdentifier());
+
+
+ // When: user nobel re-queries /buckets
+ final Bucket[] buckets3 = client
+ .target(createURL("buckets"))
+ .request()
+ .header("Authorization", "Bearer " + nobelAuthToken)
+ .get(Bucket[].class);
+
+ // Then: the authorizedActions are updated
+ assertNotNull(buckets3);
+ assertEquals(1, buckets3.length);
+ assertEquals(createdBucket.getIdentifier(), buckets3[0].getIdentifier());
+ assertEquals(2, buckets3[0].getAuthorizedActions().size());
+ assertTrue(buckets3[0].getAuthorizedActions().contains("read"));
+ assertTrue(buckets3[0].getAuthorizedActions().contains("write"));
+
+ } finally {
+ // Teardown: delete the policy we made in case other tests assume they are starting with no policies
+ for (String policyId : policiesToCleanup) {
+ Response adminDeletesPolicyResponse = client
+ .target(createURL("policies/" + policyId))
+ .request()
+ .header("Authorization", "Bearer " + adminAuthToken)
+ .delete(Response.class);
+ assertEquals(200, adminDeletesPolicyResponse.getStatus());
+ }
+ }
+
+ }
+
+ /** A helper method to lookup identifiers for tenant identities
+ *
+ * @param tenantIdentity - the identity to lookup
+ * @return A string containing the identifier of the tenant, or null if the tenant identity is not found.
+ */
+ private String getTenantIdentifierByIdentity(String tenantIdentity) {
+
+ final Tenant[] users = client
+ .target(createURL("tenants/users"))
+ .request()
+ .header("Authorization", "Bearer " + adminAuthToken)
+ .get(Tenant[].class);
+
+ final Tenant[] groups = client
+ .target(createURL("tenants/user-groups"))
+ .request()
+ .header("Authorization", "Bearer " + adminAuthToken)
+ .get(Tenant[].class);
+
+
+ final Tenant matchedTenant = Stream.concat(Arrays.stream(users), Arrays.stream(groups))
+ .filter(tenant -> tenant.getIdentity().equalsIgnoreCase(tenantIdentity))
+ .findFirst()
+ .orElse(null);
+
+ return matchedTenant != null ? matchedTenant.getIdentifier() : null;
}
}