Enable JAAS-Subjects in unit tests and REST Service

- Replace the publicCredentials in CurrentUserContext by Principals
- Add a TaskanaPrincipal interface that extends the Principal interface
by groupNames
- Update the CustomAuthenticationProvider with a taskanaPrincipal for
the jaasAuthenticationTokens login context
- Update the tests in TaskServiceImplIntExplicitTest by a subject 
- Add a SamplePrincipal class for the unit test
- Add workbasket-access-list into taskana-core to add sample data to the
database
This commit is contained in:
Konstantin Kläger 2017-12-06 08:42:00 +01:00
parent 142d801ab1
commit cda53f8c26
6 changed files with 201 additions and 20 deletions

View File

@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory;
import javax.security.auth.Subject;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.Principal;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@ -90,11 +91,11 @@ public final class CurrentUserContext {
Subject subject = Subject.getSubject(AccessController.getContext());
LOGGER.debug("Subject of caller: {}", subject);
if (subject != null) {
Set<Object> publicCredentials = subject.getPublicCredentials();
LOGGER.debug("Public credentials of caller: {}", publicCredentials);
for (Object pC : publicCredentials) {
LOGGER.debug("Returning the first public credential: {}", pC.toString());
return pC.toString();
Set<Principal> principals = subject.getPrincipals();
LOGGER.debug("Public principals of caller: {}", principals);
for (Principal pC : principals) {
LOGGER.debug("Returning the first public principal: {}", pC.getName());
return pC.getName();
}
}
LOGGER.debug("No userid found in subject!");
@ -102,6 +103,20 @@ public final class CurrentUserContext {
}
public static List<String> getGroupIds() {
Subject subject = Subject.getSubject(AccessController.getContext());
LOGGER.debug("Subject of caller: {}", subject);
if (subject != null) {
Set<Principal> principals = subject.getPrincipals();
LOGGER.debug("Public principals of caller: {}", principals);
for (Principal pC : principals) {
if (pC instanceof TaskanaPrincipal) {
TaskanaPrincipal sP = (TaskanaPrincipal) pC;
LOGGER.debug("Returning the groupIds: {}", sP.getGroupNames());
return sP.getGroupNames();
}
}
}
LOGGER.debug("No groupids found in subject!");
return null;
}

View File

@ -0,0 +1,13 @@
package pro.taskana.security;
import java.security.Principal;
import java.util.List;
/**
* This interface extends Principal by groupIds.
* @author KKL
*/
public interface TaskanaPrincipal extends Principal {
List<String> getGroupNames();
}

View File

@ -1,13 +1,20 @@
package pro.taskana.impl.integration;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;
import javax.sql.DataSource;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.h2.store.fs.FileUtils;
import org.junit.After;
import org.junit.AfterClass;
@ -32,6 +39,8 @@ import pro.taskana.impl.configuration.TaskanaEngineConfigurationTest;
import pro.taskana.impl.util.IdGenerator;
import pro.taskana.model.Task;
import pro.taskana.model.TaskState;
import pro.taskana.security.SamplePrincipal;
/**
* Integration Test for TaskServiceImpl transactions with connection management mode EXPLICIT.
@ -44,6 +53,7 @@ public class TaskServiceImplIntExplicitTest {
private TaskanaEngineConfiguration taskanaEngineConfiguration;
private TaskanaEngine taskanaEngine;
private TaskanaEngineImpl taskanaEngineImpl;
private Subject subject;
@BeforeClass
public static void resetDb() throws SQLException {
@ -55,23 +65,54 @@ public class TaskServiceImplIntExplicitTest {
@Before
public void setup() throws FileNotFoundException, SQLException, LoginException {
dataSource = TaskanaEngineConfigurationTest.getDataSource();
taskanaEngineConfiguration = new TaskanaEngineConfiguration(dataSource, false, false);
taskanaEngineConfiguration = new TaskanaEngineConfiguration(dataSource, false);
taskanaEngine = taskanaEngineConfiguration.buildTaskanaEngine();
taskServiceImpl = (TaskServiceImpl) taskanaEngine.getTaskService();
taskanaEngineImpl = (TaskanaEngineImpl) taskanaEngine;
taskanaEngineImpl.setConnectionManagementMode(ConnectionManagementMode.EXPLICIT);
DBCleaner cleaner = new DBCleaner();
cleaner.clearDb(dataSource, false);
subject = new Subject();
SamplePrincipal samplePrincipal = new SamplePrincipal("Elena");
List<String> groups = new ArrayList<String>();
groups.add("group1");
groups.add("group2");
groups.add("group3");
samplePrincipal.setGroups(groups);
subject.getPrincipals().add(samplePrincipal);
try {
Connection connection = dataSource.getConnection();
ScriptRunner runner = new ScriptRunner(connection);
runner.runScript(
new InputStreamReader(this.getClass().getResourceAsStream("/sql/workbasket-access-list.sql")));
} catch (SQLException e1) {
e1.printStackTrace();
}
}
@Test
public void testStart() throws FileNotFoundException, SQLException, TaskNotFoundException, NotAuthorizedException {
public void testStart() {
Subject.doAs(subject, new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
do_testStart();
} catch (TaskNotFoundException | FileNotFoundException | NotAuthorizedException | SQLException e) {
e.printStackTrace();
}
return null;
}
});
}
public void do_testStart() throws FileNotFoundException, SQLException, TaskNotFoundException, NotAuthorizedException {
Connection connection = dataSource.getConnection();
taskanaEngineImpl.setConnection(connection);
Task task = new Task();
task.setName("Unit Test Task");
String id1 = IdGenerator.generateWithPrefix("TWB");
task.setWorkbasketId(id1);
task.setWorkbasketId("1");
task = taskServiceImpl.create(task);
connection.commit(); // needed so that the change is visible in the other session
@ -83,7 +124,22 @@ public class TaskServiceImplIntExplicitTest {
}
@Test(expected = TaskNotFoundException.class)
public void testStartTransactionFail()
public void testStartTransactionFail() throws Throwable {
try {
Subject.doAs(subject, new PrivilegedExceptionAction<Object>() {
public Object run() throws TaskNotFoundException, FileNotFoundException, NotAuthorizedException, SQLException {
do_testStartTransactionFail();
return null;
}
});
} catch (PrivilegedActionException e) {
if (e.getCause() != null) {
throw e.getCause();
}
}
}
public void do_testStartTransactionFail()
throws FileNotFoundException, SQLException, TaskNotFoundException, NotAuthorizedException {
Connection connection = dataSource.getConnection();
taskanaEngineImpl.setConnection(connection);
@ -92,7 +148,7 @@ public class TaskServiceImplIntExplicitTest {
Task task = new Task();
task.setName("Unit Test Task");
String id1 = IdGenerator.generateWithPrefix("TWB");
task.setWorkbasketId("id1");
task.setWorkbasketId("1");
task = taskServiceImpl.create(task);
connection.commit();
taskServiceImpl.getTaskById(id1);
@ -104,7 +160,21 @@ public class TaskServiceImplIntExplicitTest {
}
@Test
public void testCreateTaskInTaskanaWithDefaultDb()
public void testCreateTaskInTaskanaWithDefaultDb() {
Subject.doAs(subject, new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
do_testCreateTaskInTaskanaWithDefaultDb();
} catch (TaskNotFoundException | FileNotFoundException | NotAuthorizedException | SQLException e) {
e.printStackTrace();
}
return null;
}
});
}
public void do_testCreateTaskInTaskanaWithDefaultDb()
throws FileNotFoundException, SQLException, TaskNotFoundException, NotAuthorizedException {
DataSource ds = TaskanaEngineConfiguration.createDefaultDataSource();
TaskanaEngineConfiguration taskanaEngineConfiguration = new TaskanaEngineConfiguration(ds, false, false);
@ -115,8 +185,8 @@ public class TaskServiceImplIntExplicitTest {
Task task = new Task();
task.setName("Unit Test Task");
String id1 = IdGenerator.generateWithPrefix("TWB");
task.setWorkbasketId(id1);
//String id1 = IdGenerator.generateWithPrefix("TWB");
task.setWorkbasketId("1");
task = taskServiceImpl.create(task);
Assert.assertNotNull(task);
@ -126,16 +196,36 @@ public class TaskServiceImplIntExplicitTest {
}
@Test
public void should_ReturnList_when_BuilderIsUsed() throws SQLException, NotAuthorizedException {
public void should_ReturnList_when_BuilderIsUsed() {
Subject.doAs(subject, new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
do_should_ReturnList_when_BuilderIsUsed();
} catch (NotAuthorizedException | SQLException e) {
e.printStackTrace();
}
return null;
}
});
}
public void do_should_ReturnList_when_BuilderIsUsed() throws SQLException, NotAuthorizedException {
Connection connection = dataSource.getConnection();
taskanaEngineImpl.setConnection(connection);
Task task = new Task();
task.setName("Unit Test Task");
String id1 = IdGenerator.generateWithPrefix("TWB");
task.setWorkbasketId(id1);
//String id1 = IdGenerator.generateWithPrefix("TWB");
task.setWorkbasketId("1");
task = taskServiceImpl.create(task);
Task task2 = new Task();
task2.setName("Unit Test Task");
task2.setWorkbasketId("2");
task2 = taskServiceImpl.create(task2);
TaskanaEngineImpl taskanaEngineImpl = (TaskanaEngineImpl) taskanaEngine;
ClassificationQuery classificationQuery = new ClassificationQueryImpl(taskanaEngineImpl)
.parentClassification("pId1", "pId2").category("cat1", "cat2").type("oneType").name("1Name", "name2")
@ -146,7 +236,7 @@ public class TaskServiceImplIntExplicitTest {
.systemInstance("sysInst1", "sysInst2").value("val1", "val2", "val3");
List<Task> results = taskServiceImpl.createTaskQuery().name("bla", "test").descriptionLike("test")
.priority(1, 2, 2).state(TaskState.CLAIMED).workbasketId("asd", "asdasdasd")
.priority(1, 2, 2).state(TaskState.CLAIMED).workbasketId("1", "2")
.owner("test", "test2", "bla").customFields("test").classification(classificationQuery)
.objectReference(objectReferenceQuery).list();

View File

@ -0,0 +1,34 @@
package pro.taskana.security;
import java.util.List;
/**
* SamplePrincipal.
* @author KKL
*/
public class SamplePrincipal implements TaskanaPrincipal {
private String name;
private List<String> groups;
public SamplePrincipal(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public List<String> getGroupNames() {
return groups;
}
public void setGroups(List<String> groups) {
this.groups = groups;
}
}

View File

@ -0,0 +1,3 @@
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('1', '1', 'Elena', true, true, true, true, true, false, false, false, false, false, false, false, false);
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('2', '2', 'Elena', true, true, true, true, true, true, true, true, true, false, false, false, false);
INSERT INTO WORKBASKET_ACCESS_LIST VALUES ('3', '3', 'Simone', true, true, true, true, true, true, true, true, true, true, true, true, true);

View File

@ -1,9 +1,14 @@
package pro.taskana.rest.security;
import java.util.ArrayList;
import java.util.List;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.jaas.JaasAuthenticationToken;
import org.springframework.security.core.Authentication;
import pro.taskana.security.TaskanaPrincipal;
public class CustomAutenticationProvider implements AuthenticationProvider {
private AuthenticationProvider delegate;
@ -17,14 +22,35 @@ public class CustomAutenticationProvider implements AuthenticationProvider {
.authenticate(authentication);
if (jaasAuthenticationToken.isAuthenticated()) {
jaasAuthenticationToken.getLoginContext().getSubject().getPublicCredentials().add(jaasAuthenticationToken.getPrincipal());
final String name = jaasAuthenticationToken.getPrincipal().toString();
final List<String> groupNames = getGroupNames(name);
TaskanaPrincipal tp = new TaskanaPrincipal() {
@Override
public String getName() {
return name;
}
@Override
public List<String> getGroupNames() {
return groupNames;
}
};
jaasAuthenticationToken.getLoginContext().getSubject().getPrincipals().add(tp);
return jaasAuthenticationToken;
} else {
return null;
}
}
@Override
private List<String> getGroupNames(String name) {
List<String> groupNames = new ArrayList<String>();
groupNames.add("group1");
groupNames.add("group2");
return groupNames;
}
@Override
public boolean supports(Class<?> authentication) {
return delegate.supports(authentication);
}