NIFI-1552: - Introducing the Authorizer API and additional components necessary for discovery and creation of configured instances. - Minor refactoring of existing Authority Provider API code/configuration to avoid some xsd naming conflicts. These components will be removed in NIFI-1551. - Introducing a number of the resource definitions that the Authorizer will make access decisions on. This list is likely not finalized may see some changes in NIFI-1554. - Address comments from PR. - This closes #318.
Signed-off-by: Matt Gilman <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/nifi/repo Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/9aa69b24 Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/9aa69b24 Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/9aa69b24 Branch: refs/heads/master Commit: 9aa69b242efca4d5103852facacb412e0f0b6022 Parents: 1ac0526 Author: Matt Gilman <[email protected]> Authored: Fri Apr 1 15:13:00 2016 -0400 Committer: Matt Gilman <[email protected]> Committed: Mon Apr 4 11:47:43 2016 -0400 ---------------------------------------------------------------------- .travis.yml | 2 - .../authorization/AuthorizationRequest.java | 132 +++++++ .../nifi/authorization/AuthorizationResult.java | 99 ++++++ .../apache/nifi/authorization/Authorizer.java | 61 ++++ .../AuthorizerConfigurationContext.java | 48 +++ .../AuthorizerInitializationContext.java | 37 ++ .../nifi/authorization/AuthorizerLookup.java | 31 ++ .../nifi/authorization/RequestAction.java | 25 ++ .../org/apache/nifi/authorization/Resource.java | 37 ++ .../annotation/AuthorizerContext.java | 35 ++ .../exception/AuthorizationAccessException.java | 32 ++ .../exception/AuthorizerCreationException.java | 39 +++ .../AuthorizerDestructionException.java | 39 +++ .../AuthorityProviderFactoryBean.java | 45 +-- .../authorization/AuthorizerFactoryBean.java | 343 +++++++++++++++++++ ...rdAuthorityProviderConfigurationContext.java | 5 +- .../StandardAuthorizerConfigurationContext.java | 51 +++ ...StandardAuthorizerInitializationContext.java | 41 +++ .../resources/nifi-administration-context.xml | 11 +- .../src/main/xsd/authority-providers.xsd | 12 +- .../src/main/xsd/authorizers.xsd | 49 +++ .../nifi-framework-authorization/pom.xml | 31 ++ .../authorization/resource/ResourceFactory.java | 272 +++++++++++++++ .../authorization/resource/ResourceType.java | 39 +++ .../nifi-framework/pom.xml | 1 + 25 files changed, 1480 insertions(+), 37 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/.travis.yml ---------------------------------------------------------------------- diff --git a/.travis.yml b/.travis.yml index b5c02d0..811a4c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,6 @@ os: jdk: - oraclejdk8 - - oraclejdk7 - - openjdk7 # before_install aids in a couple workarounds for issues within the Travis-CI environment # 1. Workaround for buffer overflow issues with OpenJDK versions of java as per https://github.com/travis-ci/travis-ci/issues/5227#issuecomment-165135711 http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizationRequest.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizationRequest.java b/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizationRequest.java new file mode 100644 index 0000000..38c9e26 --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizationRequest.java @@ -0,0 +1,132 @@ +/* + * 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.authorization; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * Represents an authorization request for a given user/entity performing an action against a resource within some context. + */ +public class AuthorizationRequest { + + private final Resource resource; + private final String identity; + private final RequestAction action; + private final Map<String, String> context; + private final Map<String, String> eventAttributes; + + private AuthorizationRequest(final Builder builder) { + Objects.requireNonNull(builder.resource, "The resource is required when creating an authorization request"); + Objects.requireNonNull(builder.identity, "The identity of the user is required when creating an authorization request"); + Objects.requireNonNull(builder.action, "The action is required when creating an authorization request"); + + this.resource = builder.resource; + this.identity = builder.identity; + this.action = builder.action; + this.context = Collections.unmodifiableMap(builder.context); + this.eventAttributes = Collections.unmodifiableMap(builder.eventAttributes); + } + + /** + * The Resource being authorized. Not null. + * + * @return The resource + */ + public Resource getResource() { + return resource; + } + + /** + * The identity accessing the Resource. Not null. + * + * @return The identity + */ + public String getIdentity() { + return identity; + } + + /** + * The action being taken against the Resource. Not null. + * + * @return The action + */ + public RequestAction getAction() { + return action; + } + + /** + * The context of the user request to make additional access decisions. May be null. + * + * @return The context of the user request + */ + public Map<String, String> getContext() { + return context; + } + + /** + * The event attributes to make additional access decisions for provenance events. May be null. + * + * @return The event attributes + */ + public Map<String, String> getEventAttributes() { + return eventAttributes; + } + + /** + * AuthorizationRequest builder. + */ + public static final class Builder { + + private Resource resource; + private String identity; + private RequestAction action; + private Map<String, String> context; + private Map<String, String> eventAttributes; + + public Builder resource(final Resource resource) { + this.resource = resource; + return this; + } + + public Builder identity(final String identity) { + this.identity = identity; + return this; + } + + public Builder action(final RequestAction action) { + this.action = action; + return this; + } + + public Builder context(final Map<String, String> context) { + this.context = new HashMap<>(context); + return this; + } + + public Builder eventAttributes(final Map<String, String> eventAttributes) { + this.eventAttributes = new HashMap<>(eventAttributes); + return this; + } + + public AuthorizationRequest build() { + return new AuthorizationRequest(this); + } + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizationResult.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizationResult.java b/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizationResult.java new file mode 100644 index 0000000..acbbbe2 --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizationResult.java @@ -0,0 +1,99 @@ +/* + * 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.authorization; + +/** + * Represents a decision whether authorization is granted. + */ +public class AuthorizationResult { + + private enum Result { + Approved, + Denied, + ResourceNotFound + } + + private static final AuthorizationResult APPROVED = new AuthorizationResult(Result.Approved, null); + private static final AuthorizationResult RESOURCE_NOT_FOUND = new AuthorizationResult(Result.ResourceNotFound, null); + + private final Result result; + private final String explanation; + + /** + * Creates a new AuthorizationResult with the specified result and explanation. + * + * @param result of the authorization + * @param explanation for the authorization attempt + */ + private AuthorizationResult(Result result, String explanation) { + if (Result.Denied.equals(result) && explanation == null) { + throw new IllegalArgumentException("An explanation is required when the authorization request is denied."); + } + + this.result = result; + this.explanation = explanation; + } + + /** + * @return Whether or not the request is approved + */ + public Result getResult() { + return result; + } + + /** + * @return If the request is denied, the reason why. Null otherwise + */ + public String getExplanation() { + return explanation; + } + + /** + * @return a new approved AuthorizationResult + */ + public static AuthorizationResult approved() { + return APPROVED; + } + + /** + * Resource not found will indicate that there are no specific authorization rules for this resource. + * @return a new resource not found AuthorizationResult + */ + public static AuthorizationResult resourceNotFound() { + return RESOURCE_NOT_FOUND; + } + + /** + * Creates a new denied AuthorizationResult with a message indicating 'Access is denied'. + * + * @return a new denied AuthorizationResult + */ + public static AuthorizationResult denied() { + return denied("Access is denied"); + } + + /** + * Creates a new denied AuthorizationResult with the specified explanation. + * + * @param explanation for why it was denied + * @return a new denied AuthorizationResult with the specified explanation + * @throws IllegalArgumentException if explanation is null + */ + public static AuthorizationResult denied(String explanation) { + return new AuthorizationResult(Result.Denied, explanation); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-api/src/main/java/org/apache/nifi/authorization/Authorizer.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/Authorizer.java b/nifi-api/src/main/java/org/apache/nifi/authorization/Authorizer.java new file mode 100644 index 0000000..eb18cf0 --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/Authorizer.java @@ -0,0 +1,61 @@ +/* + * 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.authorization; + +import org.apache.nifi.authorization.exception.AuthorityAccessException; +import org.apache.nifi.authorization.exception.AuthorizationAccessException; +import org.apache.nifi.authorization.exception.AuthorizerCreationException; +import org.apache.nifi.authorization.exception.AuthorizerDestructionException; +import org.apache.nifi.authorization.exception.UnknownIdentityException; + +/** + * Authorizes user requests. + */ +public interface Authorizer { + + /** + * Determines if the specified user/entity is authorized to access the specified resource within the given context. + * + * @param request The authorization request + * @return the authorization result + * @throws AuthorityAccessException if unable to access the authorities + */ + AuthorizationResult authorize(AuthorizationRequest request) throws AuthorizationAccessException; + + /** + * Called immediately after instance creation for implementers to perform additional setup + * + * @param initializationContext in which to initialize + */ + void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException; + + /** + * Called to configure the Authorizer. + * + * @param configurationContext at the time of configuration + * @throws AuthorizerCreationException for any issues configuring the provider + */ + void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException; + + /** + * Called immediately before instance destruction for implementers to release resources. + * + * @throws AuthorizerDestructionException If pre-destruction fails. + */ + void preDestruction() throws AuthorizerDestructionException; + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizerConfigurationContext.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizerConfigurationContext.java b/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizerConfigurationContext.java new file mode 100644 index 0000000..b2b6b3a --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizerConfigurationContext.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.authorization; + +import java.util.Map; + +/** + * + */ +public interface AuthorizerConfigurationContext { + + /** + * @return identifier for the authorizer + */ + String getIdentifier(); + + /** + * Retrieves all properties the component currently understands regardless + * of whether a value has been set for them or not. If no value is present + * then its value is null and thus any registered default for the property + * descriptor applies. + * + * @return Map of all properties + */ + Map<String, String> getProperties(); + + /** + * @param property to lookup the descriptor and value of + * @return the value the component currently understands for the given + * PropertyDescriptor. This method does not substitute default + * PropertyDescriptor values, so the value returned will be null if not set + */ + String getProperty(String property); +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizerInitializationContext.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizerInitializationContext.java b/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizerInitializationContext.java new file mode 100644 index 0000000..4b3d77c --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizerInitializationContext.java @@ -0,0 +1,37 @@ +/* + * 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.authorization; + +/** + * Initialization content for Authorizers. + */ +public interface AuthorizerInitializationContext { + + /** + * The identifier of the Authorizer. + * + * @return The identifier + */ + public String getIdentifier(); + + /** + * The lookup for accessing other configured Authorizers. + * + * @return The Authorizer lookup + */ + public AuthorizerLookup getAuthorizerLookup(); +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizerLookup.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizerLookup.java b/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizerLookup.java new file mode 100644 index 0000000..9669976 --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/AuthorizerLookup.java @@ -0,0 +1,31 @@ +/* + * 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.authorization; + +/** + * + */ +public interface AuthorizerLookup { + + /** + * Looks up the Authorizer with the specified identifier + * + * @param identifier The identifier of the Authorizer + * @return The Authorizer + */ + Authorizer getAuthorizer(String identifier); +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-api/src/main/java/org/apache/nifi/authorization/RequestAction.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/RequestAction.java b/nifi-api/src/main/java/org/apache/nifi/authorization/RequestAction.java new file mode 100644 index 0000000..182988f --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/RequestAction.java @@ -0,0 +1,25 @@ +/* + * 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.authorization; + +/** + * Actions a user/entity can take on a resource. + */ +public enum RequestAction { + READ, + WRITE; +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-api/src/main/java/org/apache/nifi/authorization/Resource.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/Resource.java b/nifi-api/src/main/java/org/apache/nifi/authorization/Resource.java new file mode 100644 index 0000000..7756bda --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/Resource.java @@ -0,0 +1,37 @@ +/* + * 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.authorization; + +/** + * Resource in an authorization request. + */ +public interface Resource { + + /** + * The identifier for this resource. + * + * @return identifier for this resource + */ + String getIdentifier(); + + /** + * The name of this resource. + * + * @return name of this resource + */ + String getName(); +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-api/src/main/java/org/apache/nifi/authorization/annotation/AuthorizerContext.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/annotation/AuthorizerContext.java b/nifi-api/src/main/java/org/apache/nifi/authorization/annotation/AuthorizerContext.java new file mode 100644 index 0000000..b0d3f83 --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/annotation/AuthorizerContext.java @@ -0,0 +1,35 @@ +/* + * 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.authorization.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * + */ +@Documented +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface AuthorizerContext { +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizationAccessException.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizationAccessException.java b/nifi-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizationAccessException.java new file mode 100644 index 0000000..8b22d45 --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizationAccessException.java @@ -0,0 +1,32 @@ +/* + * 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.authorization.exception; + +/** + * Represents the case when an authorization decision could not be made because the Authorizer was unable to access the underlying data store. + */ +public class AuthorizationAccessException extends RuntimeException { + + public AuthorizationAccessException(String message, Throwable cause) { + super(message, cause); + } + + public AuthorizationAccessException(String message) { + super(message); + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerCreationException.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerCreationException.java b/nifi-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerCreationException.java new file mode 100644 index 0000000..4264202 --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerCreationException.java @@ -0,0 +1,39 @@ +/* + * 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.authorization.exception; + +/** + * Represents the exceptional case when an Authorizer fails instantiation. + * + */ +public class AuthorizerCreationException extends RuntimeException { + + public AuthorizerCreationException() { + } + + public AuthorizerCreationException(String msg) { + super(msg); + } + + public AuthorizerCreationException(Throwable cause) { + super(cause); + } + + public AuthorizerCreationException(String msg, Throwable cause) { + super(msg, cause); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerDestructionException.java ---------------------------------------------------------------------- diff --git a/nifi-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerDestructionException.java b/nifi-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerDestructionException.java new file mode 100644 index 0000000..852eca1 --- /dev/null +++ b/nifi-api/src/main/java/org/apache/nifi/authorization/exception/AuthorizerDestructionException.java @@ -0,0 +1,39 @@ +/* + * 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.authorization.exception; + +/** + * Represents the exceptional case when an Authorizer fails destruction. + * + */ +public class AuthorizerDestructionException extends RuntimeException { + + public AuthorizerDestructionException() { + } + + public AuthorizerDestructionException(String msg) { + super(msg); + } + + public AuthorizerDestructionException(Throwable cause) { + super(cause); + } + + public AuthorizerDestructionException(String msg, Throwable cause) { + super(msg, cause); + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorityProviderFactoryBean.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorityProviderFactoryBean.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorityProviderFactoryBean.java index b3e9547..e1a02b8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorityProviderFactoryBean.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorityProviderFactoryBean.java @@ -16,38 +16,19 @@ */ package org.apache.nifi.authorization; -import java.io.File; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.xml.XMLConstants; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBElement; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Unmarshaller; -import javax.xml.transform.stream.StreamSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; +import org.apache.commons.lang3.StringUtils; import org.apache.nifi.authorization.annotation.AuthorityProviderContext; import org.apache.nifi.authorization.exception.AuthorityAccessException; import org.apache.nifi.authorization.exception.IdentityAlreadyExistsException; import org.apache.nifi.authorization.exception.ProviderCreationException; import org.apache.nifi.authorization.exception.ProviderDestructionException; import org.apache.nifi.authorization.exception.UnknownIdentityException; +import org.apache.nifi.authorization.generated.AuthorityProviderProperty; import org.apache.nifi.authorization.generated.AuthorityProviders; -import org.apache.nifi.authorization.generated.Property; import org.apache.nifi.authorization.generated.Provider; import org.apache.nifi.nar.ExtensionManager; import org.apache.nifi.nar.NarCloseable; import org.apache.nifi.util.NiFiProperties; -import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; @@ -57,6 +38,26 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.xml.sax.SAXException; +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + /** * Factory bean for loading the configured authority provider. */ @@ -196,7 +197,7 @@ public class AuthorityProviderFactoryBean implements FactoryBean, ApplicationCon private AuthorityProviderConfigurationContext loadAuthorityProviderConfiguration(final Provider provider) { final Map<String, String> providerProperties = new HashMap<>(); - for (final Property property : provider.getProperty()) { + for (final AuthorityProviderProperty property : provider.getProperty()) { providerProperties.put(property.getName(), property.getValue()); } http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java new file mode 100644 index 0000000..58caea9 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java @@ -0,0 +1,343 @@ +/* + * 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.authorization; + +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.authorization.annotation.AuthorizerContext; +import org.apache.nifi.authorization.exception.AuthorizationAccessException; +import org.apache.nifi.authorization.exception.AuthorizerCreationException; +import org.apache.nifi.authorization.exception.AuthorizerDestructionException; +import org.apache.nifi.authorization.generated.AuthorityProviders; +import org.apache.nifi.authorization.generated.Authorizers; +import org.apache.nifi.authorization.generated.Property; +import org.apache.nifi.nar.ExtensionManager; +import org.apache.nifi.nar.NarCloseable; +import org.apache.nifi.util.NiFiProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.FactoryBean; +import org.xml.sax.SAXException; + +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Unmarshaller; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import java.io.File; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +/** + * Factory bean for loading the configured authorizer. + */ +public class AuthorizerFactoryBean implements FactoryBean, DisposableBean, AuthorizerLookup { + + private static final Logger logger = LoggerFactory.getLogger(AuthorizerFactoryBean.class); + private static final String AUTHORIZERS_XSD = "/authorizers.xsd"; + private static final String JAXB_GENERATED_PATH = "org.apache.nifi.authorization.generated"; + private static final JAXBContext JAXB_CONTEXT = initializeJaxbContext(); + + /** + * Load the JAXBContext. + */ + private static JAXBContext initializeJaxbContext() { + try { + return JAXBContext.newInstance(JAXB_GENERATED_PATH, AuthorizerFactoryBean.class.getClassLoader()); + } catch (JAXBException e) { + throw new RuntimeException("Unable to create JAXBContext."); + } + } + + private Authorizer authorizer; + private NiFiProperties properties; + private final Map<String, Authorizer> authorizers = new HashMap<>(); + + @Override + public Authorizer getAuthorizer(String identifier) { + return authorizers.get(identifier); + } + + @Override + public Object getObject() throws Exception { + if (authorizer == null) { + // look up the authorizer to use + final String authorizerIdentifier = properties.getProperty(NiFiProperties.SECURITY_USER_AUTHORITY_PROVIDER); + + // ensure the authorizer class name was specified + if (StringUtils.isBlank(authorizerIdentifier)) { + // if configured for ssl, the authorizer must be specified + if (properties.getSslPort() != null) { + throw new Exception("When running securely, the authorizer identifier must be specified in the nifi properties file."); + } + + // use a default authorizer... only allowable when running not securely + authorizer = createDefaultAuthorizer(); + } else { + final Authorizers authorizerConfiguration = loadAuthorizersConfiguration(); + + // create each authorizer + for (final org.apache.nifi.authorization.generated.Authorizer authorizer : authorizerConfiguration.getAuthorizer()) { + authorizers.put(authorizer.getIdentifier(), createAuthorizer(authorizer.getIdentifier(), authorizer.getClazz())); + } + + // configure each authorizer + for (final org.apache.nifi.authorization.generated.Authorizer provider : authorizerConfiguration.getAuthorizer()) { + final Authorizer instance = authorizers.get(provider.getIdentifier()); + instance.onConfigured(loadAuthorizerConfiguration(provider)); + } + + // get the authorizer instance + authorizer = getAuthorizer(authorizerIdentifier); + + // ensure it was found + if (authorizer == null) { + throw new Exception(String.format("The specified authorizer '%s' could not be found.", authorizerIdentifier)); + } + } + } + + return authorizer; + } + + private Authorizers loadAuthorizersConfiguration() throws Exception { + final File authorizersConfigurationFile = properties.getAuthorityProviderConfiguraitonFile(); + + // load the authorizers from the specified file + if (authorizersConfigurationFile.exists()) { + try { + // find the schema + final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + final Schema schema = schemaFactory.newSchema(AuthorityProviders.class.getResource(AUTHORIZERS_XSD)); + + // attempt to unmarshal + final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller(); + unmarshaller.setSchema(schema); + final JAXBElement<Authorizers> element = unmarshaller.unmarshal(new StreamSource(authorizersConfigurationFile), Authorizers.class); + return element.getValue(); + } catch (SAXException | JAXBException e) { + throw new Exception("Unable to load the authorizer configuration file at: " + authorizersConfigurationFile.getAbsolutePath()); + } + } else { + throw new Exception("Unable to find the authorizer configuration file at " + authorizersConfigurationFile.getAbsolutePath()); + } + } + + private Authorizer createAuthorizer(final String identifier, final String authorizerClassName) throws Exception { + // get the classloader for the specified authorizer + final ClassLoader authorizerClassLoader = ExtensionManager.getClassLoader(authorizerClassName); + if (authorizerClassLoader == null) { + throw new Exception(String.format("The specified authorizer class '%s' is not known to this nifi.", authorizerClassName)); + } + + // get the current context classloader + final ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader(); + + final Authorizer instance; + try { + // set the appropriate class loader + Thread.currentThread().setContextClassLoader(authorizerClassLoader); + + // attempt to load the class + Class<?> rawAuthorizerClass = Class.forName(authorizerClassName, true, authorizerClassLoader); + Class<? extends Authorizer> authorizerClass = rawAuthorizerClass.asSubclass(Authorizer.class); + + // otherwise create a new instance + Constructor constructor = authorizerClass.getConstructor(); + instance = (Authorizer) constructor.newInstance(); + + // method injection + performMethodInjection(instance, authorizerClass); + + // field injection + performFieldInjection(instance, authorizerClass); + + // call post construction lifecycle event + instance.initialize(new StandardAuthorizerInitializationContext(identifier, this)); + } finally { + if (currentClassLoader != null) { + Thread.currentThread().setContextClassLoader(currentClassLoader); + } + } + + return withNarLoader(instance); + } + + private AuthorizerConfigurationContext loadAuthorizerConfiguration(final org.apache.nifi.authorization.generated.Authorizer authorizer) { + final Map<String, String> authorizerProperties = new HashMap<>(); + + for (final Property property : authorizer.getProperty()) { + authorizerProperties.put(property.getName(), property.getValue()); + } + + return new StandardAuthorizerConfigurationContext(authorizer.getIdentifier(), authorizerProperties); + } + + private void performMethodInjection(final Authorizer instance, final Class authorizerClass) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { + for (final Method method : authorizerClass.getMethods()) { + if (method.isAnnotationPresent(AuthorizerContext.class)) { + // make the method accessible + final boolean isAccessible = method.isAccessible(); + method.setAccessible(true); + + try { + final Class<?>[] argumentTypes = method.getParameterTypes(); + + // look for setters (single argument) + if (argumentTypes.length == 1) { + final Class<?> argumentType = argumentTypes[0]; + + // look for well known types + if (NiFiProperties.class.isAssignableFrom(argumentType)) { + // nifi properties injection + method.invoke(instance, properties); + } + } + } finally { + method.setAccessible(isAccessible); + } + } + } + + final Class parentClass = authorizerClass.getSuperclass(); + if (parentClass != null && AuthorityProvider.class.isAssignableFrom(parentClass)) { + performMethodInjection(instance, parentClass); + } + } + + private void performFieldInjection(final Authorizer instance, final Class authorizerClass) throws IllegalArgumentException, IllegalAccessException { + for (final Field field : authorizerClass.getDeclaredFields()) { + if (field.isAnnotationPresent(AuthorizerContext.class)) { + // make the method accessible + final boolean isAccessible = field.isAccessible(); + field.setAccessible(true); + + try { + // get the type + final Class<?> fieldType = field.getType(); + + // only consider this field if it isn't set yet + if (field.get(instance) == null) { + // look for well known types + if (NiFiProperties.class.isAssignableFrom(fieldType)) { + // nifi properties injection + field.set(instance, properties); + } + } + + } finally { + field.setAccessible(isAccessible); + } + } + } + + final Class parentClass = authorizerClass.getSuperclass(); + if (parentClass != null && AuthorityProvider.class.isAssignableFrom(parentClass)) { + performFieldInjection(instance, parentClass); + } + } + + /** + * @return a default Authorizer to use when running unsecurely with no authorizer configured + */ + private Authorizer createDefaultAuthorizer() { + return new Authorizer() { + @Override + public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException { + return AuthorizationResult.approved(); + } + + @Override + public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException { + } + + @Override + public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException { + } + + @Override + public void preDestruction() throws AuthorizerDestructionException { + } + }; + } + + /** + * Decorates the base authorizer to ensure the nar context classloader is used when invoking the underlying methods. + * + * @param baseAuthorizer base authorizer + * @return authorizer + */ + public Authorizer withNarLoader(final Authorizer baseAuthorizer) { + return new Authorizer() { + @Override + public AuthorizationResult authorize(final AuthorizationRequest request) throws AuthorizationAccessException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + return baseAuthorizer.authorize(request); + } + } + + @Override + public void initialize(AuthorizerInitializationContext initializationContext) throws AuthorizerCreationException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseAuthorizer.initialize(initializationContext); + } + } + + @Override + public void onConfigured(AuthorizerConfigurationContext configurationContext) throws AuthorizerCreationException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseAuthorizer.onConfigured(configurationContext); + } + } + + @Override + public void preDestruction() throws AuthorizerDestructionException { + try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) { + baseAuthorizer.preDestruction(); + } + } + }; + } + + @Override + public Class getObjectType() { + return Authorizer.class; + } + + @Override + public boolean isSingleton() { + return true; + } + + @Override + public void destroy() throws Exception { + if (authorizer != null) { + authorizer.preDestruction(); + } + } + + public void setProperties(NiFiProperties properties) { + this.properties = properties; + } +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorityProviderConfigurationContext.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorityProviderConfigurationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorityProviderConfigurationContext.java index 0535e27..45b84c8 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorityProviderConfigurationContext.java +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorityProviderConfigurationContext.java @@ -17,6 +17,7 @@ package org.apache.nifi.authorization; import java.util.Collections; +import java.util.HashMap; import java.util.Map; /** @@ -29,7 +30,7 @@ public class StandardAuthorityProviderConfigurationContext implements AuthorityP public StandardAuthorityProviderConfigurationContext(String identifier, Map<String, String> properties) { this.identifier = identifier; - this.properties = properties; + this.properties = Collections.unmodifiableMap(new HashMap<String, String>(properties)); } @Override @@ -39,7 +40,7 @@ public class StandardAuthorityProviderConfigurationContext implements AuthorityP @Override public Map<String, String> getProperties() { - return Collections.unmodifiableMap(properties); + return properties; } @Override http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerConfigurationContext.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerConfigurationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerConfigurationContext.java new file mode 100644 index 0000000..946da96 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerConfigurationContext.java @@ -0,0 +1,51 @@ +/* + * 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.authorization; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +public class StandardAuthorizerConfigurationContext implements AuthorizerConfigurationContext { + + private final String identifier; + private final Map<String, String> properties; + + public StandardAuthorizerConfigurationContext(String identifier, Map<String, String> properties) { + this.identifier = identifier; + this.properties = Collections.unmodifiableMap(new HashMap<String, String>(properties)); + } + + @Override + public String getIdentifier() { + return identifier; + } + + @Override + public Map<String, String> getProperties() { + return properties; + } + + @Override + public String getProperty(String property) { + return properties.get(property); + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerInitializationContext.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerInitializationContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerInitializationContext.java new file mode 100644 index 0000000..344f49c --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/java/org/apache/nifi/authorization/StandardAuthorizerInitializationContext.java @@ -0,0 +1,41 @@ +/* + * 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.authorization; + +/** + * + */ +public class StandardAuthorizerInitializationContext implements AuthorizerInitializationContext { + + private final String identifier; + private final AuthorizerLookup authorizerLookup; + + public StandardAuthorizerInitializationContext(String identifier, AuthorizerLookup authorizerLookup) { + this.identifier = identifier; + this.authorizerLookup = authorizerLookup; + } + + @Override + public String getIdentifier() { + return identifier; + } + + public AuthorizerLookup getAuthorizerLookup() { + return authorizerLookup; + } + +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml index 1423cbe..3a46314 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/resources/nifi-administration-context.xml @@ -16,17 +16,18 @@ <beans default-lazy-init="true" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xmlns:context="http://www.springframework.org/schema/context" - xmlns:aop="http://www.springframework.org/schema/aop" - xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd - http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd - http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd"> + xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <!-- user authority provider --> <bean id="authorityProvider" class="org.apache.nifi.authorization.AuthorityProviderFactoryBean" depends-on="clusterManager"> <property name="properties" ref="nifiProperties"/> </bean> + <!-- user/entity authorizer --> + <bean id="authorizer" class="org.apache.nifi.authorization.AuthorizerFactoryBean" depends-on="clusterManager"> + <property name="properties" ref="nifiProperties"/> + </bean> + <!-- initialize the user data source --> <bean id="userDataSource" class="org.apache.nifi.admin.UserDataSourceFactoryBean" destroy-method="shutdown"> <property name="properties" ref="nifiProperties"/> http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authority-providers.xsd ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authority-providers.xsd b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authority-providers.xsd index 122fa2c..1a5fe50 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authority-providers.xsd +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authority-providers.xsd @@ -17,22 +17,22 @@ <!-- role --> <xs:complexType name="Provider"> <xs:sequence> - <xs:element name="identifier" type="NonEmptyStringType"/> - <xs:element name="class" type="NonEmptyStringType"/> - <xs:element name="property" type="Property" minOccurs="0" maxOccurs="unbounded" /> + <xs:element name="identifier" type="AuthorityProviderNonEmptyStringType"/> + <xs:element name="class" type="AuthorityProviderNonEmptyStringType"/> + <xs:element name="property" type="AuthorityProviderProperty" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> <!-- Name/Value properties--> - <xs:complexType name="Property"> + <xs:complexType name="AuthorityProviderProperty"> <xs:simpleContent> <xs:extension base="xs:string"> - <xs:attribute name="name" type="NonEmptyStringType"></xs:attribute> + <xs:attribute name="name" type="AuthorityProviderNonEmptyStringType"></xs:attribute> </xs:extension> </xs:simpleContent> </xs:complexType> - <xs:simpleType name="NonEmptyStringType"> + <xs:simpleType name="AuthorityProviderNonEmptyStringType"> <xs:restriction base="xs:string"> <xs:minLength value="1"/> </xs:restriction> http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authorizers.xsd ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authorizers.xsd b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authorizers.xsd new file mode 100644 index 0000000..4b68b00 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-administration/src/main/xsd/authorizers.xsd @@ -0,0 +1,49 @@ +<?xml version="1.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. +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <!-- role --> + <xs:complexType name="Authorizer"> + <xs:sequence> + <xs:element name="identifier" type="NonEmptyStringType"/> + <xs:element name="class" type="NonEmptyStringType"/> + <xs:element name="property" type="Property" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + </xs:complexType> + + <!-- Name/Value properties--> + <xs:complexType name="Property"> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="name" type="NonEmptyStringType"></xs:attribute> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + + <xs:simpleType name="NonEmptyStringType"> + <xs:restriction base="xs:string"> + <xs:minLength value="1"/> + </xs:restriction> + </xs:simpleType> + + <!-- users --> + <xs:element name="authorizers"> + <xs:complexType> + <xs:sequence> + <xs:element name="authorizer" type="Authorizer" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + </xs:complexType> + </xs:element> +</xs:schema> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml new file mode 100644 index 0000000..8532ec5 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/pom.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-framework</artifactId> + <version>1.0.0-SNAPSHOT</version> + </parent> + <artifactId>nifi-framework-authorization</artifactId> + + <dependencies> + <dependency> + <groupId>org.apache.nifi</groupId> + <artifactId>nifi-api</artifactId> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java new file mode 100644 index 0000000..a641810 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceFactory.java @@ -0,0 +1,272 @@ +/* + * 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.authorization.resource; + +import org.apache.nifi.authorization.Resource; + +import java.util.Objects; + +public final class ResourceFactory { + + private final static Resource FLOW_RESOURCE = new Resource() { + @Override + public String getIdentifier() { + return "/flow"; + } + + @Override + public String getName() { + return "NiFi Flow"; + } + }; + + private final static Resource RESOURCE_RESOURCE = new Resource() { + @Override + public String getIdentifier() { + return "/resources"; + } + + @Override + public String getName() { + return "NiFi Resources"; + } + }; + + private final static Resource SYSTEM_RESOURCE = new Resource() { + @Override + public String getIdentifier() { + return "/system"; + } + + @Override + public String getName() { + return "System"; + } + }; + + private final static Resource CONTROLLER_RESOURCE = new Resource() { + @Override + public String getIdentifier() { + return "/controller"; + } + + @Override + public String getName() { + return "Controller"; + } + }; + + private final static Resource PROVENANCE_RESOURCE = new Resource() { + @Override + public String getIdentifier() { + return "/provenance"; + } + + @Override + public String getName() { + return "Provenance"; + } + }; + + private final static Resource TOKEN_RESOURCE = new Resource() { + @Override + public String getIdentifier() { + return "/token"; + } + + @Override + public String getName() { + return "API access token"; + } + }; + + private final static Resource SITE_TO_SITE_RESOURCE = new Resource() { + @Override + public String getIdentifier() { + return "/site-to-site"; + } + + @Override + public String getName() { + return "Site to Site"; + } + }; + + private final static Resource PROXY_RESOURCE = new Resource() { + @Override + public String getIdentifier() { + return "/proxy"; + } + + @Override + public String getName() { + return "Proxy User Requests"; + } + }; + + /** + * Gets the Resource for accessing the NiFi flow. This includes the data flow structure, component status, search results, and banner/about text. + * + * @return The NiFi resource + */ + public static Resource getFlowResource() { + return FLOW_RESOURCE; + } + + /** + * Gets the Resource for detailing all available NiFi Resources. + * + * @return The Resource resource + */ + public static Resource getResourceResource() { + return RESOURCE_RESOURCE; + } + + /** + * Gets the Resource for accessing details of the System NiFi is running on. + * + * @return The System resource + */ + public static Resource getSystemResource() { + return SYSTEM_RESOURCE; + } + + /** + * Gets the Resource for accessing the Controller. This includes Controller level configuration, bulletins, reporting tasks, and the cluster. + * + * @return The resource for accessing the Controller + */ + public static Resource getControllerResource() { + return CONTROLLER_RESOURCE; + } + + /** + * Gets the Resource for accessing provenance. Access to this Resource allows the user to access data provenance. However, additional authorization + * is required based on the component that generated the event and the attributes of the event. + * + * @return The provenance resource + */ + public static Resource getProvenanceResource() { + return PROVENANCE_RESOURCE; + } + + /** + * Gets the Resource for creating API access tokens. + * + * @return The token request resource + */ + public static Resource getTokenResource() { + return TOKEN_RESOURCE; + } + + /** + * Gets the Resource for obtaining site to site details. This will allow other NiFi instances to obtain necessary configuration to initiate a + * site to site data transfer. + * + * @return The resource for obtaining site to site details + */ + public static Resource getSiteToSiteResource() { + return SITE_TO_SITE_RESOURCE; + } + + /** + * Gets the Resource for proxying a user request. + * + * @return The resource for proxying a user request + */ + public static Resource getProxyResource() { + return PROXY_RESOURCE; + } + + /** + * Gets a Resource for accessing a component configuration. + * + * @param resourceType The type of resource being accessed + * @param identifier The identifier of the component being accessed + * @param name The name of the component being accessed + * @return The resource + */ + public static Resource getComponentResource(final ResourceType resourceType, final String identifier, final String name) { + Objects.requireNonNull(resourceType, "The resource must be specified."); + Objects.requireNonNull(identifier, "The component identifier must be specified."); + Objects.requireNonNull(name, "The component name must be specified."); + + return new Resource() { + @Override + public String getIdentifier() { + return String.format("%s/%s", resourceType.getValue(), identifier); + } + + @Override + public String getName() { + return name; + } + }; + } + + /** + * Gets a Resource for accessing a component's provenance events. + * + * @param resourceType The type of resource being accessed + * @param identifier The identifier of the component being accessed + * @param name The name of the component being accessed + * @return The resource + */ + public static Resource getComponentProvenanceResource(final ResourceType resourceType, final String identifier, final String name) { + final Resource componentResource = getComponentResource(resourceType, identifier, name); + return new Resource() { + @Override + public String getIdentifier() { + return String.format("%s/%s", componentResource.getIdentifier(), "provenance"); + } + + @Override + public String getName() { + return componentResource.getName() + " provenance"; + } + }; + } + + /** + * Gets a Resource fo accessing a flowfile queue for the specified connection. + * + * @param connectionIdentifier The identifier of the connection + * @param connectionName The name of the connection + * @return The resource + */ + public static Resource getFlowFileQueueResource(final String connectionIdentifier, final String connectionName) { + Objects.requireNonNull(connectionIdentifier, "The connection identifier must be specified."); + Objects.requireNonNull(connectionName, "The connection name must be specified."); + + return new Resource() { + @Override + public String getIdentifier() { + return String.format("/flowfile-queue/%s", connectionIdentifier); + } + + @Override + public String getName() { + return connectionName + " queue"; + } + }; + } + + /** + * Prevent outside instantiation. + */ + private ResourceFactory() {} +} http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java new file mode 100644 index 0000000..5e122ec --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization/src/main/java/org/apache/nifi/authorization/resource/ResourceType.java @@ -0,0 +1,39 @@ +/* + * 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.authorization.resource; + +public enum ResourceType { + Processor("/processors"), + InputPort("/input-ports"), + OutputPort("/output-ports"), + Connection("/connections"), + ProcessGroup("/process-groups"), + RemoteProcessGroup("/remote-process-groups"), + Label("/labels"), + ControllerService("/controller-services"), + Template("/templates"); + + final String value; + + private ResourceType(final String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi/blob/9aa69b24/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/pom.xml ---------------------------------------------------------------------- diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/pom.xml index e04d04d..7faf517 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/pom.xml @@ -36,6 +36,7 @@ <module>nifi-file-authorization-provider</module> <module>nifi-cluster-authorization-provider</module> <module>nifi-user-actions</module> + <module>nifi-framework-authorization</module> <module>nifi-administration</module> <module>nifi-web</module> <module>nifi-resources</module>
