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> <groupId>org.apache.nifi</groupId>
<artifactId>nifi-properties</artifactId> <artifactId>nifi-properties</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-security-utils</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.h2database</groupId> <groupId>com.h2database</groupId>
<artifactId>h2</artifactId> <artifactId>h2</artifactId>
@ -78,10 +74,6 @@
<groupId>org.aspectj</groupId> <groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId> <artifactId>aspectjweaver</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId> <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 { public interface DAOFactory {
ActionDAO getActionDAO(); ActionDAO getActionDAO();
IdpUserGroupDAO getIdpUserGroupDAO();
} }

View File

@ -32,8 +32,4 @@ public class DataAccessException extends RuntimeException {
public DataAccessException(String message) { public DataAccessException(String message) {
super(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.ActionDAO;
import org.apache.nifi.admin.dao.DAOFactory; import org.apache.nifi.admin.dao.DAOFactory;
import org.apache.nifi.admin.dao.IdpUserGroupDAO;
import java.sql.Connection; import java.sql.Connection;
@ -37,9 +36,4 @@ public class DAOFactoryImpl implements DAOFactory {
public ActionDAO getActionDAO() { public ActionDAO getActionDAO() {
return new StandardActionDAO(connection); 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"/> <property name="properties" ref="nifiProperties"/>
</bean> </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 --> <!-- initialize the audit transaction builder -->
<bean id="auditTransactionBuilder" class="org.apache.nifi.admin.service.transaction.impl.StandardTransactionBuilder"> <bean id="auditTransactionBuilder" class="org.apache.nifi.admin.service.transaction.impl.StandardTransactionBuilder">
<property name="dataSource" ref="auditDataSource"/> <property name="dataSource" ref="auditDataSource"/>
</bean> </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 --> <!-- audit service -->
<bean id="auditService" class="org.apache.nifi.admin.service.impl.StandardAuditService"> <bean id="auditService" class="org.apache.nifi.admin.service.impl.StandardAuditService">
<property name="transactionBuilder" ref="auditTransactionBuilder"/> <property name="transactionBuilder" ref="auditTransactionBuilder"/>
</bean> </bean>
<!-- idp user group service -->
<bean id="idpUserGroupService" class="org.apache.nifi.admin.service.impl.StandardIdpUserGroupService">
<property name="transactionBuilder" ref="idpTransactionBuilder"/>
</bean>
</beans> </beans>

View File

@ -22,7 +22,6 @@ import com.nimbusds.jwt.proc.DefaultJWTClaimsVerifier;
import com.nimbusds.jwt.proc.DefaultJWTProcessor; import com.nimbusds.jwt.proc.DefaultJWTProcessor;
import com.nimbusds.jwt.proc.JWTClaimsSetVerifier; import com.nimbusds.jwt.proc.JWTClaimsSetVerifier;
import com.nimbusds.jwt.proc.JWTProcessor; import com.nimbusds.jwt.proc.JWTProcessor;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.authorization.Authorizer; import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.components.state.StateManager; import org.apache.nifi.components.state.StateManager;
import org.apache.nifi.components.state.StateManagerProvider; import org.apache.nifi.components.state.StateManagerProvider;
@ -79,15 +78,14 @@ public class JwtAuthenticationSecurityConfiguration {
SupportedClaim.EXPIRATION.getClaim(), SupportedClaim.EXPIRATION.getClaim(),
SupportedClaim.NOT_BEFORE.getClaim(), SupportedClaim.NOT_BEFORE.getClaim(),
SupportedClaim.ISSUED_AT.getClaim(), SupportedClaim.ISSUED_AT.getClaim(),
SupportedClaim.JWT_ID.getClaim() SupportedClaim.JWT_ID.getClaim(),
SupportedClaim.GROUPS.getClaim()
)); ));
private final NiFiProperties niFiProperties; private final NiFiProperties niFiProperties;
private final Authorizer authorizer; private final Authorizer authorizer;
private final IdpUserGroupService idpUserGroupService;
private final StateManagerProvider stateManagerProvider; private final StateManagerProvider stateManagerProvider;
private final Duration keyRotationPeriod; private final Duration keyRotationPeriod;
@ -96,12 +94,10 @@ public class JwtAuthenticationSecurityConfiguration {
public JwtAuthenticationSecurityConfiguration( public JwtAuthenticationSecurityConfiguration(
final NiFiProperties niFiProperties, final NiFiProperties niFiProperties,
final Authorizer authorizer, final Authorizer authorizer,
final IdpUserGroupService idpUserGroupService,
final StateManagerProvider stateManagerProvider final StateManagerProvider stateManagerProvider
) { ) {
this.niFiProperties = niFiProperties; this.niFiProperties = niFiProperties;
this.authorizer = authorizer; this.authorizer = authorizer;
this.idpUserGroupService = idpUserGroupService;
this.stateManagerProvider = stateManagerProvider; this.stateManagerProvider = stateManagerProvider;
this.keyRotationPeriod = niFiProperties.getSecurityUserJwsKeyRotationPeriod(); this.keyRotationPeriod = niFiProperties.getSecurityUserJwsKeyRotationPeriod();
} }
@ -180,7 +176,7 @@ public class JwtAuthenticationSecurityConfiguration {
@Bean @Bean
public StandardJwtAuthenticationConverter jwtAuthenticationConverter() { public StandardJwtAuthenticationConverter jwtAuthenticationConverter() {
return new StandardJwtAuthenticationConverter(authorizer, idpUserGroupService, niFiProperties); return new StandardJwtAuthenticationConverter(authorizer, niFiProperties);
} }
@Bean @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.Cache;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.authorization.util.IdentityMappingUtil; import org.apache.nifi.authorization.util.IdentityMappingUtil;
import org.apache.nifi.components.state.StateManager; import org.apache.nifi.components.state.StateManager;
import org.apache.nifi.components.state.StateManagerProvider; import org.apache.nifi.components.state.StateManagerProvider;
@ -129,8 +128,6 @@ public class OidcSecurityConfiguration {
private final BearerTokenResolver bearerTokenResolver; private final BearerTokenResolver bearerTokenResolver;
private final IdpUserGroupService idpUserGroupService;
private final JwtDecoder jwtDecoder; private final JwtDecoder jwtDecoder;
private final LogoutRequestManager logoutRequestManager; private final LogoutRequestManager logoutRequestManager;
@ -142,7 +139,6 @@ public class OidcSecurityConfiguration {
final PropertyEncryptor propertyEncryptor, final PropertyEncryptor propertyEncryptor,
final BearerTokenProvider bearerTokenProvider, final BearerTokenProvider bearerTokenProvider,
final BearerTokenResolver bearerTokenResolver, final BearerTokenResolver bearerTokenResolver,
final IdpUserGroupService idpUserGroupService,
final JwtDecoder jwtDecoder, final JwtDecoder jwtDecoder,
final LogoutRequestManager logoutRequestManager final LogoutRequestManager logoutRequestManager
) { ) {
@ -151,7 +147,6 @@ public class OidcSecurityConfiguration {
this.propertyEncryptor = Objects.requireNonNull(propertyEncryptor, "Property Encryptor required"); this.propertyEncryptor = Objects.requireNonNull(propertyEncryptor, "Property Encryptor required");
this.bearerTokenProvider = Objects.requireNonNull(bearerTokenProvider, "Bearer Token Provider required"); this.bearerTokenProvider = Objects.requireNonNull(bearerTokenProvider, "Bearer Token Provider required");
this.bearerTokenResolver = Objects.requireNonNull(bearerTokenResolver, "Bearer Token Resolver 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.jwtDecoder = Objects.requireNonNull(jwtDecoder, "JWT Decoder required");
this.logoutRequestManager = Objects.requireNonNull(logoutRequestManager, "Logout Request Manager required"); this.logoutRequestManager = Objects.requireNonNull(logoutRequestManager, "Logout Request Manager required");
this.keyRotationPeriod = properties.getSecurityUserJwsKeyRotationPeriod(); this.keyRotationPeriod = properties.getSecurityUserJwsKeyRotationPeriod();
@ -261,7 +256,6 @@ public class OidcSecurityConfiguration {
public LogoutSuccessHandler oidcLogoutSuccessHandler() { public LogoutSuccessHandler oidcLogoutSuccessHandler() {
return new OidcLogoutSuccessHandler( return new OidcLogoutSuccessHandler(
logoutRequestManager, logoutRequestManager,
idpUserGroupService,
clientRegistrationRepository(), clientRegistrationRepository(),
authorizedClientRepository(), authorizedClientRepository(),
tokenRevocationResponseClient() tokenRevocationResponseClient()
@ -480,7 +474,6 @@ public class OidcSecurityConfiguration {
return new OidcAuthenticationSuccessHandler( return new OidcAuthenticationSuccessHandler(
bearerTokenProvider, bearerTokenProvider,
idpUserGroupService,
IdentityMappingUtil.getIdentityMappings(properties), IdentityMappingUtil.getIdentityMappings(properties),
IdentityMappingUtil.getGroupMappings(properties), IdentityMappingUtil.getGroupMappings(properties),
userClaimNames, 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.Cache;
import com.github.benmanes.caffeine.cache.Caffeine; 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.authorization.util.IdentityMappingUtil;
import org.apache.nifi.util.FormatUtils; import org.apache.nifi.util.FormatUtils;
import org.apache.nifi.util.NiFiProperties; import org.apache.nifi.util.NiFiProperties;
@ -93,19 +92,15 @@ public class SamlAuthenticationSecurityConfiguration {
private final LogoutRequestManager logoutRequestManager; private final LogoutRequestManager logoutRequestManager;
private final IdpUserGroupService idpUserGroupService;
@Autowired @Autowired
public SamlAuthenticationSecurityConfiguration( public SamlAuthenticationSecurityConfiguration(
final NiFiProperties properties, final NiFiProperties properties,
final BearerTokenProvider bearerTokenProvider, final BearerTokenProvider bearerTokenProvider,
final LogoutRequestManager logoutRequestManager, final LogoutRequestManager logoutRequestManager
final IdpUserGroupService idpUserGroupService
) { ) {
this.properties = Objects.requireNonNull(properties, "Properties required"); this.properties = Objects.requireNonNull(properties, "Properties required");
this.bearerTokenProvider = Objects.requireNonNull(bearerTokenProvider, "Bearer Token Provider required"); this.bearerTokenProvider = Objects.requireNonNull(bearerTokenProvider, "Bearer Token Provider required");
this.logoutRequestManager = Objects.requireNonNull(logoutRequestManager, "Logout Request Manager 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 @Bean
public Saml2LogoutSuccessHandler saml2LogoutSuccessHandler() { 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 String issuer = entityId == null ? Saml2RegistrationProperty.REGISTRATION_ID.getProperty() : entityId;
final Saml2AuthenticationSuccessHandler handler = new Saml2AuthenticationSuccessHandler( final Saml2AuthenticationSuccessHandler handler = new Saml2AuthenticationSuccessHandler(
bearerTokenProvider, bearerTokenProvider,
idpUserGroupService,
IdentityMappingUtil.getIdentityMappings(properties), IdentityMappingUtil.getIdentityMappings(properties),
IdentityMappingUtil.getGroupMappings(properties), IdentityMappingUtil.getGroupMappings(properties),
expiration, expiration,

View File

@ -16,7 +16,6 @@
*/ */
package org.apache.nifi.web.security.jwt.converter; 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.Authorizer;
import org.apache.nifi.authorization.user.NiFiUser; import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserDetails; 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.IdentityMapping;
import org.apache.nifi.authorization.util.IdentityMappingUtil; import org.apache.nifi.authorization.util.IdentityMappingUtil;
import org.apache.nifi.authorization.util.UserGroupUtil; import org.apache.nifi.authorization.util.UserGroupUtil;
import org.apache.nifi.idp.IdpUserGroup;
import org.apache.nifi.util.NiFiProperties; 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.apache.nifi.web.security.token.NiFiAuthenticationToken;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.Jwt;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
/** /**
* Standard Converter from JSON Web Token to NiFi Authentication Token * 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> { public class StandardJwtAuthenticationConverter implements Converter<Jwt, NiFiAuthenticationToken> {
private final Authorizer authorizer; private final Authorizer authorizer;
private final IdpUserGroupService idpUserGroupService;
private final List<IdentityMapping> identityMappings; 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.authorizer = authorizer;
this.idpUserGroupService = idpUserGroupService;
this.identityMappings = IdentityMappingUtil.getIdentityMappings(properties); this.identityMappings = IdentityMappingUtil.getIdentityMappings(properties);
} }
@ -65,16 +62,23 @@ public class StandardJwtAuthenticationConverter implements Converter<Jwt, NiFiAu
private NiFiUser getUser(final Jwt jwt) { private NiFiUser getUser(final Jwt jwt) {
final String identity = IdentityMappingUtil.mapIdentity(jwt.getSubject(), identityMappings); final String identity = IdentityMappingUtil.mapIdentity(jwt.getSubject(), identityMappings);
final Set<String> providedGroups = getProvidedGroups(jwt);
return new StandardNiFiUser.Builder() return new StandardNiFiUser.Builder()
.identity(identity) .identity(identity)
.groups(UserGroupUtil.getUserGroups(authorizer, identity)) .groups(UserGroupUtil.getUserGroups(authorizer, identity))
.identityProviderGroups(getIdentityProviderGroups(identity)) .identityProviderGroups(providedGroups)
.build(); .build();
} }
private Set<String> getIdentityProviderGroups(final String identity) { private Set<String> getProvidedGroups(final Jwt jwt) {
return idpUserGroupService.getUserGroups(identity).stream() final List<String> claimGroups = jwt.getClaimAsStringList(SupportedClaim.GROUPS.getClaim());
.map(IdpUserGroup::getGroupName)
.collect(Collectors.toSet()); 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.apache.nifi.web.security.token.LoginAuthenticationToken;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.security.core.GrantedAuthority;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* Standard Bearer Token Provider supports returning serialized and signed JSON Web Tokens * 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 subject = Objects.requireNonNull(loginAuthenticationToken.getPrincipal(), "Principal required").toString();
final String username = loginAuthenticationToken.getName(); final String username = loginAuthenticationToken.getName();
final List<String> groups = getGroups(loginAuthenticationToken.getAuthorities());
final String issuer = getUrlEncoded(loginAuthenticationToken.getIssuer()); final String issuer = getUrlEncoded(loginAuthenticationToken.getIssuer());
final Date now = new Date(); final Date now = new Date();
final Date expirationTime = getExpirationTime(loginAuthenticationToken); final Date expirationTime = getExpirationTime(loginAuthenticationToken);
@ -80,6 +85,7 @@ public class StandardBearerTokenProvider implements BearerTokenProvider {
.issueTime(now) .issueTime(now)
.expirationTime(expirationTime) .expirationTime(expirationTime)
.claim(SupportedClaim.PREFERRED_USERNAME.getClaim(), username) .claim(SupportedClaim.PREFERRED_USERNAME.getClaim(), username)
.claim(SupportedClaim.GROUPS.getClaim(), groups)
.build(); .build();
return getSignedBearerToken(claims); return getSignedBearerToken(claims);
} }
@ -131,4 +137,8 @@ public class StandardBearerTokenProvider implements BearerTokenProvider {
throw new IllegalArgumentException(String.format("URL Encoding [%s] Failed", string), e); 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"), JWT_ID("jti"),
/** Preferred Username defined in OpenID Connect Core 1.0 Standard Claims */ /** 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; private final String claim;

View File

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

View File

@ -16,10 +16,8 @@
*/ */
package org.apache.nifi.web.security.oidc.web.authentication; 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.IdentityMapping;
import org.apache.nifi.authorization.util.IdentityMappingUtil; 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.ApplicationCookieName;
import org.apache.nifi.web.security.cookie.ApplicationCookieService; import org.apache.nifi.web.security.cookie.ApplicationCookieService;
import org.apache.nifi.web.security.cookie.StandardApplicationCookieService; 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.security.token.LoginAuthenticationToken;
import org.apache.nifi.web.util.RequestUriBuilder; import org.apache.nifi.web.util.RequestUriBuilder;
import org.springframework.security.core.Authentication; 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.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.oauth2.core.OAuth2AccessToken; import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.OAuth2Token; import org.springframework.security.oauth2.core.OAuth2Token;
@ -59,8 +59,6 @@ public class OidcAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuc
private final BearerTokenProvider bearerTokenProvider; private final BearerTokenProvider bearerTokenProvider;
private final IdpUserGroupService idpUserGroupService;
private final List<IdentityMapping> userIdentityMappings; private final List<IdentityMapping> userIdentityMappings;
private final List<IdentityMapping> groupIdentityMappings; 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 * OpenID Connect Authentication Success Handler requires Bearer Token Provider and expiration for generated tokens
* *
* @param bearerTokenProvider Bearer Token Provider * @param bearerTokenProvider Bearer Token Provider
* @param idpUserGroupService User Group Service for persisting groups from the Identity Provider
* @param userIdentityMappings User Identity Mappings * @param userIdentityMappings User Identity Mappings
* @param groupIdentityMappings Group Identity Mappings * @param groupIdentityMappings Group Identity Mappings
* @param userClaimNames Claim Names for User Identity * @param userClaimNames Claim Names for User Identity
@ -81,14 +78,12 @@ public class OidcAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuc
*/ */
public OidcAuthenticationSuccessHandler( public OidcAuthenticationSuccessHandler(
final BearerTokenProvider bearerTokenProvider, final BearerTokenProvider bearerTokenProvider,
final IdpUserGroupService idpUserGroupService,
final List<IdentityMapping> userIdentityMappings, final List<IdentityMapping> userIdentityMappings,
final List<IdentityMapping> groupIdentityMappings, final List<IdentityMapping> groupIdentityMappings,
final List<String> userClaimNames, final List<String> userClaimNames,
final String groupsClaimName final String groupsClaimName
) { ) {
this.bearerTokenProvider = Objects.requireNonNull(bearerTokenProvider, "Bearer Token Provider required"); 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.userIdentityMappings = Objects.requireNonNull(userIdentityMappings, "User Identity Mappings required");
this.groupIdentityMappings = Objects.requireNonNull(groupIdentityMappings, "Group Identity Mappings required"); this.groupIdentityMappings = Objects.requireNonNull(groupIdentityMappings, "Group Identity Mappings required");
this.userClaimNames = Objects.requireNonNull(userClaimNames, "User Claim Names 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 OidcUser oidcUser = getOidcUser(authenticationToken);
final String identity = getIdentity(oidcUser); final String identity = getIdentity(oidcUser);
final Set<String> groups = getGroups(oidcUser); final Set<String> groups = getGroups(oidcUser);
idpUserGroupService.replaceUserGroups(identity, IdpType.OIDC, groups);
final OAuth2AccessToken accessToken = getAccessToken(authenticationToken); 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); 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 long sessionExpiration = getSessionExpiration(accessToken);
final String issuer = oidcUser.getIssuer().toString(); 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); return bearerTokenProvider.getBearerToken(loginAuthenticationToken);
} }

View File

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

View File

@ -16,7 +16,6 @@
*/ */
package org.apache.nifi.web.security.saml2.web.authentication.logout; 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.ApplicationCookieName;
import org.apache.nifi.web.security.cookie.ApplicationCookieService; import org.apache.nifi.web.security.cookie.ApplicationCookieService;
import org.apache.nifi.web.security.cookie.StandardApplicationCookieService; import org.apache.nifi.web.security.cookie.StandardApplicationCookieService;
@ -47,14 +46,10 @@ public class Saml2LogoutSuccessHandler implements LogoutSuccessHandler {
private final LogoutRequestManager logoutRequestManager; private final LogoutRequestManager logoutRequestManager;
private final IdpUserGroupService idpUserGroupService;
public Saml2LogoutSuccessHandler( public Saml2LogoutSuccessHandler(
final LogoutRequestManager logoutRequestManager, final LogoutRequestManager logoutRequestManager
final IdpUserGroupService idpUserGroupService
) { ) {
this.logoutRequestManager = Objects.requireNonNull(logoutRequestManager, "Logout Request Manager required"); 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); logger.warn("Logout Request [{}] not found", requestIdentifier);
} else { } else {
final String mappedUserIdentity = logoutRequest.getMappedUserIdentity(); final String mappedUserIdentity = logoutRequest.getMappedUserIdentity();
idpUserGroupService.deleteUserGroups(mappedUserIdentity);
logger.info("Logout Request [{}] Identity [{}] completed", requestIdentifier, 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.JWTClaimsSet;
import com.nimbusds.jwt.PlainJWT; import com.nimbusds.jwt.PlainJWT;
import org.apache.nifi.admin.service.IdpUserGroupService;
import org.apache.nifi.authorization.AccessPolicyProvider; import org.apache.nifi.authorization.AccessPolicyProvider;
import org.apache.nifi.authorization.Group; import org.apache.nifi.authorization.Group;
import org.apache.nifi.authorization.ManagedAuthorizer; 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.UserGroupProvider;
import org.apache.nifi.authorization.user.NiFiUser; import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserDetails; import org.apache.nifi.authorization.user.NiFiUserDetails;
import org.apache.nifi.idp.IdpUserGroup;
import org.apache.nifi.util.NiFiProperties; import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.StringUtils; 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.apache.nifi.web.security.token.NiFiAuthenticationToken;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -39,6 +38,7 @@ import org.springframework.security.oauth2.jwt.Jwt;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -71,16 +71,13 @@ public class StandardJwtAuthenticationConverterTest {
@Mock @Mock
private UserAndGroups userAndGroups; private UserAndGroups userAndGroups;
@Mock
private IdpUserGroupService idpUserGroupService;
private StandardJwtAuthenticationConverter converter; private StandardJwtAuthenticationConverter converter;
@BeforeEach @BeforeEach
public void setConverter() { public void setConverter() {
final Map<String, String> properties = new HashMap<>(); final Map<String, String> properties = new HashMap<>();
final NiFiProperties niFiProperties = NiFiProperties.createBasicNiFiProperties(StringUtils.EMPTY, properties); 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(authorizer.getAccessPolicyProvider()).thenReturn(accessPolicyProvider);
when(accessPolicyProvider.getUserGroupProvider()).thenReturn(userGroupProvider); 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(); final Group group = new Group.Builder().name(AUTHORIZER_GROUP).identifier(AUTHORIZER_GROUP).build();
when(userAndGroups.getGroups()).thenReturn(Collections.singleton(group)); 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 @Test
public void testConvert() { public void testConvert() {
final List<String> providerGroups = Collections.singletonList(PROVIDER_GROUP);
final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() final JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
.subject(USERNAME) .subject(USERNAME)
.claim(SupportedClaim.GROUPS.getClaim(), providerGroups)
.build(); .build();
final String token = new PlainJWT(claimsSet).serialize(); final String token = new PlainJWT(claimsSet).serialize();
final Jwt jwt = Jwt.withTokenValue(token) final Jwt jwt = Jwt.withTokenValue(token)
.header(TYPE_FIELD, JWT_TYPE) .header(TYPE_FIELD, JWT_TYPE)
.subject(USERNAME) .subject(USERNAME)
.claim(SupportedClaim.GROUPS.getClaim(), providerGroups)
.build(); .build();
final NiFiAuthenticationToken authenticationToken = converter.convert(jwt); 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.JwsSignerContainer;
import org.apache.nifi.web.security.jwt.jws.JwsSignerProvider; import org.apache.nifi.web.security.jwt.jws.JwsSignerProvider;
import org.apache.nifi.web.security.token.LoginAuthenticationToken; 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.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; 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.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
@ -40,9 +43,12 @@ import java.security.interfaces.RSAPublicKey;
import java.text.ParseException; import java.text.ParseException;
import java.time.Duration; import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; 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 JWSAlgorithm JWS_ALGORITHM = JWSAlgorithm.PS512;
private static final String GROUP = "ProviderGroup";
private static KeyPair keyPair;
@Mock @Mock
private JwsSignerProvider jwsSignerProvider; private JwsSignerProvider jwsSignerProvider;
@ -78,49 +88,50 @@ public class StandardBearerTokenProviderTest {
private JWSVerifier jwsVerifier; private JWSVerifier jwsVerifier;
private JWSSigner jwsSigner; @BeforeAll
public static void setKeyPair() throws NoSuchAlgorithmException {
@BeforeEach
public void setProvider() throws NoSuchAlgorithmException {
provider = new StandardBearerTokenProvider(jwsSignerProvider);
final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM); final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGenerator.initialize(KEY_SIZE); 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()); 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 @Test
public void testGetBearerToken() throws ParseException, JOSEException { public void testGetBearerToken() throws ParseException, JOSEException {
final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, EXPIRATION.toMillis(), ISSUER); final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, EXPIRATION.toMillis(), ISSUER);
setSignerProvider();
final String bearerToken = provider.getBearerToken(loginAuthenticationToken); final String bearerToken = provider.getBearerToken(loginAuthenticationToken);
final SignedJWT signedJwt = assertTokenVerified(bearerToken); assertTokenMatched(bearerToken, loginAuthenticationToken);
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(); @Test
assertNotNull(claimExpirationTime, "Expiration Time not found"); 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()); final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, EXPIRATION.toMillis(), ISSUER, authorities);
assertEquals(loginExpirationTime.toString(), claimExpirationTime.toString(), "Expiration Time not matched");
assertEquals(ISSUER, claims.getIssuer()); final String bearerToken = provider.getBearerToken(loginAuthenticationToken);
assertEquals(Collections.singletonList(ISSUER), claims.getAudience());
assertEquals(IDENTITY, claims.getSubject()); assertTokenMatched(bearerToken, loginAuthenticationToken);
assertEquals(USERNAME, claims.getClaim(SupportedClaim.PREFERRED_USERNAME.getClaim()));
assertNotNull("JSON Web Token Identifier not found", claims.getJWTID());
} }
@Test @Test
public void testGetBearerTokenExpirationMaximum() throws ParseException, JOSEException { public void testGetBearerTokenExpirationMaximum() throws ParseException, JOSEException {
final long expiration = MAXIMUM_DURATION_EXCEEDED.toMillis(); final long expiration = MAXIMUM_DURATION_EXCEEDED.toMillis();
final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, expiration, ISSUER); final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, expiration, ISSUER);
setSignerProvider();
final String bearerToken = provider.getBearerToken(loginAuthenticationToken); final String bearerToken = provider.getBearerToken(loginAuthenticationToken);
@ -139,7 +150,6 @@ public class StandardBearerTokenProviderTest {
public void testGetBearerTokenExpirationMinimum() throws ParseException, JOSEException { public void testGetBearerTokenExpirationMinimum() throws ParseException, JOSEException {
final long expiration = MINIMUM_DURATION_EXCEEDED.toMillis(); final long expiration = MINIMUM_DURATION_EXCEEDED.toMillis();
final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, expiration, ISSUER); final LoginAuthenticationToken loginAuthenticationToken = new LoginAuthenticationToken(IDENTITY, USERNAME, expiration, ISSUER);
setSignerProvider();
final String bearerToken = provider.getBearerToken(loginAuthenticationToken); final String bearerToken = provider.getBearerToken(loginAuthenticationToken);
@ -154,15 +164,36 @@ public class StandardBearerTokenProviderTest {
assertTrue(claimExpirationTime.toInstant().isAfter(loginExpirationTime.toInstant()), "Claim Expiration before Login Expiration"); 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 { private SignedJWT assertTokenVerified(final String bearerToken) throws ParseException, JOSEException {
final SignedJWT signedJwt = SignedJWT.parse(bearerToken); final SignedJWT signedJwt = SignedJWT.parse(bearerToken);
assertTrue(signedJwt.verify(jwsVerifier), "Verification Failed"); assertTrue(signedJwt.verify(jwsVerifier), "Verification Failed");
return signedJwt; 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; 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.ApplicationCookieName;
import org.apache.nifi.web.security.logout.LogoutRequest; import org.apache.nifi.web.security.logout.LogoutRequest;
import org.apache.nifi.web.security.logout.LogoutRequestManager; 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.ArgumentMatchers.isA;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class) @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); 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 @Mock
ClientRegistrationRepository clientRegistrationRepository; ClientRegistrationRepository clientRegistrationRepository;
@ -131,7 +126,6 @@ class OidcLogoutSuccessHandlerTest {
logoutRequestManager = new LogoutRequestManager(); logoutRequestManager = new LogoutRequestManager();
handler = new OidcLogoutSuccessHandler( handler = new OidcLogoutSuccessHandler(
logoutRequestManager, logoutRequestManager,
idpUserGroupService,
clientRegistrationRepository, clientRegistrationRepository,
authorizedClientRepository, authorizedClientRepository,
tokenRevocationResponseClient tokenRevocationResponseClient
@ -150,8 +144,6 @@ class OidcLogoutSuccessHandlerTest {
final String redirectedUrl = httpServletResponse.getRedirectedUrl(); final String redirectedUrl = httpServletResponse.getRedirectedUrl();
assertEquals(REDIRECTED_URL, redirectedUrl); assertEquals(REDIRECTED_URL, redirectedUrl);
verifyNoInteractions(idpUserGroupService);
} }
@Test @Test
@ -167,7 +159,6 @@ class OidcLogoutSuccessHandlerTest {
final String redirectedUrl = httpServletResponse.getRedirectedUrl(); final String redirectedUrl = httpServletResponse.getRedirectedUrl();
assertEquals(REDIRECTED_URL, redirectedUrl); assertEquals(REDIRECTED_URL, redirectedUrl);
assertUserGroupAuthorizedClientRemoved();
} }
@Test @Test
@ -184,7 +175,6 @@ class OidcLogoutSuccessHandlerTest {
final String redirectedUrl = httpServletResponse.getRedirectedUrl(); final String redirectedUrl = httpServletResponse.getRedirectedUrl();
assertEquals(REDIRECTED_URL, redirectedUrl); assertEquals(REDIRECTED_URL, redirectedUrl);
assertUserGroupAuthorizedClientRemoved();
} }
@Test @Test
@ -220,7 +210,6 @@ class OidcLogoutSuccessHandlerTest {
final String redirectedUrl = httpServletResponse.getRedirectedUrl(); final String redirectedUrl = httpServletResponse.getRedirectedUrl();
assertEquals(END_SESSION_REDIRECT_URL, redirectedUrl); assertEquals(END_SESSION_REDIRECT_URL, redirectedUrl);
assertUserGroupAuthorizedClientRemoved();
verify(authorizedClientRepository).removeAuthorizedClient(eq(OidcRegistrationProperty.REGISTRATION_ID.getProperty()), any(), eq(httpServletRequest), eq(httpServletResponse)); verify(authorizedClientRepository).removeAuthorizedClient(eq(OidcRegistrationProperty.REGISTRATION_ID.getProperty()), any(), eq(httpServletRequest), eq(httpServletResponse));
verify(tokenRevocationResponseClient, times(2)).getRevocationResponse(revocationRequestCaptor.capture()); verify(tokenRevocationResponseClient, times(2)).getRevocationResponse(revocationRequestCaptor.capture());
@ -235,10 +224,6 @@ class OidcLogoutSuccessHandlerTest {
assertEquals(ACCESS_TOKEN, secondRevocationRequest.getToken()); assertEquals(ACCESS_TOKEN, secondRevocationRequest.getToken());
} }
void assertUserGroupAuthorizedClientRemoved() {
verify(idpUserGroupService).deleteUserGroups(eq(USER_IDENTITY));
}
void setRequestCookie() { void setRequestCookie() {
final Cookie cookie = new Cookie(ApplicationCookieName.LOGOUT_REQUEST_IDENTIFIER.getCookieName(), REQUEST_IDENTIFIER); final Cookie cookie = new Cookie(ApplicationCookieName.LOGOUT_REQUEST_IDENTIFIER.getCookieName(), REQUEST_IDENTIFIER);
httpServletRequest.setCookies(cookie); httpServletRequest.setCookies(cookie);

View File

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

View File

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

View File

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