mirror of https://github.com/apache/nifi.git
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:
parent
9709bd6fb7
commit
0f736e060a
|
@ -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>
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -22,7 +22,4 @@ package org.apache.nifi.admin.dao;
|
||||||
public interface DAOFactory {
|
public interface DAOFactory {
|
||||||
|
|
||||||
ActionDAO getActionDAO();
|
ActionDAO getActionDAO();
|
||||||
|
|
||||||
IdpUserGroupDAO getIdpUserGroupDAO();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,8 +32,4 @@ public class DataAccessException extends RuntimeException {
|
||||||
public DataAccessException(String message) {
|
public DataAccessException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataAccessException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue