NIFI-11735 Refactored Identity Provider Groups Handling (#7419)

- Removed H2 database approach in favor of passing groups in Application Bearer Token
This commit is contained in:
exceptionfactory 2023-06-22 10:07:23 -05:00 committed by GitHub
parent 9709bd6fb7
commit 0f736e060a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 116 additions and 1219 deletions

View File

@ -50,10 +50,6 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-properties</artifactId>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-security-utils</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
@ -78,10 +74,6 @@
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>

View File

@ -1,152 +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.admin;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.util.NiFiProperties;
import org.h2.jdbcx.JdbcConnectionPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import java.io.File;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class IdpDataSourceFactoryBean implements FactoryBean<JdbcConnectionPool> {
private static final Logger logger = LoggerFactory.getLogger(IdpDataSourceFactoryBean.class);
private static final String NF_USERNAME_PASSWORD = "nf";
private static final int MAX_CONNECTIONS = 5;
// database file name
private static final String IDP_DATABASE_FILE_NAME = "nifi-identity-providers";
// ----------
// idp tables
// ----------
private static final String IDP_USER_GROUP_TABLE_NAME = "IDENTITY_PROVIDER_USER_GROUP";
private static final String CREATE_IDP_USER_GROUP_TABLE = "CREATE TABLE " + IDP_USER_GROUP_TABLE_NAME + " ("
+ "ID INT NOT NULL PRIMARY KEY AUTO_INCREMENT, "
+ "IDENTITY VARCHAR2(4096) NOT NULL, "
+ "IDP_TYPE VARCHAR2(200) NOT NULL, "
+ "GROUP_NAME VARCHAR2(4096) NOT NULL, "
+ "CREATED TIMESTAMP NOT NULL, "
+ "CONSTRAINT UK__IDENTITY_GROUP_NAME UNIQUE (IDENTITY, GROUP_NAME)" +
")";
private JdbcConnectionPool connectionPool;
private NiFiProperties properties;
@Override
public JdbcConnectionPool getObject() throws Exception {
if (connectionPool == null) {
// locate the repository directory
String repositoryDirectoryPath = properties.getProperty(NiFiProperties.REPOSITORY_DATABASE_DIRECTORY);
// ensure the repository directory is specified
if (repositoryDirectoryPath == null) {
throw new NullPointerException("Database directory must be specified.");
}
// create a handle to the repository directory
File repositoryDirectory = new File(repositoryDirectoryPath);
// create a handle to the database directory and file
File dbFileNoExtension = new File(repositoryDirectory, IDP_DATABASE_FILE_NAME);
String databaseUrl = getDatabaseUrl(dbFileNoExtension);
// create the pool
connectionPool = JdbcConnectionPool.create(databaseUrl, NF_USERNAME_PASSWORD, NF_USERNAME_PASSWORD);
connectionPool.setMaxConnections(MAX_CONNECTIONS);
Connection connection = null;
ResultSet rs = null;
Statement statement = null;
try {
// get a connection
connection = connectionPool.getConnection();
connection.setAutoCommit(false);
// create a statement for creating/updating the database
statement = connection.createStatement();
// determine if the idp tables need to be created
rs = connection.getMetaData().getTables(null, null, IDP_USER_GROUP_TABLE_NAME, null);
if (!rs.next()) {
statement.execute(CREATE_IDP_USER_GROUP_TABLE);
}
// commit any changes
connection.commit();
} catch (SQLException sqle) {
RepositoryUtils.rollback(connection, logger);
throw sqle;
} finally {
RepositoryUtils.closeQuietly(rs);
RepositoryUtils.closeQuietly(statement);
RepositoryUtils.closeQuietly(connection);
}
}
return connectionPool;
}
private String getDatabaseUrl(File databaseFile) {
String databaseUrl = "jdbc:h2:" + databaseFile + ";AUTOCOMMIT=OFF;DB_CLOSE_ON_EXIT=FALSE;LOCK_MODE=3";
String databaseUrlAppend = properties.getProperty(NiFiProperties.H2_URL_APPEND);
if (StringUtils.isNotBlank(databaseUrlAppend)) {
databaseUrl += databaseUrlAppend;
}
return databaseUrl;
}
@Override
public Class getObjectType() {
return JdbcConnectionPool.class;
}
@Override
public boolean isSingleton() {
return true;
}
public void setProperties(NiFiProperties properties) {
this.properties = properties;
}
public void shutdown() {
// shutdown the connection pool
if (connectionPool != null) {
try {
connectionPool.dispose();
} catch (Exception e) {
logger.warn("Unable to dispose of connection pool: " + e.getMessage());
if (logger.isDebugEnabled()) {
logger.warn(StringUtils.EMPTY, e);
}
}
}
}
}

View File

@ -22,7 +22,4 @@ package org.apache.nifi.admin.dao;
public interface DAOFactory {
ActionDAO getActionDAO();
IdpUserGroupDAO getIdpUserGroupDAO();
}

View File

@ -32,8 +32,4 @@ public class DataAccessException extends RuntimeException {
public DataAccessException(String message) {
super(message);
}
public DataAccessException() {
}
}

View File

@ -1,37 +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.admin.dao;
import org.apache.nifi.idp.IdpUserGroup;
import java.util.List;
public interface IdpUserGroupDAO {
IdpUserGroup createUserGroup(IdpUserGroup userGroup) throws DataAccessException;
List<IdpUserGroup> createUserGroups(List<IdpUserGroup> userGroups) throws DataAccessException;
IdpUserGroup findUserGroupById(int id) throws DataAccessException;
List<IdpUserGroup> findUserGroupsByIdentity(String identity) throws DataAccessException;
int deleteUserGroupById(int id) throws DataAccessException;
int deleteUserGroupsByIdentity(String identity) throws DataAccessException;
}

View File

@ -18,7 +18,6 @@ package org.apache.nifi.admin.dao.impl;
import org.apache.nifi.admin.dao.ActionDAO;
import org.apache.nifi.admin.dao.DAOFactory;
import org.apache.nifi.admin.dao.IdpUserGroupDAO;
import java.sql.Connection;
@ -37,9 +36,4 @@ public class DAOFactoryImpl implements DAOFactory {
public ActionDAO getActionDAO() {
return new StandardActionDAO(connection);
}
@Override
public IdpUserGroupDAO getIdpUserGroupDAO() {
return new StandardIdpUserGroupDAO(connection);
}
}

View File

@ -1,244 +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.admin.dao.impl;
import org.apache.nifi.admin.RepositoryUtils;
import org.apache.nifi.admin.dao.DataAccessException;
import org.apache.nifi.admin.dao.IdpUserGroupDAO;
import org.apache.nifi.idp.IdpType;
import org.apache.nifi.idp.IdpUserGroup;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class StandardIdpUserGroupDAO implements IdpUserGroupDAO {
private static final String INSERT_USER_GROUP = "INSERT INTO IDENTITY_PROVIDER_USER_GROUP " +
"(IDENTITY, IDP_TYPE, GROUP_NAME, CREATED) VALUES (?, ?, ?, ?)";
private static final String SELECT_USER_GROUP_BY_ID = "SELECT ID, IDENTITY, IDP_TYPE, GROUP_NAME, CREATED " +
"FROM IDENTITY_PROVIDER_USER_GROUP " +
"WHERE ID =?";
private static final String SELECT_USER_GROUP_BY_IDENTITY = "SELECT ID, IDENTITY, IDP_TYPE, GROUP_NAME, CREATED " +
"FROM IDENTITY_PROVIDER_USER_GROUP " +
"WHERE IDENTITY =?";
private static final String DELETE_USER_GROUPS_BY_ID = "DELETE FROM IDENTITY_PROVIDER_USER_GROUP " +
"WHERE ID = ?";
private static final String DELETE_USER_GROUPS_BY_IDENTITY = "DELETE FROM IDENTITY_PROVIDER_USER_GROUP " +
"WHERE IDENTITY = ?";
private final Connection connection;
public StandardIdpUserGroupDAO(final Connection connection) {
this.connection = connection;
}
@Override
public IdpUserGroup createUserGroup(final IdpUserGroup userGroup) throws DataAccessException {
if (userGroup == null) {
throw new IllegalArgumentException("UserGroup cannot be null");
}
PreparedStatement statement = null;
ResultSet rs = null;
try {
// populate the parameters
statement = connection.prepareStatement(INSERT_USER_GROUP, Statement.RETURN_GENERATED_KEYS);
populateStatement(statement, userGroup);
// execute the insert
int updateCount = statement.executeUpdate();
rs = statement.getGeneratedKeys();
// verify the results
if (updateCount == 1 && rs.next()) {
userGroup.setId(rs.getInt(1));
return userGroup;
} else {
throw new DataAccessException("Unable to save IDP User Group.");
}
} catch (SQLException sqle) {
throw new DataAccessException(sqle);
} finally {
RepositoryUtils.closeQuietly(rs);
RepositoryUtils.closeQuietly(statement);
}
}
@Override
public List<IdpUserGroup> createUserGroups(final List<IdpUserGroup> userGroups) throws DataAccessException {
if (userGroups == null) {
throw new IllegalArgumentException("UserGroups cannot be null");
}
PreparedStatement statement = null;
ResultSet rs = null;
try {
// populate the parameters
statement = connection.prepareStatement(INSERT_USER_GROUP, Statement.RETURN_GENERATED_KEYS);
for (final IdpUserGroup userGroup : userGroups) {
populateStatement(statement, userGroup);
statement.addBatch();
}
int[] updateCounts = statement.executeBatch();
if (updateCounts.length != userGroups.size()) {
throw new DataAccessException("Unable to save IDP User Groups");
}
for (int i=0; i < updateCounts.length; i++) {
if (updateCounts[i] == 0) {
throw new DataAccessException("Unable to save IDP User Groups");
}
}
rs = statement.getGeneratedKeys();
int count = 0;
while (rs.next()) {
final int id = rs.getInt(1);
final IdpUserGroup userGroup = userGroups.get(count);
userGroup.setId(id);
count++;
}
} catch (SQLException sqle) {
throw new DataAccessException(sqle);
} finally {
RepositoryUtils.closeQuietly(rs);
RepositoryUtils.closeQuietly(statement);
}
return userGroups;
}
private void populateStatement(PreparedStatement statement, IdpUserGroup userGroup) throws SQLException {
statement.setString(1, userGroup.getIdentity());
statement.setString(2, userGroup.getType().name());
statement.setString(3, userGroup.getGroupName());
statement.setTimestamp(4, new java.sql.Timestamp(userGroup.getCreated().getTime()));
}
@Override
public IdpUserGroup findUserGroupById(final int id) throws DataAccessException {
IdpUserGroup userGroup = null;
PreparedStatement statement = null;
ResultSet rs = null;
try {
// set parameters
statement = connection.prepareStatement(SELECT_USER_GROUP_BY_ID);
statement.setInt(1, id);
// execute the query
rs = statement.executeQuery();
// if the group was found, add it
if (rs.next()) {
userGroup = new IdpUserGroup();
populateUserGroup(rs, userGroup);
}
} catch (SQLException sqle) {
throw new DataAccessException(sqle);
} finally {
RepositoryUtils.closeQuietly(rs);
RepositoryUtils.closeQuietly(statement);
}
return userGroup;
}
@Override
public List<IdpUserGroup> findUserGroupsByIdentity(final String identity) throws DataAccessException {
final List<IdpUserGroup> userGroups = new ArrayList<>();
PreparedStatement statement = null;
ResultSet rs = null;
try {
// set parameters
statement = connection.prepareStatement(SELECT_USER_GROUP_BY_IDENTITY);
statement.setString(1, identity);
// execute the query
rs = statement.executeQuery();
// add any found groups to the result list
while (rs.next()) {
final IdpUserGroup userGroup = new IdpUserGroup();
populateUserGroup(rs, userGroup);
userGroups.add(userGroup);
}
} catch (SQLException sqle) {
throw new DataAccessException(sqle);
} finally {
RepositoryUtils.closeQuietly(rs);
RepositoryUtils.closeQuietly(statement);
}
return userGroups;
}
@Override
public int deleteUserGroupById(int id) throws DataAccessException {
PreparedStatement statement = null;
try {
statement = connection.prepareStatement(DELETE_USER_GROUPS_BY_ID);
statement.setInt(1, id);
return statement.executeUpdate();
} catch (SQLException sqle) {
throw new DataAccessException(sqle);
} catch (DataAccessException dae) {
throw dae;
} finally {
RepositoryUtils.closeQuietly(statement);
}
}
@Override
public int deleteUserGroupsByIdentity(final String identity) throws DataAccessException {
PreparedStatement statement = null;
try {
statement = connection.prepareStatement(DELETE_USER_GROUPS_BY_IDENTITY);
statement.setString(1, identity);
return statement.executeUpdate();
} catch (SQLException sqle) {
throw new DataAccessException(sqle);
} catch (DataAccessException dae) {
throw dae;
} finally {
RepositoryUtils.closeQuietly(statement);
}
}
private void populateUserGroup(final ResultSet rs, final IdpUserGroup userGroup) throws SQLException {
userGroup.setId(rs.getInt("ID"));
userGroup.setIdentity(rs.getString("IDENTITY"));
userGroup.setType(IdpType.valueOf(rs.getString("IDP_TYPE")));
userGroup.setGroupName(rs.getString("GROUP_NAME"));
userGroup.setCreated(new Date(rs.getTimestamp("CREATED").getTime()));
}
}

View File

@ -1,71 +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.admin.service;
import org.apache.nifi.idp.IdpType;
import org.apache.nifi.idp.IdpUserGroup;
import java.util.List;
import java.util.Set;
/**
* Manages IDP User Groups.
*/
public interface IdpUserGroupService {
/**
* Creates the given user group.
*
* @param userGroup the user group to create
* @return the created user group
*/
IdpUserGroup createUserGroup(IdpUserGroup userGroup);
/**
* Creates the given user groups.
*
* @param userGroups the user group to create
* @return the created user group
*/
List<IdpUserGroup> createUserGroups(List<IdpUserGroup> userGroups);
/**
* Gets the user groups for the given identity.
*
* @param identity the user identity
* @return the list of user groups
*/
List<IdpUserGroup> getUserGroups(String identity);
/**
* Deletes the user groups for the given identity.
*
* @param identity the user identity
*/
void deleteUserGroups(String identity);
/**
* Replaces any existing groups for the given user identity with a new set specified by the set of group names.
*
* @param userIdentity the user identity
* @param idpType the idp type for the groups
* @param groupNames the group names, should already have identity mappings applied if necessary
* @return the created groups
*/
List<IdpUserGroup> replaceUserGroups(String userIdentity, IdpType idpType, Set<String> groupNames);
}

View File

@ -1,37 +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.admin.service.action;
import org.apache.nifi.admin.dao.DAOFactory;
import org.apache.nifi.admin.dao.IdpUserGroupDAO;
import org.apache.nifi.idp.IdpUserGroup;
public class CreateIdpUserGroup implements AdministrationAction<IdpUserGroup> {
final IdpUserGroup userGroup;
public CreateIdpUserGroup(final IdpUserGroup userGroup) {
this.userGroup = userGroup;
}
@Override
public IdpUserGroup execute(DAOFactory daoFactory) {
final IdpUserGroupDAO userGroupDAO = daoFactory.getIdpUserGroupDAO();
return userGroupDAO.createUserGroup(userGroup);
}
}

View File

@ -1,38 +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.admin.service.action;
import org.apache.nifi.admin.dao.DAOFactory;
import org.apache.nifi.admin.dao.IdpUserGroupDAO;
import org.apache.nifi.idp.IdpUserGroup;
import java.util.List;
public class CreateIdpUserGroups implements AdministrationAction<List<IdpUserGroup>> {
private final List<IdpUserGroup> userGroups;
public CreateIdpUserGroups(List<IdpUserGroup> userGroups) {
this.userGroups = userGroups;
}
@Override
public List<IdpUserGroup> execute(DAOFactory daoFactory) {
final IdpUserGroupDAO userGroupDAO = daoFactory.getIdpUserGroupDAO();
return userGroupDAO.createUserGroups(userGroups);
}
}

View File

@ -1,35 +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.admin.service.action;
import org.apache.nifi.admin.dao.DAOFactory;
import org.apache.nifi.admin.dao.IdpUserGroupDAO;
public class DeleteIdpUserGroupsByIdentity implements AdministrationAction<Integer> {
final String identity;
public DeleteIdpUserGroupsByIdentity(String identity) {
this.identity = identity;
}
@Override
public Integer execute(DAOFactory daoFactory) {
final IdpUserGroupDAO userGroupDAO = daoFactory.getIdpUserGroupDAO();
return userGroupDAO.deleteUserGroupsByIdentity(identity);
}
}

View File

@ -1,38 +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.admin.service.action;
import org.apache.nifi.admin.dao.DAOFactory;
import org.apache.nifi.admin.dao.IdpUserGroupDAO;
import org.apache.nifi.idp.IdpUserGroup;
import java.util.List;
public class GetIdpUserGroupsByIdentity implements AdministrationAction<List<IdpUserGroup>> {
final String identity;
public GetIdpUserGroupsByIdentity(String identity) {
this.identity = identity;
}
@Override
public List<IdpUserGroup> execute(DAOFactory daoFactory) {
final IdpUserGroupDAO userGroupDAO = daoFactory.getIdpUserGroupDAO();
return userGroupDAO.findUserGroupsByIdentity(identity);
}
}

View File

@ -1,247 +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.admin.service.impl;
import org.apache.nifi.admin.dao.DataAccessException;
import org.apache.nifi.admin.service.AdministrationException;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.admin.service.action.CreateIdpUserGroup;
import org.apache.nifi.admin.service.action.CreateIdpUserGroups;
import org.apache.nifi.admin.service.action.DeleteIdpUserGroupsByIdentity;
import org.apache.nifi.admin.service.action.GetIdpUserGroupsByIdentity;
import org.apache.nifi.admin.service.transaction.Transaction;
import org.apache.nifi.admin.service.transaction.TransactionBuilder;
import org.apache.nifi.admin.service.transaction.TransactionException;
import org.apache.nifi.idp.IdpType;
import org.apache.nifi.idp.IdpUserGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class StandardIdpUserGroupService implements IdpUserGroupService {
private static Logger LOGGER = LoggerFactory.getLogger(StandardIdpUserGroupService.class);
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
private TransactionBuilder transactionBuilder;
@Override
public IdpUserGroup createUserGroup(final IdpUserGroup userGroup) {
Transaction transaction = null;
IdpUserGroup createdUserGroup;
writeLock.lock();
try {
// ensure the created date is set
if (userGroup.getCreated() == null) {
userGroup.setCreated(new Date());
}
// start the transaction
transaction = transactionBuilder.start();
// create the user group
final CreateIdpUserGroup action = new CreateIdpUserGroup(userGroup);
createdUserGroup = transaction.execute(action);
// commit the transaction
transaction.commit();
} catch (TransactionException | DataAccessException te) {
rollback(transaction);
throw new AdministrationException(te);
} catch (Throwable t) {
rollback(transaction);
throw t;
} finally {
closeQuietly(transaction);
writeLock.unlock();
}
return createdUserGroup;
}
@Override
public List<IdpUserGroup> createUserGroups(final List<IdpUserGroup> userGroups) {
Transaction transaction = null;
List<IdpUserGroup> createdUserGroups;
writeLock.lock();
try {
// ensure the created date is set
for (final IdpUserGroup userGroup : userGroups) {
if (userGroup.getCreated() == null) {
userGroup.setCreated(new Date());
}
}
// start the transaction
transaction = transactionBuilder.start();
// create the user group
final CreateIdpUserGroups action = new CreateIdpUserGroups(userGroups);
createdUserGroups = transaction.execute(action);
// commit the transaction
transaction.commit();
} catch (TransactionException | DataAccessException te) {
rollback(transaction);
throw new AdministrationException(te);
} catch (Throwable t) {
rollback(transaction);
throw t;
} finally {
closeQuietly(transaction);
writeLock.unlock();
}
return createdUserGroups;
}
@Override
public List<IdpUserGroup> getUserGroups(final String identity) {
Transaction transaction = null;
List<IdpUserGroup> userGroups;
readLock.lock();
try {
// start the transaction
transaction = transactionBuilder.start();
// get the user groups
final GetIdpUserGroupsByIdentity action = new GetIdpUserGroupsByIdentity(identity);
userGroups = transaction.execute(action);
// commit the transaction
transaction.commit();
} catch (TransactionException | DataAccessException te) {
rollback(transaction);
throw new AdministrationException(te);
} catch (Throwable t) {
rollback(transaction);
throw t;
} finally {
closeQuietly(transaction);
readLock.unlock();
}
return userGroups;
}
@Override
public void deleteUserGroups(final String identity) {
Transaction transaction = null;
writeLock.lock();
try {
// start the transaction
transaction = transactionBuilder.start();
// delete the credential
final DeleteIdpUserGroupsByIdentity action = new DeleteIdpUserGroupsByIdentity(identity);
Integer rowsDeleted = transaction.execute(action);
LOGGER.debug("Deleted {} user groups for identity {}", rowsDeleted, identity);
// commit the transaction
transaction.commit();
} catch (TransactionException | DataAccessException te) {
rollback(transaction);
throw new AdministrationException(te);
} catch (Throwable t) {
rollback(transaction);
throw t;
} finally {
closeQuietly(transaction);
writeLock.unlock();
}
}
@Override
public List<IdpUserGroup> replaceUserGroups(final String userIdentity, final IdpType idpType, final Set<String> groupNames) {
Transaction transaction = null;
List<IdpUserGroup> createdUserGroups;
writeLock.lock();
try {
// start the transaction
transaction = transactionBuilder.start();
// delete the existing groups
final DeleteIdpUserGroupsByIdentity deleteAction = new DeleteIdpUserGroupsByIdentity(userIdentity);
Integer rowsDeleted = transaction.execute(deleteAction);
LOGGER.debug("Deleted {} user groups for identity {}", rowsDeleted, userIdentity);
// create the user groups
final List<IdpUserGroup> idpUserGroups = new ArrayList<>();
for (final String groupName : groupNames) {
final IdpUserGroup idpUserGroup = new IdpUserGroup();
idpUserGroup.setIdentity(userIdentity);
idpUserGroup.setType(idpType);
idpUserGroup.setGroupName(groupName);
idpUserGroup.setCreated(new Date());
idpUserGroups.add(idpUserGroup);
LOGGER.debug("{} belongs to {}", userIdentity, groupName);
}
final CreateIdpUserGroups createAction = new CreateIdpUserGroups(idpUserGroups);
createdUserGroups = transaction.execute(createAction);
// commit the transaction
transaction.commit();
} catch (TransactionException | DataAccessException te) {
rollback(transaction);
throw new AdministrationException(te);
} catch (Throwable t) {
rollback(transaction);
throw t;
} finally {
closeQuietly(transaction);
writeLock.unlock();
}
return createdUserGroups;
}
private void rollback(final Transaction transaction) {
if (transaction != null) {
transaction.rollback();
}
}
private void closeQuietly(final Transaction transaction) {
if (transaction != null) {
try {
transaction.close();
} catch (final IOException ioe) {
}
}
}
public void setTransactionBuilder(TransactionBuilder transactionBuilder) {
this.transactionBuilder = transactionBuilder;
}
}

View File

@ -1,27 +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.idp;
/**
* Types of identity providers.
*/
public enum IdpType {
OIDC,
SAML;
}

View File

@ -1,85 +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.idp;
import java.util.Date;
public class IdpUserGroup {
private int id;
private String identity;
private IdpType type;
private String groupName;
private Date created;
public IdpUserGroup() {
}
public IdpUserGroup(int id, String identity, IdpType type, String groupName) {
this(id, identity, type, groupName, new Date());
}
public IdpUserGroup(int id, String identity, IdpType type, String groupName, Date created) {
this.id = id;
this.identity = identity;
this.type = type;
this.groupName = groupName;
this.created = created;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getIdentity() {
return identity;
}
public void setIdentity(String identity) {
this.identity = identity;
}
public IdpType getType() {
return type;
}
public void setType(IdpType type) {
this.type = type;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
}

View File

@ -23,29 +23,14 @@
<property name="properties" ref="nifiProperties"/>
</bean>
<!-- initialize the idp data source -->
<bean id="idpDataSource" class="org.apache.nifi.admin.IdpDataSourceFactoryBean" destroy-method="shutdown">
<property name="properties" ref="nifiProperties"/>
</bean>
<!-- initialize the audit transaction builder -->
<bean id="auditTransactionBuilder" class="org.apache.nifi.admin.service.transaction.impl.StandardTransactionBuilder">
<property name="dataSource" ref="auditDataSource"/>
</bean>
<!-- initialize the idp transaction builder -->
<bean id="idpTransactionBuilder" class="org.apache.nifi.admin.service.transaction.impl.StandardTransactionBuilder">
<property name="dataSource" ref="idpDataSource"/>
</bean>
<!-- audit service -->
<bean id="auditService" class="org.apache.nifi.admin.service.impl.StandardAuditService">
<property name="transactionBuilder" ref="auditTransactionBuilder"/>
</bean>
<!-- idp user group service -->
<bean id="idpUserGroupService" class="org.apache.nifi.admin.service.impl.StandardIdpUserGroupService">
<property name="transactionBuilder" ref="idpTransactionBuilder"/>
</bean>
</beans>

View File

@ -22,7 +22,6 @@ import com.nimbusds.jwt.proc.DefaultJWTClaimsVerifier;
import com.nimbusds.jwt.proc.DefaultJWTProcessor;
import com.nimbusds.jwt.proc.JWTClaimsSetVerifier;
import com.nimbusds.jwt.proc.JWTProcessor;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.components.state.StateManager;
import org.apache.nifi.components.state.StateManagerProvider;
@ -79,15 +78,14 @@ public class JwtAuthenticationSecurityConfiguration {
SupportedClaim.EXPIRATION.getClaim(),
SupportedClaim.NOT_BEFORE.getClaim(),
SupportedClaim.ISSUED_AT.getClaim(),
SupportedClaim.JWT_ID.getClaim()
SupportedClaim.JWT_ID.getClaim(),
SupportedClaim.GROUPS.getClaim()
));
private final NiFiProperties niFiProperties;
private final Authorizer authorizer;
private final IdpUserGroupService idpUserGroupService;
private final StateManagerProvider stateManagerProvider;
private final Duration keyRotationPeriod;
@ -96,12 +94,10 @@ public class JwtAuthenticationSecurityConfiguration {
public JwtAuthenticationSecurityConfiguration(
final NiFiProperties niFiProperties,
final Authorizer authorizer,
final IdpUserGroupService idpUserGroupService,
final StateManagerProvider stateManagerProvider
) {
this.niFiProperties = niFiProperties;
this.authorizer = authorizer;
this.idpUserGroupService = idpUserGroupService;
this.stateManagerProvider = stateManagerProvider;
this.keyRotationPeriod = niFiProperties.getSecurityUserJwsKeyRotationPeriod();
}
@ -180,7 +176,7 @@ public class JwtAuthenticationSecurityConfiguration {
@Bean
public StandardJwtAuthenticationConverter jwtAuthenticationConverter() {
return new StandardJwtAuthenticationConverter(authorizer, idpUserGroupService, niFiProperties);
return new StandardJwtAuthenticationConverter(authorizer, niFiProperties);
}
@Bean

View File

@ -19,7 +19,6 @@ package org.apache.nifi.web.security.configuration;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import okhttp3.OkHttpClient;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.authorization.util.IdentityMappingUtil;
import org.apache.nifi.components.state.StateManager;
import org.apache.nifi.components.state.StateManagerProvider;
@ -129,8 +128,6 @@ public class OidcSecurityConfiguration {
private final BearerTokenResolver bearerTokenResolver;
private final IdpUserGroupService idpUserGroupService;
private final JwtDecoder jwtDecoder;
private final LogoutRequestManager logoutRequestManager;
@ -142,7 +139,6 @@ public class OidcSecurityConfiguration {
final PropertyEncryptor propertyEncryptor,
final BearerTokenProvider bearerTokenProvider,
final BearerTokenResolver bearerTokenResolver,
final IdpUserGroupService idpUserGroupService,
final JwtDecoder jwtDecoder,
final LogoutRequestManager logoutRequestManager
) {
@ -151,7 +147,6 @@ public class OidcSecurityConfiguration {
this.propertyEncryptor = Objects.requireNonNull(propertyEncryptor, "Property Encryptor required");
this.bearerTokenProvider = Objects.requireNonNull(bearerTokenProvider, "Bearer Token Provider required");
this.bearerTokenResolver = Objects.requireNonNull(bearerTokenResolver, "Bearer Token Resolver required");
this.idpUserGroupService = Objects.requireNonNull(idpUserGroupService, "User Group Service required");
this.jwtDecoder = Objects.requireNonNull(jwtDecoder, "JWT Decoder required");
this.logoutRequestManager = Objects.requireNonNull(logoutRequestManager, "Logout Request Manager required");
this.keyRotationPeriod = properties.getSecurityUserJwsKeyRotationPeriod();
@ -261,7 +256,6 @@ public class OidcSecurityConfiguration {
public LogoutSuccessHandler oidcLogoutSuccessHandler() {
return new OidcLogoutSuccessHandler(
logoutRequestManager,
idpUserGroupService,
clientRegistrationRepository(),
authorizedClientRepository(),
tokenRevocationResponseClient()
@ -480,7 +474,6 @@ public class OidcSecurityConfiguration {
return new OidcAuthenticationSuccessHandler(
bearerTokenProvider,
idpUserGroupService,
IdentityMappingUtil.getIdentityMappings(properties),
IdentityMappingUtil.getGroupMappings(properties),
userClaimNames,

View File

@ -18,7 +18,6 @@ package org.apache.nifi.web.security.configuration;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.authorization.util.IdentityMappingUtil;
import org.apache.nifi.util.FormatUtils;
import org.apache.nifi.util.NiFiProperties;
@ -93,19 +92,15 @@ public class SamlAuthenticationSecurityConfiguration {
private final LogoutRequestManager logoutRequestManager;
private final IdpUserGroupService idpUserGroupService;
@Autowired
public SamlAuthenticationSecurityConfiguration(
final NiFiProperties properties,
final BearerTokenProvider bearerTokenProvider,
final LogoutRequestManager logoutRequestManager,
final IdpUserGroupService idpUserGroupService
final LogoutRequestManager logoutRequestManager
) {
this.properties = Objects.requireNonNull(properties, "Properties required");
this.bearerTokenProvider = Objects.requireNonNull(bearerTokenProvider, "Bearer Token Provider required");
this.logoutRequestManager = Objects.requireNonNull(logoutRequestManager, "Logout Request Manager required");
this.idpUserGroupService = Objects.requireNonNull(idpUserGroupService, "User Group Service required");
}
/**
@ -336,7 +331,7 @@ public class SamlAuthenticationSecurityConfiguration {
*/
@Bean
public Saml2LogoutSuccessHandler saml2LogoutSuccessHandler() {
return new Saml2LogoutSuccessHandler(logoutRequestManager, idpUserGroupService);
return new Saml2LogoutSuccessHandler(logoutRequestManager);
}
/**
@ -373,7 +368,6 @@ public class SamlAuthenticationSecurityConfiguration {
final String issuer = entityId == null ? Saml2RegistrationProperty.REGISTRATION_ID.getProperty() : entityId;
final Saml2AuthenticationSuccessHandler handler = new Saml2AuthenticationSuccessHandler(
bearerTokenProvider,
idpUserGroupService,
IdentityMappingUtil.getIdentityMappings(properties),
IdentityMappingUtil.getGroupMappings(properties),
expiration,

View File

@ -16,7 +16,6 @@
*/
package org.apache.nifi.web.security.jwt.converter;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserDetails;
@ -24,15 +23,16 @@ import org.apache.nifi.authorization.user.StandardNiFiUser;
import org.apache.nifi.authorization.util.IdentityMapping;
import org.apache.nifi.authorization.util.IdentityMappingUtil;
import org.apache.nifi.authorization.util.UserGroupUtil;
import org.apache.nifi.idp.IdpUserGroup;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.web.security.jwt.provider.SupportedClaim;
import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.oauth2.jwt.Jwt;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Standard Converter from JSON Web Token to NiFi Authentication Token
@ -40,13 +40,10 @@ import java.util.stream.Collectors;
public class StandardJwtAuthenticationConverter implements Converter<Jwt, NiFiAuthenticationToken> {
private final Authorizer authorizer;
private final IdpUserGroupService idpUserGroupService;
private final List<IdentityMapping> identityMappings;
public StandardJwtAuthenticationConverter(final Authorizer authorizer, final IdpUserGroupService idpUserGroupService, final NiFiProperties properties) {
public StandardJwtAuthenticationConverter(final Authorizer authorizer, final NiFiProperties properties) {
this.authorizer = authorizer;
this.idpUserGroupService = idpUserGroupService;
this.identityMappings = IdentityMappingUtil.getIdentityMappings(properties);
}
@ -65,16 +62,23 @@ public class StandardJwtAuthenticationConverter implements Converter<Jwt, NiFiAu
private NiFiUser getUser(final Jwt jwt) {
final String identity = IdentityMappingUtil.mapIdentity(jwt.getSubject(), identityMappings);
final Set<String> providedGroups = getProvidedGroups(jwt);
return new StandardNiFiUser.Builder()
.identity(identity)
.groups(UserGroupUtil.getUserGroups(authorizer, identity))
.identityProviderGroups(getIdentityProviderGroups(identity))
.identityProviderGroups(providedGroups)
.build();
}
private Set<String> getIdentityProviderGroups(final String identity) {
return idpUserGroupService.getUserGroups(identity).stream()
.map(IdpUserGroup::getGroupName)
.collect(Collectors.toSet());
private Set<String> getProvidedGroups(final Jwt jwt) {
final List<String> claimGroups = jwt.getClaimAsStringList(SupportedClaim.GROUPS.getClaim());
final Set<String> providedGroups;
if (claimGroups == null) {
providedGroups = Collections.emptySet();
} else {
providedGroups = new LinkedHashSet<>(claimGroups);
}
return providedGroups;
}
}

View File

@ -28,15 +28,19 @@ import org.apache.nifi.web.security.jwt.jws.JwsSignerProvider;
import org.apache.nifi.web.security.token.LoginAuthenticationToken;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.GrantedAuthority;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* Standard Bearer Token Provider supports returning serialized and signed JSON Web Tokens
@ -68,6 +72,7 @@ public class StandardBearerTokenProvider implements BearerTokenProvider {
final String subject = Objects.requireNonNull(loginAuthenticationToken.getPrincipal(), "Principal required").toString();
final String username = loginAuthenticationToken.getName();
final List<String> groups = getGroups(loginAuthenticationToken.getAuthorities());
final String issuer = getUrlEncoded(loginAuthenticationToken.getIssuer());
final Date now = new Date();
final Date expirationTime = getExpirationTime(loginAuthenticationToken);
@ -80,6 +85,7 @@ public class StandardBearerTokenProvider implements BearerTokenProvider {
.issueTime(now)
.expirationTime(expirationTime)
.claim(SupportedClaim.PREFERRED_USERNAME.getClaim(), username)
.claim(SupportedClaim.GROUPS.getClaim(), groups)
.build();
return getSignedBearerToken(claims);
}
@ -131,4 +137,8 @@ public class StandardBearerTokenProvider implements BearerTokenProvider {
throw new IllegalArgumentException(String.format("URL Encoding [%s] Failed", string), e);
}
}
private List<String> getGroups(final Collection<? extends GrantedAuthority> authorities) {
return authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
}
}

View File

@ -42,7 +42,10 @@ public enum SupportedClaim {
JWT_ID("jti"),
/** Preferred Username defined in OpenID Connect Core 1.0 Standard Claims */
PREFERRED_USERNAME("preferred_username");
PREFERRED_USERNAME("preferred_username"),
/** RFC 7643 Section 4.1.2 */
GROUPS("groups");
private final String claim;

View File

@ -16,7 +16,6 @@
*/
package org.apache.nifi.web.security.oidc.logout;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.web.security.cookie.ApplicationCookieName;
import org.apache.nifi.web.security.cookie.ApplicationCookieService;
import org.apache.nifi.web.security.cookie.StandardApplicationCookieService;
@ -71,8 +70,6 @@ public class OidcLogoutSuccessHandler implements LogoutSuccessHandler {
private final LogoutRequestManager logoutRequestManager;
private final IdpUserGroupService idpUserGroupService;
private final ClientRegistrationRepository clientRegistrationRepository;
private final OAuth2AuthorizedClientRepository authorizedClientRepository;
@ -83,20 +80,17 @@ public class OidcLogoutSuccessHandler implements LogoutSuccessHandler {
* OpenID Connect Logout Success Handler with RP-Initiated Logout 1.0 and RFC 7009 Token Revocation
*
* @param logoutRequestManager Application Logout Request Manager
* @param idpUserGroupService User Group Service for clearing cached groups
* @param clientRegistrationRepository OIDC Client Registry Repository for configuration information
* @param authorizedClientRepository OIDC Authorized Client Repository for cached tokens
* @param tokenRevocationResponseClient OIDC Revocation Response Client for revoking Refresh Tokens
*/
public OidcLogoutSuccessHandler(
final LogoutRequestManager logoutRequestManager,
final IdpUserGroupService idpUserGroupService,
final ClientRegistrationRepository clientRegistrationRepository,
final OAuth2AuthorizedClientRepository authorizedClientRepository,
final TokenRevocationResponseClient tokenRevocationResponseClient
) {
this.logoutRequestManager = Objects.requireNonNull(logoutRequestManager, "Logout Request Manager required");
this.idpUserGroupService = Objects.requireNonNull(idpUserGroupService, "User Group Service required");
this.clientRegistrationRepository = Objects.requireNonNull(clientRegistrationRepository, "Client Registration Repository required");
this.authorizedClientRepository = Objects.requireNonNull(authorizedClientRepository, "Authorized Client Repository required");
this.tokenRevocationResponseClient = Objects.requireNonNull(tokenRevocationResponseClient, "Revocation Response Client required");
@ -123,7 +117,6 @@ public class OidcLogoutSuccessHandler implements LogoutSuccessHandler {
targetUrl = getPostLogoutRedirectUri(request);
} else {
final String mappedUserIdentity = logoutRequest.getMappedUserIdentity();
idpUserGroupService.deleteUserGroups(mappedUserIdentity);
targetUrl = processLogoutRequest(request, response, requestIdentifier, mappedUserIdentity);
}

View File

@ -16,10 +16,8 @@
*/
package org.apache.nifi.web.security.oidc.web.authentication;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.authorization.util.IdentityMapping;
import org.apache.nifi.authorization.util.IdentityMappingUtil;
import org.apache.nifi.idp.IdpType;
import org.apache.nifi.web.security.cookie.ApplicationCookieName;
import org.apache.nifi.web.security.cookie.ApplicationCookieService;
import org.apache.nifi.web.security.cookie.StandardApplicationCookieService;
@ -28,6 +26,8 @@ import org.apache.nifi.web.security.oidc.OidcConfigurationException;
import org.apache.nifi.web.security.token.LoginAuthenticationToken;
import org.apache.nifi.web.util.RequestUriBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2Token;
@ -59,8 +59,6 @@ public class OidcAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuc
private final BearerTokenProvider bearerTokenProvider;
private final IdpUserGroupService idpUserGroupService;
private final List<IdentityMapping> userIdentityMappings;
private final List<IdentityMapping> groupIdentityMappings;
@ -73,7 +71,6 @@ public class OidcAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuc
* OpenID Connect Authentication Success Handler requires Bearer Token Provider and expiration for generated tokens
*
* @param bearerTokenProvider Bearer Token Provider
* @param idpUserGroupService User Group Service for persisting groups from the Identity Provider
* @param userIdentityMappings User Identity Mappings
* @param groupIdentityMappings Group Identity Mappings
* @param userClaimNames Claim Names for User Identity
@ -81,14 +78,12 @@ public class OidcAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuc
*/
public OidcAuthenticationSuccessHandler(
final BearerTokenProvider bearerTokenProvider,
final IdpUserGroupService idpUserGroupService,
final List<IdentityMapping> userIdentityMappings,
final List<IdentityMapping> groupIdentityMappings,
final List<String> userClaimNames,
final String groupsClaimName
) {
this.bearerTokenProvider = Objects.requireNonNull(bearerTokenProvider, "Bearer Token Provider required");
this.idpUserGroupService = Objects.requireNonNull(idpUserGroupService, "User Group Service required");
this.userIdentityMappings = Objects.requireNonNull(userIdentityMappings, "User Identity Mappings required");
this.groupIdentityMappings = Objects.requireNonNull(groupIdentityMappings, "Group Identity Mappings required");
this.userClaimNames = Objects.requireNonNull(userClaimNames, "User Claim Names required");
@ -117,17 +112,17 @@ public class OidcAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuc
final OidcUser oidcUser = getOidcUser(authenticationToken);
final String identity = getIdentity(oidcUser);
final Set<String> groups = getGroups(oidcUser);
idpUserGroupService.replaceUserGroups(identity, IdpType.OIDC, groups);
final OAuth2AccessToken accessToken = getAccessToken(authenticationToken);
final String bearerToken = getBearerToken(identity, oidcUser, accessToken);
final String bearerToken = getBearerToken(identity, oidcUser, accessToken, groups);
applicationCookieService.addSessionCookie(resourceUri, response, ApplicationCookieName.AUTHORIZATION_BEARER, bearerToken);
}
private String getBearerToken(final String identity, final OidcUser oidcUser, final OAuth2AccessToken accessToken) {
private String getBearerToken(final String identity, final OidcUser oidcUser, final OAuth2AccessToken accessToken, final Set<String> groups) {
final long sessionExpiration = getSessionExpiration(accessToken);
final String issuer = oidcUser.getIssuer().toString();
final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(identity, identity, sessionExpiration, issuer);
final Set<? extends GrantedAuthority> authorities = groups.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet());
final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(identity, identity, sessionExpiration, issuer, authorities);
return bearerTokenProvider.getBearerToken(loginAuthenticationToken);
}

View File

@ -16,10 +16,8 @@
*/
package org.apache.nifi.web.security.saml2.web.authentication;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.authorization.util.IdentityMapping;
import org.apache.nifi.authorization.util.IdentityMappingUtil;
import org.apache.nifi.idp.IdpType;
import org.apache.nifi.web.security.cookie.ApplicationCookieName;
import org.apache.nifi.web.security.cookie.ApplicationCookieService;
import org.apache.nifi.web.security.cookie.StandardApplicationCookieService;
@ -29,6 +27,7 @@ import org.apache.nifi.web.util.RequestUriBuilder;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
@ -53,8 +52,6 @@ public class Saml2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSu
private final BearerTokenProvider bearerTokenProvider;
private final IdpUserGroupService idpUserGroupService;
private final List<IdentityMapping> userIdentityMappings;
private final List<IdentityMapping> groupIdentityMappings;
@ -69,7 +66,6 @@ public class Saml2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSu
* SAML 2 Authentication Success Handler requires Bearer Token Provider and expiration for generated tokens
*
* @param bearerTokenProvider Bearer Token Provider
* @param idpUserGroupService User Group Service for persisting groups from the Identity Provider
* @param userIdentityMappings User Identity Mappings
* @param groupIdentityMappings Group Identity Mappings
* @param expiration Expiration for generated tokens
@ -77,14 +73,12 @@ public class Saml2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSu
*/
public Saml2AuthenticationSuccessHandler(
final BearerTokenProvider bearerTokenProvider,
final IdpUserGroupService idpUserGroupService,
final List<IdentityMapping> userIdentityMappings,
final List<IdentityMapping> groupIdentityMappings,
final Duration expiration,
final String issuer
) {
this.bearerTokenProvider = Objects.requireNonNull(bearerTokenProvider, "Bearer Token Provider required");
this.idpUserGroupService = Objects.requireNonNull(idpUserGroupService, "User Group Service required");
this.userIdentityMappings = Objects.requireNonNull(userIdentityMappings, "User Identity Mappings required");
this.groupIdentityMappings = Objects.requireNonNull(groupIdentityMappings, "Group Identity Mappings required");
this.expiration = Objects.requireNonNull(expiration, "Expiration required");
@ -120,14 +114,14 @@ public class Saml2AuthenticationSuccessHandler extends SimpleUrlAuthenticationSu
private void processAuthentication(final HttpServletResponse response, final Authentication authentication, final URI resourceUri) {
final String identity = getIdentity(authentication);
final Set<String> groups = getGroups(authentication);
idpUserGroupService.replaceUserGroups(identity, IdpType.SAML, groups);
final String bearerToken = getBearerToken(identity);
final String bearerToken = getBearerToken(identity, groups);
applicationCookieService.addSessionCookie(resourceUri, response, ApplicationCookieName.AUTHORIZATION_BEARER, bearerToken);
}
private String getBearerToken(final String identity) {
final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(identity, identity, expiration.toMillis(), issuer);
private String getBearerToken(final String identity, final Set<String> groups) {
final Set<? extends GrantedAuthority> authorities = groups.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet());
final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(identity, identity, expiration.toMillis(), issuer, authorities);
return bearerTokenProvider.getBearerToken(loginAuthenticationToken);
}

View File

@ -16,7 +16,6 @@
*/
package org.apache.nifi.web.security.saml2.web.authentication.logout;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.web.security.cookie.ApplicationCookieName;
import org.apache.nifi.web.security.cookie.ApplicationCookieService;
import org.apache.nifi.web.security.cookie.StandardApplicationCookieService;
@ -47,14 +46,10 @@ public class Saml2LogoutSuccessHandler implements LogoutSuccessHandler {
private final LogoutRequestManager logoutRequestManager;
private final IdpUserGroupService idpUserGroupService;
public Saml2LogoutSuccessHandler(
final LogoutRequestManager logoutRequestManager,
final IdpUserGroupService idpUserGroupService
final LogoutRequestManager logoutRequestManager
) {
this.logoutRequestManager = Objects.requireNonNull(logoutRequestManager, "Logout Request Manager required");
this.idpUserGroupService = Objects.requireNonNull(idpUserGroupService, "User Group Service required");
}
/**
@ -76,8 +71,6 @@ public class Saml2LogoutSuccessHandler implements LogoutSuccessHandler {
logger.warn("Logout Request [{}] not found", requestIdentifier);
} else {
final String mappedUserIdentity = logoutRequest.getMappedUserIdentity();
idpUserGroupService.deleteUserGroups(mappedUserIdentity);
logger.info("Logout Request [{}] Identity [{}] completed", requestIdentifier, mappedUserIdentity);
}

View File

@ -18,7 +18,6 @@ package org.apache.nifi.web.security.jwt.converter;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.PlainJWT;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.authorization.AccessPolicyProvider;
import org.apache.nifi.authorization.Group;
import org.apache.nifi.authorization.ManagedAuthorizer;
@ -26,9 +25,9 @@ import org.apache.nifi.authorization.UserAndGroups;
import org.apache.nifi.authorization.UserGroupProvider;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserDetails;
import org.apache.nifi.idp.IdpUserGroup;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.StringUtils;
import org.apache.nifi.web.security.jwt.provider.SupportedClaim;
import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -39,6 +38,7 @@ import org.springframework.security.oauth2.jwt.Jwt;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -71,16 +71,13 @@ public class StandardJwtAuthenticationConverterTest {
@Mock
private UserAndGroups userAndGroups;
@Mock
private IdpUserGroupService idpUserGroupService;
private StandardJwtAuthenticationConverter converter;
@BeforeEach
public void setConverter() {
final Map<String, String> properties = new HashMap<>();
final NiFiProperties niFiProperties = NiFiProperties.createBasicNiFiProperties(StringUtils.EMPTY, properties);
converter = new StandardJwtAuthenticationConverter(authorizer, idpUserGroupService, niFiProperties);
converter = new StandardJwtAuthenticationConverter(authorizer, niFiProperties);
when(authorizer.getAccessPolicyProvider()).thenReturn(accessPolicyProvider);
when(accessPolicyProvider.getUserGroupProvider()).thenReturn(userGroupProvider);
@ -88,21 +85,21 @@ public class StandardJwtAuthenticationConverterTest {
final Group group = new Group.Builder().name(AUTHORIZER_GROUP).identifier(AUTHORIZER_GROUP).build();
when(userAndGroups.getGroups()).thenReturn(Collections.singleton(group));
final IdpUserGroup idpUserGroup = new IdpUserGroup();
idpUserGroup.setGroupName(PROVIDER_GROUP);
when(idpUserGroupService.getUserGroups(eq(USERNAME))).thenReturn(Collections.singletonList(idpUserGroup));
}
@Test
public void testConvert() {
final List<String> providerGroups = Collections.singletonList(PROVIDER_GROUP);
final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
.subject(USERNAME)
.claim(SupportedClaim.GROUPS.getClaim(), providerGroups)
.build();
final String token = new PlainJWT(claimsSet).serialize();
final Jwt jwt = Jwt.withTokenValue(token)
.header(TYPE_FIELD, JWT_TYPE)
.subject(USERNAME)
.claim(SupportedClaim.GROUPS.getClaim(), providerGroups)
.build();
final NiFiAuthenticationToken authenticationToken = converter.convert(jwt);

View File

@ -27,11 +27,14 @@ import com.nimbusds.jwt.SignedJWT;
import org.apache.nifi.web.security.jwt.jws.JwsSignerContainer;
import org.apache.nifi.web.security.jwt.jws.JwsSignerProvider;
import org.apache.nifi.web.security.token.LoginAuthenticationToken;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
@ -40,9 +43,12 @@ import java.security.interfaces.RSAPublicKey;
import java.text.ParseException;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -71,6 +77,10 @@ public class StandardBearerTokenProviderTest {
private static final JWSAlgorithm JWS_ALGORITHM = JWSAlgorithm.PS512;
private static final String GROUP = "ProviderGroup";
private static KeyPair keyPair;
@Mock
private JwsSignerProvider jwsSignerProvider;
@ -78,49 +88,50 @@ public class StandardBearerTokenProviderTest {
private JWSVerifier jwsVerifier;
private JWSSigner jwsSigner;
@BeforeEach
public void setProvider() throws NoSuchAlgorithmException {
provider = new StandardBearerTokenProvider(jwsSignerProvider);
@BeforeAll
public static void setKeyPair() throws NoSuchAlgorithmException {
final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGenerator.initialize(KEY_SIZE);
final KeyPair keyPair = keyPairGenerator.generateKeyPair();
keyPair = keyPairGenerator.generateKeyPair();
}
@BeforeEach
public void setProvider() {
provider = new StandardBearerTokenProvider(jwsSignerProvider);
jwsVerifier = new RSASSAVerifier((RSAPublicKey) keyPair.getPublic());
jwsSigner = new RSASSASigner(keyPair.getPrivate());
final JWSSigner jwsSigner = new RSASSASigner(keyPair.getPrivate());
final String keyIdentifier = UUID.randomUUID().toString();
final JwsSignerContainer jwsSignerContainer = new JwsSignerContainer(keyIdentifier, JWS_ALGORITHM, jwsSigner);
when(jwsSignerProvider.getJwsSignerContainer(isA(Instant.class))).thenReturn(jwsSignerContainer);
}
@Test
public void testGetBearerToken() throws ParseException, JOSEException {
final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, EXPIRATION.toMillis(), ISSUER);
setSignerProvider();
final String bearerToken = provider.getBearerToken(loginAuthenticationToken);
final SignedJWT signedJwt = assertTokenVerified(bearerToken);
final JWTClaimsSet claims = signedJwt.getJWTClaimsSet();
assertNotNull(claims.getIssueTime(), "Issue Time not found");
assertNotNull(claims.getNotBeforeTime(), "Not Before Time not found");
assertTokenMatched(bearerToken, loginAuthenticationToken);
}
final Date claimExpirationTime = claims.getExpirationTime();
assertNotNull(claimExpirationTime, "Expiration Time not found");
@Test
public void testGetBearerTokenGroups() throws ParseException, JOSEException {
final GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(GROUP);
final Collection<GrantedAuthority> authorities = Collections.singletonList(grantedAuthority);
final Date loginExpirationTime = new Date(loginAuthenticationToken.getExpiration());
assertEquals(loginExpirationTime.toString(), claimExpirationTime.toString(), "Expiration Time not matched");
final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, EXPIRATION.toMillis(), ISSUER, authorities);
assertEquals(ISSUER, claims.getIssuer());
assertEquals(Collections.singletonList(ISSUER), claims.getAudience());
assertEquals(IDENTITY, claims.getSubject());
assertEquals(USERNAME, claims.getClaim(SupportedClaim.PREFERRED_USERNAME.getClaim()));
assertNotNull("JSON Web Token Identifier not found", claims.getJWTID());
final String bearerToken = provider.getBearerToken(loginAuthenticationToken);
assertTokenMatched(bearerToken, loginAuthenticationToken);
}
@Test
public void testGetBearerTokenExpirationMaximum() throws ParseException, JOSEException {
final long expiration = MAXIMUM_DURATION_EXCEEDED.toMillis();
final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, expiration, ISSUER);
setSignerProvider();
final String bearerToken = provider.getBearerToken(loginAuthenticationToken);
@ -139,7 +150,6 @@ public class StandardBearerTokenProviderTest {
public void testGetBearerTokenExpirationMinimum() throws ParseException, JOSEException {
final long expiration = MINIMUM_DURATION_EXCEEDED.toMillis();
final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, expiration, ISSUER);
setSignerProvider();
final String bearerToken = provider.getBearerToken(loginAuthenticationToken);
@ -154,15 +164,36 @@ public class StandardBearerTokenProviderTest {
assertTrue(claimExpirationTime.toInstant().isAfter(loginExpirationTime.toInstant()), "Claim Expiration before Login Expiration");
}
private void setSignerProvider() {
final String keyIdentifier = UUID.randomUUID().toString();
final JwsSignerContainer jwsSignerContainer = new JwsSignerContainer(keyIdentifier, JWS_ALGORITHM, jwsSigner);
when(jwsSignerProvider.getJwsSignerContainer(isA(Instant.class))).thenReturn(jwsSignerContainer);
}
private SignedJWT assertTokenVerified(final String bearerToken) throws ParseException, JOSEException {
final SignedJWT signedJwt = SignedJWT.parse(bearerToken);
assertTrue(signedJwt.verify(jwsVerifier), "Verification Failed");
return signedJwt;
}
private void assertTokenMatched(final String bearerToken, final LoginAuthenticationToken loginAuthenticationToken) throws ParseException, JOSEException {
final SignedJWT signedJwt = assertTokenVerified(bearerToken);
final JWTClaimsSet claims = signedJwt.getJWTClaimsSet();
assertNotNull(claims.getIssueTime(), "Issue Time not found");
assertNotNull(claims.getNotBeforeTime(), "Not Before Time not found");
final Date claimExpirationTime = claims.getExpirationTime();
assertNotNull(claimExpirationTime, "Expiration Time not found");
final Date loginExpirationTime = new Date(loginAuthenticationToken.getExpiration());
assertEquals(loginExpirationTime.toString(), claimExpirationTime.toString(), "Expiration Time not matched");
assertEquals(ISSUER, claims.getIssuer());
assertEquals(Collections.singletonList(ISSUER), claims.getAudience());
assertEquals(IDENTITY, claims.getSubject());
assertEquals(USERNAME, claims.getClaim(SupportedClaim.PREFERRED_USERNAME.getClaim()));
assertNotNull(claims.getJWTID(), "JSON Web Token Identifier not found");
final List<String> groups = claims.getStringListClaim(SupportedClaim.GROUPS.getClaim());
assertNotNull(groups);
final Collection<GrantedAuthority> grantedAuthorities = loginAuthenticationToken.getAuthorities();
final List<String> authorities = grantedAuthorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
assertEquals(authorities, groups);
}
}

View File

@ -16,7 +16,6 @@
*/
package org.apache.nifi.web.security.oidc.logout;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.web.security.cookie.ApplicationCookieName;
import org.apache.nifi.web.security.logout.LogoutRequest;
import org.apache.nifi.web.security.logout.LogoutRequestManager;
@ -58,7 +57,6 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
@ -91,9 +89,6 @@ class OidcLogoutSuccessHandlerTest {
private static final String END_SESSION_REDIRECT_URL = String.format("%s?id_token_hint=%s&post_logout_redirect_uri=%s", END_SESSION_URI, ID_TOKEN, REDIRECTED_URL);
@Mock
IdpUserGroupService idpUserGroupService;
@Mock
ClientRegistrationRepository clientRegistrationRepository;
@ -131,7 +126,6 @@ class OidcLogoutSuccessHandlerTest {
logoutRequestManager = new LogoutRequestManager();
handler = new OidcLogoutSuccessHandler(
logoutRequestManager,
idpUserGroupService,
clientRegistrationRepository,
authorizedClientRepository,
tokenRevocationResponseClient
@ -150,8 +144,6 @@ class OidcLogoutSuccessHandlerTest {
final String redirectedUrl = httpServletResponse.getRedirectedUrl();
assertEquals(REDIRECTED_URL, redirectedUrl);
verifyNoInteractions(idpUserGroupService);
}
@Test
@ -167,7 +159,6 @@ class OidcLogoutSuccessHandlerTest {
final String redirectedUrl = httpServletResponse.getRedirectedUrl();
assertEquals(REDIRECTED_URL, redirectedUrl);
assertUserGroupAuthorizedClientRemoved();
}
@Test
@ -184,7 +175,6 @@ class OidcLogoutSuccessHandlerTest {
final String redirectedUrl = httpServletResponse.getRedirectedUrl();
assertEquals(REDIRECTED_URL, redirectedUrl);
assertUserGroupAuthorizedClientRemoved();
}
@Test
@ -220,7 +210,6 @@ class OidcLogoutSuccessHandlerTest {
final String redirectedUrl = httpServletResponse.getRedirectedUrl();
assertEquals(END_SESSION_REDIRECT_URL, redirectedUrl);
assertUserGroupAuthorizedClientRemoved();
verify(authorizedClientRepository).removeAuthorizedClient(eq(OidcRegistrationProperty.REGISTRATION_ID.getProperty()), any(), eq(httpServletRequest), eq(httpServletResponse));
verify(tokenRevocationResponseClient, times(2)).getRevocationResponse(revocationRequestCaptor.capture());
@ -235,10 +224,6 @@ class OidcLogoutSuccessHandlerTest {
assertEquals(ACCESS_TOKEN, secondRevocationRequest.getToken());
}
void assertUserGroupAuthorizedClientRemoved() {
verify(idpUserGroupService).deleteUserGroups(eq(USER_IDENTITY));
}
void setRequestCookie() {
final Cookie cookie = new Cookie(ApplicationCookieName.LOGOUT_REQUEST_IDENTIFIER.getCookieName(), REQUEST_IDENTIFIER);
httpServletRequest.setCookies(cookie);

View File

@ -16,9 +16,7 @@
*/
package org.apache.nifi.web.security.oidc.web.authentication;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.authorization.util.IdentityMapping;
import org.apache.nifi.idp.IdpType;
import org.apache.nifi.web.security.cookie.ApplicationCookieName;
import org.apache.nifi.web.security.jwt.provider.BearerTokenProvider;
import org.apache.nifi.web.security.oidc.client.web.OidcRegistrationProperty;
@ -66,9 +64,6 @@ class OidcAuthenticationSuccessHandlerTest {
@Mock
BearerTokenProvider bearerTokenProvider;
@Mock
IdpUserGroupService idpUserGroupService;
@Captor
ArgumentCaptor<LoginAuthenticationToken> authenticationTokenCaptor;
@ -98,12 +93,8 @@ class OidcAuthenticationSuccessHandlerTest {
private static final String IDENTITY = Authentication.class.getSimpleName();
private static final String IDENTITY_UPPER = IDENTITY.toUpperCase();
private static final String AUTHORITY = GrantedAuthority.class.getSimpleName();
private static final String AUTHORITY_LOWER = AUTHORITY.toLowerCase();
private static final String ACCESS_TOKEN = "access-token";
private static final Duration TOKEN_EXPIRATION = Duration.ofHours(1);
@ -142,7 +133,6 @@ class OidcAuthenticationSuccessHandlerTest {
void setHandler() {
handler = new OidcAuthenticationSuccessHandler(
bearerTokenProvider,
idpUserGroupService,
Collections.singletonList(UPPER_IDENTITY_MAPPING),
Collections.singletonList(LOWER_IDENTITY_MAPPING),
Collections.singletonList(USER_NAME_CLAIM),
@ -159,7 +149,6 @@ class OidcAuthenticationSuccessHandlerTest {
assertTargetUrlEquals(TARGET_URL);
assertBearerCookieAdded(ROOT_PATH);
assertReplaceUserGroupsInvoked();
}
@Test
@ -172,11 +161,6 @@ class OidcAuthenticationSuccessHandlerTest {
assertTargetUrlEquals(FORWARDED_TARGET_URL);
assertBearerCookieAdded(FORWARDED_COOKIE_PATH);
assertReplaceUserGroupsInvoked();
}
void assertReplaceUserGroupsInvoked() {
verify(idpUserGroupService).replaceUserGroups(eq(IDENTITY_UPPER), eq(IdpType.OIDC), eq(Collections.singleton(AUTHORITY_LOWER)));
}
void assertTargetUrlEquals(final String expectedTargetUrl) {

View File

@ -16,9 +16,7 @@
*/
package org.apache.nifi.web.security.saml2.web.authentication;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.authorization.util.IdentityMapping;
import org.apache.nifi.idp.IdpType;
import org.apache.nifi.web.security.cookie.ApplicationCookieName;
import org.apache.nifi.web.security.jwt.provider.BearerTokenProvider;
import org.apache.nifi.web.util.WebUtils;
@ -41,8 +39,6 @@ import java.util.regex.Pattern;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
@ExtendWith(MockitoExtension.class)
class Saml2AuthenticationSuccessHandlerTest {
@ -52,12 +48,8 @@ class Saml2AuthenticationSuccessHandlerTest {
private static final String IDENTITY = Authentication.class.getSimpleName();
private static final String IDENTITY_UPPER = IDENTITY.toUpperCase();
private static final String AUTHORITY = GrantedAuthority.class.getSimpleName();
private static final String AUTHORITY_LOWER = AUTHORITY.toLowerCase();
private static final String REQUEST_URI = "/nifi-api";
private static final String UI_PATH = "/nifi/";
@ -99,9 +91,6 @@ class Saml2AuthenticationSuccessHandlerTest {
@Mock
BearerTokenProvider bearerTokenProvider;
@Mock
IdpUserGroupService idpUserGroupService;
MockHttpServletRequest httpServletRequest;
MockHttpServletResponse httpServletResponse;
@ -112,7 +101,6 @@ class Saml2AuthenticationSuccessHandlerTest {
void setHandler() {
handler = new Saml2AuthenticationSuccessHandler(
bearerTokenProvider,
idpUserGroupService,
Collections.singletonList(UPPER_IDENTITY_MAPPING),
Collections.singletonList(LOWER_IDENTITY_MAPPING),
EXPIRATION,
@ -129,7 +117,6 @@ class Saml2AuthenticationSuccessHandlerTest {
assertTargetUrlEquals(TARGET_URL);
assertBearerCookieAdded(ROOT_PATH);
assertReplaceUserGroupsInvoked();
}
@Test
@ -142,11 +129,6 @@ class Saml2AuthenticationSuccessHandlerTest {
assertTargetUrlEquals(FORWARDED_TARGET_URL);
assertBearerCookieAdded(FORWARDED_COOKIE_PATH);
assertReplaceUserGroupsInvoked();
}
void assertReplaceUserGroupsInvoked() {
verify(idpUserGroupService).replaceUserGroups(eq(IDENTITY_UPPER), eq(IdpType.SAML), eq(Collections.singleton(AUTHORITY_LOWER)));
}
void assertTargetUrlEquals(final String expectedTargetUrl) {

View File

@ -16,7 +16,6 @@
*/
package org.apache.nifi.web.security.saml2.web.authentication.logout;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.web.security.cookie.ApplicationCookieName;
import org.apache.nifi.web.security.logout.LogoutRequest;
import org.apache.nifi.web.security.logout.LogoutRequestManager;
@ -34,9 +33,6 @@ import java.io.IOException;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
@ExtendWith(MockitoExtension.class)
class Saml2LogoutSuccessHandlerTest {
@ -50,9 +46,6 @@ class Saml2LogoutSuccessHandlerTest {
private static final String REDIRECTED_URL = "http://localhost:8080/nifi/logout-complete";
@Mock
IdpUserGroupService idpUserGroupService;
@Mock
Authentication authentication;
@ -67,7 +60,7 @@ class Saml2LogoutSuccessHandlerTest {
@BeforeEach
void setHandler() {
logoutRequestManager = new LogoutRequestManager();
handler = new Saml2LogoutSuccessHandler(logoutRequestManager, idpUserGroupService);
handler = new Saml2LogoutSuccessHandler(logoutRequestManager);
httpServletRequest = new MockHttpServletRequest();
httpServletRequest.setServerPort(SERVER_PORT);
httpServletResponse = new MockHttpServletResponse();
@ -84,8 +77,6 @@ class Saml2LogoutSuccessHandlerTest {
final String redirectedUrl = httpServletResponse.getRedirectedUrl();
assertEquals(REDIRECTED_URL, redirectedUrl);
verifyNoInteractions(idpUserGroupService);
}
@Test
@ -102,6 +93,5 @@ class Saml2LogoutSuccessHandlerTest {
final String redirectedUrl = httpServletResponse.getRedirectedUrl();
assertEquals(REDIRECTED_URL, redirectedUrl);
verify(idpUserGroupService).deleteUserGroups(eq(USER_IDENTITY));
}
}