mirror of https://github.com/apache/nifi.git
NIFI-655:
- Removing registration support. - Removing file based implementation.
This commit is contained in:
parent
efa1939fc5
commit
f250560474
|
@ -17,7 +17,6 @@
|
|||
package org.apache.nifi.authentication;
|
||||
|
||||
import org.apache.nifi.authentication.exception.IdentityAccessException;
|
||||
import org.apache.nifi.authorization.exception.IdentityAlreadyExistsException;
|
||||
import org.apache.nifi.authorization.exception.ProviderCreationException;
|
||||
import org.apache.nifi.authorization.exception.ProviderDestructionException;
|
||||
|
||||
|
@ -26,25 +25,12 @@ import org.apache.nifi.authorization.exception.ProviderDestructionException;
|
|||
*/
|
||||
public interface LoginIdentityProvider {
|
||||
|
||||
/**
|
||||
* Returns whether this provider supports user registration.
|
||||
*
|
||||
* @return whether user registration is supported
|
||||
*/
|
||||
boolean supportsRegistration();
|
||||
|
||||
/**
|
||||
* Invoked to register the user with the specified login credentials.
|
||||
*
|
||||
* @param credentials the login credentials
|
||||
*/
|
||||
void register(LoginCredentials credentials) throws IdentityAlreadyExistsException, IdentityAccessException;
|
||||
|
||||
/**
|
||||
* Authenticates the specified login credentials.
|
||||
*
|
||||
* @param credentials the credentials
|
||||
* @return whether the user was authenticated
|
||||
* @return was able to check the user credentials and returns whether the user was authenticated
|
||||
* @throws IdentityAccessException Unable to register the user due to an issue accessing the underlying storage
|
||||
*/
|
||||
boolean authenticate(LoginCredentials credentials) throws IdentityAccessException;
|
||||
|
||||
|
@ -52,6 +38,7 @@ public interface LoginIdentityProvider {
|
|||
* Called immediately after instance creation for implementers to perform additional setup
|
||||
*
|
||||
* @param initializationContext in which to initialize
|
||||
* @throws ProviderCreationException Unable to initialize
|
||||
*/
|
||||
void initialize(LoginIdentityProviderInitializationContext initializationContext) throws ProviderCreationException;
|
||||
|
||||
|
|
|
@ -1,33 +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.authentication.exception;
|
||||
|
||||
/**
|
||||
* Represents the case when the identity could not be registered for some reason.
|
||||
* Like the credentials did not meet the minimum requirements
|
||||
*/
|
||||
public class IdentityRegistrationException extends RuntimeException {
|
||||
|
||||
public IdentityRegistrationException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public IdentityRegistrationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
|
@ -35,10 +35,6 @@
|
|||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-file-authorization-provider</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-file-identity-provider</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- mark these nifi artifacts as provided since it is included in the lib -->
|
||||
<dependency>
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
<?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>0.3.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>nifi-authorized-users</artifactId>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/xsd</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>jaxb2-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>xjc</id>
|
||||
<goals>
|
||||
<goal>xjc</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<packageName>org.apache.nifi.user.generated</packageName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<generateDirectory>${project.build.directory}/generated-sources/jaxb</generateDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>**/user/generated/*.java</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-properties</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-utils</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -1,445 +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.authorized.users;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
import org.apache.nifi.authorization.exception.AuthorityAccessException;
|
||||
import org.apache.nifi.authorization.exception.ProviderCreationException;
|
||||
import org.apache.nifi.authorization.exception.UnknownIdentityException;
|
||||
import org.apache.nifi.user.generated.LoginUser;
|
||||
import org.apache.nifi.user.generated.NiFiUser;
|
||||
import org.apache.nifi.user.generated.User;
|
||||
import org.apache.nifi.user.generated.Users;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.nifi.util.file.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Access to the configured Authorized Users.
|
||||
*/
|
||||
public final class AuthorizedUsers {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AuthorizedUsers.class);
|
||||
|
||||
private static final String USERS_XSD = "/users.xsd";
|
||||
private static final String JAXB_GENERATED_PATH = "org.apache.nifi.user.generated";
|
||||
private static final JAXBContext JAXB_CONTEXT = initializeJaxbContext();
|
||||
|
||||
private static final Map<String, AuthorizedUsers> instances = new HashMap<>();
|
||||
|
||||
private File usersFile;
|
||||
private File restoreFile;
|
||||
|
||||
/**
|
||||
* Load the JAXBContext.
|
||||
*/
|
||||
private static JAXBContext initializeJaxbContext() {
|
||||
try {
|
||||
return JAXBContext.newInstance(JAXB_GENERATED_PATH, AuthorizedUsers.class.getClassLoader());
|
||||
} catch (JAXBException e) {
|
||||
throw new RuntimeException("Unable to create JAXBContext.");
|
||||
}
|
||||
}
|
||||
|
||||
private AuthorizedUsers(final File usersFile, final NiFiProperties properties) throws IOException, IllegalStateException {
|
||||
this.usersFile = usersFile;
|
||||
|
||||
// the restore directory is optional and may be null
|
||||
final File restoreDirectory = properties.getRestoreDirectory();
|
||||
if (restoreDirectory != null) {
|
||||
|
||||
// sanity check that restore directory is a directory, creating it if necessary
|
||||
FileUtils.ensureDirectoryExistAndCanAccess(restoreDirectory);
|
||||
|
||||
// check that restore directory is not the same as the primary directory
|
||||
final File usersFileDirectory = usersFile.getParentFile();
|
||||
if (usersFileDirectory.getAbsolutePath().equals(restoreDirectory.getAbsolutePath())) {
|
||||
throw new IllegalStateException(String.format("Directory of users file '%s' is the same as restore directory '%s' ",
|
||||
usersFileDirectory.getAbsolutePath(), restoreDirectory.getAbsolutePath()));
|
||||
}
|
||||
|
||||
// the restore copy will have same file name, but reside in a different directory
|
||||
restoreFile = new File(restoreDirectory, usersFile.getName());
|
||||
|
||||
// sync the primary copy with the restore copy
|
||||
try {
|
||||
FileUtils.syncWithRestore(usersFile, restoreFile, logger);
|
||||
} catch (final IOException | IllegalStateException ioe) {
|
||||
throw new ProviderCreationException(ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static AuthorizedUsers getInstance(final String usersFilePath, final NiFiProperties properties) throws IOException, IllegalStateException {
|
||||
final File usersFile = new File(usersFilePath);
|
||||
|
||||
// see if an authorizedUsers has already been created using this filename
|
||||
AuthorizedUsers authorizedUsers = instances.get(usersFile.getName());
|
||||
|
||||
if (authorizedUsers == null) {
|
||||
// create a new authorizedUsers
|
||||
authorizedUsers = new AuthorizedUsers(usersFile, properties);
|
||||
|
||||
// store it for later
|
||||
instances.put(usersFile.getName(), authorizedUsers);
|
||||
} else {
|
||||
// ensure the file paths are the same, the restore capability cannot support different files with the same name
|
||||
if (!authorizedUsers.usersFile.equals(usersFile)) {
|
||||
throw new IllegalStateException(String.format("A users file with this name has already been initialized. The name must be unique given the constraints of "
|
||||
+ "the restore directory. The paths in question are '%s' and '%s'", authorizedUsers.usersFile.getAbsolutePath(), usersFile.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
|
||||
return authorizedUsers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the user identity.
|
||||
*
|
||||
* @param user The user
|
||||
* @return The user identity
|
||||
*/
|
||||
public String getUserIdentity(final NiFiUser user) {
|
||||
if (user instanceof User) {
|
||||
return ((User) user).getDn();
|
||||
} else {
|
||||
return ((LoginUser) user).getUsername();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all users from configured file.
|
||||
*
|
||||
* @return The Users
|
||||
*/
|
||||
public synchronized Users getUsers() {
|
||||
try {
|
||||
// ensure the directory exists and it can be created
|
||||
if (!usersFile.exists() && !usersFile.mkdirs()) {
|
||||
throw new IllegalStateException("The users file does not exist and could not be created.");
|
||||
}
|
||||
|
||||
// find the schema
|
||||
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||
final Schema schema = schemaFactory.newSchema(AuthorizedUsers.class.getResource(USERS_XSD));
|
||||
|
||||
// attempt to unmarshal
|
||||
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
|
||||
unmarshaller.setSchema(schema);
|
||||
final JAXBElement<Users> element = unmarshaller.unmarshal(new StreamSource(usersFile), Users.class);
|
||||
return element.getValue();
|
||||
} catch (SAXException | JAXBException e) {
|
||||
throw new AuthorityAccessException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a user exists through the specified HasUser.
|
||||
*
|
||||
* @param finder The finder
|
||||
* @return Whether the user exists
|
||||
*/
|
||||
public synchronized boolean hasUser(final HasUser finder) {
|
||||
// load the users
|
||||
final Users users = getUsers();
|
||||
|
||||
// combine the user lists
|
||||
final List<NiFiUser> nifiUsers = new ArrayList<>();
|
||||
nifiUsers.addAll(users.getUser());
|
||||
nifiUsers.addAll(users.getLoginUser());
|
||||
|
||||
// find the desired user
|
||||
return finder.hasUser(nifiUsers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the desired user.
|
||||
*
|
||||
* @param finder The finder
|
||||
* @return The NiFiUser
|
||||
* @throws UnknownIdentityException If the desired user could not be found
|
||||
*/
|
||||
public synchronized NiFiUser getUser(final FindUser finder) {
|
||||
// load the users
|
||||
final Users users = getUsers();
|
||||
|
||||
// combine the user lists
|
||||
final List<NiFiUser> nifiUsers = new ArrayList<>();
|
||||
nifiUsers.addAll(users.getUser());
|
||||
nifiUsers.addAll(users.getLoginUser());
|
||||
|
||||
// find the desired user
|
||||
return finder.findUser(nifiUsers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the desired users.
|
||||
*
|
||||
* @param finder The finder
|
||||
* @return The NiFiUsers
|
||||
* @throws UnknownIdentityException If the users could not be found
|
||||
*/
|
||||
public synchronized List<NiFiUser> getUsers(final FindUsers finder) {
|
||||
// load the users
|
||||
final Users users = getUsers();
|
||||
|
||||
// combine the user lists
|
||||
final List<NiFiUser> nifiUsers = new ArrayList<>();
|
||||
nifiUsers.addAll(users.getUser());
|
||||
nifiUsers.addAll(users.getLoginUser());
|
||||
|
||||
// find the desired user
|
||||
return finder.findUsers(nifiUsers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the user via the specified CreateUser.
|
||||
*
|
||||
* @param creator The creator
|
||||
*/
|
||||
public synchronized void createUser(final CreateUser creator) {
|
||||
// add the user
|
||||
final Users users = getUsers();
|
||||
|
||||
// create the user
|
||||
final NiFiUser newUser = creator.createUser();
|
||||
if (newUser instanceof User) {
|
||||
users.getUser().add((User) newUser);
|
||||
} else {
|
||||
users.getLoginUser().add((LoginUser) newUser);
|
||||
}
|
||||
|
||||
// save the users
|
||||
saveUsers(users);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or Updates a user identified by the finder. If the user exists, it's updated otherwise it's created.
|
||||
*
|
||||
* @param finder The finder
|
||||
* @param creator The creator
|
||||
* @param updater The updater
|
||||
*/
|
||||
public synchronized void createOrUpdateUser(final FindUser finder, final CreateUser creator, final UpdateUser updater) {
|
||||
try {
|
||||
updateUser(finder, updater);
|
||||
} catch (final UnknownIdentityException uie) {
|
||||
createUser(creator);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the user identified by the finder.
|
||||
*
|
||||
* @param finder The finder
|
||||
* @param updater The updater
|
||||
*/
|
||||
public synchronized void updateUser(final FindUser finder, final UpdateUser updater) {
|
||||
// update the user
|
||||
final Users users = getUsers();
|
||||
|
||||
// combine the user lists
|
||||
final List<NiFiUser> nifiUsers = new ArrayList<>();
|
||||
nifiUsers.addAll(users.getUser());
|
||||
nifiUsers.addAll(users.getLoginUser());
|
||||
|
||||
// find the user to update
|
||||
final NiFiUser user = finder.findUser(nifiUsers);
|
||||
|
||||
// update the user
|
||||
updater.updateUser(user);
|
||||
|
||||
// save the users
|
||||
saveUsers(users);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the users identified by the finder.
|
||||
*
|
||||
* @param finder The finder
|
||||
* @param updater The updater
|
||||
*/
|
||||
public synchronized void updateUsers(final FindUsers finder, final UpdateUsers updater) {
|
||||
// update the user
|
||||
final Users users = getUsers();
|
||||
|
||||
// combine the user lists
|
||||
final List<NiFiUser> nifiUsers = new ArrayList<>();
|
||||
nifiUsers.addAll(users.getUser());
|
||||
nifiUsers.addAll(users.getLoginUser());
|
||||
|
||||
final List<NiFiUser> userToUpdate = finder.findUsers(nifiUsers);
|
||||
|
||||
// update the user
|
||||
updater.updateUsers(userToUpdate);
|
||||
|
||||
// save the users
|
||||
saveUsers(users);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the user identified by the finder.
|
||||
*
|
||||
* @param finder The finder
|
||||
*/
|
||||
public synchronized void removeUser(final FindUser finder) {
|
||||
// load the users
|
||||
final Users users = getUsers();
|
||||
|
||||
// combine the user lists
|
||||
final List<NiFiUser> nifiUsers = new ArrayList<>();
|
||||
nifiUsers.addAll(users.getUser());
|
||||
nifiUsers.addAll(users.getLoginUser());
|
||||
|
||||
// find the desired user
|
||||
final NiFiUser user = finder.findUser(nifiUsers);
|
||||
if (user instanceof User) {
|
||||
users.getUser().remove((User) user);
|
||||
} else {
|
||||
users.getLoginUser().remove((LoginUser) user);
|
||||
}
|
||||
|
||||
// save the users
|
||||
saveUsers(users);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the users identified by the finder.
|
||||
*
|
||||
* @param finder The finder
|
||||
*/
|
||||
public synchronized void removeUsers(final FindUsers finder) {
|
||||
// load the users
|
||||
final Users users = getUsers();
|
||||
|
||||
// combine the user lists
|
||||
final List<NiFiUser> nifiUsers = new ArrayList<>();
|
||||
nifiUsers.addAll(users.getUser());
|
||||
nifiUsers.addAll(users.getLoginUser());
|
||||
|
||||
// find the desired user
|
||||
final List<NiFiUser> usersToRemove = finder.findUsers(nifiUsers);
|
||||
for (final NiFiUser user : usersToRemove) {
|
||||
if (user instanceof User) {
|
||||
users.getUser().remove((User) user);
|
||||
} else {
|
||||
users.getLoginUser().remove((LoginUser) user);
|
||||
}
|
||||
}
|
||||
|
||||
// save the users
|
||||
saveUsers(users);
|
||||
}
|
||||
|
||||
private synchronized void saveUsers(final Users users) {
|
||||
try {
|
||||
final Marshaller marshaller = JAXB_CONTEXT.createMarshaller();
|
||||
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
|
||||
|
||||
// save users to restore directory before primary directory
|
||||
if (restoreFile != null) {
|
||||
marshaller.marshal(users, restoreFile);
|
||||
}
|
||||
|
||||
// save users to primary directory
|
||||
marshaller.marshal(users, usersFile);
|
||||
} catch (JAXBException e) {
|
||||
throw new AuthorityAccessException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface HasUser {
|
||||
|
||||
/**
|
||||
* Determines if a user exists. Returns whether this user exists and will never through an UnknownIdentityException.
|
||||
*
|
||||
* @param users the users
|
||||
* @return whether the desired user exists
|
||||
*/
|
||||
boolean hasUser(List<NiFiUser> users);
|
||||
}
|
||||
|
||||
public static interface FindUser {
|
||||
|
||||
/**
|
||||
* Finds the desired user. If the user cannot be found throws an UnknownIdentityException. Never returns null.
|
||||
*
|
||||
* @param users the users
|
||||
* @return the desired user
|
||||
* @throws UnknownIdentityException if the user cannot be found
|
||||
*/
|
||||
NiFiUser findUser(List<NiFiUser> users) throws UnknownIdentityException;
|
||||
}
|
||||
|
||||
public static interface FindUsers {
|
||||
|
||||
/**
|
||||
* Finds the specified users.
|
||||
*
|
||||
* @param users the userss
|
||||
* @return the desired users
|
||||
* @throws UnknownIdentityException if the users cannot be found
|
||||
*/
|
||||
List<NiFiUser> findUsers(List<NiFiUser> users) throws UnknownIdentityException;
|
||||
}
|
||||
|
||||
public static interface CreateUser {
|
||||
|
||||
/**
|
||||
* Creates the user to add.
|
||||
*
|
||||
* @return the users to add
|
||||
*/
|
||||
NiFiUser createUser();
|
||||
}
|
||||
|
||||
public static interface UpdateUser {
|
||||
|
||||
/**
|
||||
* Updates the specified user.
|
||||
*
|
||||
* @param user the user
|
||||
*/
|
||||
void updateUser(NiFiUser user);
|
||||
}
|
||||
|
||||
public static interface UpdateUsers {
|
||||
|
||||
/**
|
||||
* Updates the specified users.
|
||||
*
|
||||
* @param users the users to update
|
||||
*/
|
||||
void updateUsers(List<NiFiUser> users);
|
||||
}
|
||||
}
|
|
@ -26,7 +26,6 @@ import javax.xml.bind.annotation.XmlType;
|
|||
public class LoginConfigurationDTO {
|
||||
|
||||
private Boolean supportsLogin;
|
||||
private Boolean supportsRegistration;
|
||||
|
||||
/**
|
||||
* @return Indicates whether or not this NiFi supports user login.
|
||||
|
@ -42,19 +41,4 @@ public class LoginConfigurationDTO {
|
|||
public void setSupportsLogin(Boolean supportsLogin) {
|
||||
this.supportsLogin = supportsLogin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If this NiFi supports login, indicates whether or not registration is supported.
|
||||
*/
|
||||
@ApiModelProperty(
|
||||
value = "If this NiFi supports login, indicates whether or not registration is supported.",
|
||||
readOnly = true
|
||||
)
|
||||
public Boolean getSupportsRegistration() {
|
||||
return supportsRegistration;
|
||||
}
|
||||
|
||||
public void setSupportsRegistration(Boolean supportsRegistration) {
|
||||
this.supportsRegistration = supportsRegistration;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,19 +21,52 @@
|
|||
<version>0.3.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>nifi-file-authorization-provider</artifactId>
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>src/main/xsd</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>jaxb2-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>xjc</id>
|
||||
<goals>
|
||||
<goal>xjc</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<packageName>org.apache.nifi.user.generated</packageName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<generateDirectory>${project.build.directory}/generated-sources/jaxb</generateDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-checkstyle-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>**/user/generated/*.java</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-authorized-users</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-utils</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
|
|
|
@ -16,34 +16,38 @@
|
|||
*/
|
||||
package org.apache.nifi.authorization;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
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.Marshaller;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
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.UnknownIdentityException;
|
||||
import org.apache.nifi.util.file.FileUtils;
|
||||
import org.apache.nifi.user.generated.ObjectFactory;
|
||||
import org.apache.nifi.user.generated.Role;
|
||||
import org.apache.nifi.user.generated.User;
|
||||
import org.apache.nifi.user.generated.Users;
|
||||
import org.apache.nifi.util.NiFiProperties;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.nifi.authorized.users.AuthorizedUsers;
|
||||
import org.apache.nifi.authorized.users.AuthorizedUsers.CreateUser;
|
||||
import org.apache.nifi.authorized.users.AuthorizedUsers.FindUser;
|
||||
import org.apache.nifi.authorized.users.AuthorizedUsers.FindUsers;
|
||||
import org.apache.nifi.authorized.users.AuthorizedUsers.HasUser;
|
||||
import org.apache.nifi.authorized.users.AuthorizedUsers.UpdateUser;
|
||||
import org.apache.nifi.authorized.users.AuthorizedUsers.UpdateUsers;
|
||||
import org.apache.nifi.user.generated.LoginUser;
|
||||
import org.apache.nifi.user.generated.NiFiUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Provides identity checks and grants authorities.
|
||||
|
@ -51,26 +55,84 @@ import org.slf4j.LoggerFactory;
|
|||
public class FileAuthorizationProvider implements AuthorityProvider {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(FileAuthorizationProvider.class);
|
||||
private static final String USERS_XSD = "/users.xsd";
|
||||
private static final String JAXB_GENERATED_PATH = "org.apache.nifi.user.generated";
|
||||
private static final JAXBContext JAXB_CONTEXT = initializeJaxbContext();
|
||||
|
||||
/**
|
||||
* Load the JAXBContext.
|
||||
*/
|
||||
private static JAXBContext initializeJaxbContext() {
|
||||
try {
|
||||
return JAXBContext.newInstance(JAXB_GENERATED_PATH, FileAuthorizationProvider.class.getClassLoader());
|
||||
} catch (JAXBException e) {
|
||||
throw new RuntimeException("Unable to create JAXBContext.");
|
||||
}
|
||||
}
|
||||
|
||||
private NiFiProperties properties;
|
||||
private File usersFile;
|
||||
private File restoreUsersFile;
|
||||
private Users users;
|
||||
private final Set<String> defaultAuthorities = new HashSet<>();
|
||||
|
||||
private AuthorizedUsers authorizedUsers;
|
||||
|
||||
@Override
|
||||
public void initialize(final AuthorityProviderInitializationContext initializationContext) throws ProviderCreationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigured(final AuthorityProviderConfigurationContext configurationContext) throws ProviderCreationException {
|
||||
final String usersFilePath = configurationContext.getProperty("Authorized Users File");
|
||||
if (usersFilePath == null || usersFilePath.trim().isEmpty()) {
|
||||
throw new ProviderCreationException("The authorized users file must be specified.");
|
||||
}
|
||||
|
||||
try {
|
||||
// initialize the authorized users
|
||||
authorizedUsers = AuthorizedUsers.getInstance(usersFilePath, properties);
|
||||
final String usersFilePath = configurationContext.getProperty("Authorized Users File");
|
||||
if (usersFilePath == null || usersFilePath.trim().isEmpty()) {
|
||||
throw new ProviderCreationException("The authorized users file must be specified.");
|
||||
}
|
||||
|
||||
// the users file instance will never be null because a default is used
|
||||
usersFile = new File(usersFilePath);
|
||||
final File usersFileDirectory = usersFile.getParentFile();
|
||||
|
||||
// the restore directory is optional and may be null
|
||||
final File restoreDirectory = properties.getRestoreDirectory();
|
||||
|
||||
if (restoreDirectory != null) {
|
||||
|
||||
// sanity check that restore directory is a directory, creating it if necessary
|
||||
FileUtils.ensureDirectoryExistAndCanAccess(restoreDirectory);
|
||||
|
||||
// check that restore directory is not the same as the primary directory
|
||||
if (usersFileDirectory.getAbsolutePath().equals(restoreDirectory.getAbsolutePath())) {
|
||||
throw new ProviderCreationException(String.format("Authorized User's directory '%s' is the same as restore directory '%s' ",
|
||||
usersFileDirectory.getAbsolutePath(), restoreDirectory.getAbsolutePath()));
|
||||
}
|
||||
|
||||
// the restore copy will have same file name, but reside in a different directory
|
||||
restoreUsersFile = new File(restoreDirectory, usersFile.getName());
|
||||
|
||||
// sync the primary copy with the restore copy
|
||||
try {
|
||||
FileUtils.syncWithRestore(usersFile, restoreUsersFile, logger);
|
||||
} catch (final IOException | IllegalStateException ioe) {
|
||||
throw new ProviderCreationException(ioe);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// load the users from the specified file
|
||||
if (usersFile.exists()) {
|
||||
// find the schema
|
||||
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||
final Schema schema = schemaFactory.newSchema(FileAuthorizationProvider.class.getResource(USERS_XSD));
|
||||
|
||||
// attempt to unmarshal
|
||||
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
|
||||
unmarshaller.setSchema(schema);
|
||||
final JAXBElement<Users> element = unmarshaller.unmarshal(new StreamSource(usersFile), Users.class);
|
||||
users = element.getValue();
|
||||
} else {
|
||||
final ObjectFactory objFactory = new ObjectFactory();
|
||||
users = objFactory.createUsers();
|
||||
}
|
||||
|
||||
// attempt to load a default roles
|
||||
final String rawDefaultAuthorities = configurationContext.getProperty("Default User Roles");
|
||||
|
@ -95,9 +157,10 @@ public class FileAuthorizationProvider implements AuthorityProvider {
|
|||
StringUtils.join(invalidDefaultAuthorities, ", "), StringUtils.join(Authority.getRawAuthorities(), ", ")));
|
||||
}
|
||||
}
|
||||
} catch (IOException | IllegalStateException | ProviderCreationException e) {
|
||||
} catch (IOException | ProviderCreationException | SAXException | JAXBException e) {
|
||||
throw new ProviderCreationException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,64 +172,67 @@ public class FileAuthorizationProvider implements AuthorityProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean doesDnExist(final String dn) throws AuthorityAccessException {
|
||||
public boolean doesDnExist(String dn) throws AuthorityAccessException {
|
||||
if (hasDefaultRoles()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return authorizedUsers.hasUser(new HasUserByIdentity(dn));
|
||||
final User user = getUser(dn);
|
||||
return user != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Authority> getAuthorities(final String dn) throws UnknownIdentityException, AuthorityAccessException {
|
||||
public synchronized Set<Authority> getAuthorities(String dn) throws UnknownIdentityException, AuthorityAccessException {
|
||||
final Set<Authority> authorities = EnumSet.noneOf(Authority.class);
|
||||
|
||||
// get the user
|
||||
final NiFiUser user = authorizedUsers.getUser(new FindUser() {
|
||||
@Override
|
||||
public NiFiUser findUser(List<NiFiUser> users) {
|
||||
final FindUser byDn = new FindUserByIdentity(dn);
|
||||
NiFiUser user = byDn.findUser(users);
|
||||
final User user = getUser(dn);
|
||||
|
||||
// if the user is not found, add them and locate them
|
||||
if (user == null) {
|
||||
if (hasDefaultRoles()) {
|
||||
logger.debug(String.format("User identity not found: %s. Creating new user with default roles.", dn));
|
||||
// ensure the user was located
|
||||
if (user == null) {
|
||||
if (hasDefaultRoles()) {
|
||||
logger.debug(String.format("User DN not found: %s. Creating new user with default roles.", dn));
|
||||
|
||||
// create the user (which will automatically add any default authorities)
|
||||
addUser(dn, null);
|
||||
// create the user (which will automatically add any default authorities)
|
||||
addUser(dn, null);
|
||||
|
||||
// find the user that was just added
|
||||
user = byDn.findUser(users);
|
||||
} else {
|
||||
throw new UnknownIdentityException(String.format("User identity not found: %s.", dn));
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
// get the authorities for the newly created user
|
||||
authorities.addAll(getAuthorities(dn));
|
||||
} else {
|
||||
throw new UnknownIdentityException(String.format("User DN not found: %s.", dn));
|
||||
}
|
||||
} else {
|
||||
// create the authorities that this user has
|
||||
for (final Role role : user.getRole()) {
|
||||
authorities.add(Authority.valueOfAuthority(role.getName()));
|
||||
}
|
||||
});
|
||||
|
||||
// create the authorities that this user has
|
||||
for (final Role role : user.getRole()) {
|
||||
authorities.add(Authority.valueOfAuthority(role.getName()));
|
||||
}
|
||||
|
||||
return authorities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthorities(final String dn, final Set<Authority> authorities) throws UnknownIdentityException, AuthorityAccessException {
|
||||
authorizedUsers.updateUser(new FindUserByIdentity(dn), new UpdateUser() {
|
||||
@Override
|
||||
public void updateUser(NiFiUser user) {
|
||||
// add the user authorities
|
||||
setUserAuthorities(user, authorities);
|
||||
}
|
||||
});
|
||||
public synchronized void setAuthorities(String dn, Set<Authority> authorities) throws UnknownIdentityException, AuthorityAccessException {
|
||||
// get the user
|
||||
final User user = getUser(dn);
|
||||
|
||||
// ensure the user was located
|
||||
if (user == null) {
|
||||
throw new UnknownIdentityException(String.format("User DN not found: %s.", dn));
|
||||
}
|
||||
|
||||
// add the user authorities
|
||||
setUserAuthorities(user, authorities);
|
||||
|
||||
try {
|
||||
// save the file
|
||||
save();
|
||||
} catch (Exception e) {
|
||||
throw new AuthorityAccessException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void setUserAuthorities(final NiFiUser user, final Set<Authority> authorities) {
|
||||
private void setUserAuthorities(final User user, final Set<Authority> authorities) {
|
||||
// clear the existing rules
|
||||
user.getRole().clear();
|
||||
|
||||
|
@ -182,145 +248,186 @@ public class FileAuthorizationProvider implements AuthorityProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addUser(final String dn, final String group) throws IdentityAlreadyExistsException, AuthorityAccessException {
|
||||
authorizedUsers.createOrUpdateUser(new FindUser() {
|
||||
@Override
|
||||
public NiFiUser findUser(final List<NiFiUser> users) throws UnknownIdentityException {
|
||||
// attempt to get the user and ensure it was located
|
||||
NiFiUser desiredUser = null;
|
||||
for (final NiFiUser user : users) {
|
||||
if (dn.equalsIgnoreCase(authorizedUsers.getUserIdentity(user))) {
|
||||
desiredUser = user;
|
||||
break;
|
||||
}
|
||||
}
|
||||
public synchronized void addUser(String dn, String group) throws IdentityAlreadyExistsException, AuthorityAccessException {
|
||||
final User user = getUser(dn);
|
||||
|
||||
// user does not exist, will create
|
||||
if (desiredUser == null) {
|
||||
throw new UnknownIdentityException("This exception will trigger the creator to be invoked.");
|
||||
}
|
||||
// ensure the user doesn't already exist
|
||||
if (user != null) {
|
||||
throw new IdentityAlreadyExistsException(String.format("User DN already exists: %s", dn));
|
||||
}
|
||||
|
||||
// user exists, verify its still pending
|
||||
if (LoginUser.class.isAssignableFrom(desiredUser.getClass())) {
|
||||
if (((LoginUser) desiredUser).isPending()) {
|
||||
return desiredUser;
|
||||
}
|
||||
}
|
||||
// create the new user
|
||||
final ObjectFactory objFactory = new ObjectFactory();
|
||||
final User newUser = objFactory.createUser();
|
||||
|
||||
// user exists and account is valid... no good
|
||||
throw new IdentityAlreadyExistsException(String.format("User identity already exists: %s", dn));
|
||||
// set the user properties
|
||||
newUser.setDn(dn);
|
||||
newUser.setGroup(group);
|
||||
|
||||
// add default roles if appropriate
|
||||
if (hasDefaultRoles()) {
|
||||
for (final String authority : defaultAuthorities) {
|
||||
Role role = objFactory.createRole();
|
||||
role.setName(authority);
|
||||
|
||||
// add the role
|
||||
newUser.getRole().add(role);
|
||||
}
|
||||
}, new CreateUser() {
|
||||
@Override
|
||||
public NiFiUser createUser() {
|
||||
// only support adding PreAuthenticated User's via this API - LoginUser's are added
|
||||
// via the LoginIdentityProvider
|
||||
final ObjectFactory objFactory = new ObjectFactory();
|
||||
final User newUser = objFactory.createUser();
|
||||
}
|
||||
|
||||
// set the user properties
|
||||
newUser.setDn(dn);
|
||||
newUser.setGroup(group);
|
||||
// add the user
|
||||
users.getUser().add(newUser);
|
||||
|
||||
// add default roles if appropriate
|
||||
if (hasDefaultRoles()) {
|
||||
for (final String authority : defaultAuthorities) {
|
||||
Role role = objFactory.createRole();
|
||||
role.setName(authority);
|
||||
|
||||
// add the role
|
||||
newUser.getRole().add(role);
|
||||
}
|
||||
}
|
||||
|
||||
return newUser;
|
||||
}
|
||||
}, new UpdateUser() {
|
||||
@Override
|
||||
public void updateUser(final NiFiUser user) {
|
||||
// only support updating Login Users's via this API - need to mark the account as non pending
|
||||
LoginUser loginUser = (LoginUser) user;
|
||||
loginUser.setPending(false);
|
||||
}
|
||||
});
|
||||
try {
|
||||
// save the file
|
||||
save();
|
||||
} catch (Exception e) {
|
||||
throw new AuthorityAccessException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getUsers(final Authority authority) throws AuthorityAccessException {
|
||||
final List<NiFiUser> matchingUsers = authorizedUsers.getUsers(new FindUsers() {
|
||||
@Override
|
||||
public List<NiFiUser> findUsers(List<NiFiUser> users) throws UnknownIdentityException {
|
||||
final List<NiFiUser> matchingUsers = new ArrayList<>();
|
||||
for (final NiFiUser user : users) {
|
||||
for (final Role role : user.getRole()) {
|
||||
if (role.getName().equals(authority.toString())) {
|
||||
matchingUsers.add(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
return matchingUsers;
|
||||
}
|
||||
});
|
||||
|
||||
public synchronized Set<String> getUsers(Authority authority) throws AuthorityAccessException {
|
||||
final Set<String> userSet = new HashSet<>();
|
||||
for (final NiFiUser user : matchingUsers) {
|
||||
userSet.add(authorizedUsers.getUserIdentity(user));
|
||||
for (final User user : users.getUser()) {
|
||||
for (final Role role : user.getRole()) {
|
||||
if (role.getName().equals(authority.toString())) {
|
||||
userSet.add(user.getDn());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return userSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revokeUser(final String dn) throws UnknownIdentityException, AuthorityAccessException {
|
||||
authorizedUsers.removeUser(new FindUserByIdentity(dn));
|
||||
public synchronized void revokeUser(String dn) throws UnknownIdentityException, AuthorityAccessException {
|
||||
// get the user
|
||||
final User user = getUser(dn);
|
||||
|
||||
// ensure the user was located
|
||||
if (user == null) {
|
||||
throw new UnknownIdentityException(String.format("User DN not found: %s.", dn));
|
||||
}
|
||||
|
||||
// remove the specified user
|
||||
users.getUser().remove(user);
|
||||
|
||||
try {
|
||||
// save the file
|
||||
save();
|
||||
} catch (Exception e) {
|
||||
throw new AuthorityAccessException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUsersGroup(final Set<String> dns, final String group) throws UnknownIdentityException, AuthorityAccessException {
|
||||
authorizedUsers.updateUsers(new FindUsersByIdentity(dns), new UpdateUsers() {
|
||||
@Override
|
||||
public void updateUsers(List<NiFiUser> users) {
|
||||
// update each user group
|
||||
for (final NiFiUser user : users) {
|
||||
user.setGroup(group);
|
||||
}
|
||||
public void setUsersGroup(Set<String> dns, String group) throws UnknownIdentityException, AuthorityAccessException {
|
||||
final Collection<User> groupedUsers = new HashSet<>();
|
||||
|
||||
// get the specified users
|
||||
for (final String dn : dns) {
|
||||
// get the user
|
||||
final User user = getUser(dn);
|
||||
|
||||
// ensure the user was located
|
||||
if (user == null) {
|
||||
throw new UnknownIdentityException(String.format("User DN not found: %s.", dn));
|
||||
}
|
||||
});
|
||||
|
||||
groupedUsers.add(user);
|
||||
}
|
||||
|
||||
// update each user group
|
||||
for (final User user : groupedUsers) {
|
||||
user.setGroup(group);
|
||||
}
|
||||
|
||||
try {
|
||||
// save the file
|
||||
save();
|
||||
} catch (Exception e) {
|
||||
throw new AuthorityAccessException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ungroupUser(String dn) throws UnknownIdentityException, AuthorityAccessException {
|
||||
authorizedUsers.updateUser(new FindUserByIdentity(dn), new UpdateUser() {
|
||||
@Override
|
||||
public void updateUser(NiFiUser user) {
|
||||
// remove the users group
|
||||
user.setGroup(null);
|
||||
}
|
||||
});
|
||||
// get the user
|
||||
final User user = getUser(dn);
|
||||
|
||||
// ensure the user was located
|
||||
if (user == null) {
|
||||
throw new UnknownIdentityException(String.format("User DN not found: %s.", dn));
|
||||
}
|
||||
|
||||
// remove the users group
|
||||
user.setGroup(null);
|
||||
|
||||
try {
|
||||
// save the file
|
||||
save();
|
||||
} catch (Exception e) {
|
||||
throw new AuthorityAccessException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ungroup(final String group) throws AuthorityAccessException {
|
||||
authorizedUsers.updateUsers(new FindUsersByGroup(group), new UpdateUsers() {
|
||||
@Override
|
||||
public void updateUsers(List<NiFiUser> users) {
|
||||
// update each user group
|
||||
for (final NiFiUser user : users) {
|
||||
user.setGroup(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
public void ungroup(String group) throws AuthorityAccessException {
|
||||
// get the user group
|
||||
final Collection<User> userGroup = getUserGroup(group);
|
||||
|
||||
// ensure the user group was located
|
||||
if (userGroup == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// update each user group
|
||||
for (final User user : userGroup) {
|
||||
user.setGroup(null);
|
||||
}
|
||||
|
||||
try {
|
||||
// save the file
|
||||
save();
|
||||
} catch (Exception e) {
|
||||
throw new AuthorityAccessException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupForUser(final String dn) throws UnknownIdentityException, AuthorityAccessException {
|
||||
final NiFiUser user = authorizedUsers.getUser(new FindUserByIdentity(dn));
|
||||
public String getGroupForUser(String dn) throws UnknownIdentityException, AuthorityAccessException {
|
||||
// get the user
|
||||
final User user = getUser(dn);
|
||||
|
||||
// ensure the user was located
|
||||
if (user == null) {
|
||||
throw new UnknownIdentityException(String.format("User DN not found: %s.", dn));
|
||||
}
|
||||
|
||||
return user.getGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void revokeGroup(String group) throws UnknownIdentityException, AuthorityAccessException {
|
||||
authorizedUsers.removeUsers(new FindUsersByGroup(group));
|
||||
// get the user group
|
||||
final Collection<User> userGroup = getUserGroup(group);
|
||||
|
||||
// ensure the user group was located
|
||||
if (userGroup == null) {
|
||||
throw new UnknownIdentityException(String.format("User group not found: %s.", group));
|
||||
}
|
||||
|
||||
// remove each user in the group
|
||||
for (final User user : userGroup) {
|
||||
users.getUser().remove(user);
|
||||
}
|
||||
|
||||
try {
|
||||
// save the file
|
||||
save();
|
||||
} catch (Exception e) {
|
||||
throw new AuthorityAccessException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -331,143 +438,59 @@ public class FileAuthorizationProvider implements AuthorityProvider {
|
|||
return DownloadAuthorization.approved();
|
||||
}
|
||||
|
||||
private User getUser(String dn) throws UnknownIdentityException {
|
||||
// ensure the DN was specified
|
||||
if (dn == null) {
|
||||
throw new UnknownIdentityException("User DN not specified.");
|
||||
}
|
||||
|
||||
// attempt to get the user and ensure it was located
|
||||
User desiredUser = null;
|
||||
for (final User user : users.getUser()) {
|
||||
if (dn.equalsIgnoreCase(user.getDn())) {
|
||||
desiredUser = user;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return desiredUser;
|
||||
}
|
||||
|
||||
private Collection<User> getUserGroup(String group) throws UnknownIdentityException {
|
||||
// ensure the DN was specified
|
||||
if (group == null) {
|
||||
throw new UnknownIdentityException("User group not specified.");
|
||||
}
|
||||
|
||||
// get all users with this group
|
||||
Collection<User> userGroup = null;
|
||||
for (final User user : users.getUser()) {
|
||||
if (group.equals(user.getGroup())) {
|
||||
if (userGroup == null) {
|
||||
userGroup = new HashSet<>();
|
||||
}
|
||||
userGroup.add(user);
|
||||
}
|
||||
}
|
||||
|
||||
return userGroup;
|
||||
}
|
||||
|
||||
private void save() throws Exception {
|
||||
final Marshaller marshaller = JAXB_CONTEXT.createMarshaller();
|
||||
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
|
||||
|
||||
// save users to restore directory before primary directory
|
||||
if (restoreUsersFile != null) {
|
||||
marshaller.marshal(users, restoreUsersFile);
|
||||
}
|
||||
|
||||
// save users to primary directory
|
||||
marshaller.marshal(users, usersFile);
|
||||
}
|
||||
|
||||
@AuthorityProviderContext
|
||||
public void setNiFiProperties(NiFiProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
private boolean isPendingLoginUser(final NiFiUser user) {
|
||||
if (LoginUser.class.isAssignableFrom(user.getClass())) {
|
||||
return ((LoginUser) user).isPending();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public class HasUserByIdentity implements HasUser {
|
||||
|
||||
private final String identity;
|
||||
|
||||
public HasUserByIdentity(String identity) {
|
||||
// ensure the identity was specified
|
||||
if (identity == null) {
|
||||
throw new UnknownIdentityException("User identity not specified.");
|
||||
}
|
||||
|
||||
this.identity = identity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasUser(List<NiFiUser> users) {
|
||||
// attempt to get the user and ensure it was located
|
||||
NiFiUser desiredUser = null;
|
||||
for (final NiFiUser user : users) {
|
||||
if (identity.equalsIgnoreCase(authorizedUsers.getUserIdentity(user)) && !isPendingLoginUser(user)) {
|
||||
desiredUser = user;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return desiredUser != null;
|
||||
}
|
||||
}
|
||||
|
||||
public class FindUserByIdentity implements FindUser {
|
||||
|
||||
private final String identity;
|
||||
|
||||
public FindUserByIdentity(String identity) {
|
||||
// ensure the identity was specified
|
||||
if (identity == null) {
|
||||
throw new UnknownIdentityException("User identity not specified.");
|
||||
}
|
||||
|
||||
this.identity = identity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NiFiUser findUser(List<NiFiUser> users) {
|
||||
// attempt to get the user and ensure it was located
|
||||
NiFiUser desiredUser = null;
|
||||
for (final NiFiUser user : users) {
|
||||
if (identity.equalsIgnoreCase(authorizedUsers.getUserIdentity(user)) && !isPendingLoginUser(user)) {
|
||||
desiredUser = user;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (desiredUser == null) {
|
||||
throw new UnknownIdentityException(String.format("User identity not found: %s.", identity));
|
||||
}
|
||||
|
||||
return desiredUser;
|
||||
}
|
||||
}
|
||||
|
||||
public class FindUsersByGroup implements FindUsers {
|
||||
|
||||
private final String group;
|
||||
|
||||
public FindUsersByGroup(String group) {
|
||||
// ensure the group was specified
|
||||
if (group == null) {
|
||||
throw new UnknownIdentityException("User group not specified.");
|
||||
}
|
||||
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NiFiUser> findUsers(List<NiFiUser> users) throws UnknownIdentityException {
|
||||
// get all users with this group
|
||||
List<NiFiUser> userGroup = new ArrayList<>();
|
||||
for (final NiFiUser user : users) {
|
||||
if (group.equals(user.getGroup()) && !isPendingLoginUser(user)) {
|
||||
userGroup.add(user);
|
||||
}
|
||||
}
|
||||
|
||||
// ensure the user group was located
|
||||
if (userGroup.isEmpty()) {
|
||||
throw new UnknownIdentityException(String.format("User group not found: %s.", group));
|
||||
}
|
||||
|
||||
return userGroup;
|
||||
}
|
||||
}
|
||||
|
||||
public class FindUsersByIdentity implements FindUsers {
|
||||
|
||||
private final Set<String> identities;
|
||||
|
||||
public FindUsersByIdentity(Set<String> identities) {
|
||||
// ensure the group was specified
|
||||
if (identities == null) {
|
||||
throw new UnknownIdentityException("User identities not specified.");
|
||||
}
|
||||
|
||||
this.identities = identities;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<NiFiUser> findUsers(List<NiFiUser> users) throws UnknownIdentityException {
|
||||
final Set<String> copy = new HashSet<>(identities);
|
||||
|
||||
// get all users with this group
|
||||
List<NiFiUser> userList = new ArrayList<>();
|
||||
for (final NiFiUser user : users) {
|
||||
final String userIdentity = authorizedUsers.getUserIdentity(user);
|
||||
if (copy.contains(userIdentity) && !isPendingLoginUser(user)) {
|
||||
copy.remove(userIdentity);
|
||||
userList.add(user);
|
||||
}
|
||||
}
|
||||
|
||||
if (!copy.isEmpty()) {
|
||||
throw new UnknownIdentityException("Unable to find users with identities: " + StringUtils.join(copy, ", "));
|
||||
}
|
||||
|
||||
return userList;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,10 +30,19 @@
|
|||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="NiFiUser">
|
||||
<!-- user -->
|
||||
<xs:complexType name="User">
|
||||
<xs:sequence>
|
||||
<xs:element name="role" type="Role" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="dn">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:pattern value=".*[^\s].*"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="group">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
|
@ -44,53 +53,11 @@
|
|||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- preauthenticated user -->
|
||||
<xs:complexType name="User">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="NiFiUser">
|
||||
<xs:attribute name="dn" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:pattern value=".*[^\s].*"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- login user -->
|
||||
<xs:complexType name="LoginUser">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="NiFiUser">
|
||||
<xs:attribute name="username" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:pattern value=".*[^\s].*"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="password" use="required">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:pattern value=".*[^\s].*"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="pending" type="xs:boolean" use="required"/>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
|
||||
<!-- users -->
|
||||
<xs:element name="users">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="user" type="User" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="loginUser" type="LoginUser" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
|
@ -1,39 +0,0 @@
|
|||
<?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>0.3.1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>nifi-file-identity-provider</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-properties</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-authorized-users</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -1,15 +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.
|
||||
org.apache.nifi.authentication.FileLoginIdentityProvider
|
|
@ -19,9 +19,4 @@
|
|||
must be specified in the nifi.properties file.
|
||||
-->
|
||||
<loginIdentityProviders>
|
||||
<provider>
|
||||
<identifier>file-provider</identifier>
|
||||
<class>org.apache.nifi.authentication.FileLoginIdentityProvider</class>
|
||||
<property name="Authenticated Users File">./conf/authorized-users.xml</property>
|
||||
</provider>
|
||||
</loginIdentityProviders>
|
|
@ -25,7 +25,6 @@ import org.apache.nifi.web.security.anonymous.NiFiAnonymousUserFilter;
|
|||
import org.apache.nifi.web.security.NiFiAuthenticationEntryPoint;
|
||||
import org.apache.nifi.web.security.RegistrationStatusFilter;
|
||||
import org.apache.nifi.web.security.login.LoginAuthenticationFilter;
|
||||
import org.apache.nifi.web.security.login.RegistrationFilter;
|
||||
import org.apache.nifi.web.security.jwt.JwtAuthenticationFilter;
|
||||
import org.apache.nifi.web.security.jwt.JwtService;
|
||||
import org.apache.nifi.web.security.node.NodeAuthorizedUserFilter;
|
||||
|
@ -88,13 +87,6 @@ public class NiFiWebApiSecurityConfiguration extends WebSecurityConfigurerAdapte
|
|||
.sessionManagement()
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||
|
||||
if (loginIdentityProvider != null) {
|
||||
// verify the configured login authenticator supports user login registration
|
||||
if (loginIdentityProvider.supportsRegistration()) {
|
||||
http.addFilterBefore(buildRegistrationFilter("/registration"), UsernamePasswordAuthenticationFilter.class);
|
||||
}
|
||||
}
|
||||
|
||||
// login authentication for /token - exchanges for JWT for subsequent API usage
|
||||
http.addFilterBefore(buildLoginFilter("/token"), UsernamePasswordAuthenticationFilter.class);
|
||||
|
||||
|
@ -139,14 +131,6 @@ public class NiFiWebApiSecurityConfiguration extends WebSecurityConfigurerAdapte
|
|||
return loginFilter;
|
||||
}
|
||||
|
||||
private Filter buildRegistrationFilter(final String url) {
|
||||
final RegistrationFilter registrationFilter = new RegistrationFilter(url);
|
||||
registrationFilter.setJwtService(jwtService);
|
||||
registrationFilter.setLoginIdentityProvider(loginIdentityProvider);
|
||||
registrationFilter.setUserService(userService);
|
||||
return registrationFilter;
|
||||
}
|
||||
|
||||
private Filter buildRegistrationStatusFilter(final String url) {
|
||||
final RegistrationStatusFilter registrationStatusFilter = new RegistrationStatusFilter(url);
|
||||
registrationStatusFilter.setCertificateExtractor(certificateExtractor);
|
||||
|
|
|
@ -2354,14 +2354,8 @@ public class StandardNiFiServiceFacade implements NiFiServiceFacade {
|
|||
public LoginConfigurationDTO getLoginConfiguration() {
|
||||
final LoginConfigurationDTO loginConfiguration = new LoginConfigurationDTO();
|
||||
|
||||
// specify whether login/registration should be supported
|
||||
if (loginIdentityProvider == null) {
|
||||
loginConfiguration.setSupportsLogin(false);
|
||||
loginConfiguration.setSupportsRegistration(false);
|
||||
} else {
|
||||
loginConfiguration.setSupportsLogin(true);
|
||||
loginConfiguration.setSupportsRegistration(loginIdentityProvider.supportsRegistration());
|
||||
}
|
||||
// specify whether login should be supported
|
||||
loginConfiguration.setSupportsLogin(loginIdentityProvider != null);
|
||||
|
||||
return loginConfiguration;
|
||||
}
|
||||
|
|
|
@ -688,7 +688,6 @@ public class ControllerResource extends ApplicationResource {
|
|||
|
||||
// only support login/registration when running securely
|
||||
loginConfig.setSupportsLogin(loginConfig.getSupportsLogin() && httpServletRequest.isSecure());
|
||||
loginConfig.setSupportsRegistration(loginConfig.getSupportsRegistration() && httpServletRequest.isSecure());
|
||||
|
||||
// create the revision
|
||||
final RevisionDTO revision = new RevisionDTO();
|
||||
|
|
|
@ -1,163 +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.web.security.login;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import org.apache.nifi.admin.service.AccountDisabledException;
|
||||
import org.apache.nifi.admin.service.AccountNotFoundException;
|
||||
import org.apache.nifi.admin.service.AccountPendingException;
|
||||
import org.apache.nifi.admin.service.AdministrationException;
|
||||
import org.apache.nifi.admin.service.UserService;
|
||||
import org.apache.nifi.authentication.LoginCredentials;
|
||||
import org.apache.nifi.authentication.LoginIdentityProvider;
|
||||
import org.apache.nifi.authentication.exception.IdentityAccessException;
|
||||
import org.apache.nifi.authentication.exception.IdentityRegistrationException;
|
||||
import org.apache.nifi.authorization.exception.IdentityAlreadyExistsException;
|
||||
import org.apache.nifi.util.StringUtils;
|
||||
import org.apache.nifi.web.security.jwt.JwtService;
|
||||
import org.apache.nifi.web.security.token.LoginAuthenticationToken;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.security.authentication.AccountStatusException;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
|
||||
/**
|
||||
* Exchanges a successful login with the configured provider for a ID token for accessing the API.
|
||||
*/
|
||||
public class RegistrationFilter extends AbstractAuthenticationProcessingFilter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(RegistrationFilter.class);
|
||||
|
||||
private LoginIdentityProvider loginIdentityProvider;
|
||||
private JwtService jwtService;
|
||||
private UserService userService;
|
||||
|
||||
public RegistrationFilter(final String defaultFilterProcessesUrl) {
|
||||
super(defaultFilterProcessesUrl);
|
||||
|
||||
// do not continue filter chain... simply exchanging authentication for token
|
||||
setContinueChainBeforeSuccessfulAuthentication(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(final HttpServletRequest request, final HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
|
||||
// only suppport registration when running securely
|
||||
if (!request.isSecure()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// look for the credentials in the request
|
||||
final LoginCredentials credentials = getLoginCredentials(request);
|
||||
|
||||
// if the credentials were not part of the request, attempt to log in with the certificate in the request
|
||||
if (credentials == null) {
|
||||
throw new UsernameNotFoundException("User login credentials not found in request.");
|
||||
} else {
|
||||
try {
|
||||
// attempt to register the user
|
||||
loginIdentityProvider.register(credentials);
|
||||
} catch (final IdentityAlreadyExistsException iaee) {
|
||||
// if the identity already exists, try to create the nifi account request
|
||||
} catch (final IdentityRegistrationException ire) {
|
||||
// the credentials are not acceptable for some reason
|
||||
throw new BadCredentialsException(ire.getMessage(), ire);
|
||||
} catch (final IdentityAccessException iae) {
|
||||
throw new AuthenticationServiceException(iae.getMessage(), iae);
|
||||
}
|
||||
|
||||
try {
|
||||
// see if the account already exists so we're able to return the current status
|
||||
userService.checkAuthorization(credentials.getUsername());
|
||||
|
||||
// account exists and is valid
|
||||
throw new AccountStatusException(String.format("An account for %s already exists.", credentials.getUsername())) {
|
||||
};
|
||||
} catch (AdministrationException ase) {
|
||||
throw new AuthenticationServiceException(ase.getMessage(), ase);
|
||||
} catch (AccountDisabledException | AccountPendingException e) {
|
||||
throw new AccountStatusException(e.getMessage(), e) {
|
||||
};
|
||||
} catch (AccountNotFoundException anfe) {
|
||||
// create the pending user account
|
||||
userService.createPendingUserAccount(credentials.getUsername(), request.getParameter("justification"));
|
||||
|
||||
// create the login token
|
||||
return new LoginAuthenticationToken(credentials);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LoginCredentials getLoginCredentials(HttpServletRequest request) {
|
||||
final String username = request.getParameter("username");
|
||||
final String password = request.getParameter("password");
|
||||
|
||||
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
|
||||
return null;
|
||||
} else {
|
||||
return new LoginCredentials(username, password);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void successfulAuthentication(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain, final Authentication authentication)
|
||||
throws IOException, ServletException {
|
||||
|
||||
// generate JWT for response
|
||||
jwtService.addToken(response, authentication);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void unsuccessfulAuthentication(final HttpServletRequest request, final HttpServletResponse response, final AuthenticationException failed) throws IOException, ServletException {
|
||||
response.setContentType("text/plain");
|
||||
|
||||
final PrintWriter out = response.getWriter();
|
||||
out.println(failed.getMessage());
|
||||
|
||||
// set the appropriate response status
|
||||
if (failed instanceof UsernameNotFoundException || failed instanceof BadCredentialsException) {
|
||||
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
||||
} else if (failed instanceof AccountStatusException) {
|
||||
// account exists (maybe valid, pending, revoked)
|
||||
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
} else {
|
||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public void setJwtService(JwtService jwtService) {
|
||||
this.jwtService = jwtService;
|
||||
}
|
||||
|
||||
public void setLoginIdentityProvider(LoginIdentityProvider loginIdentityProvider) {
|
||||
this.loginIdentityProvider = loginIdentityProvider;
|
||||
}
|
||||
|
||||
public void setUserService(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
}
|
|
@ -258,20 +258,6 @@ public class LoginIdentityProviderFactoryBean implements FactoryBean, Disposable
|
|||
private LoginIdentityProvider withNarLoader(final LoginIdentityProvider baseProvider) {
|
||||
return new LoginIdentityProvider() {
|
||||
|
||||
@Override
|
||||
public boolean supportsRegistration() {
|
||||
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
|
||||
return baseProvider.supportsRegistration();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(LoginCredentials credentials) {
|
||||
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
|
||||
baseProvider.register(credentials);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean authenticate(LoginCredentials credentials) {
|
||||
try (final NarCloseable narCloseable = NarCloseable.withNarLoader()) {
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
<div id="login-contents-container">
|
||||
<jsp:include page="/WEB-INF/partials/login/login-message.jsp"/>
|
||||
<jsp:include page="/WEB-INF/partials/login/login-form.jsp"/>
|
||||
<jsp:include page="/WEB-INF/partials/login/user-registration-form.jsp"/>
|
||||
<jsp:include page="/WEB-INF/partials/login/nifi-registration-form.jsp"/>
|
||||
<jsp:include page="/WEB-INF/partials/login/login-submission.jsp"/>
|
||||
</div>
|
||||
|
|
|
@ -27,10 +27,6 @@
|
|||
<div class="setting-name">Password</div>
|
||||
<div class="setting-field">
|
||||
<input type="password" id="password"/>
|
||||
<div id="create-account-message" class="hidden">
|
||||
<div style="font-style: italic;">Don't have an account?</div>
|
||||
<div><span id="create-account-link" class="link">Create one</span> to request access.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -30,10 +30,6 @@
|
|||
<div class="setting-field">
|
||||
<textarea cols="30" rows="4" id="nifi-registration-justification" maxlength="500" class="setting-input"></textarea>
|
||||
</div>
|
||||
<div id="login-to-account-message" class="hidden">
|
||||
<div style="font-style: italic;">Already have an account?</div>
|
||||
<div style="margin-top: 2px;"><span id="login-to-account-link" class="link">Log in</span></div>
|
||||
</div>
|
||||
<div style="text-align: right; color: #666; margin-top: 2px; float: right;">
|
||||
<span id="remaining-characters"></span> characters remaining
|
||||
</div>
|
||||
|
|
|
@ -1,34 +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.
|
||||
--%>
|
||||
<%@ page contentType="text/html" pageEncoding="UTF-8" session="false" %>
|
||||
<div id="user-registration-container" class="hidden">
|
||||
<div class="login-title">Create Account</div>
|
||||
<div class="setting">
|
||||
<div class="setting-name">Username</div>
|
||||
<div class="setting-field">
|
||||
<input type="text" id="registration-username"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting">
|
||||
<div class="setting-name">Password</div>
|
||||
<div class="setting-field">
|
||||
<input type="password" id="registration-password" style="margin-bottom: 5px;"/>
|
||||
<br/>
|
||||
<input type="password" id="registration-password-confirmation" placeholder="Confirm password"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -56,18 +56,6 @@ body.login-body input, body.login-body textarea {
|
|||
width: 400px;
|
||||
}
|
||||
|
||||
#create-account-message {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
#create-account-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/*
|
||||
User Registration
|
||||
*/
|
||||
|
||||
/*
|
||||
NiFi Registration
|
||||
*/
|
||||
|
@ -88,15 +76,6 @@ body.login-body input, body.login-body textarea {
|
|||
height: 200px;
|
||||
}
|
||||
|
||||
#login-to-account-message {
|
||||
float: left;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
#login-to-account-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/*
|
||||
Submission
|
||||
*/
|
||||
|
|
|
@ -141,21 +141,15 @@ nf.CanvasHeader = (function () {
|
|||
nf.Shell.showPage(config.urls.helpDocument);
|
||||
});
|
||||
|
||||
// show the login link if supported and user is currently anonymous
|
||||
var isAnonymous = $('#current-user').text() === nf.Canvas.ANONYMOUS_USER_TEXT;
|
||||
if (supportsLogin === true && isAnonymous) {
|
||||
// login link
|
||||
$('#login-link').click(function () {
|
||||
nf.Shell.showPage('login', false);
|
||||
});
|
||||
} else {
|
||||
// hide the login link if the user is already logged in
|
||||
if ($('#current-user').text() !== nf.Canvas.ANONYMOUS_USER_TEXT) {
|
||||
$('#login-link-container').css('display', 'none');
|
||||
}
|
||||
|
||||
// if login is not supported, don't show the current user
|
||||
if (supportsLogin !== true) {
|
||||
$('#current-user-container').css('display', 'none');
|
||||
}
|
||||
// login link
|
||||
$('#login-link').click(function () {
|
||||
nf.Shell.showPage('login', false);
|
||||
});
|
||||
|
||||
// logout link
|
||||
$('#logout-link').click(function () {
|
||||
|
|
|
@ -1087,13 +1087,6 @@ nf.Canvas = (function () {
|
|||
dataType: 'json'
|
||||
});
|
||||
|
||||
// get the login config
|
||||
var loginXhr = $.ajax({
|
||||
type: 'GET',
|
||||
url: config.urls.loginConfig,
|
||||
dataType: 'json'
|
||||
});
|
||||
|
||||
// create the deferred cluster request
|
||||
var isClusteredRequest = $.Deferred(function (deferred) {
|
||||
$.ajax({
|
||||
|
@ -1113,9 +1106,8 @@ nf.Canvas = (function () {
|
|||
}).promise();
|
||||
|
||||
// ensure the config requests are loaded
|
||||
$.when(configXhr, loginXhr, userXhr).done(function (configResult, loginResult) {
|
||||
$.when(configXhr, userXhr).done(function (configResult) {
|
||||
var configResponse = configResult[0];
|
||||
var loginResponse = loginResult[0];
|
||||
|
||||
// calculate the canvas offset
|
||||
var canvasContainer = $('#canvas-container');
|
||||
|
@ -1123,7 +1115,6 @@ nf.Canvas = (function () {
|
|||
|
||||
// get the config details
|
||||
var configDetails = configResponse.config;
|
||||
var loginDetails = loginResponse.config;
|
||||
|
||||
// when both request complete, load the application
|
||||
isClusteredRequest.done(function () {
|
||||
|
@ -1143,7 +1134,7 @@ nf.Canvas = (function () {
|
|||
nf.ContextMenu.init();
|
||||
nf.CanvasToolbar.init();
|
||||
nf.CanvasToolbox.init();
|
||||
nf.CanvasHeader.init(loginDetails.supportsLogin);
|
||||
nf.CanvasHeader.init();
|
||||
nf.GraphControl.init();
|
||||
nf.Search.init();
|
||||
nf.Settings.init();
|
||||
|
|
|
@ -40,20 +40,7 @@ nf.Login = (function () {
|
|||
$('#login-message-container').show();
|
||||
};
|
||||
|
||||
var initializeLogin = function (supportsRegistration) {
|
||||
// if this nifi supports registration, render the registration form
|
||||
if (supportsRegistration === true) {
|
||||
initializeUserRegistration();
|
||||
initializeNiFiRegistration();
|
||||
|
||||
// show the create account message
|
||||
$('#create-account-message').show();
|
||||
|
||||
// toggle between login and signup
|
||||
$('#create-account-link').on('click', function () {
|
||||
showUserRegistration();
|
||||
});
|
||||
}
|
||||
var initializeLogin = function () {
|
||||
};
|
||||
|
||||
var showLogin = function () {
|
||||
|
@ -82,7 +69,6 @@ nf.Login = (function () {
|
|||
|
||||
$('div.nifi-submit-justification').hide();
|
||||
$('#user-registration-container').show();
|
||||
$('#login-to-account-message').show();
|
||||
$('#login-submission-button').text('Create');
|
||||
};
|
||||
|
||||
|
@ -416,7 +402,7 @@ nf.Login = (function () {
|
|||
if (showMessage === true) {
|
||||
initializeMessage();
|
||||
} else if (needsLogin === true) {
|
||||
initializeLogin(loginConfig.supportsRegistration);
|
||||
initializeLogin();
|
||||
showLogin();
|
||||
} else if (needsNiFiRegistration === true) {
|
||||
initializeNiFiRegistration();
|
||||
|
|
|
@ -40,8 +40,6 @@
|
|||
<module>nifi-web</module>
|
||||
<module>nifi-resources</module>
|
||||
<module>nifi-documentation</module>
|
||||
<module>nifi-authorized-users</module>
|
||||
<module>nifi-file-identity-provider</module>
|
||||
</modules>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
|
|
@ -43,11 +43,6 @@
|
|||
<artifactId>nifi-file-authorization-provider</artifactId>
|
||||
<version>0.3.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-file-identity-provider</artifactId>
|
||||
<version>0.3.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-cluster-authorization-provider</artifactId>
|
||||
|
@ -63,11 +58,6 @@
|
|||
<artifactId>nifi-runtime</artifactId>
|
||||
<version>0.3.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-authorized-users</artifactId>
|
||||
<version>0.3.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.nifi</groupId>
|
||||
<artifactId>nifi-client-dto</artifactId>
|
||||
|
|
Loading…
Reference in New Issue