public String error = "";
public String fromTestID = "";
public String auth = "";
+ public String adminAuth = "";
public String boundary = "";
public String payloadStrictness = "";
public long contentLength = 0;
* See example usage in calling class XmlReplayTest in services/IntegrationTests, and also in main() in this class.
* @author Laramie Crocker
*/
+@SuppressWarnings("unchecked")
public class XmlReplay {
public XmlReplay(String basedir, String reportsDir){
return reportsList;
}
- public String toString(){
+ @Override
+ public String toString(){
return "XmlReplay{"+this.basedir+", "+this.defaultAuthsMap+", "+this.dump+", "+this.reportsDir+'}';
}
/** Creates new instances of XmlReplay, one for each controlFile specified in the master,
* and setting defaults from this instance, but not sharing ServiceResult objects or maps. */
- public List<List<ServiceResult>> runMaster(String masterFilename, boolean readOptionsFromMaster) throws Exception {
+ public List<List<ServiceResult>> runMaster(String masterFilename, boolean readOptionsFromMaster) throws Exception {
List<List<ServiceResult>> list = new ArrayList<List<ServiceResult>>();
org.dom4j.Document document;
if (readOptionsFromMaster){
return runTests(testGroupID, "");
}
- public List<ServiceResult> autoDelete(String logName){
- return autoDelete(this.serviceResultsMap, logName, 0);
+ public List<ServiceResult> autoDelete(String logName){
+ return autoDelete(this.defaultAuthsMap, this.serviceResultsMap, logName, 0);
}
/** Use this method to clean up resources created on the server that returned CSIDs, if you have
* @param serviceResultsMap a Map of ServiceResult objects, which will contain ServiceResult.deleteURL.
* @return a List<String> of debug info about which URLs could not be deleted.
*/
- private static List<ServiceResult> autoDelete(Map<String, ServiceResult> serviceResultsMap, String logName, int reattempt) {
+ private static List<ServiceResult> autoDelete(AuthsMap defaultAuths, Map<String, ServiceResult> serviceResultsMap, String logName, int reattempt) {
List<ServiceResult> results = new ArrayList<ServiceResult>();
HashMap<String, ServiceResult> reattemptList = new HashMap<String, ServiceResult>();
int deleteFailures = 0;
for (ServiceResult pr : serviceResultsMap.values()) {
try {
if (pr.autoDelete == true && Tools.notEmpty(pr.deleteURL)){
- ServiceResult deleteResult = XmlReplayTransport.doDELETE(pr.deleteURL, pr.auth, pr.testID, "[autodelete:"+logName+"]");
+ ServiceResult deleteResult = XmlReplayTransport.doDELETE(pr.deleteURL, defaultAuths.getDefaultAuth(), pr.testID, "[autodelete:"+logName+"]");
if (deleteResult.gotExpectedResult() == false || deleteResult.responseCode != 200) {
reattemptList.put(REATTEMPT_KEY + deleteFailures++, pr); // We need to try again after our dependents have been deleted. cow()
}
// our MAX_REATTEMPTS limit.
//
if (reattemptList.size() > 0 && reattempt < MAX_REATTEMPTS) {
- return autoDelete(reattemptList, logName, ++reattempt); // recursive call
+ return autoDelete(defaultAuths, reattemptList, logName, ++reattempt); // recursive call
}
return results;
public String getDefaultAuth(){
return map.get(defaultID);
}
- public String toString(){
+ @Override
+ public String toString(){
return "AuthsMap: {default='"+defaultID+"'; "+map.keySet()+'}';
}
}
public boolean payloads = false;
//public static final ServiceResult.DUMP_OPTIONS dumpServiceResultOptions = ServiceResult.DUMP_OPTIONS;
public ServiceResult.DUMP_OPTIONS dumpServiceResult = ServiceResult.DUMP_OPTIONS.minimal;
- public String toString(){
+ @Override
+ public String toString(){
return "payloads: "+payloads+" dumpServiceResult: "+dumpServiceResult;
}
}
byte[] b = FileUtils.readFileToByteArray(new File(expectedResponseParts.responseFilename));
String expectedPartContent = new String(b);
Map<String,String> vars = expectedResponseParts.varsList.get(0); //just one part, so just one varsList. Must be there, even if empty.
- expectedPartContent = evalStruct.eval(expectedPartContent, serviceResultsMap, vars, evalStruct.jexl, evalStruct.jc);
+ expectedPartContent = XmlReplayEval.eval(expectedPartContent, serviceResultsMap, vars, evalStruct.jexl, evalStruct.jc);
serviceResult.expectedContentExpanded = expectedPartContent;
String label = "NOLABEL";
String leftID = "{from expected part, label:"+label+" filename: "+expectedResponseParts.responseFilename+"}";
} else {
tests = testgroup.selectNodes("test");
}
- String authForTest = "";
+ String authForTest = ""; // reset auth for each test group
int testElementIndex = -1;
for (Node testNode : tests) {
if (Tools.notEmpty(authIDForTest)){
currentAuthForTest = authsMap.map.get(authIDForTest);
- }
- else {
+ } else {
String tokenAuthExpression = testNode.valueOf("@tokenauth");
-
if (Tools.notEmpty(tokenAuthExpression)){
- currentAuthForTest = "Bearer " + evalStruct.eval(tokenAuthExpression, serviceResultsMap, null, jexl, jc);
+ currentAuthForTest = "Bearer " + XmlReplayEval.eval(tokenAuthExpression, serviceResultsMap, null, jexl, jc);
}
}
}
if (uri.indexOf("$")>-1){
- uri = evalStruct.eval(uri, serviceResultsMap, null, jexl, jc);
+ uri = XmlReplayEval.eval(uri, serviceResultsMap, null, jexl, jc);
}
fullURL = fixupFullURL(fullURL, protoHostPort, uri);
hasError = ! serviceResult.gotExpectedResult();
}
- boolean doingAuto = (dump.dumpServiceResult == ServiceResult.DUMP_OPTIONS.auto);
- String serviceResultRow = serviceResult.dump(dump.dumpServiceResult, hasError)+"; time:"+(System.currentTimeMillis()-startTime);
- String leader = (dump.dumpServiceResult == ServiceResult.DUMP_OPTIONS.detailed) ? "XmlReplay:"+testIDLabel+": ": "";
-
report.addTestResult(serviceResult);
- if ( (dump.dumpServiceResult == ServiceResult.DUMP_OPTIONS.detailed)
- || (dump.dumpServiceResult == ServiceResult.DUMP_OPTIONS.full) ){
+ if ((dump.dumpServiceResult == ServiceResult.DUMP_OPTIONS.detailed) || (dump.dumpServiceResult == ServiceResult.DUMP_OPTIONS.full)) {
System.out.println("\r\n#---------------------#");
}
- System.out.println(timeString()+" "+leader+serviceResultRow+"\r\n");
+
+ String leader = (dump.dumpServiceResult == ServiceResult.DUMP_OPTIONS.detailed) ? "XmlReplay:" + testIDLabel +": ": "";
+ String serviceResultRow = serviceResult.dump(dump.dumpServiceResult, hasError) + "; time:" + (System.currentTimeMillis()-startTime);
+ //System.out.println(timeString() + "\n" + leader + serviceResultRow + "\r\n");
+ System.out.println(String.format("Time: %s\nLeader: %s\nAuth: %s\nResult: %s\r\n",
+ timeString(), testIDLabel, Tools.notEmpty(authIDForTest) ? authIDForTest : "<inferred>", serviceResultRow));
+
+ boolean doingAuto = (dump.dumpServiceResult == ServiceResult.DUMP_OPTIONS.auto);
if (dump.payloads || (doingAuto&&hasError) ) {
if (Tools.notBlank(serviceResult.requestPayload)){
System.out.println("\r\n========== request payload ===============");
}
}
if (Tools.isTrue(autoDeletePOSTS) && param_autoDeletePOSTS){
- autoDelete(serviceResultsMap, "default", 0);
+ autoDelete(defaultAuths, serviceResultsMap, "default", 0);
}
}
return result;
}
- public static void main(String[]args) throws Exception {
+ public static void main(String[]args) throws Exception {
Options options = createOptions();
//System.out.println("System CLASSPATH: "+prop.getProperty("java.class.path", null));
CommandLineParser parser = new GnuParser();
</account>
<role>
<roleId>${createRole.CSID}</roleId>
- <roleName>ROLE_1_BIRD</roleName>
+ <roleName>xROLE_1_BIRD</roleName>
</role>
</ns2:account_role>
</permission>
<role>
<roleId>${createRole.CSID}</roleId>
- <roleName>ROLE_1_BIRD</roleName>
+ <roleName>xROLE_1_BIRD</roleName>
</role>
</ns2:permission_role>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:role xmlns:ns2="http://collectionspace.org/services/authorization">
- <roleName>ROLE_1_BIRD</roleName>
+ <roleName>xROLE_1_BIRD</roleName>
<description>Role for testing batch invoke permissions</description>
</ns2:role>
<auth ID="user1@museum1">dXNlcjFAbXVzZXVtMS5vcmc6dXNlcjFAbXVzZXVtMS5vcmc=</auth>
<auth ID="bigbird2010">YmlnYmlyZDIwMTA6YmlnYmlyZDIwMTA=</auth>
<auth ID="elmo2010">ZWxtbzIwMTA6ZWxtbzIwMTA=</auth>
+ <auth ID="grover2018">Z3JvdmVyMjAxODpncm92ZXIyMDE4</auth>
+
</auths>
+ <testGroup ID="slipOut" autoDeletePOSTS="true">
+ <test ID="slipOutPerm">
+ <method>POST</method>
+ <uri>/cspace-services/authorization/permissions</uri>
+ <filename>security/slipOutPerm.xml</filename>
+ </test>
+ <test ID="slipOutRole">
+ <method>POST</method>
+ <uri>/cspace-services/authorization/roles</uri>
+ <filename>security/slipOutRole.xml</filename>
+ </test>
+ <test ID="accountGrover">
+ <method>POST</method>
+ <uri>/cspace-services/accounts</uri>
+ <filename>security/create-account-grover.xml</filename>
+ </test>
+ <test ID="slipOutVocab-1" auth="grover2018">
+ <method>POST</method>
+ <uri>/cspace-services/vocabularies</uri>
+ <filename>security/slipOutVocab-1.xml</filename>
+ </test>
+ <test ID="update-slipOutPerm" auth="admin@core.collectionspace.org">
+ <method>PUT</method>
+ <uri>/cspace-services/authorization/permissions/${slipOutPerm.CSID}</uri>
+ <filename>security/slipOutPerm-update.xml</filename>
+ </test>
+ <test ID="slipOutVocab-2" auth="grover2018">
+ <expectedCodes>403</expectedCodes>
+ <method>POST</method>
+ <uri>/cspace-services/vocabularies</uri>
+ <filename>security/slipOutVocab-2.xml</filename>
+ </test>
+ </testGroup>
+
+ <testGroup ID="DefaultPermmissions" autoDeletePOSTS="true">
+ <test ID="get1-loansin-CRUDL">
+ <method>GET</method>
+ <uri>/cspace-services/authorization/permissions/1-loansin-CRUDL</uri>
+ <response>
+ <expected level="TEXT" />
+ <filename>security/res/get1-loansin-CRUDL.res.xml</filename>
+ <label>permission</label>
+ </response>
+ </test>
+ <test ID="get1-loansin-CRUDLpermRoles">
+ <method>GET</method>
+ <uri>/cspace-services/authorization/permissions/1-loansin-CRUDL/permroles</uri>
+ </test>
+ </testGroup>
<testGroup ID="deleteBug" autoDeletePOSTS="false">
+
<test ID="permElmo">
<method>POST</method>
<uri>/cspace-services/authorization/permissions</uri>
<filename>security/2-elmo-permission.xml</filename>
</test>
<test ID="elmoPermroles">
+ <expectedCodes>400</expectedCodes>
<method>POST</method>
<uri>/cspace-services/authorization/permissions/${permElmo.CSID}/permroles</uri>
- <filename>security/10-permissionroles-elmo.xml</filename>
+ <filename>security/14-permissionroles-bogus.xml</filename>
</test>
<test ID="accountElmo">
<method>POST</method>
<fromTestID>dimension1</fromTestID>
</test>
<test ID="deleteElmoPermroles">
+ <expectedCodes>404</expectedCodes>
<method>DELETE</method>
<uri>/cspace-services/authorization/permissions/${permElmo.CSID}/permroles</uri>
</test>
<filename>dimension/2-put.xml</filename>
</test>
-
-
<test ID="dimensionBigbird_GET">
<method>GET</method>
<uri>/cspace-services/dimensions/</uri>
<!-- CLEANUP -->
<test ID="deletePermrolesBigbird" auth="admin@core.collectionspace.org">
- <msg>Deleting permroles from bigbird2010</msg>
+ <msg>Deleting permroles already deleted in test ID="deletePermrolesBigbird"</msg>
+ <expectedCodes>404</expectedCodes>
<method>DELETE</method>
<uri>/cspace-services/authorization/permissions/${permBigbird.CSID}/permroles</uri>
</test>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:permission xmlns:ns2="http://collectionspace.org/services/authorization/perms">
- <resourceName>dimensions</resourceName>
- <action>
- <name>CREATE</name>
- </action>
- <action>
- <name>READ</name>
- </action>
- <action>
- <name>UPDATE</name>
- </action>
- <action>
- <name>DELETE</name>
- </action>
- <effect>PERMIT</effect>
+ <resourceName>dimensions</resourceName>
+ <action>
+ <name>CREATE</name>
+ </action>
+ <action>
+ <name>READ</name>
+ </action>
+ <action>
+ <name>UPDATE</name>
+ </action>
+ <action>
+ <name>DELETE</name>
+ </action>
+ <effect>PERMIT</effect>
</ns2:permission>
-
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<document name="vocabularies">
+ <ns3:vocabularies_common xmlns:ns3="http://collectionspace.org/services/vocabulary"
+ xmlns:ns2="http://collectionspace.org/services/jaxb">
+ <displayName>TestOrder Vocabulary</displayName>
+ <shortIdentifier>TestOrderVocab</shortIdentifier>
+ <refName>
+ urn:cspace:org.collectionspace.demo:vocabulary:name(TestOrderVocab)'TestOrder Vocabulary'</refName>
+ <vocabType>enum</vocabType>
+ <description>This is a test vocabulary</description>
+ <source>Some mythical book</source>
+ </ns3:vocabularies_common>
+</document>
+
</permission>
<role>
<roleId>${roleIntern.CSID}</roleId>
- <roleName>ROLE_TEST_INTERN</roleName>
+ <roleName>xROLE_TEST_INTERN</roleName>
</role>
</ns2:permission_role>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<ns2:permission
-xmlns:ns2="http://collectionspace.org/services/authorization">
- <resourceName>dimensions</resourceName>
- <action>
- <name>CREATE</name>
- </action>
- <action>
- <name>READ</name>
- </action>
- <action>
- <name>UPDATE</name>
- </action>
- <effect>PERMIT</effect>
+<ns2:permission xmlns:ns2="http://collectionspace.org/services/authorization/perms">
+ <resourceName>dimensions</resourceName>
+ <action>
+ <name>CREATE</name>
+ </action>
+ <action>
+ <name>READ</name>
+ </action>
+ <action>
+ <name>UPDATE</name>
+ </action>
+ <effect>PERMIT</effect>
</ns2:permission>
-
</permission>
<role>
<roleId>${roleTestCM.CSID}</roleId>
- <roleName>ROLE_TEST_CM</roleName>
+ <roleName>xROLE_TEST_CM</roleName>
</role>
</ns2:permission_role>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<ns2:permission
-xmlns:ns2="http://collectionspace.org/services/authorization">
- <resourceName>dimensions</resourceName>
- <action>
- <name>READ</name>
- </action>
- <effect>PERMIT</effect>
+<ns2:permission xmlns:ns2="http://collectionspace.org/services/authorization/perms">
+ <resourceName>dimensions</resourceName>
+ <action>
+ <name>READ</name>
+ </action>
+ <effect>PERMIT</effect>
</ns2:permission>
-
</permission>
<role>
<roleId>${roleTestCM.CSID}</roleId>
- <roleName>ROLE_TEST_CM</roleName>
+ <roleName>xROLE_TEST_CM</roleName>
</role>
</ns2:permission_role>
</permission>
<role>
<roleId>${roleTestCM.CSID}</roleId>
- <roleName>ROLE_TEST_CM</roleName>
+ <roleName>xROLE_TEST_CM</roleName>
</role>
</ns2:permission_role>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<ns2:permission_role
+xmlns:ns2="http://collectionspace.org/services/authorization">
+ <permission>
+ <permissionId>bogus-perm</permissionId>
+ <resourceName>dimensions</resourceName>
+ </permission>
+ <role>
+ <roleId>bogus-role</roleId>
+ <roleName>xROLE_TEST_INTERN</roleName>
+ </role>
+</ns2:permission_role>
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:role xmlns:ns2="http://collectionspace.org/services/authorization">
- <roleName>ROLE_TEST_CM</roleName>
+ <roleName>xROLE_TEST_CM</roleName>
<description>role for ROLE_TEST_CM</description>
<permission>
- <permRelationshipId>4381</permRelationshipId>
<permissionId>1-vocabularies-RL</permissionId>
<resourceName>vocabularies</resourceName>
<actionGroup>RL</actionGroup>
</permission>
<permission>
- <permRelationshipId>4382</permRelationshipId>
<permissionId>1-groups-RL</permissionId>
<resourceName>groups</resourceName>
<actionGroup>RL</actionGroup>
</permission>
<permission>
- <permRelationshipId>4381</permRelationshipId>
- <permissionId>1-vocabularies-CRUL</permissionId>
+ <permissionId>1-vocabularies-CRUDL</permissionId>
<resourceName>vocabularies</resourceName>
<actionGroup>CRUL</actionGroup>
</permission>
<permission>
- <permRelationshipId>4382</permRelationshipId>
- <permissionId>1-groups-CRUL</permissionId>
<resourceName>groups</resourceName>
<actionGroup>CRUL</actionGroup>
</permission>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:role xmlns:ns2="http://collectionspace.org/services/authorization">
- <roleName>ROLE_TEST_CM</roleName>
+ <roleName>xROLE_TEST_CM</roleName>
<description>role for ROLE_TEST_CM</description>
<permission>
<permissionId>1-vocabularies-RL</permissionId>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:role xmlns:ns2="http://collectionspace.org/services/authorization">
- <roleName>ROLE_TEST_INTERN</roleName>
+ <roleName>xROLE_TEST_INTERN</roleName>
<description>role for ROLE_TEST_INTERN</description>
<permission>
<permRelationshipId>4381</permRelationshipId>
</account>
<role>
<roleId>${roleTestCM.CSID}</roleId>
- <roleName>ROLE_TEST_CM</roleName>
+ <roleName>xROLE_TEST_CM</roleName>
</role>
</ns2:account_role>
</account>
<role>
<roleId>${roleIntern.CSID}</roleId>
- <roleName>ROLE_TEST_INTERN</roleName>
+ <roleName>xROLE_TEST_INTERN</roleName>
</role>
</ns2:account_role>
</permission>
<role>
<roleId>${roleTestCM.CSID}</roleId>
- <roleName>ROLE_TEST_CM</roleName>
+ <roleName>xROLE_TEST_CM</roleName>
</role>
</ns2:permission_role>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<ns2:accounts_common xmlns:ns2="http://collectionspace.org/services/account" xmlns:ns3="http://collectionspace.org/services/hyperjaxb">
+ <screenName>grover2018</screenName>
+ <personRefName>grover2018</personRefName>
+ <email>grover@cspace.org</email>
+ <phone>1234567890</phone>
+ <userId>grover2018</userId>
+ <!-- Pass word is grover2018, base64 encoded -->
+ <password>Z3JvdmVyMjAxOA==</password>
+ <tenants>
+ <tenant_id>1</tenant_id>
+ </tenants>
+ <role>
+ <roleId>${slipOutRole.CSID}</roleId> <!-- It should be ok that role name is missing -->
+ </role>
+</ns2:accounts_common>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ns2:permission xmlns:ns2="http://collectionspace.org/services/authorization/perms" csid="1-loansin-CRUDL">
+ <description>Generated admin permission.</description>
+ <resourceName>loansin</resourceName>
+ <actionGroup>CRUDL</actionGroup>
+ <action>
+ <name>CREATE</name>
+ <objectIdentity>1011301984</objectIdentity>
+ <objectIdentityResource>1:loansin#create</objectIdentityResource>
+ </action>
+ <action>
+ <name>READ</name>
+ <objectIdentity>1927741434</objectIdentity>
+ <objectIdentityResource>1:loansin#read</objectIdentityResource>
+ </action>
+ <action>
+ <name>UPDATE</name>
+ <objectIdentity>1524749869</objectIdentity>
+ <objectIdentityResource>1:loansin#update</objectIdentityResource>
+ </action>
+ <action>
+ <name>DELETE</name>
+ <objectIdentity>1028137743</objectIdentity>
+ <objectIdentityResource>1:loansin#delete</objectIdentityResource>
+ </action>
+ <action>
+ <name>SEARCH</name>
+ <objectIdentity>1457259276</objectIdentity>
+ <objectIdentityResource>1:loansin#search</objectIdentityResource>
+ </action>
+ <effect>PERMIT</effect>
+ <metadataProtection>immutable</metadataProtection>
+ <actionsProtection>immutable</actionsProtection>
+ <tenant_id>1</tenant_id>
+</ns2:permission>
+
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<ns3:permission xmlns:ns3="http://collectionspace.org/services/authorization/perms">
+ <resourceName>vocabularies</resourceName>
+ <action>
+ <name>READ</name>
+ </action>
+ <effect>PERMIT</effect>
+</ns3:permission>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<ns3:permission xmlns:ns3="http://collectionspace.org/services/authorization/perms">
+ <resourceName>vocabularies</resourceName>
+ <action>
+ <name>CREATE</name>
+ </action>
+ <action>
+ <name>READ</name>
+ </action>
+ <effect>PERMIT</effect>
+</ns3:permission>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<ns2:role xmlns:ns2="http://collectionspace.org/services/authorization">
+ <roleName>SLIP_OUT_ROLE1</roleName>
+ <permission>
+ <permissionId>${slipOutPerm.CSID}</permissionId>
+ </permission>
+</ns2:role>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<document name="vocabularies">
+ <ns3:vocabularies_common xmlns:ns3="http://collectionspace.org/services/vocabulary"
+ xmlns:ns2="http://collectionspace.org/services/jaxb">
+ <displayName>SlipRole Vocabulary</displayName>
+ <shortIdentifier>sliprole1</shortIdentifier>
+ <refName>
+ urn:cspace:org.collectionspace.demo:vocabulary:name(sliprole1)'SlipRole Vocabulary'</refName>
+ <vocabType>enum</vocabType>
+ <description>This is a test vocabulary</description>
+ <source>Some rug book</source>
+ </ns3:vocabularies_common>
+</document>
+
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<document name="vocabularies">
+ <ns3:vocabularies_common xmlns:ns3="http://collectionspace.org/services/vocabulary"
+ xmlns:ns2="http://collectionspace.org/services/jaxb">
+ <displayName>SlipRole Vocabulary</displayName>
+ <shortIdentifier>sliprole2</shortIdentifier>
+ <refName>
+ urn:cspace:org.collectionspace.demo:vocabulary:name(sliprole2)'SlipRole Vocabulary'</refName>
+ <vocabType>enum</vocabType>
+ <description>This is a test vocabulary</description>
+ <source>Some rug book</source>
+ </ns3:vocabularies_common>
+</document>
+
</hj:basic>
</xs:appinfo>
</xs:annotation>
- </xs:element>
- <xs:element name="createdAt" type="xs:dateTime">
+ </xs:element>
+ <xs:element name="createdAt" type="xs:dateTime">
<xs:annotation>
<xs:appinfo>
<hj:basic>
DROP TABLE IF EXISTS accounts_tenants CASCADE;
DROP TABLE IF EXISTS tenants CASCADE;
DROP SEQUENCE IF EXISTS hibernate_sequence;
-create table accounts_common (csid varchar(128) not null, created_at timestamp not null, email varchar(255) not null, mobile varchar(255), person_ref_name varchar(255), phone varchar(255), screen_name varchar(128) not null, status varchar(15) not null, updated_at timestamp, userid varchar(128) not null, metadata_protection varchar(255), roles_protection varchar(255), primary key (csid), unique (userid));
-create table accounts_tenants (HJID int8 not null, tenant_id varchar(128) not null, TENANTS_ACCOUNTS_COMMON_CSID varchar(128), primary key (HJID));
+create table accounts_common (csid varchar(128) not null, created_at timestamp not null, email varchar(255) not null, mobile varchar(255), person_ref_name varchar(255), phone varchar(255), screen_name varchar(128) not null,
+ status varchar(15) not null, updated_at timestamp, userid varchar(128) not null,
+ metadata_protection varchar(255), roles_protection varchar(255),
+ primary key (csid), unique (userid));
+
+ create table accounts_tenants (HJID int8 not null, tenant_id varchar(128) not null, TENANTS_ACCOUNTS_COMMON_CSID varchar(128), primary key (HJID));
create table tenants (id varchar(128) not null, created_at timestamp not null, name varchar(255) not null, config_md5hash varchar(255), authorities_initialized boolean not null, disabled boolean not null, updated_at timestamp, primary key (id));
alter table accounts_tenants add constraint FKFDA649B05A9CEEB5 foreign key (TENANTS_ACCOUNTS_COMMON_CSID) references accounts_common;
create sequence hibernate_sequence;
import org.collectionspace.services.common.document.DocumentNotFoundException;
import org.collectionspace.services.common.query.UriInfoImpl;
import org.collectionspace.services.common.storage.StorageClient;
+import org.collectionspace.services.common.storage.TransactionContext;
import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
import org.collectionspace.services.config.tenant.EmailConfig;
import org.collectionspace.services.config.tenant.TenantBindingType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
-import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Path(AccountClient.SERVICE_PATH)
@Consumes("application/xml")
@Produces("application/xml")
-public class AccountResource extends SecurityResourceBase {
+public class AccountResource extends SecurityResourceBase<AccountsCommon, AccountsCommon> {
final Logger logger = LoggerFactory.getLogger(AccountResource.class);
final StorageClient storageClient = new AccountStorageClient();
@PUT
@Path("{csid}")
- public AccountsCommon updateAccount(@Context UriInfo ui, @PathParam("csid") String csid,AccountsCommon theUpdate) {
+ public AccountsCommon updateAccount(@Context UriInfo ui, @PathParam("csid") String csid, AccountsCommon theUpdate) {
return (AccountsCommon)update(ui, csid, theUpdate, AccountsCommon.class);
}
+
+ /*
+ * Use this when you have an existing and active ServiceContext.
+ */
+ public AccountsCommon updateAccount(ServiceContext<AccountsCommon, AccountsCommon> parentContext, UriInfo ui, String csid, AccountsCommon theUpdate) {
+ return (AccountsCommon)update(parentContext, ui, csid, theUpdate, AccountsCommon.class);
+ }
+
/**
* Resets an accounts password.
*
* @param ui
* @return
- * @throws UnsupportedEncodingException
- * @throws DocumentNotFoundException
+ * @throws
* @throws IOException
*/
@POST
@Path(PROCESS_PASSWORD_RESET_PATH)
- synchronized public Response processPasswordReset(Passwordreset passwordreset, @Context UriInfo ui) throws UnsupportedEncodingException, DocumentNotFoundException {
+ synchronized public Response processPasswordReset(Passwordreset passwordreset, @Context UriInfo ui) {
Response response = null;
//
response = Response.status(Response.Status.BAD_REQUEST).entity(errMsg).type("text/plain").build();
return response;
}
-
- //
//
+ // Finally, try to update the account with the new password.
//
String tenantId = token.getTenantId();
TenantBindingType tenantBindingType = ServiceMain.getInstance().getTenantBindingConfigReader().getTenantBinding(tenantId);
EmailConfig emailConfig = tenantBindingType.getEmailConfig();
if (emailConfig != null) {
try {
- if (AuthorizationCommon.hasTokenExpired(emailConfig, token) == false) {
- AccountsCommon accountUpdate = new AccountsCommon();
- accountUpdate.setUserId(targetAccount.getUserId());
- accountUpdate.setPassword(password.getBytes());
- updateAccount(ui, targetAccount.getCsid(), accountUpdate);
- TokenStorageClient.update(tokenId, false); // disable the token so it can't be used again.
- String msg = String.format("Successfully reset password using token ID='%s'.",
- token.getId());
- response = Response.status(Response.Status.OK).entity(msg).type("text/plain").build();
- } else {
- String errMsg = String.format("Could not reset password using token with ID='%s'. Password reset token has expired.",
- token.getId());
- response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).type("text/plain").build();
- }
- } catch (NoSuchAlgorithmException e) {
- String errMsg = String.format("Could not reset password for using token ID='%s'. Error: '%s'",
+ ServiceContext<AccountsCommon, AccountsCommon> ctx = createServiceContext((AccountsCommon) null, AccountsCommon.class, ui);
+ TransactionContext transactionCtx = ctx.openConnection();
+ try {
+ if (AuthorizationCommon.hasTokenExpired(emailConfig, token) == false) {
+ transactionCtx.beginTransaction();
+ AccountsCommon accountUpdate = new AccountsCommon();
+ accountUpdate.setUserId(targetAccount.getUserId());
+ accountUpdate.setPassword(password.getBytes());
+ updateAccount(ctx, ui, targetAccount.getCsid(), accountUpdate);
+ TokenStorageClient.update(transactionCtx, tokenId, false); // disable the token so it can't be used again.
+ transactionCtx.commitTransaction();
+ //
+ // Success!
+ //
+ String msg = String.format("Successfully reset password using token ID='%s'.", token.getId());
+ response = Response.status(Response.Status.OK).entity(msg).type("text/plain").build();
+ } else {
+ String errMsg = String.format("Could not reset password using token with ID='%s'. Password reset token has expired.",
+ token.getId());
+ response = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errMsg).type("text/plain").build();
+ }
+ } catch (Throwable t) {
+ transactionCtx.markForRollback();
+ String errMsg = String.format("Could not reset password using token ID='%s'. Error: '%s'",
+ t.getMessage(), token.getId());
+ response = Response.status(Response.Status.BAD_REQUEST).entity(errMsg).type("text/plain").build();
+ } finally {
+ ctx.closeConnection();
+ }
+ } catch (Exception e) {
+ String errMsg = String.format("Could not reset password using token ID='%s'. Error: '%s'",
e.getMessage(), token.getId());
response = Response.status(Response.Status.BAD_REQUEST).entity(errMsg).type("text/plain").build();
}
return result;
}
-
+
@DELETE
@Path("{csid}")
public Response deleteAccount(@Context UriInfo uriInfo, @PathParam("csid") String csid) {
try {
AccountsCommon account = (AccountsCommon)get(csid, AccountsCommon.class);
+ //
// If marked as metadata immutable, do not delete
- if (AccountClient.IMMUTABLE.equals(account.getMetadataProtection())) {
+ //
+ if (AccountClient.IMMUTABLE.equals(account.getMetadataProtection())) {
Response response =
Response.status(Response.Status.FORBIDDEN).entity("Account: "+csid+" is immutable.").type("text/plain").build();
return response;
//
ServiceContext<AccountsCommon, AccountsCommon> ctx = createServiceContext((AccountsCommon) null,
AccountsCommon.class, uriInfo);
- ctx.openConnection();
+ TransactionContext transactionContext = ctx.openConnection();
try {
+ transactionContext.beginTransaction();
+ //
+ // Delete all the account-role relationships
+ //
AccountRoleSubResource subResource = new AccountRoleSubResource("accounts/accountroles");
subResource.deleteAccountRole(ctx, csid, SubjectType.ROLE);
+ //
+ // Now delete the account.
+ //
getStorageClient(ctx).delete(ctx, csid);
+ transactionContext.commitTransaction();
+ } catch (Throwable t) {
+ transactionContext.markForRollback();
+ throw t;
} finally {
ctx.closeConnection();
}
return Response.status(HttpResponseCodes.SC_OK).build();
}
- @POST
+ @POST
@Path("{csid}/accountroles")
- public Response createAccountRole(@QueryParam("_method") String method,
+ public Response createAccountRole(
+ @Context UriInfo uriInfo,
+ @QueryParam("_method") String method,
@PathParam("csid") String accCsid,
AccountRole input) {
if (method != null) {
}
logger.debug("createAccountRole with accCsid=" + accCsid);
ensureCSID(accCsid, ServiceMessages.POST_FAILED+ "accountroles account ");
+
try {
AccountsCommon account = (AccountsCommon)get(accCsid, AccountsCommon.class);
- // If marked as roles immutable, do not create
+ // If marked as immutable, fail.
if (AccountClient.IMMUTABLE.equals(account.getRolesProtection())) {
Response response =
Response.status(Response.Status.FORBIDDEN).entity("Roles for Account: "+accCsid+" are immutable.").type("text/plain").build();
return response;
}
- AccountRoleSubResource subResource =
- new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE);
- String accrolecsid = subResource.createAccountRole((ServiceContext)null, input, SubjectType.ROLE);
- UriBuilder path = UriBuilder.fromResource(AccountResource.class);
- path.path(accCsid + "/accountroles/" + accrolecsid);
- Response response = Response.created(path.build()).build();
- return response;
+
+ ServiceContext<AccountsCommon, AccountsCommon> ctx = createServiceContext((AccountsCommon) null, AccountsCommon.class, uriInfo);
+ ctx.openConnection();
+ try {
+ AccountRoleSubResource subResource =
+ new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE);
+ String accrolecsid = subResource.createAccountRole(ctx, input, SubjectType.ROLE);
+ UriBuilder path = UriBuilder.fromResource(AccountResource.class);
+ path.path(accCsid + "/accountroles/" + accrolecsid);
+ Response response = Response.created(path.build()).build();
+ return response;
+ } finally {
+ ctx.closeConnection();
+ }
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.POST_FAILED, accCsid);
}
logger.debug("getAccountRole with accCsid=" + accCsid);
ensureCSID(accCsid, ServiceMessages.GET_FAILED+ "accountroles account ");
AccountRoleRel result = null;
+ ServiceContext<AccountsCommon, AccountsCommon> ctx = null;
+
try {
AccountRoleSubResource subResource =
new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE);
//get relationships for an account
- result = subResource.getAccountRoleRel((ServiceContext)null, accCsid, SubjectType.ROLE, accrolecsid);
+ result = subResource.getAccountRoleRel(ctx, accCsid, SubjectType.ROLE, accrolecsid);
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.GET_FAILED, accCsid);
}
checkResult(result, accCsid, ServiceMessages.GET_FAILED);
+
return result;
}
logger.debug("getAccountRole with accCsid=" + accCsid);
ensureCSID(accCsid, ServiceMessages.GET_FAILED+ "accountroles account ");
AccountRole result = null;
+ ServiceContext<AccountsCommon, AccountsCommon> ctx = null;
try {
AccountRoleSubResource subResource =
new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE);
//get relationships for an account
- result = subResource.getAccountRole((ServiceContext)null, accCsid, SubjectType.ROLE);
+ result = subResource.getAccountRole(ctx, accCsid, SubjectType.ROLE);
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.GET_FAILED, accCsid);
}
return result;
}
- public Response deleteAccountRole(String accCsid, AccountRole input) {
+ public Response deleteAccountRole(String accCsid, AccountRole input) {
logger.debug("deleteAccountRole with accCsid=" + accCsid);
ensureCSID(accCsid, ServiceMessages.DELETE_FAILED+ "accountroles account ");
try {
AccountsCommon account = (AccountsCommon)get(accCsid, AccountsCommon.class);
// If marked as roles immutable, do not delete
- if(AccountClient.IMMUTABLE.equals(account.getRolesProtection())) {
+ if (AccountClient.IMMUTABLE.equals(account.getRolesProtection())) {
Response response =
Response.status(Response.Status.FORBIDDEN).entity("Roles for Account: "+accCsid+" are immutable.").type("text/plain").build();
return response;
}
- AccountRoleSubResource subResource =
- new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE);
- //delete all relationships for an account
- subResource.deleteAccountRole((ServiceContext)null, accCsid, SubjectType.ROLE, input);
+
+ ServiceContext<AccountsCommon, AccountsCommon> ctx = createServiceContext((AccountsCommon) null,
+ AccountsCommon.class, (UriInfo) null);
+ ctx.openConnection();
+ try {
+ AccountRoleSubResource subResource =
+ new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE);
+ //delete all relationships for an account
+ subResource.deleteAccountRole(ctx, accCsid, SubjectType.ROLE, input);
+ } finally {
+ ctx.closeConnection();
+ }
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.DELETE_FAILED, accCsid);
}
@DELETE
@Path("{csid}/accountroles")
- public Response deleteAccountRole(@PathParam("csid") String accCsid) {
+ public Response deleteAccountRole(@Context UriInfo uriInfo, @PathParam("csid") String accCsid) {
+
logger.debug("deleteAccountRole: All roles related to account with accCsid=" + accCsid);
ensureCSID(accCsid, ServiceMessages.DELETE_FAILED+ "accountroles account ");
Response.status(Response.Status.FORBIDDEN).entity("Roles for Account: "+accCsid+" are immutable.").type("text/plain").build();
return response;
}
- AccountRoleSubResource subResource =
- new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE);
- //delete all relationships for an account
- subResource.deleteAccountRole((ServiceContext)null, accCsid, SubjectType.ROLE);
+
+ ServiceContext<AccountsCommon, AccountsCommon> ctx = createServiceContext((AccountsCommon) null, AccountsCommon.class, uriInfo);
+ ctx.openConnection();
+ try {
+ AccountRoleSubResource subResource =
+ new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE);
+ //delete all relationships for an account
+ subResource.deleteAccountRole(ctx, accCsid, SubjectType.ROLE);
+ } finally {
+ ctx.closeConnection();
+ }
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.DELETE_FAILED, accCsid);
}
*/
public String createAccountRole(ServiceContext parentCtx, AccountRole input, SubjectType subject)
throws Exception {
-
//
// We need to associate every new account with the Spring Security Admin role so we can make
// changes to the Spring Security ACL tables. The Spring Security Admin role has NO CollectionSpace
// specific permissions. It is an internal/private role that service consumers and end-users NEVER see.
//
- //Preserve the original incoming list of roles
+ // Preserve the original incoming list of roles
List<RoleValue> inputRoleValues = input.getRole();
- //Change the role list to be just the Spring role
- List<RoleValue> springRoles = new ArrayList<RoleValue>();
- input.setRole(springRoles);
- RoleValue springAdminRole = new RoleValue();
- springRoles.add(springAdminRole);
- springAdminRole.setRoleId(AuthN.ROLE_SPRING_ADMIN_ID);
- springAdminRole.setRoleName(AuthN.ROLE_SPRING_ADMIN_NAME);
+ // Temporarily change the role list to be just the Spring role
+ List<RoleValue> springRoleValueList = new ArrayList<RoleValue>();
+ input.setRole(springRoleValueList);
+
+ RoleValue springAdminRoleValue = new RoleValue();
+ springRoleValueList.add(springAdminRoleValue);
+ springAdminRoleValue.setRoleId(AuthN.ROLE_SPRING_ADMIN_ID);
+ springAdminRoleValue.setRoleName(AuthN.ROLE_SPRING_ADMIN_NAME);
// The Spring role relationship may already exist, if it does then we'll get a PersistenceException that
// we'll just ignore.
}
//
- // Now we'll add the account relationships for the original incoming roles.
+ // Now we'll add the actual account-role relationships for the original incoming payload.
//
input.setRole(inputRoleValues);
ServiceContext<AccountRole, AccountRole> ctx = createServiceContext(parentCtx, input, subject);
import org.collectionspace.services.client.AccountClient;
import org.collectionspace.services.client.AccountFactory;
import org.collectionspace.services.client.AccountRoleFactory;
+import org.collectionspace.services.common.storage.TransactionContext;
import org.collectionspace.services.common.storage.jpa.JpaDocumentHandler;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.document.DocumentFilter;
}
@Override
+ /**
+ * If the create payload included a list of role, relate them to the account.
+ */
public void completeCreate(DocumentWrapper<AccountsCommon> wrapDoc) throws Exception {
AccountsCommon accountsCommon = wrapDoc.getWrappedObject();
List<RoleValue> roleValueList = account.getRole();
if (roleValueList != null && roleValueList.size() > 0) {
+ //
+ // To prevent new Accounts being created (especially low-level Spring Security accounts/SIDs), we'll first flush the current
+ // JPA context to ensure our Account can be successfully persisted.
+ //
+ TransactionContext jpaTransactionContext = this.getServiceContext().getCurrentTransactionContext();
+ jpaTransactionContext.flush();
+
AccountRoleSubResource subResource = new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE);
AccountRole accountRole = AccountRoleFactory.createAccountRoleInstance(accountsCommon, roleValueList, true, true);
- String accountRoleCsid = subResource.createAccountRole(this.getServiceContext(), accountRole, SubjectType.ROLE);
+ subResource.createAccountRole(this.getServiceContext(), accountRole, SubjectType.ROLE);
}
}
import java.util.List;
import org.collectionspace.services.common.authorization_mgt.AuthorizationRoleRel;
+import org.collectionspace.services.common.authorization_mgt.PermissionRoleUtil;
import org.collectionspace.services.authorization.AccountRole;
import org.collectionspace.services.authorization.AccountRoleRel;
import org.collectionspace.services.authorization.AccountValue;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.storage.jpa.JpaDocumentFilter;
import org.collectionspace.services.common.storage.jpa.JpaDocumentHandler;
+import org.collectionspace.services.common.document.DocumentException;
import org.collectionspace.services.common.document.DocumentFilter;
import org.collectionspace.services.common.document.DocumentWrapper;
import org.collectionspace.services.common.context.ServiceContextProperties;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/* (non-Javadoc)
* @see org.collectionspace.services.common.document.AbstractDocumentHandlerImpl#handleGet(org.collectionspace.services.common.document.DocumentWrapper)
*/
- @Override
+ @SuppressWarnings({ "unchecked" })
+ @Override
public void handleGet(DocumentWrapper<List<AccountRoleRel>> wrapDoc) throws Exception {
AccountRole output = extractCommonPart(wrapDoc);
setCommonPart(output);
// Ensure the roles exist
}
- public void fillCommonPart(AccountRole ar,
+ /**
+ * Populate the incoming wrapDoc (AccountRoleRel) object with account-role data.
+ *
+ * @param accountRole
+ * @param wrapDoc
+ * @param handleDelete
+ * @throws Exception
+ */
+ public void fillCommonPart(AccountRole accountRole,
DocumentWrapper<List<AccountRoleRel>> wrapDoc,
boolean handleDelete)
throws Exception {
- List<AccountRoleRel> arrl = wrapDoc.getWrappedObject();
- SubjectType subject = ar.getSubject();
+ List<AccountRoleRel> accountRoleRelList = wrapDoc.getWrappedObject();
+ SubjectType subject = accountRole.getSubject();
if (subject == null) {
//it is not required to give subject as URI determines the subject
subject = getSubject(getServiceContext());
- } else {
- //subject mismatch should have been checked during validation
}
+
if (subject.equals(SubjectType.ROLE)) {
- //FIXME: potential index out of bounds exception...negative test needed
- AccountValue av = ar.getAccount().get(0);
-
- for (RoleValue rv : ar.getRole()) {
- AccountRoleRel arr = buildAccountRoleRel(av, rv, handleDelete);
- arrl.add(arr);
- }
+ if (accountRole.getAccount() != null && accountRole.getAccount().size() == 1) {
+ AccountValue av = accountRole.getAccount().get(0); // Since ROLE is the subject, they'll be just one account
+ for (RoleValue rv : accountRole.getRole()) {
+ if (rv.getRoleName() == null) { // We need the role name, so get it if the payload just includes the role CSID
+ rv = PermissionRoleUtil.fetchRoleValue(getServiceContext(), rv.getRoleId());
+ }
+ AccountRoleRel arr = buildAccountRoleRel(av, rv, handleDelete);
+ accountRoleRelList.add(arr);
+ }
+ } else {
+ String msg = "There must be one (and only one) account supplied in an account-role relationship where the subject is the role.";
+ throw new DocumentException(msg);
+ }
} else if (SubjectType.ACCOUNT.equals(subject)) {
- //FIXME: potential index out of bounds exception...negative test needed
- RoleValue rv = ar.getRole().get(0);
- for (AccountValue av : ar.getAccount()) {
- AccountRoleRel arr = buildAccountRoleRel(av, rv, handleDelete);
- arrl.add(arr);
- }
+ if (accountRole.getRole() != null && accountRole.getRole().size() == 1) {
+ RoleValue rv = accountRole.getRole().get(0);
+ for (AccountValue av : accountRole.getAccount()) {
+ AccountRoleRel arr = buildAccountRoleRel(av, rv, handleDelete);
+ accountRoleRelList.add(arr);
+ }
+ } else {
+ String msg = "There must be one (and only one) role supplied in an account-role relationship where the subject is the account.";
+ throw new DocumentException(msg);
+ }
+ } else {
+ String msg = String.format("Unknown subject '%s' encounted when working with an AccountRole object",
+ subject.value());
+ throw new DocumentException(msg);
}
}
* @return the account role rel
*/
private AccountRoleRel buildAccountRoleRel(AccountValue av, RoleValue rv, boolean handleDelete) {
- AccountRoleRel arr = new AccountRoleRel();
- arr.setAccountId(av.getAccountId());
- arr.setUserId(av.getUserId());
- arr.setScreenName(av.getScreenName());
- arr.setRoleId(rv.getRoleId());
- arr.setRoleName(rv.getRoleName());
+ AccountRoleRel accountRoleRel = new AccountRoleRel();
+ accountRoleRel.setAccountId(av.getAccountId());
+ accountRoleRel.setUserId(av.getUserId());
+ accountRoleRel.setScreenName(av.getScreenName());
+ accountRoleRel.setRoleId(rv.getRoleId());
+ accountRoleRel.setRoleName(rv.getRoleName());
String relationshipId = rv.getRoleRelationshipId();
if (relationshipId != null && handleDelete == true) {
- arr.setHjid(Long.parseLong(relationshipId)); // set this so we can convince JPA to del the relation
+ accountRoleRel.setHjid(Long.parseLong(relationshipId)); // set this so we can convince JPA to delete the relationship
}
- return arr;
+ return accountRoleRel;
}
/**
* @param ctx the ctx
* @return the subject
*/
- static SubjectType getSubject(ServiceContext ctx) {
+ static SubjectType getSubject(ServiceContext<?, ?> ctx) {
Object o = ctx.getProperty(ServiceContextProperties.SUBJECT);
if (o == null) {
throw new IllegalArgumentException(ServiceContextProperties.SUBJECT
try {
account = (AccountsCommon) handler.getCommonPart();
handler.prepare(Action.CREATE);
- DocumentWrapper<AccountsCommon> wrapDoc =
- new DocumentWrapperImpl<AccountsCommon>(account);
+ DocumentWrapper<AccountsCommon> wrapDoc = new DocumentWrapperImpl<AccountsCommon>(account);
handler.handle(Action.CREATE, wrapDoc);
jpaConnectionContext.beginTransaction();
//
- // If userid and password are given, add to default id provider
+ // If userid and password are given, add to default ID provider -i.e., add it to the Spring Security account list
//
if (account.getUserId() != null && isForCSpaceIdentityProvider(account.getPassword())) {
User user = userStorageClient.create(account.getUserId(), account.getPassword());
- jpaConnectionContext.persist(user);
+ jpaConnectionContext.persist(user);
}
-
+ //
+ // Now add the account to the CSpace list of accounts
+ //
account.setCreatedAtItem(new Date());
jpaConnectionContext.persist(account);
-
+ //
+ // Finish creating related resources -e.g., account-role relationships
+ //
handler.complete(Action.CREATE, wrapDoc);
jpaConnectionContext.commitTransaction();
import org.collectionspace.services.common.document.DocumentException;
import org.collectionspace.services.common.document.DocumentNotFoundException;
import org.collectionspace.services.common.document.JaxbUtils;
+import org.collectionspace.services.common.document.TransactionException;
import org.collectionspace.services.common.security.SecurityUtils;
+import org.collectionspace.services.common.storage.TransactionContext;
+import org.collectionspace.services.common.storage.jpa.JPATransactionContext;
import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
import org.slf4j.Logger;
}
/**
- * Get token for given ID
- * @param em EntityManager
+ * Update a token for given an id
* @param id
+ * @param enabledFlag
+ * @throws TransactionException
*/
- static public Token get(String id) throws DocumentNotFoundException {
- EntityManagerFactory emf = JpaStorageUtils.getEntityManagerFactory();
+ static public void update(TransactionContext transactionContext, String id, boolean enabledFlag) throws DocumentNotFoundException, TransactionException {
Token tokenFound = null;
- try {
- EntityManager em = emf.createEntityManager();
- tokenFound = get(em, id);
- } finally {
- if (emf != null) {
- JpaStorageUtils.releaseEntityManagerFactory(emf);
+ tokenFound = get((JPATransactionContext)transactionContext, id);
+ if (tokenFound != null) {
+ tokenFound.setEnabled(enabledFlag);
+ tokenFound.setUpdatedAtItem(new Date());
+ if (logger.isDebugEnabled()) {
+ logger.debug("Updated token=" + JaxbUtils.toString(tokenFound, Token.class));
}
+ } else {
+ String msg = String.format("Could not find token with id='%s'", id);
+ throw new DocumentNotFoundException(msg);
}
-
- return tokenFound;
}
/**
- * Update a token for given an id
+ * Get token for given ID
+ * @param em EntityManager
* @param id
- * @param enabledFlag
- */
- static public void update(String id, boolean enabledFlag) throws DocumentNotFoundException {
- EntityManagerFactory emf = JpaStorageUtils.getEntityManagerFactory();
- EntityManager em = null;
+ */
+ public static Token get(JPATransactionContext jpaTransactionContext, String id) throws DocumentNotFoundException, TransactionException {
+ Token tokenFound = null;
+ tokenFound = (Token) jpaTransactionContext.find(Token.class, id);
+ if (tokenFound == null) {
+ String msg = "Could not find token with ID=" + id;
+ logger.error(msg);
+ throw new DocumentNotFoundException(msg);
+ }
+
+ return tokenFound;
+ }
+
+ static public Token get(String id) throws DocumentNotFoundException {
Token tokenFound = null;
+ EntityManagerFactory emf = JpaStorageUtils.getEntityManagerFactory();
+
try {
- em = emf.createEntityManager();
- tokenFound = get(em, id);
- if (tokenFound != null) {
- em.getTransaction().begin();
- tokenFound.setEnabled(enabledFlag);
- tokenFound.setUpdatedAtItem(new Date());
- if (logger.isDebugEnabled()) {
- logger.debug("Updated token=" + JaxbUtils.toString(tokenFound, Token.class));
- }
- em.getTransaction().commit();
- } else {
- String msg = String.format("Could not find token with id='%s'", id);
- throw new DocumentNotFoundException(msg);
- }
+ EntityManager em = emf.createEntityManager();
+ tokenFound = (Token) em.find(Token.class, id);
+ if (tokenFound == null) {
+ String msg = "Could not find token with ID=" + id;
+ logger.error(msg);
+ throw new DocumentNotFoundException(msg);
+ }
} finally {
- if (em != null && em.isOpen()) {
- em.close();
- }
if (emf != null) {
JpaStorageUtils.releaseEntityManagerFactory(emf);
}
- }
- }
-
- public static Token get(EntityManager em, String id) throws DocumentNotFoundException {
- Token tokenFound = null;
-
- em.getTransaction().begin();
- tokenFound = em.find(Token.class, id);
- em.getTransaction().commit();
- if (tokenFound == null) {
- String msg = "Could not find token with ID=" + id;
- logger.error(msg);
- throw new DocumentNotFoundException(msg);
}
return tokenFound;
- }
+ }
/**
* Deletes the token with given id
public static final String ROLE_SPRING_ADMIN_ID = "-1";
public static final String ROLE_SPRING_ADMIN_NAME = "ROLE_SPRING_ADMIN";
+ public static final String ROLE_SPRING_GROUP_NAME = "Spring Security Administrator";
// Define a special account value for the tenantManager. Yes, this is a hack, but
// less troublesome than the alternatives.
//FIXME initialize with the help of configuration meta data
authnContext = new SpringAuthNContext();
}
+
+ public boolean isSystemAdmin() {
+ boolean result = false;
+
+ String currentUserId = this.getUserId();
+ if (currentUserId.equals(AuthN.SPRING_ADMIN_USER) || currentUserId.equals(AuthN.ADMIN_TENANT_NAME)) {
+ result = true;
+ }
+
+ return result;
+ }
public final static AuthN get() {
return self;
public static final String SERVICE_PATH_COMPONENT = SERVICE_NAME;
public static final String SERVICE_PATH = "/" + SERVICE_PATH_COMPONENT;
public static final String SERVICE_PATH_PROXY = SERVICE_PATH + "/";
+ public final static String IMMUTABLE = "immutable";
+ public static final String PERMISSION_UPDATE_CSID = "PERMISSION_UPDATE_CSID";
public enum ActionCompare {
ACTION_GROUP_EMPTY, ACTION_LIST_EMPTY, ACTIONS_MISSING, MATCHES, MISMATCHES
public static final String SERVICE_PATH_PROXY = SERVICE_PATH + "/";
public final static String IMMUTABLE = "immutable";
public final static String INCLUDE_PERMS_QP = "showPerms";
-
+
//
// Used to qualify backend role name
- private final static String BACKEND_ROLE_PREFIX = "ROLE_";
+ //
+ public final static String BACKEND_ROLE_PREFIX = "ROLE_";
public RoleClient() throws Exception {
super();
public RoleClient(String clientPropertiesFilename) throws Exception {
super(clientPropertiesFilename);
}
-
+
/**
* Creates a backend (Spring Security as of v4.5) role name.
* @param roleDisplayName
// pvi.setPermissionId(iPermId);
// permValues.put(pvi.getResourceName(), pvi);
- String rn1 = "ROLE_CO1" + TEST_MARKER;
+ String rn1 = "xROLE_CO1" + TEST_MARKER;
String r1RoleId = createRole(rn1);
RoleValue rv1 = new RoleValue();
rv1.setRoleId(r1RoleId);
rv1.setRoleName(rn1);
roleValues.put(rv1.getRoleName(), rv1);
- String rn2 = "ROLE_CO2" + TEST_MARKER;
+ String rn2 = "xROLE_CO2" + TEST_MARKER;
String r2RoleId = createRole(rn2);
RoleValue rv2 = new RoleValue();
rv2.setRoleId(r2RoleId);
private final static Logger logger = LoggerFactory.getLogger(CLASS_NAME);
// Instance variables specific to this test.
final private static String TEST_MARKER = "_RolePermissionServiceTest";
- final private static String TEST_ROLE_NAME = "ROLE";
+ final private static String TEST_ROLE_NAME = "xROLE";
final private static String NO_REL_SUFFIX = "-no-rel";
/** The perm values. */
private Hashtable<String, PermissionValue> permValues = new Hashtable<String, PermissionValue>();
// Used to create unique identifiers
static private final Random random = new Random(System.currentTimeMillis());
- private static final String PERM_1_RL_RESOURCE = "ROLE_TEST_PERMVALUE_RESOURCE_1";
+ private static final String PERM_1_RL_RESOURCE = "xROLE_TEST_PERMVALUE_RESOURCE_1";
private static final String PERM_1_RL_ACTIONGROUP = "RL";
- private static final String PERM_2_RL_RESOURCE = "ROLE_TEST_PERMVALUE_RESOURCE_2";
+ private static final String PERM_2_RL_RESOURCE = "xROLE_TEST_PERMVALUE_RESOURCE_2";
private static final String PERM_2_RL_ACTIONGROUP = "CRUL";
- private static final String PERM_3_RL_RESOURCE = "ROLE_TEST_PERMVALUE_RESOURCE_3";
+ private static final String PERM_3_RL_RESOURCE = "xROLE_TEST_PERMVALUE_RESOURCE_3";
private static final String PERM_3_RL_ACTIONGROUP = "CRUDL";
// Instance variables specific to this test.
/** The known resource id. */
- private String knownRoleName = "ROLE_USERS_MOCK-1";
- private String knownRoleDisplayName = "ROLE_DISPLAYNAME_USERS_MOCK-1";
+ private String knownRoleName = "xROLE_USERS_MOCK-1";
+ private String knownRoleDisplayName = "xROLE_DISPLAYNAME_USERS_MOCK-1";
private String verifyResourceId = null;
private String verifyRoleName = "collections_manager_mock-1";
//
res.close();
}
- Role role2 = createRoleInstance("ROLE_COLLECTIONS_CURATOR_TEST",
+ Role role2 = createRoleInstance("xROLE_COLLECTIONS_CURATOR_TEST",
"collections curator", true);
res = client.create(role2);
try {
res.close();
}
- Role role3 = createRoleInstance("ROLE_MOVINGIMAGE_ADMIN_TEST",
+ Role role3 = createRoleInstance("xROLE_MOVINGIMAGE_ADMIN_TEST",
"moving image admin", true);
res = client.create(role3);
try {
Assert.assertNotNull(output);
//FIXME: Tenant ID of "1" should not be hard coded
- String roleNameToVerify = "ROLE_" +
+ String roleNameToVerify = RoleClient.BACKEND_ROLE_PREFIX +
"1_" +
verifyRoleName.toUpperCase();
Assert.assertEquals(output.getRoleName(), roleNameToVerify,
// Note: The ID used in this 'create' call may be arbitrary.
// The only relevant ID may be the one used in updateRole(), below.
RoleClient client = new RoleClient();
- Role role = createRoleInstance("ROLE_XXX",
+ Role role = createRoleInstance("xROLE_XXX",
"xxx",
true);
Response res = client.update(NON_EXISTENT_ID, role);
public void generate(JPATransactionContext jpaTransactionContext) {
try {
+ login();
authzGen = new AuthorizationGen();
authzGen.initialize(tenantBindingFile);
authzGen.createDefaultRoles(jpaTransactionContext);
} catch (Exception ex) {
logger.error("AuthorizationSeedDriver caught an exception: ", ex);
throw new RuntimeException(ex);
+ } finally {
+ logout();
}
}
public void seed(JPATransactionContext jpaTransactionContext) {
TransactionStatus status = null;
try {
+ login();
+ //
// Push all the authz info into the cspace DB tables -this include default roles, permissions, and permroles
+ //
store();
-
- setupSpring();
+
+ setupSpringSecurity();
status = beginTransaction("seedData");
AuthorizationSeed authzSeed = new AuthorizationSeed();
authzSeed.seedPermissions(jpaTransactionContext, authzGen.getDefaultPermissions(), authzGen.getDefaultPermissionRoles());
/**
* Setup of Spring Security context
*/
- private void setupSpring() {
+ private void setupSpringSecurity() {
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[]{SPRING_SECURITY_METADATA});
- login();
System.setProperty("spring-beans-config", SPRING_SECURITY_METADATA);
//
// authZ local not used but call to AuthZ.get() has side-effect of initializing our Spring Security context
* @author
*/
public class AuthorizationGen {
-
+ final Logger logger = LoggerFactory.getLogger(AuthorizationGen.class);
//
// Should the base resource act as a proxy for its sub-resources for AuthZ purposes
//
private static final boolean USE_APP_GENERATED_BINDINGS = true;
- final Logger logger = LoggerFactory.getLogger(AuthorizationGen.class);
+ private List<Permission> readWritePermList = new ArrayList<Permission>();
private List<Permission> tenantMgmntPermList = new ArrayList<Permission>();
private List<PermissionRole> tenantMgmntPermRoleList = new ArrayList<PermissionRole>();
+
private List<Permission> adminPermList = new ArrayList<Permission>();
private List<PermissionRole> adminPermRoleList = new ArrayList<PermissionRole>();
+
private List<Permission> readerPermList = new ArrayList<Permission>();
private List<PermissionRole> readerPermRoleList = new ArrayList<PermissionRole>();
+
private List<Role> adminRoles = new ArrayList<Role>();
private List<Role> readerRoles = new ArrayList<Role>();
+
private Role cspaceTenantMgmntRole;
- private Hashtable<String, TenantBindingType> tenantBindings =
- new Hashtable<String, TenantBindingType>();
+ private Hashtable<String, TenantBindingType> tenantBindings = new Hashtable<String, TenantBindingType>();
//
// Store the list of default roles, perms, and roleperms
//
*/
public void createDefaultPermissions(JPATransactionContext jpaTransactionContext) {
for (String tenantId : tenantBindings.keySet()) {
- List<Permission> adminPerms = createDefaultAdminPermissions(tenantId, AUTHZ_IS_ENTITY_PROXY);
+ List<Permission> adminPerms = createDefaultAdminPermissions(tenantId, AUTHZ_IS_ENTITY_PROXY); // CRUDL perms
adminPermList.addAll(adminPerms);
- List<Permission> readerPerms = createDefaultReaderPermissions(tenantId, AUTHZ_IS_ENTITY_PROXY);
+ List<Permission> readerPerms = createDefaultReaderPermissions(tenantId, AUTHZ_IS_ENTITY_PROXY); // RL perms
readerPermList.addAll(readerPerms);
+
+ List<Permission> readWritePerms = createDefaultReadWritePermissions(tenantId, AUTHZ_IS_ENTITY_PROXY); // CRUL perms
+ readWritePermList.addAll(readWritePerms);
}
List<Permission> tenantMgmntPerms = createDefaultTenantMgmntPermissions();
return perm;
}
- private Permission buildAdminPermission(String tenantId, String resourceName) {
- String description = "Generated admin permission.";
- return AuthorizationCommon.createPermission(tenantId, resourceName, description, AuthorizationCommon.ACTIONGROUP_CRUDL_NAME);
- }
+ /**
+ * createDefaultReadWritePermissions creates read-write (CRUL) permissions for all services
+ * used by the given tenant
+ * @param tenantId
+ * @return
+ */
+ public List<Permission> createDefaultReadWritePermissions(String tenantId, boolean isEntityProxy) {
+ ArrayList<Permission> apcList = new ArrayList<Permission>();
+ TenantBindingType tbinding = tenantBindings.get(tenantId);
+ for (ServiceBindingType sbinding : tbinding.getServiceBindings()) {
+ //add permissions for the main path
+ String resourceName = sbinding.getName().toLowerCase().trim();
+ if (isEntityProxy == true) {
+ resourceName = SecurityUtils.getResourceEntity(resourceName);
+ }
+ Permission perm = buildReadWritePermission(tbinding.getId(), resourceName);
+ apcList.add(perm);
+
+ //add permissions for alternate paths
+ if (isEntityProxy == false) {
+ List<String> uriPaths = sbinding.getUriPath();
+ for (String uriPath : uriPaths) {
+ perm = buildReadWritePermission(tbinding.getId(), uriPath.toLowerCase());
+ apcList.add(perm);
+ }
+ }
+ }
+
+ return apcList;
+ }
+
/**
* createDefaultReaderPermissions creates read only permissions for all services
* used by the given tenant
+ *
* @param tenantId
* @return
*/
public List<Permission> createDefaultReaderPermissions(String tenantId, boolean isEntityProxy) {
ArrayList<Permission> apcList = new ArrayList<Permission>();
+
TenantBindingType tbinding = tenantBindings.get(tenantId);
for (ServiceBindingType sbinding : tbinding.getServiceBindings()) {
//add permissions for the main path
if (isEntityProxy == true) {
resourceName = SecurityUtils.getResourceEntity(resourceName);
}
- Permission perm = buildReaderPermission(tbinding.getId(),
- resourceName);
+ Permission perm = buildReaderPermission(tbinding.getId(), resourceName);
apcList.add(perm);
//add permissions for alternate paths
if (isEntityProxy == false) {
List<String> uriPaths = sbinding.getUriPath();
for (String uriPath : uriPaths) {
- perm = buildReaderPermission(tbinding.getId(),
- uriPath.toLowerCase());
+ perm = buildReaderPermission(tbinding.getId(), uriPath.toLowerCase());
apcList.add(perm);
}
}
}
+
return apcList;
-
}
+ private Permission buildAdminPermission(String tenantId, String resourceName) {
+ String description = "Generated admin permission.";
+ return AuthorizationCommon.createPermission(tenantId, resourceName, description, AuthorizationCommon.ACTIONGROUP_CRUDL_NAME, true);
+ }
+
private Permission buildReaderPermission(String tenantId, String resourceName) {
- String description = "Generated read-only permission.";
- return AuthorizationCommon.createPermission(tenantId, resourceName, description, AuthorizationCommon.ACTIONGROUP_RL_NAME);
+ String description = "Generated read-only (RL) permission.";
+ return AuthorizationCommon.createPermission(tenantId, resourceName, description, AuthorizationCommon.ACTIONGROUP_RL_NAME, true);
+ }
+
+ private Permission buildReadWritePermission(String tenantId, String resourceName) {
+ String description = "Generated read-write (CRUL) permission.";
+ return AuthorizationCommon.createPermission(tenantId, resourceName, description, AuthorizationCommon.ACTIONGROUP_CRUL_NAME, true);
}
public List<Permission> getDefaultPermissions() {
allPermList = new ArrayList<Permission>();
allPermList.addAll(adminPermList);
allPermList.addAll(readerPermList);
+ allPermList.addAll(readWritePermList);
allPermList.addAll(tenantMgmntPermList);
}
return allPermList;
/* for (Permission p : adminPermList) {
PermissionRole permCAdmRole = associatePermissionRoles(p, roles, false);
adminPermRoleList.add(permCAdmRole);
- } */
+ } */
+
// Now associate the tenant management perms to the role
for (Permission p : tenantMgmntPermList) {
// Note we enforce tenant, as should all be tenant 0 (the special one)
}
for (PermissionRole pr : permRoleList) {
if (pr.getPermission().get(0).getPermissionId().equals(p.getCsid())) {
- AuthorizationCommon.addPermissionsForUri(p, pr);
+ AuthorizationCommon.addPermissionsForUri(jpaTransactionContext, p, pr);
}
}
}
import org.collectionspace.services.common.context.RemoteServiceContextFactory;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.context.ServiceContextFactory;
+import org.collectionspace.services.common.document.DocumentNotFoundException;
import org.collectionspace.services.common.storage.StorageClient;
import org.collectionspace.services.common.storage.TransactionContext;
import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl;
@Consumes("application/xml")
@Produces("application/xml")
@SuppressWarnings("unchecked")
-public class RoleResource extends SecurityResourceBase {
+public class RoleResource extends SecurityResourceBase<Role, Role> {
final Logger logger = LoggerFactory.getLogger(RoleResource.class);
final StorageClient storageClient = new JpaStorageClientImpl();
}
@Override
- public ServiceContextFactory getServiceContextFactory() {
+ public ServiceContextFactory<Role, Role> getServiceContextFactory() {
return RemoteServiceContextFactory.get();
}
@Override
- public StorageClient getStorageClient(ServiceContext ctx) {
+ public StorageClient getStorageClient(ServiceContext<Role, Role> ctx) {
//FIXME use ctx to identify storage client
return storageClient;
}
AccountRoleSubResource subResource =
new AccountRoleSubResource(AccountRoleSubResource.ACCOUNT_ACCOUNTROLE_SERVICE);
//get relationships for a role
- result = subResource.getAccountRole((ServiceContext)null, accCsid, SubjectType.ACCOUNT);
+ result = subResource.getAccountRole((ServiceContext<Role, Role>)null, accCsid, SubjectType.ACCOUNT);
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.GET_FAILED, accCsid);
}
// If marked as metadata immutable, do not delete
if (RoleClient.IMMUTABLE.equals(role.getMetadataProtection())) {
Response response =
- Response.status(Response.Status.FORBIDDEN).entity("Role: "+csid+" is immutable.").type("text/plain").build();
+ Response.status(Response.Status.FORBIDDEN).entity("Role: "+csid+" is immutable.").type("text/plain").build(); // FIXME: Should be status code 423 (resource locked)
return response;
}
//
- // delete all the permission/role relationships
+ // delete all the permission/role relationships (if any)
//
PermissionRoleSubResource permRoleResource =
new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE);
- permRoleResource.deletePermissionRole(ctx, csid, SubjectType.PERMISSION);
+ try {
+ permRoleResource.deletePermissionRole(ctx, csid, SubjectType.PERMISSION);
+ } catch (DocumentNotFoundException dnf) {
+ // consume exception, not a problem. Just means no relationships exist
+ }
//
//delete all the account/role relationships associate with this role
//
//
//finally, delete the role itself
//
- ((JpaStorageClientImpl) getStorageClient(ctx)).deleteWhere(ctx, csid);
+ ((JpaStorageClientImpl) getStorageClient(ctx)).deleteWhere(ctx, csid); // FIXME: We should/could get rid the SID in Spring Security table as well
transactionContext.commitTransaction();
} catch(Exception e) {
transactionContext.markForRollback();
@Path("{csid}/permroles")
public Response createRolePermission(@QueryParam("_method") String method, @PathParam("csid") String roleCsid,
PermissionRole input) {
- if (method != null) {
+ if (method != null) { // FIXME: Not sure how method could every be "delete"
if ("delete".equalsIgnoreCase(method)) {
return deleteRolePermission(roleCsid, input);
}
}
-
+
logger.debug("createRolePermission with roleCsid=" + roleCsid);
ensureCSID(roleCsid, ServiceMessages.PUT_FAILED + "permroles role ");
Response response = null;
try {
Role role = (Role)get(roleCsid, Role.class);
- // If marked as metadata immutable, do not delete
+ //
+ // If marked as metadata immutable, do not change
+ //
if (RoleClient.IMMUTABLE.equals(role.getPermsProtection())) {
response =
Response.status(Response.Status.FORBIDDEN).entity("Role: "+roleCsid+" is immutable.").type("text/plain").build();
return response;
}
+ //
+ // Create new role-permission relationships
+ //
PermissionRoleSubResource subResource =
new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE);
- String permrolecsid = subResource.createPermissionRole((ServiceContext)null, input, SubjectType.PERMISSION);
+ String permrolecsid = subResource.createPermissionRole((ServiceContext<Role, Role>)null, input, SubjectType.PERMISSION);
UriBuilder path = UriBuilder.fromResource(RoleResource.class);
path.path(roleCsid + "/permroles/" + permrolecsid);
response = Response.created(path.build()).build();
PermissionRoleSubResource subResource =
new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE);
//get relationships for a role
- result = subResource.getPermissionRole((ServiceContext)null, roleCsid, SubjectType.PERMISSION);
+ result = subResource.getPermissionRole((ServiceContext<Role, Role>)null, roleCsid, SubjectType.PERMISSION);
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.GET_FAILED, roleCsid);
}
PermissionRoleSubResource subResource =
new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE);
//get relationships for a role
- result = subResource.getPermissionRoleRel((ServiceContext)null, roleCsid, SubjectType.PERMISSION, permrolecsid);
+ result = subResource.getPermissionRoleRel((ServiceContext<Role, Role>)null, roleCsid, SubjectType.PERMISSION, permrolecsid);
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.GET_FAILED, roleCsid);
}
PermissionRoleSubResource subResource =
new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE);
//delete all relationships for a permission
- subResource.deletePermissionRole((ServiceContext)null, roleCsid, SubjectType.PERMISSION, input);
+ subResource.deletePermissionRole((ServiceContext<Role, Role>)null, roleCsid, SubjectType.PERMISSION, input);
result = Response.status(HttpResponseCodes.SC_OK).build();
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.DELETE_FAILED, roleCsid);
PermissionRoleSubResource subResource =
new PermissionRoleSubResource(PermissionRoleSubResource.ROLE_PERMROLE_SERVICE);
//delete all relationships for a permission
- subResource.deletePermissionRole((ServiceContext)null, roleCsid, SubjectType.PERMISSION);
+ subResource.deletePermissionRole((ServiceContext<Role, Role>)null, roleCsid, SubjectType.PERMISSION);
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.DELETE_FAILED, roleCsid);
}
-/**
- * This document is a part of the source code and related artifacts
- * for CollectionSpace, an open source collections management system
- * for museums and related institutions:
-
- * http://www.collectionspace.org
- * http://wiki.collectionspace.org
-
- * Copyright 2009 University of California at Berkeley
-
- * Licensed under the Educational Community License (ECL), Version 2.0.
- * You may not use this file except in compliance with this License.
-
- * You may obtain a copy of the ECL 2.0 License at
-
- * https://source.collectionspace.org/collection-space/LICENSE.txt
-
- * 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.collectionspace.services.authorization.storage;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-import org.collectionspace.services.authorization.perms.ActionType;
-import org.collectionspace.services.authorization.CSpaceAction;
-import org.collectionspace.services.authorization.perms.Permission;
-import org.collectionspace.services.authorization.perms.PermissionAction;
-import org.collectionspace.services.authorization.perms.PermissionsList;
-import org.collectionspace.services.authorization.URIResourceImpl;
-
-import org.collectionspace.services.common.document.BadRequestException;
-import org.collectionspace.services.common.document.DocumentFilter;
-import org.collectionspace.services.common.document.DocumentWrapper;
-import org.collectionspace.services.common.document.JaxbUtils;
-import org.collectionspace.services.common.security.SecurityUtils;
-import org.collectionspace.services.common.storage.jpa.JpaDocumentHandler;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Document handler for Permission
- * @author
- */
-public class PermissionDocumentHandler
- extends JpaDocumentHandler<Permission, PermissionsList, Permission, List> {
-
- private final Logger logger = LoggerFactory.getLogger(PermissionDocumentHandler.class);
- private Permission permission;
- private PermissionsList permissionsList;
-
- public CSpaceAction getAction(ActionType action) {
- if (ActionType.CREATE.name().equals(action.name())) {
- return CSpaceAction.CREATE;
- } else if (ActionType.READ.equals(action)) {
- return CSpaceAction.READ;
- } else if (ActionType.UPDATE.equals(action)) {
- return CSpaceAction.UPDATE;
- } else if (ActionType.DELETE.equals(action)) {
- return CSpaceAction.DELETE;
- } else if (ActionType.SEARCH.equals(action)) {
- return CSpaceAction.SEARCH;
- } else if (ActionType.ADMIN.equals(action)) {
- return CSpaceAction.ADMIN;
- } else if (ActionType.START.equals(action)) {
- return CSpaceAction.START;
- } else if (ActionType.STOP.equals(action)) {
- return CSpaceAction.STOP;
- }
- //
- // We could not find a match, so we need to throw an exception.
- //
- throw new IllegalArgumentException("action = " + action.toString());
- }
-
- /*
- * Add the ACE hashed ID to the permission action so we can map the permission to the Spring Security
- * tables.
- */
- private void handlePermissionActions(Permission perm) {
- //FIXME: REM - Having Java class loader issues with ActionType class. Not sure of the cause.
- try {
- List<PermissionAction> permActions = perm.getAction();
- for (PermissionAction permAction : permActions) {
- CSpaceAction action = getAction(permAction.getName());
- URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(),
- perm.getResourceName(), action);
- permAction.setObjectIdentity(uriRes.getHashedId().toString());
- permAction.setObjectIdentityResource(uriRes.getId());
- //PermissionActionUtil.update(perm, permAction);
- }
- } catch (Exception x) {
- x.printStackTrace();
- }
- }
-
- @Override
- public void handleCreate(DocumentWrapper<Permission> wrapDoc) throws Exception {
- String id = UUID.randomUUID().toString();
- Permission permission = wrapDoc.getWrappedObject();
- permission.setCsid(id);
- setTenant(permission);
- handlePermissionActions(permission);
- }
-
- @Override
- public void completeCreate(DocumentWrapper<Permission> wrapDoc) throws Exception {
- }
-
- @Override
- public void handleUpdate(DocumentWrapper<Permission> wrapDoc) throws Exception {
- Permission permissionFound = wrapDoc.getWrappedObject();
- Permission permissionReceived = getCommonPart();
- merge(permissionReceived, permissionFound);
- }
-
- /**
- * merge manually merges the from from to the to permission
- * -this method is created due to inefficiency of JPA EM merge
- * @param from
- * @param to
- * @return merged permission
- */
- private Permission merge(Permission from, Permission to) throws Exception {
- if (!(from.getResourceName().equalsIgnoreCase(to.getResourceName()))) {
- String msg = "Resource name cannot be changed " + to.getResourceName();
- logger.error(msg);
- throw new BadRequestException(msg);
- }
- //resource name, attribute cannot be changed
-
- if (from.getDescription() != null) {
- to.setDescription(from.getDescription());
- }
- if (from.getEffect() != null) {
- to.setEffect(from.getEffect());
- }
- List<PermissionAction> fromActions = from.getAction();
- if (!fromActions.isEmpty()) {
- //override the whole list, no reconcilliation by design
- to.setAction(fromActions);
- }
-
- if (logger.isDebugEnabled()) {
- logger.debug("merged permission=" + JaxbUtils.toString(to, Permission.class));
- }
-
- handlePermissionActions(to);
- return to;
- }
-
- @Override
- public void completeUpdate(DocumentWrapper<Permission> wrapDoc) throws Exception {
- Permission upAcc = wrapDoc.getWrappedObject();
- getServiceContext().setOutput(upAcc);
- sanitize(upAcc);
- //FIXME update lower-layer authorization (acls)
- //will require deleting old permissions for this resource and adding
- //new based on new actions and effect
- }
-
- @Override
- public void handleGet(DocumentWrapper<Permission> wrapDoc) throws Exception {
- setCommonPart(extractCommonPart(wrapDoc));
- sanitize(getCommonPart());
- getServiceContext().setOutput(permission);
- }
-
- @Override
- public void handleGetAll(DocumentWrapper<List> wrapDoc) throws Exception {
- PermissionsList permissionsList = extractCommonPartList(wrapDoc);
- setCommonPartList(permissionsList);
- getServiceContext().setOutput(getCommonPartList());
- }
-
- @Override
- public void completeDelete(DocumentWrapper<Permission> wrapDoc) throws Exception {
- }
-
- @Override
- public Permission extractCommonPart(
- DocumentWrapper<Permission> wrapDoc)
- throws Exception {
- return wrapDoc.getWrappedObject();
- }
-
- @Override
- public void fillCommonPart(Permission obj, DocumentWrapper<Permission> wrapDoc)
- throws Exception {
- throw new UnsupportedOperationException("operation not relevant for AccountDocumentHandler");
- }
-
- @Override
- public PermissionsList extractCommonPartList(
- DocumentWrapper<List> wrapDoc)
- throws Exception {
-
- PermissionsList permissionsList = new PermissionsList();
- List<Permission> list = new ArrayList<Permission>();
- permissionsList.setPermission(list);
- for (Object obj : wrapDoc.getWrappedObject()) {
- Permission permission = (Permission) obj;
- sanitize(permission);
- list.add(permission);
- }
- return permissionsList;
- }
-
- @Override
- public Permission getCommonPart() {
- return permission;
- }
-
- @Override
- public void setCommonPart(Permission permission) {
- this.permission = permission;
- }
-
- @Override
- public PermissionsList getCommonPartList() {
- return permissionsList;
- }
-
- @Override
- public void setCommonPartList(PermissionsList permissionsList) {
- this.permissionsList = permissionsList;
- }
-
- @Override
- public String getQProperty(
- String prop) {
- return null;
- }
-
- @Override
- public DocumentFilter createDocumentFilter() {
- DocumentFilter filter = new PermissionJpaFilter(this.getServiceContext());
- return filter;
- }
-
- /**
- * sanitize removes data not needed to be sent to the consumer
- * @param permission
- */
- private void sanitize(Permission permission) {
- if (!SecurityUtils.isCSpaceAdmin()) {
- permission.setTenantId(null);
- }
- }
-
- private void setTenant(Permission permission) {
- //set tenant only if not available from input
- if (permission.getTenantId() == null || permission.getTenantId().isEmpty()) {
- permission.setTenantId(getServiceContext().getTenantId());
- }
- }
-}
+The PermissionDocumentHandler.java file has been move to the "org.collectionspace.services.common" module.
\ No newline at end of file
import java.util.List;
+import javax.xml.bind.JAXBElement;
+
import org.collectionspace.services.authorization.perms.Permission;
import org.collectionspace.services.authorization.perms.PermissionAction;
import org.collectionspace.services.client.PermissionClient;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.document.DocumentHandler.Action;
import org.collectionspace.services.common.document.InvalidDocumentException;
+import org.collectionspace.services.common.document.JaxbUtils;
import org.collectionspace.services.common.document.ValidatorHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* PermissionValidatorHandler executes validation rules for permission
* @author
*/
-public class PermissionValidatorHandler implements ValidatorHandler {
+public class PermissionValidatorHandler implements ValidatorHandler<Permission, Permission> {
final Logger logger = LoggerFactory.getLogger(PermissionValidatorHandler.class);
@Override
- public void validate(Action action, ServiceContext ctx)
+ public void validate(Action action, ServiceContext<Permission, Permission> ctx)
throws InvalidDocumentException {
if (logger.isDebugEnabled()) {
logger.debug("validate() action=" + action.name());
boolean invalid = false;
if (action.equals(Action.CREATE)) {
- //create specific validation here
if (permission.getResourceName() == null || permission.getResourceName().isEmpty()) {
invalid = true;
msgBldr.append("\nThe resource name for creating a new permission resource is missing or empty.");
- } else {
- invalid = !validateActionFields(permission);
}
+ if (validateActionFields(action, permission) == false) {
+ invalid = true;
+ msgBldr.append("\nAction info is missing or inconsistent.");
+ }
+ if (permission.getEffect() == null) {
+ invalid = true;
+ msgBldr.append("\n'effect' elment is missing from the payload or is not set to either PERMIT or DENY.");
+ }
} else if (action.equals(Action.UPDATE)) {
- //update specific validation here
if (permission.getResourceName() == null || permission.getResourceName().isEmpty()) {
invalid = true;
msgBldr.append("\nThe resource name for updating an existing permission is missing or empty.");
- } else {
- invalid = !validateActionFields(permission);
}
+ if (validateActionFields(action, permission) == false) {
+ invalid = true;
+ msgBldr.append("\nAction info is missing or inconsistent.");
+ }
}
if (invalid) {
}
}
- private boolean validateActionFields(Permission permission) {
+ private boolean validateActionFields(Action action, Permission permission) {
boolean result = true;
List<PermissionAction> permActionList = permission.getAction();
// if the action list field is not set, but the action group is set then set the action actionL
permission.setAction(PermissionClient.getActionList(permActionGroup));
} else {
- // both action fields are not set, we don't care.
+ if (action.equals(Action.CREATE)) {
+ result = false;
+ org.collectionspace.services.authorization.perms.ObjectFactory objectFactory =
+ new org.collectionspace.services.authorization.perms.ObjectFactory();
+ JAXBElement<Permission> permJaxbElement = objectFactory.createPermission(permission);
+ String msg = String.format("Either (or both) the 'action' or 'actiongroup' element needs to be set: %s",
+ JaxbUtils.toString(permJaxbElement, Permission.class));
+ logger.error(msg);
+ }
}
return result;
import org.collectionspace.services.common.document.DocumentWrapper;
import org.collectionspace.services.common.document.JaxbUtils;
import org.collectionspace.services.common.security.SecurityUtils;
+import org.collectionspace.services.common.storage.TransactionContext;
import org.collectionspace.services.common.storage.jpa.JpaDocumentHandler;
import org.slf4j.Logger;
//
List<PermissionValue> permValueList = role.getPermission();
if (permValueList != null && permValueList.size() > 0) {
+ //
+ // To prevent new Permissions being created (especially low-level Spring Security perms), we'll first flush the current
+ // JPA context to ensure our Role can be successfully persisted.
+ //
+ TransactionContext jpaTransactionContext = this.getServiceContext().getCurrentTransactionContext();
+ jpaTransactionContext.flush();
+
// create and persist a permrole instance
// The caller of this method needs to ensure a valid and active EM (EntityManager) instance is in the Service context
RoleValue roleValue = RoleFactory.createRoleValueInstance(role);
package org.collectionspace.services.authorization.storage;
import org.collectionspace.services.authorization.Role;
+import org.collectionspace.services.client.RoleClient;
import org.collectionspace.services.common.ServiceMessages;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.document.DocumentHandler.Action;
* RoleValidatorHandler executes validation rules for role
* @author
*/
-public class RoleValidatorHandler implements ValidatorHandler {
+public class RoleValidatorHandler implements ValidatorHandler<Role, Role> {
final Logger logger = LoggerFactory.getLogger(RoleValidatorHandler.class);
@Override
- public void validate(Action action, ServiceContext ctx)
+ public void validate(Action action, ServiceContext<Role, Role> ctx)
throws InvalidDocumentException {
if (logger.isDebugEnabled()) {
logger.debug("validate() action=" + action.name());
}
try {
- Role role = (Role) ctx.getInput();
+ Role role = ctx.getInput();
StringBuilder msgBldr = new StringBuilder(ServiceMessages.VALIDATION_FAILURE);
boolean invalid = false;
if (action.equals(Action.CREATE)) {
-
- //create specific validation here
if (role.getRoleName() == null || role.getRoleName().isEmpty()) {
invalid = true;
msgBldr.append("\nroleName : missing or empty");
+ } else {
+ if (role.getRoleName().startsWith(RoleClient.BACKEND_ROLE_PREFIX)) {
+ invalid = true;
+ msgBldr.append(String.format("\nroleName : cannot beging with '%s'", RoleClient.BACKEND_ROLE_PREFIX));
+ }
}
} else if (action.equals(Action.UPDATE)) {
- //update specific validation here
if (role.getRoleName() == null || role.getRoleName().isEmpty()) {
invalid = true;
msgBldr.append("\nroleName : cannot be missing or empty");
}
}
+
if (invalid) {
String msg = msgBldr.toString();
logger.error(msg);
DROP TABLE IF EXISTS permissions_roles CASCADE;
DROP TABLE IF EXISTS roles CASCADE;
DROP SEQUENCE IF EXISTS hibernate_sequence;
-create table accounts_roles (HJID int8 not null, account_id varchar(128) not null, created_at timestamp not null, role_id varchar(128) not null, role_name varchar(255), screen_name varchar(255), user_id varchar(128) not null, primary key (HJID), unique (account_id, role_id));
-create table permissions (csid varchar(128) not null, action_group varchar(128), attribute_name varchar(128), created_at timestamp not null, description varchar(255), effect varchar(32) not null, resource_name varchar(128) not null, tenant_id varchar(128) not null, updated_at timestamp, primary key (csid), unique (resource_name, action_group, tenant_id));
-create table permissions_actions (HJID int8 not null, name varchar(128) not null, objectIdentity varchar(128) not null, objectIdentityResource varchar(128) not null, ACTION__PERMISSION_CSID varchar(128), primary key (HJID));
-create table permissions_roles (HJID int8 not null, actionGroup varchar(255), created_at timestamp not null, permission_id varchar(128) not null, permission_resource varchar(255), role_id varchar(128) not null, role_name varchar(255), primary key (HJID), unique (permission_id, role_id));
-create table roles (csid varchar(128) not null, created_at timestamp not null, description varchar(255), displayname varchar(200) not null, rolegroup varchar(255), rolename varchar(200) not null, tenant_id varchar(128) not null, metadata_protection varchar(255), perms_protection varchar(255), updated_at timestamp, primary key (csid), unique (rolename, tenant_id), unique (displayname, tenant_id));
+
+create table accounts_roles (HJID int8 not null, account_id varchar(128) not null, created_at timestamp not null, role_id varchar(128) not null,
+ role_name varchar(255) not null, screen_name varchar(255), user_id varchar(128) not null, primary key (HJID), unique (account_id, role_id));
+
+create table permissions (csid varchar(128) not null, action_group varchar(128), attribute_name varchar(128), created_at timestamp not null, description varchar(255), effect varchar(32) not null,
+ metadata_protection varchar(255), actions_protection varchar(255),
+ resource_name varchar(128) not null, tenant_id varchar(128) not null,
+ updated_at timestamp, primary key (csid));
+
+create table permissions_actions (HJID int8 not null, name varchar(128) not null, objectIdentity varchar(128) not null, objectIdentityResource varchar(128) not null,
+ ACTION__PERMISSION_CSID varchar(128), primary key (HJID));
+
+ create table permissions_roles (HJID int8 not null, actionGroup varchar(255), created_at timestamp not null, permission_id varchar(128) not null, permission_resource varchar(255), role_id varchar(128) not null, role_name varchar(255), primary key (HJID), unique (permission_id, role_id));
+
+create table roles (csid varchar(128) not null, created_at timestamp not null, description varchar(255), displayname varchar(200) not null, rolegroup varchar(255),
+ rolename varchar(200) not null, tenant_id varchar(128) not null,
+ metadata_protection varchar(255), perms_protection varchar(255),
+ updated_at timestamp, primary key (csid), unique (rolename, tenant_id), unique (displayname, tenant_id));
+
alter table permissions_actions add constraint FK85F82042E2DC84FD foreign key (ACTION__PERMISSION_CSID) references permissions;
create sequence hibernate_sequence;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.collectionspace.authentication.AuthN;
import org.collectionspace.authentication.CSpaceTenant;
import org.collectionspace.authentication.CSpaceUser;
-import org.collectionspace.authentication.spi.AuthNContext;
import org.collectionspace.services.authorization.perms.ActionType;
import org.collectionspace.services.authorization.spi.CSpaceAuthorizationProvider;
+
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
if (logger.isDebugEnabled()) {
logger.debug("reading beanConfig=" + beanConfig);
}
- ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
- new String[]{beanConfig});
+ ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(new String[]{beanConfig}); // FIXME: This is never used. Keep it for debugging?
provider = (CSpaceAuthorizationProvider) appContext.getBean("cspaceAuthorizationProvider");
if (logger.isDebugEnabled()) {
logger.debug("initialized the authz provider");
try {
for (CSpaceResource res : resources) {
CSpaceAction action = res.getAction();
- addPermissions(res, action, principals, grant);
+ addPermission(res, action, principals, grant);
}
provider.commitTransaction(status);
} catch (Throwable t) {
* @param principals
* @param grant true to grant false to deny
*/
- private void addPermissions(CSpaceResource res, CSpaceAction action, String[] principals, boolean grant)
+ private void addPermission(CSpaceResource res, CSpaceAction action, String[] principals, boolean grant)
throws PermissionException {
provider.getPermissionManager().addPermissionsToRoles(res, action, principals, grant);
provider.clearAclCache();
* @param res
* @param principals
*/
- public void deletePermissionsFromRoles(CSpaceResource[] resources, String[] principals)
+ public void deletePermissionsFromRoles(CSpaceResource[] resources, String[] principals) // FIXME: # Can tx move one level up?
throws PermissionNotFoundException, PermissionException {
TransactionStatus status = provider.beginTransaction("deletePermssions");
try {
for (CSpaceResource res : resources) {
CSpaceAction action = res.getAction();
- deletePermissionsFromRoles(res, action, principals);
+ deletePermissionFromRoles(res, action, principals);
}
provider.commitTransaction(status);
} catch (Throwable t) {
* @param action
* @param principals
*/
- private void deletePermissionsFromRoles(CSpaceResource res, CSpaceAction action, String[] principals)
+ private void deletePermissionFromRoles(CSpaceResource res, CSpaceAction action, String[] principals)
throws PermissionNotFoundException, PermissionException {
- provider.getPermissionManager().deletePermissionsFromRoles(res, action, principals);
+ provider.getPermissionManager().deletePermissionFromRoles(res, action, principals);
provider.clearAclCache();
}
* @see CSpaceResource
* @see CSpaceAction
*/
- public void deletePermissionsFromRoles(CSpaceResource res, CSpaceAction action, String[] principals)
+ public void deletePermissionFromRoles(CSpaceResource res, CSpaceAction action, String[] principals)
throws PermissionNotFoundException, PermissionException;
/**
* @throws PermissionException
*/
@Override
- public void deletePermissionsFromRoles(CSpaceResource res, CSpaceAction action, String[] principals)
+ public void deletePermissionFromRoles(CSpaceResource res, CSpaceAction action, String[] principals)
throws PermissionNotFoundException, PermissionException {
ObjectIdentity oid = SpringAuthorizationProvider.getObjectIdentity(res);
Sid[] sids = SpringAuthorizationProvider.getSids(principals);
throw new PermissionException(msg, ex);
}
}
- if (log.isDebugEnabled()) {
- log.debug("deletedpermissions(res,action,prin[]), success for "
- + " res=" + res.toString()
- + " action=" + action.toString()
- + " oid=" + oid.toString()
- + " perm=" + p.toString()
- + " sids=" + sids.toString());
- }
}
/**
+ " found " + aces + " aces");
}
ArrayList<Integer> foundAces = new ArrayList<Integer>();
- Iterator iter = acel.listIterator();
+ Iterator<AccessControlEntry> iter = acel.listIterator();
//not possible to delete while iterating
while (iter.hasNext()) {
AccessControlEntry ace = (AccessControlEntry) iter.next();
}
i++;
}
+
+ boolean updateNeeded = false;
for (int j = foundAces.size() - 1; j >= 0; j--) {
//the following operation does not work while iterating in the while loop
acl.deleteAce(foundAces.get(j)); //autobox
+ updateNeeded = true;
+ }
+
+ if (updateNeeded) {
+ provider.getProviderAclService().updateAcl(acl);
}
- provider.getProviderAclService().updateAcl(acl);
if (log.isDebugEnabled()) {
log.debug("deletePermissions: for acl oid=" + oid.toString()
import java.io.File;
import java.io.InputStream;
+import java.util.List;
import java.util.Properties;
import java.util.regex.Pattern;
+
import java.util.regex.Matcher;
/** General utility methods.
return result;
}
+
+ public static boolean isEmpty(List<?> theList) {
+ if (theList != null && theList.size() > 0) {
+ return false;
+ } else {
+ return true;
+ }
+ }
}
import org.collectionspace.services.authorization.PermissionRoleRel;
import org.collectionspace.services.authorization.SubjectType;
import org.collectionspace.services.authorization.perms.Permission;
+import org.collectionspace.services.authorization.perms.PermissionAction;
import org.collectionspace.services.authorization.perms.PermissionsList;
-import org.collectionspace.services.authorization.storage.AuthorizationDelegate;
+import org.collectionspace.services.authorization.storage.PermissionDocumentHandler;
import org.collectionspace.services.client.CollectionSpaceClientUtils;
import org.collectionspace.services.client.PayloadOutputPart;
import org.collectionspace.services.client.PermissionClient;
+import org.collectionspace.services.common.CSWebApplicationException;
import org.collectionspace.services.common.SecurityResourceBase;
import org.collectionspace.services.common.ServiceMessages;
+import org.collectionspace.services.common.api.Tools;
+import org.collectionspace.services.common.authorization_mgt.PermissionRoleUtil;
import org.collectionspace.services.common.context.RemoteServiceContextFactory;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.context.ServiceContextFactory;
+import org.collectionspace.services.common.document.DocumentException;
+import org.collectionspace.services.common.document.DocumentHandler;
+import org.collectionspace.services.common.document.DocumentHandler.Action;
+import org.collectionspace.services.common.document.DocumentNotFoundException;
import org.collectionspace.services.common.storage.StorageClient;
import org.collectionspace.services.common.storage.TransactionContext;
import org.collectionspace.services.common.storage.jpa.JPATransactionContext;
import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl;
+
import org.jboss.resteasy.util.HttpResponseCodes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.List;
+
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
@Path(PermissionClient.SERVICE_PATH)
@Consumes("application/xml")
@Produces("application/xml")
-public class PermissionResource extends SecurityResourceBase {
+public class PermissionResource extends SecurityResourceBase<Permission, Permission> {
final Logger logger = LoggerFactory.getLogger(PermissionResource.class);
final StorageClient storageClient = new JpaStorageClientImpl();
}
@Override
- public StorageClient getStorageClient(@SuppressWarnings("rawtypes") ServiceContext ctx) {
+ public StorageClient getStorageClient(ServiceContext<Permission, Permission> ctx) {
//FIXME use ctx to identify storage client
return storageClient;
}
Response response = createPermission(jpaTransactionContext, input);
if (response.getStatus() == Response.Status.CREATED.getStatusCode()) {
permCsid = CollectionSpaceClientUtils.extractId(response);
- result = (Permission)get(jpaTransactionContext, permCsid, Permission.class);
+ result = (Permission)get(jpaTransactionContext, permCsid, Permission.class); // return the result of a full lookup of what we just persisted
}
return result;
return result;
}
+ /**
+ * Updates a permission by first deleting it and all of it's relationships (with roles, and perm-actions) and then
+ * recreating it. Unfortunately, we can't seem to be able to just update the perm-actions because of an issue with JPA.
+ *
+ * @param ui
+ * @param csid
+ * @param theUpdate
+ * @return
+ * @throws Exception
+ */
@PUT
@Path("{csid}")
- public Permission updatePermission(@PathParam("csid") String csid,Permission theUpdate) {
- return (Permission)update(csid, theUpdate, Permission.class);
+ synchronized public Permission updatePermission(@Context UriInfo ui, @PathParam("csid") String csid, Permission theUpdate) throws Exception {
+ Permission result = null;
+ ensureCSID(csid, ServiceMessages.UPDATE_FAILED + "permission ");
+
+ ServiceContext<Permission, Permission> ctx = createServiceContext(null, Permission.class);
+ PermissionDocumentHandler docHandler = (PermissionDocumentHandler) createDocumentHandler(ctx);
+
+ TransactionContext transactionContext = ctx.openConnection();
+ try {
+ transactionContext.beginTransaction();
+ //
+ // Get a copy of the currently persisted resource
+ //
+ Permission original = (Permission) get(transactionContext, csid, Permission.class);
+ if (original == null) {
+ throw new DocumentNotFoundException(String.format("The Permission resource CSID=%s could not be found.", csid));
+ } else if (isImmutable(original) == true) {
+ String msg = String.format("Permission resource CSID=%s is immutable and cannot be updated.", csid);
+ throw new DocumentException(msg);
+ }
+
+ Permission perm = copyForUpdate(original); // If we upgrade to JPA 2.0, we could just "detach" the original instead of needing to copy it.
+
+ //
+ // Before we start the update process, verify the payload is valid
+ //
+ ctx.setInput(theUpdate);
+ docHandler.prepare(Action.UPDATE);
+
+ //
+ // Get a copy of the permission-role relationships
+ //
+ PermissionRole permRole = getPermissionRole(ctx, csid);
+
+ //
+ // Delete the Permission resource (and related perm-actions, and perm-roles) from storage and remove from current JPA context
+ //
+ Response deletedRes = deletePermission(ctx, csid);
+ if (deletedRes.getStatus() != Response.Status.OK.getStatusCode()) {
+ throw new DocumentException(String.format("Could not update Permission resource CSID=%s", csid));
+ }
+
+ //
+ // Merge the "update" payload with the corresponding Permission resource payload
+ //
+ perm = docHandler.merge(perm, theUpdate);
+
+ //
+ // Recreate the Permission resource (and related perm-actions) using the same CSID and updated Permission object
+ //
+ ctx.setInput(perm);
+ ctx.setProperty(PermissionClient.PERMISSION_UPDATE_CSID, csid);
+ Response res = create(ctx, perm);
+ if (res.getStatus() != Response.Status.CREATED.getStatusCode()) {
+ throw new DocumentException(String.format("Could not update Permission resource CSID=%s", csid));
+ }
+
+ //
+ // Recreate the permission-role relationships
+ //
+ if (PermissionRoleUtil.isEmpty(permRole) == false) {
+ Response permRoleRes = createPermissionRole(ctx, csid, permRole);
+ if (permRoleRes.getStatus() != Response.Status.CREATED.getStatusCode()) {
+ throw new DocumentException(String.format("Could not update Permission resource CSID=%s", csid));
+ }
+ }
+
+ transactionContext.commitTransaction();
+ result = perm;
+ } catch (Exception e) {
+ transactionContext.markForRollback();
+ throw bigReThrow(e, ServiceMessages.UPDATE_FAILED, csid);
+ } finally {
+ if (result == null) {
+ //
+ //
+ //
+ }
+ ctx.closeConnection();
+ }
+
+ return result;
}
- @SuppressWarnings("unchecked")
+ /**
+ * Return true if the permission is immutable.
+ *
+ * @param original
+ * @return
+ */
+ private boolean isImmutable(Permission original) {
+ boolean result = false;
+
+ if ((!Tools.isEmpty(original.getMetadataProtection()) && original.getMetadataProtection().equals(PermissionClient.IMMUTABLE))
+ || (!Tools.isEmpty(original.getActionsProtection()) && original.getActionsProtection().equals(PermissionClient.IMMUTABLE))) {
+ result = true;
+ }
+
+ return result;
+ }
+
+ private Permission copyForUpdate(Permission theOriginal) throws DocumentException {
+ Permission result = null;
+
+ if (theOriginal != null) {
+ result = new Permission();
+ result.setAttributeName(theOriginal.getAttributeName());
+ result.setDescription(theOriginal.getDescription());
+ result.setEffect(theOriginal.getEffect());
+ result.setResourceName(theOriginal.getResourceName());
+ result.setTenantId(theOriginal.getTenantId());
+ result.setActionGroup(theOriginal.getActionGroup());
+
+ for (PermissionAction permissionAction : theOriginal.getAction()) {
+ result.getAction().add(copyForUpdate(permissionAction));
+ }
+ }
+
+ return result;
+ }
+
+ private PermissionAction copyForUpdate(PermissionAction permissionAction) {
+ PermissionAction result = new PermissionAction();
+
+ result.setName(permissionAction.getName());
+ result.setObjectIdentity(permissionAction.getObjectIdentity());
+ result.setObjectIdentityResource(permissionAction.getObjectIdentityResource());
+
+ return result;
+ }
+
+ /**
+ * Deletes the Permission resource and its relationship(s) with any role(s). Does not delete the actual low-level permission-action tuples.
+ * See https://issues.collectionspace.org/browse/DRYD-223
+ *
+ * @param csid
+ * @return
+ * @throws Exception
+ */
@DELETE
@Path("{csid}")
- synchronized public Response deletePermission(@PathParam("csid") String csid) throws Exception {
+ public Response deletePermission(@PathParam("csid") String csid) throws Exception {
logger.debug("deletePermission with csid=" + csid);
ensureCSID(csid, ServiceMessages.DELETE_FAILED + "permission ");
ServiceContext<Permission, Permission> ctx = createServiceContext((Permission) null, Permission.class);
+ return deletePermission(ctx, csid);
+ }
+
+ synchronized public Response deletePermission(ServiceContext<Permission, Permission> ctx, String csid) throws Exception {
+ DocumentHandler docHandler = createDocumentHandler(ctx);
+
TransactionContext transactionContext = ctx.openConnection();
try {
transactionContext.beginTransaction();
//
// First, delete the relationships between the Permission resource and any Role resources.
//
- PermissionRoleSubResource subResource =
- new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE);
- subResource.deletePermissionRole(ctx, csid, SubjectType.ROLE);
- //
- // Next, delete the low-level (Spring Security) permissions.
- //
- // NOTE: For deletePermission() in the authz provider at the PermissionRoleSubResource/DocHandler level, there is no visibility
- // if permission is deleted, so do it here.
- //
- // WARNING: This operation deletes the Spring ACL (not the ACEs). It's possible the ACL might be needed for other ACEs roles...
- //
- AuthorizationDelegate.deletePermissions((JPATransactionContext)transactionContext, csid); // Deletes the low-level (Spring Security) permissions
+ try {
+ PermissionRoleSubResource subResource =
+ new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE);
+ subResource.deletePermissionRole(ctx, csid, SubjectType.ROLE);
+ } catch (DocumentNotFoundException dnf) {
+ // ignore, just means we didn't find any relationships to delete
+ }
//
// Lastly, delete the Permission resource itself and commit the transaction
//
- getStorageClient(ctx).delete(ctx, csid);
+ getStorageClient(ctx).delete(ctx, csid, docHandler);
transactionContext.commitTransaction();
} catch (Exception e) {
transactionContext.markForRollback();
return Response.status(HttpResponseCodes.SC_OK).build();
}
-
+
@POST
@Path("{csid}/permroles")
- public Response createPermissionRole(@QueryParam("_method") String method,
+ public Response createPermissionRole(
+ @QueryParam("_method") String method,
@PathParam("csid") String permCsid,
- PermissionRole input) {
- if (method != null) {
- if ("delete".equalsIgnoreCase(method)) {
- return deletePermissionRole(permCsid, input);
- }
- }
- logger.debug("createPermissionRole with permCsid=" + permCsid);
- ensureCSID(permCsid, ServiceMessages.POST_FAILED + "permroles permission ");
- try {
- PermissionRoleSubResource subResource =
- new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE);
- String permrolecsid = subResource.createPermissionRole((ServiceContext<Permission, Permission>)null, input, SubjectType.ROLE);
- UriBuilder path = UriBuilder.fromResource(PermissionResource.class);
- path.path(permCsid + "/permroles/" + permrolecsid);
- Response response = Response.created(path.build()).build();
- return response;
- } catch (Exception e) {
- throw bigReThrow(e, ServiceMessages.POST_FAILED, permCsid);
- }
- }
+ PermissionRole input) {
+ if (method != null) {
+ if ("delete".equalsIgnoreCase(method)) { // FIXME: How could 'method' ever equal "delete"
+ return deletePermissionRole(permCsid, input);
+ }
+ }
+ logger.debug("createPermissionRole with permCsid=" + permCsid);
+ ensureCSID(permCsid, ServiceMessages.POST_FAILED + "permroles permission ");
+
+ return createPermissionRole((ServiceContext<Permission, Permission>)null, permCsid, input);
+ }
+
+ protected Response createPermissionRole(
+ ServiceContext<Permission, Permission> ctx,
+ String permCsid,
+ PermissionRole input) {
+ try {
+ PermissionRoleSubResource subResource = new PermissionRoleSubResource(
+ PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE);
+ String permrolecsid = subResource.createPermissionRole(ctx, input, SubjectType.ROLE);
+ UriBuilder path = UriBuilder.fromResource(PermissionResource.class);
+ path.path(permCsid + "/permroles/" + permrolecsid);
+ Response response = Response.created(path.build()).build();
+ return response;
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.POST_FAILED, permCsid);
+ }
+ }
@GET
@Path("{csid}/permroles/{id}")
@GET
@Path("{csid}/permroles")
- public PermissionRole getPermissionRole(
- @PathParam("csid") String permCsid) {
+ public PermissionRole getPermissionRole(@PathParam("csid") String permCsid) {
logger.debug("getPermissionRole with permCsid=" + permCsid);
ensureCSID(permCsid, ServiceMessages.GET_FAILED + "permroles permission ");
+
+ PermissionRole result = getPermissionRole((ServiceContext<Permission, Permission>)null, permCsid);
+
+ if (PermissionRoleUtil.isEmpty(result)) {
+ String msg = String.format("Could not find any permission-role relationships for Permission resource CSID=%s", permCsid);
+ Response response = Response.status(Response.Status.NOT_FOUND).entity(msg).type("text/plain").build();
+ throw new CSWebApplicationException(response);
+ }
+
+ return result;
+ }
+
+ private PermissionRole getPermissionRole(ServiceContext<Permission, Permission> ctx, String permCsid) {
+ ensureCSID(permCsid, ServiceMessages.GET_FAILED + "permroles permission ");
PermissionRole result = null;
+
try {
PermissionRoleSubResource subResource =
new PermissionRoleSubResource(PermissionRoleSubResource.PERMISSION_PERMROLE_SERVICE);
- //get relationships for a permission
- result = subResource.getPermissionRole((ServiceContext<Permission, Permission>)null, permCsid, SubjectType.ROLE);
+ result = subResource.getPermissionRole(ctx, permCsid, SubjectType.ROLE);
} catch (Exception e) {
throw bigReThrow(e, ServiceMessages.GET_FAILED, permCsid);
}
- checkResult(result, permCsid, ServiceMessages.GET_FAILED);
+
return result;
- }
-
- public Response deletePermissionRole(String permCsid, PermissionRole input) {
+ }
+
+ private Response deletePermissionRole(String permCsid, PermissionRole input) {
logger.debug("Delete payload of permrole relationships with permission permCsid=" + permCsid);
ensureCSID(permCsid, ServiceMessages.DELETE_FAILED + "permroles permission ");
try {
import org.collectionspace.services.authorization.perms.Permission;
import org.collectionspace.services.authorization.storage.PermissionRoleDocumentHandler;
import org.collectionspace.services.common.AbstractCollectionSpaceResourceImpl;
+import org.collectionspace.services.common.authorization_mgt.PermissionRoleUtil;
import org.collectionspace.services.common.context.RemoteServiceContextFactory;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.context.ServiceContextFactory;
@SuppressWarnings("rawtypes")
public class PermissionRoleSubResource
extends AbstractCollectionSpaceResourceImpl<PermissionRole, PermissionRole> {
+ /** The logger. */
+ final Logger logger = LoggerFactory.getLogger(PermissionRoleSubResource.class);
public final static String ROLE_PERMROLE_SERVICE = "authorization/roles/permroles";
public final static String PERMISSION_PERMROLE_SERVICE = "authorization/permissions/permroles";
//service name to identify binding
/** The service name. */
private String serviceName = "authorization/permroles";
- /** The logger. */
- final Logger logger = LoggerFactory.getLogger(PermissionRoleSubResource.class);
/** The storage client. */
final StorageClient storageClient = new JpaRelationshipStorageClient<PermissionRole>();
/**
if (logger.isDebugEnabled()) {
logger.debug("deletePermissionRole with csid=" + csid);
}
+
PermissionRole permRole = getPermissionRole(parentCtx, csid, subject);
- if (permRole != null) {
+ if (PermissionRoleUtil.isEmpty(permRole) == false) {
deletePermissionRole(parentCtx, csid, subject, permRole);
} else {
- String msg = String.format("The permission CSID=%s is missing or not related to any roles.", csid);
+ String msg = String.format("The %s CSID=%s is missing or not related to any objects.",
+ getInverse(subject).toString().toLowerCase(), csid);
throw new DocumentNotFoundException(msg);
}
}
-
+
+ /*
+ * Returns the inverse of the subject (the object)
+ */
+ private SubjectType getInverse(SubjectType subject) {
+ SubjectType result;
+
+ if (subject.equals(SubjectType.PERMISSION)) {
+ result = SubjectType.ROLE;
+ } else {
+ result = SubjectType.PERMISSION;
+ }
+
+ return result;
+ }
+
/**
* deletePermissionRole deletes permission-role relationships using given
* csid of object (permission/role) and subject (role/permission)
import java.util.List;
import org.collectionspace.authentication.AuthN;
+
import org.collectionspace.services.authorization.perms.ActionType;
import org.collectionspace.services.authorization.AuthZ;
import org.collectionspace.services.authorization.CSpaceAction;
import org.collectionspace.services.authorization.perms.EffectType;
import org.collectionspace.services.authorization.perms.Permission;
import org.collectionspace.services.authorization.perms.PermissionAction;
-import org.collectionspace.services.authorization.PermissionException;
import org.collectionspace.services.authorization.PermissionRole;
import org.collectionspace.services.authorization.PermissionValue;
import org.collectionspace.services.authorization.Role;
import org.collectionspace.services.authorization.RoleValue;
import org.collectionspace.services.authorization.SubjectType;
import org.collectionspace.services.authorization.URIResourceImpl;
+
import org.collectionspace.services.common.authorization_mgt.PermissionRoleUtil;
import org.collectionspace.services.common.context.ServiceContext;
+import org.collectionspace.services.common.document.DocumentException;
import org.collectionspace.services.common.document.DocumentNotFoundException;
import org.collectionspace.services.common.storage.jpa.JPATransactionContext;
import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(AuthorizationDelegate.class);
/**
- * addPermissions add permissions represented given PermissionRole
+ * Add low-level Spring permissions represented by the given PermissionRole instance
+ *
* @param ctx
* @param pr permission role
* @throws Exception
* @see PermissionRole
*/
- public static void addRelationships(ServiceContext ctx, PermissionRole pr) throws Exception {
+ public static void addRelationships(ServiceContext<?, ?> ctx, PermissionRole pr) throws Exception {
JPATransactionContext jpaTransactionContext = (JPATransactionContext) ctx.getCurrentTransactionContext();
SubjectType subject = PermissionRoleUtil.getRelationSubject(ctx, pr);
String[] roles = getRoles(jpaTransactionContext, pr.getRole());
boolean grant = permission.getEffect().equals(EffectType.PERMIT) ? true : false;
authz.addPermissions(resources, roles, grant);
+ jpaTransactionContext.setAclTablesUpdateFlag(true); // Tell the containing JPA transaction that we've committed changes to the Spring Tables
} else if (SubjectType.PERMISSION.equals(subject)) {
RoleValue rv = pr.getRole().get(0);
Role role = getRole(jpaTransactionContext, rv.getRoleId());
for (PermissionValue pv : pr.getPermission()) {
Permission p = getPermission(jpaTransactionContext, pv.getPermissionId());
if (p == null) {
- String msg = "addPermissions: No permission resource found for csid=" + pv.getPermissionId();
- logger.error(msg);
- //TODO: would be nice contiue to still send 400 back
- continue;
+ String msg = "addRelationships: No permission resource found for csid=" + pv.getPermissionId();
+ throw new DocumentException(msg);
}
CSpaceResource[] resources = getResources(p);
boolean grant = p.getEffect().equals(EffectType.PERMIT) ? true : false;
authz.addPermissions(resources, roles, grant);
+ jpaTransactionContext.setAclTablesUpdateFlag(true); // Tell the containing JPA transaction that we've committed changes to the Spring Tables
}
}
}
/**
* deletePermissions delete all permissions associated with given permission role
* @param ctx
- * @param pr permissionrole
+ * @param permRole permissionrole
* @throws Exception
*/
- public static void deletePermissionsFromRoles(ServiceContext ctx, PermissionRole pr)
+ public static void deletePermissionsFromRoles(ServiceContext<?, ?> ctx, PermissionRole permRole)
throws Exception {
JPATransactionContext jpaTransactionContext = (JPATransactionContext) ctx.getCurrentTransactionContext();
- SubjectType subject = PermissionRoleUtil.getRelationSubject(ctx, pr);
+ SubjectType subject = PermissionRoleUtil.getRelationSubject(ctx, permRole);
AuthZ authz = AuthZ.get();
if (subject.equals(SubjectType.ROLE)) {
- List<PermissionValue> permissionValues = pr.getPermission();
- if (permissionValues != null & permissionValues.size() > 0) {
- PermissionValue pv = permissionValues.get(0);
- Permission p = getPermission(jpaTransactionContext, pv.getPermissionId());
+ List<PermissionValue> permissionValues = permRole.getPermission();
+ if (permissionValues != null && permissionValues.size() == 1) {
+ PermissionValue permValue = permissionValues.get(0);
+ Permission p = getPermission(jpaTransactionContext, permValue.getPermissionId());
if (p == null) {
- String msg = "deletePermissions: No permission found for id=" + pv.getPermissionId();
+ String msg = "deletePermissions: No permission found for id=" + permValue.getPermissionId();
logger.error(msg);
throw new DocumentNotFoundException(msg);
}
CSpaceResource[] resources = getResources(p);
- String[] roles = getRoles(jpaTransactionContext, pr.getRole());
+ String[] roles = getRoles(jpaTransactionContext, permRole.getRole());
authz.deletePermissionsFromRoles(resources, roles);
+ jpaTransactionContext.setAclTablesUpdateFlag(true); // Tell the containing JPA transaction that we've committed changes to the Spring Tables
+ } else {
+ throw new DocumentException("When the subject of a permrole is ROLE, there should be only ONE permission specified.");
}
} else if (SubjectType.PERMISSION.equals(subject)) {
- List<RoleValue> roleValues = pr.getRole();
- if (roleValues != null && roleValues.size() > 0) {
- RoleValue rv = roleValues.get(0);
- Role r = getRole(jpaTransactionContext, rv.getRoleId());
- if (r == null) {
- String msg = "deletePermissions: No role found for id=" + rv.getRoleId();
+ List<RoleValue> roleValues = permRole.getRole();
+ if (roleValues != null && roleValues.size() == 1) {
+ RoleValue roleValue = roleValues.get(0);
+ Role role = getRole(jpaTransactionContext, roleValue.getRoleId());
+ if (role == null) {
+ String msg = "deletePermissions: No role found for id=" + roleValue.getRoleId();
logger.error(msg);
throw new DocumentNotFoundException(msg);
}
- //using r not rv ensures we're getting the "ROLE" prefix/qualified name
+ // Using role not roleValue ensures we're getting the "ROLE" prefix/qualified name
// This needs to use the qualified name, not the display name
- String[] roles = {r.getRoleName()};
- for (PermissionValue pv : pr.getPermission()) {
- Permission p = getPermission(jpaTransactionContext, pv.getPermissionId());
- if (p == null) {
+ String[] roles = {role.getRoleName()};
+ for (PermissionValue pv : permRole.getPermission()) {
+ Permission perm = getPermission(jpaTransactionContext, pv.getPermissionId());
+ if (perm == null) {
String msg = "deletePermissions: No permission found for id=" + pv.getPermissionId();
- logger.error(msg);
- //TODO: would be nice contiue to still send 400 back
- continue;
+ throw new DocumentException(msg);
}
- CSpaceResource[] resources = getResources(p);
+ CSpaceResource[] resources = getResources(perm);
authz.deletePermissionsFromRoles(resources, roles);
+ jpaTransactionContext.setAclTablesUpdateFlag(true); // Tell the containing JPA transaction that we've committed changes to the Spring Tables
}
+ } else {
+ throw new DocumentException("When the subject of a permrole is PERMISSION, there should be only ONE role specified.");
}
}
}
CSpaceResource[] resources = getResources(p);
AuthZ.get().deletePermissions(resources);
+ jpaTransactionContext.setAclTablesUpdateFlag(true); // Tell the containing JPA transaction that we've committed changes to the Spring Tables
}
/**
import org.collectionspace.services.authorization.perms.PermissionAction;
import org.collectionspace.services.authorization.perms.PermissionsList;
import org.collectionspace.services.authorization.URIResourceImpl;
-
+import org.collectionspace.services.common.api.Tools;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.document.BadRequestException;
import org.collectionspace.services.common.document.DocumentException;
public class PermissionDocumentHandler
extends JpaDocumentHandler<Permission, PermissionsList, Permission, List<Permission>> {
- private final Logger logger = LoggerFactory.getLogger(PermissionDocumentHandler.class);
+ private final Logger logger = LoggerFactory.getLogger(PermissionDocumentHandler.class);
private Permission permission;
private PermissionsList permissionsList;
URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(), perm.getResourceName(), action);
permAction.setObjectIdentity(uriRes.getHashedId().toString());
permAction.setObjectIdentityResource(uriRes.getId());
- //PermissionActionUtil.update(perm, permAction);
}
}
//
// First check to see if an equivalent permission exists
//
+ ServiceContext<Permission, Permission> ctx = getServiceContext();
Permission permission = wrapDoc.getWrappedObject();
Permission existingPermission = findExistingPermission(permission);
if (existingPermission == null) {
- String id = UUID.randomUUID().toString();
+ //
+ // If our call originates from an UPDATE/PUT request, then we can find a CSID in the service context
+ //
+ String id = (String)ctx.getProperty(PermissionClient.PERMISSION_UPDATE_CSID);
+ if (Tools.isEmpty(id) == true) {
+ id = UUID.randomUUID().toString();
+ }
permission.setCsid(id);
setTenant(permission);
handlePermissionActions(permission);
public void completeCreate(DocumentWrapper<Permission> wrapDoc) throws Exception {
}
+ /**
+ * Not used. Due to an issue with the JPA 1.0 update mechanism, we had to perform the update process
+ * in the PermissionResource class. Look there for more details.
+ */
+ @Deprecated
@Override
public void handleUpdate(DocumentWrapper<Permission> wrapDoc) throws Exception {
- Permission permissionFound = wrapDoc.getWrappedObject();
- Permission permissionReceived = getCommonPart();
- merge(permissionReceived, permissionFound);
}
- /**
- * merge manually merges the from from to the to permission
- * -this method is created due to inefficiency of JPA EM merge
- * @param from
- * @param to
- * @return merged permission
+ /*
+ * Merge two Permission resources for an update/put request.
*/
- private Permission merge(Permission from, Permission to) throws Exception {
- if (!(from.getResourceName().equalsIgnoreCase(to.getResourceName()))) {
- String msg = "Resource name cannot be changed " + to.getResourceName();
- logger.error(msg);
- throw new BadRequestException(msg);
+ public Permission merge(Permission perm, Permission theUpdate) throws DocumentException {
+ Permission result = perm;
+
+ if (!Tools.isEmpty(theUpdate.getResourceName()) && !theUpdate.getResourceName().equalsIgnoreCase(perm.getResourceName())) {
+ String msg = String.format("Failed attempt to change Permission's (CSID='%S') resource name from '%s' to '%s'.",
+ perm.getCsid(), perm.getResourceName(), theUpdate.getResourceName());
+ throw new DocumentException(msg);
}
- //resource name, attribute cannot be changed
- if (from.getDescription() != null) {
- to.setDescription(from.getDescription());
+ if (theUpdate.getDescription() != null) {
+ perm.setDescription(theUpdate.getDescription());
}
- if (from.getEffect() != null) {
- to.setEffect(from.getEffect());
+ if (theUpdate.getEffect() != null) {
+ perm.setEffect(theUpdate.getEffect());
}
- List<PermissionAction> fromActions = from.getAction();
- if (!fromActions.isEmpty()) {
- // Override the whole list, no reconciliation by design
- to.setAction(fromActions);
- // Update the actionGroup field to reflect the new action list
- to.setActionGroup(PermissionClient.getActionGroup(fromActions));
+ //
+ // Override the whole perm-action list, no reconciliation by design. We've
+ // already cleaned-up and removed all the old perm-role relationships
+ //
+ // If the update didn't provide any new perm-actions, then we leave the
+ // existing ones alone.
+ //
+ if (Tools.isEmpty(theUpdate.getAction()) == false) {
+ perm.setAction(theUpdate.getAction());
+ perm.setActionGroup(PermissionClient.getActionGroup(theUpdate.getAction()));
}
-
+
if (logger.isDebugEnabled()) {
- logger.debug("merged permission=" + JaxbUtils.toString(to, Permission.class));
+ logger.debug("merged permission=" + JaxbUtils.toString(perm, Permission.class));
}
-
- handlePermissionActions(to);
- return to;
+
+ return result;
}
-
+
+ /**
+ * Because of issues with JPA 1.0 not being able to propagate updates from the 'permissions' table to the related 'permissions_actions'
+ * table, we need to handle updates in the PermissionResource class by deleting and creating the Permission resource
+ */
@SuppressWarnings("unchecked")
@Override
+ @Deprecated
public void completeUpdate(DocumentWrapper<Permission> wrapDoc) throws Exception {
- Permission upAcc = wrapDoc.getWrappedObject();
- getServiceContext().setOutput(upAcc);
- sanitize(upAcc);
- //FIXME update lower-layer authorization (acls)
- //will require deleting old permissions for this resource and adding
- //new based on new actions and effect
+ Permission updatedPerm = wrapDoc.getWrappedObject();
+ getServiceContext().setOutput(updatedPerm);
+ sanitize(updatedPerm);
}
@SuppressWarnings("unchecked")
import org.collectionspace.services.common.authorization_mgt.AuthorizationRoleRel;
import org.collectionspace.services.common.authorization_mgt.PermissionRoleUtil;
import org.collectionspace.services.common.context.ServiceContext;
+import org.collectionspace.services.common.document.DocumentException;
import org.collectionspace.services.common.document.DocumentFilter;
+import org.collectionspace.services.common.document.DocumentNotFoundException;
import org.collectionspace.services.common.document.DocumentWrapper;
+import org.collectionspace.services.common.document.JaxbUtils;
import org.collectionspace.services.common.document.TransactionException;
import org.collectionspace.services.common.storage.jpa.JPATransactionContext;
import org.collectionspace.services.common.storage.jpa.JpaDocumentFilter;
AuthorizationDelegate.deletePermissionsFromRoles(getServiceContext(), pr);
}
- /* (non-Javadoc)
+ /*
+ * Turns a list of permission-role rows from the database into a PermissionRole object. The list of rows
+ * was the result of a query where the subject was either a Role or a Permission.
+ *
+ * (non-Javadoc)
* @see org.collectionspace.services.common.document.AbstractDocumentHandlerImpl#extractCommonPart(org.collectionspace.services.common.document.DocumentWrapper)
*/
@Override
- public PermissionRole extractCommonPart(
- DocumentWrapper<List<PermissionRoleRel>> wrapDoc)
+ public PermissionRole extractCommonPart(DocumentWrapper<List<PermissionRoleRel>> wrapDoc)
throws Exception {
- List<PermissionRoleRel> prrl = wrapDoc.getWrappedObject();
- PermissionRole pr = new PermissionRole();
- SubjectType subject = PermissionRoleUtil.getRelationSubject(getServiceContext());
- if (prrl.size() == 0) {
- return pr;
+ PermissionRole result = new PermissionRole();
+
+ List<PermissionRoleRel> permissionRoleRel = wrapDoc.getWrappedObject();
+ if (permissionRoleRel.size() == 0) {
+ return result;
}
- PermissionRoleRel prr0 = prrl.get(0);
+
+ SubjectType subject = PermissionRoleUtil.getRelationSubject(getServiceContext());
+ result.setSubject(subject);
+
+ PermissionRoleRel prr0 = permissionRoleRel.get(0);
if (SubjectType.ROLE.equals(subject)) {
-
- List<PermissionValue> pvs = new ArrayList<PermissionValue>();
- pr.setPermission(pvs);
+ //
+ // Since ROLE is the subject, they'll be just one Permission
+ //
+ List<PermissionValue> permissionValueList = new ArrayList<PermissionValue>();
+ result.setPermission(permissionValueList);
PermissionValue pv = AuthorizationRoleRel.buildPermissionValue(prr0);
- pvs.add(pv);
-
- //add roles
- List<RoleValue> rvs = new ArrayList<RoleValue>();
- pr.setRole(rvs);
- for (PermissionRoleRel prr : prrl) {
+ permissionValueList.add(pv);
+ //
+ // Add role values
+ //
+ List<RoleValue> roleValueList = new ArrayList<RoleValue>();
+ result.setRole(roleValueList);
+ for (PermissionRoleRel prr : permissionRoleRel) {
RoleValue rv = AuthorizationRoleRel.buildRoleValue(prr);
- rvs.add(rv);
+ roleValueList.add(rv);
}
} else if (SubjectType.PERMISSION.equals(subject)) {
-
- List<RoleValue> rvs = new ArrayList<RoleValue>();
- pr.setRole(rvs);
+ //
+ // Since PERMISSION is the subject, they'll be just one Role and one or more Permissions
+ //
+ List<RoleValue> roleValueList = new ArrayList<RoleValue>();
+ result.setRole(roleValueList);
RoleValue rv = AuthorizationRoleRel.buildRoleValue(prr0);
- rvs.add(rv);
-
- //add permssions
- List<PermissionValue> pvs = new ArrayList<PermissionValue>();
- pr.setPermission(pvs);
- for (PermissionRoleRel prr : prrl) {
+ roleValueList.add(rv);
+ //
+ // Add permssions values
+ //
+ List<PermissionValue> permissionValueList = new ArrayList<PermissionValue>();
+ result.setPermission(permissionValueList);
+ for (PermissionRoleRel prr : permissionRoleRel) {
PermissionValue pv = AuthorizationRoleRel.buildPermissionValue(prr);
- pvs.add(pv);
+ permissionValueList.add(pv);
}
}
- return pr;
+
+ return result;
}
/**
ServiceContext ctx = this.getServiceContext();
String tenantId = ctx.getTenantId();
- PermissionRoleUtil.buildPermissionRoleRel(ctx, pr, subject, prrl, handleDelete, tenantId);
+ try {
+ PermissionRoleUtil.buildPermissionRoleRel(ctx, pr, subject, prrl, handleDelete, tenantId);
+ } catch (DocumentNotFoundException dnf) {
+ String msg = String.format("The following perm-role payload references permissions and/or roles that do not exist: \n%s",
+ JaxbUtils.toString(pr, PermissionRole.class));
+ throw new DocumentException(msg);
+ }
}
/* (non-Javadoc)
final public static String Q_RESOURCE_NAME = "res";
final public static String Q_ACTION_GROUP = "actGrp";
+
+ final public static String ID = "csid";
+ final public static String TENANT_ID = "tenant_id";
final public static String RESOURCE_NAME = "resourceName";
final public static String ACTION_GROUP = "actionGroup";
public static final String PERMREL_ROLE_ID = "roleId";
package org.collectionspace.services.authorization.storage;
/**
- * RoleStorageConstants declares query params, etc.
+ * RoleStorageConstants declares JPA query params, etc. See JAX-B file roles.xsd for details
* @author
*/
public class RoleStorageConstants {
final public static String Q_ROLE_NAME = "r";
final public static String ROLE_NAME = "roleName";
+ final public static String ROLE_ID = "csid";
+ final public static String ROLE_TENANT_ID = "tenant_id";
final public static String PERM_ROLE_REL_ROLE_ID = "roleId";
final public static String PERM_ROLE_REL_PERM_ID = "permissionId";
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.document.DocumentFilter;
import org.collectionspace.services.common.document.DocumentHandler;
+import org.collectionspace.services.common.storage.TransactionContext;
import org.collectionspace.services.common.storage.jpa.JPATransactionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
-@SuppressWarnings({ "unchecked", "rawtypes" })
-public abstract class SecurityResourceBase extends AbstractCollectionSpaceResourceImpl {
+@SuppressWarnings("rawtypes")
+public abstract class SecurityResourceBase<IT, OT> extends AbstractCollectionSpaceResourceImpl<IT, OT> {
- final Logger logger = LoggerFactory.getLogger(SecurityResourceBase.class);
+ @SuppressWarnings("hiding")
+ final Logger logger = LoggerFactory.getLogger(SecurityResourceBase.class);
- public Response create(Object input) {
+ public Response create(IT input) {
+ Response response = null;
+
+ try {
+ ServiceContext<IT, OT> ctx = createServiceContext(input, input.getClass());
+ response = create(ctx, input);
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.POST_FAILED+"create in "+this.getClass().getName());
+ }
+
+ return response;
+ }
+
+ protected Response create(ServiceContext<IT, OT> ctx, IT input) {
Response response = null;
try {
- ServiceContext ctx = createServiceContext(input, input.getClass());
DocumentHandler handler = createDocumentHandler(ctx);
String csid = getStorageClient(ctx).create(ctx, handler);
UriBuilder path = UriBuilder.fromResource(this.getClass());
return response;
}
- public Response create(JPATransactionContext jpaTransactionContext, Object input) {
+ public Response create(JPATransactionContext jpaTransactionContext, IT input) {
Response response = null;
try {
- ServiceContext ctx = createServiceContext(jpaTransactionContext, input, input.getClass());
+ ServiceContext<IT, OT> ctx = createServiceContext(jpaTransactionContext, input, input.getClass());
DocumentHandler handler = createDocumentHandler(ctx);
String csid = getStorageClient(ctx).create(ctx, handler);
UriBuilder path = UriBuilder.fromResource(this.getClass());
return response;
}
- private ServiceContext createServiceContext(JPATransactionContext jpaTransactionContext, Object input,
+ private ServiceContext<IT, OT> createServiceContext(JPATransactionContext jpaTransactionContext, IT input,
Class<? extends Object> clazz) throws Exception {
- ServiceContext result = createServiceContext(input, clazz);
+ ServiceContext<IT, OT> result = createServiceContext(input, clazz);
if (jpaTransactionContext != null) {
result.setTransactionContext(jpaTransactionContext);
ensureCSID(csid, ServiceMessages.GET_FAILED + "csid");
Object result = null;
try {
- ServiceContext ctx = createServiceContext((Object) null, objectClass, ui);
+ ServiceContext<IT, OT> ctx = createServiceContext((IT) null, objectClass, ui);
DocumentHandler handler = createDocumentHandler(ctx);
getStorageClient(ctx).get(ctx, csid, handler);
result = ctx.getOutput();
return result;
}
- public Object get(JPATransactionContext jpaTransactionContext, String csid, Class objectClass) {
+ protected Object get(TransactionContext transactionContext, String csid, Class<?> objectClass) {
logger.debug("get with csid=" + csid);
+ JPATransactionContext jpaTransactionContext = (JPATransactionContext)transactionContext;
ensureCSID(csid, ServiceMessages.GET_FAILED + "csid");
Object result = null;
try {
- ServiceContext ctx = createServiceContext(jpaTransactionContext, (Object) null, objectClass);
+ ServiceContext<IT, OT> ctx = createServiceContext(jpaTransactionContext, (IT) null, objectClass);
DocumentHandler handler = createDocumentHandler(ctx);
getStorageClient(ctx).get(ctx, csid, handler);
result = ctx.getOutput();
public Object getList(UriInfo ui, Class objectClass) {
try {
- ServiceContext ctx = createServiceContext((Object) null, objectClass, ui);
+ ServiceContext<IT, OT> ctx = createServiceContext((IT) null, objectClass, ui);
DocumentHandler handler = createDocumentHandler(ctx);
MultivaluedMap<String, String> queryParams = (ui != null ? ui.getQueryParameters() : null);
DocumentFilter myFilter = handler.createDocumentFilter();
}
}
- public Object update(String csid, Object theUpdate, Class<?> objectClass) {
+ public Object update(String csid, IT theUpdate, Class<?> objectClass) {
return update((UriInfo)null, csid, theUpdate, objectClass);
}
- public Object update(UriInfo ui, String csid, Object theUpdate, Class objectClass) {
+ public Object update(UriInfo ui, String csid, IT theUpdate, Class objectClass) {
if (logger.isDebugEnabled()) {
logger.debug("updateRole with csid=" + csid);
}
ensureCSID(csid, ServiceMessages.PUT_FAILED + this.getClass().getName());
try {
- ServiceContext ctx = createServiceContext(theUpdate, objectClass, ui);
+ ServiceContext<IT, OT> ctx = createServiceContext(theUpdate, objectClass, ui);
DocumentHandler handler = createDocumentHandler(ctx);
getStorageClient(ctx).update(ctx, csid, handler);
return ctx.getOutput();
throw bigReThrow(e, ServiceMessages.PUT_FAILED, csid);
}
}
+
+ public Object update(ServiceContext<?, ?> parentCtx, UriInfo ui, String csid, IT theUpdate, Class objectClass) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("updateRole with csid=" + csid);
+ }
+ ensureCSID(csid, ServiceMessages.PUT_FAILED + this.getClass().getName());
+
+ try {
+ ServiceContext<IT, OT> ctx = createServiceContext(parentCtx, theUpdate, objectClass, ui);
+ DocumentHandler handler = createDocumentHandler(ctx);
+ getStorageClient(ctx).update(ctx, csid, handler);
+ return ctx.getOutput();
+ } catch (Exception e) {
+ throw bigReThrow(e, ServiceMessages.PUT_FAILED, csid);
+ }
+ }
+
+ protected ServiceContext<IT, OT> createServiceContext(
+ ServiceContext<?, ?> parentCtx,
+ IT input,
+ Class<?> theClass,
+ UriInfo uriInfo) throws Exception {
+ ServiceContext<IT, OT> ctx = createServiceContext(input, theClass, uriInfo);
+ JPATransactionContext parentTransactionContext = parentCtx != null ? (JPATransactionContext)parentCtx.getCurrentTransactionContext() : null;
+ //
+ // If the parent context has an active JPA connection then we'll use it.
+ //
+ if (parentTransactionContext != null) {
+ ctx.setTransactionContext(parentTransactionContext);
+ }
+
+ return ctx;
+ }
}
import java.util.List;
import java.util.Map;
import java.util.UUID;
-
import javax.naming.NamingException;
-import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
import org.collectionspace.authentication.AuthN;
import org.collectionspace.services.account.AccountListItem;
import org.collectionspace.services.authorization.perms.EffectType;
import org.collectionspace.services.authorization.perms.Permission;
import org.collectionspace.services.authorization.perms.PermissionAction;
-
+import org.collectionspace.services.client.PermissionClient;
import org.collectionspace.services.client.Profiler;
import org.collectionspace.services.client.RoleClient;
import org.collectionspace.services.client.workflow.WorkflowClient;
import org.collectionspace.services.common.config.ServiceConfigUtils;
import org.collectionspace.services.common.config.TenantBindingConfigReaderImpl;
import org.collectionspace.services.common.context.ServiceBindingUtils;
+import org.collectionspace.services.common.document.DocumentException;
import org.collectionspace.services.common.document.DocumentHandler;
import org.collectionspace.services.common.security.SecurityUtils;
import org.collectionspace.services.common.storage.DatabaseProductType;
//import org.mortbay.log.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.security.acls.model.AlreadyExistsException;
public class AuthorizationCommon {
// For token generation and password reset
//
final private static String DEFAULT_PASSWORD_RESET_EMAIL_MESSAGE = "Hello {{greeting}},\n\r\n\rYou've started the process to reset your CollectionSpace account password. To finish resetting your password, go to the Reset Password page {{link}} on CollectionSpace.\n\r\n\rIf clicking the link doesn't work, copy and paste the following link into your browser address bar and click Go.\n\r\n\r{{link}}\n\r Thanks,\n\r\n\r CollectionSpace Administrator\n\r\n\rPlease do not reply to this email. This mailbox is not monitored and you will not receive a response. For assistance, contact your CollectionSpace Administrator directly.";
- final private static String tokensalt = "74102328UserDetailsReset";
- final private static int TIME_SCALAR = 100000;
private static final String DEFAULT_PASSWORD_RESET_EMAIL_SUBJECT = "Password reset for CollectionSpace account";
//
// ActionGroup labels/constants
//
- // for READ-WRITE
+ // for READ-WRITE-DELETE
final public static String ACTIONGROUP_CRUDL_NAME = "CRUDL";
final public static ActionType[] ACTIONSET_CRUDL = {ActionType.CREATE, ActionType.READ, ActionType.UPDATE, ActionType.DELETE, ActionType.SEARCH};
+ // for READ-WRITE
+ final public static String ACTIONGROUP_CRUL_NAME = "CRUL";
+ final public static ActionType[] ACTIONSET_CRUL = {ActionType.CREATE, ActionType.READ, ActionType.UPDATE, ActionType.SEARCH};
// for READ-ONLY
final public static String ACTIONGROUP_RL_NAME = "RL";
final public static ActionType[] ACTIONSET_RL = {ActionType.READ, ActionType.SEARCH};
static ActionGroup ACTIONGROUP_CRUDL;
+ static ActionGroup ACTIONGROUP_CRUL;
static ActionGroup ACTIONGROUP_RL;
// A static block to initialize the predefined action groups
ACTIONGROUP_RL = new ActionGroup();
ACTIONGROUP_RL.name = ACTIONGROUP_RL_NAME;
ACTIONGROUP_RL.actions = ACTIONSET_RL;
-
+ // For read-write
+ ACTIONGROUP_CRUL = new ActionGroup();
+ ACTIONGROUP_CRUL.name = ACTIONGROUP_CRUL_NAME;
+ ACTIONGROUP_CRUL.actions = ACTIONSET_CRUL;
}
final static Logger logger = LoggerFactory.getLogger(AuthorizationCommon.class);
public static String setTenantConfigMD5Hash(String tenantId, String md5hash) {
return tenantConfigMD5HashTable.put(tenantId, md5hash);
}
-
- @Deprecated
- public static Role xgetRole(String tenantId, String displayName) {
- Role role = null;
-
- String roleName = AuthorizationCommon.getQualifiedRoleName(tenantId, displayName);
- //role = AuthorizationStore.getRoleByName(roleName, tenantId);
-
- return role;
- }
-
+
public static Role getRole(JPATransactionContext jpaTransactionContext, String tenantId, String displayName) {
Role role = null;
return role;
}
-
- public static Role createRole(String tenantId, String name, String description) {
- return createRole(tenantId, name, description, false /* mutable by default */);
- }
-
+ /**
+ * Create a new role instance to be persisted later.
+ *
+ * @param tenantId
+ * @param name
+ * @param description
+ * @param immutable
+ * @return
+ */
public static Role createRole(String tenantId, String name, String description, boolean immutable) {
Role role = new Role();
* with assumption that resource is of type URI
* @param permission configuration
*/
- public static void addPermissionsForUri(Permission perm,
+ public static void addPermissionsForUri(JPATransactionContext jpaTransactionContext,
+ Permission perm,
PermissionRole permRole) throws PermissionException {
//
// First check the integrity of the incoming arguments.
resources.add(uriRes);
}
AuthZ.get().addPermissions(resources.toArray(new CSpaceResource[0]), principals.toArray(new String[0]), grant); // CSPACE-4967
+ jpaTransactionContext.setAclTablesUpdateFlag(true); // Tell the containing JPA transaction that we've committed changes to the Spring Tables
}
private static Connection getConnection(String databaseName) throws NamingException, SQLException {
result = ACTIONGROUP_CRUDL;
} else if (actionGroupStr.equalsIgnoreCase(ACTIONGROUP_RL_NAME)) {
result = ACTIONGROUP_RL;
+ } else if (actionGroupStr.equalsIgnoreCase(ACTIONGROUP_CRUL_NAME)) {
+ result = ACTIONGROUP_CRUL;
}
return result;
public static Permission createPermission(String tenantId,
String resourceName,
String description,
- String actionGroupStr) {
+ String actionGroupStr,
+ boolean immutable) {
Permission result = null;
ActionGroup actionGroup = getActionGroup(actionGroupStr);
- result = createPermission(tenantId, resourceName, description, actionGroup);
+ result = createPermission(tenantId, resourceName, description, actionGroup, immutable);
return result;
}
private static Permission createPermission(String tenantId,
String resourceName,
String description,
- ActionGroup actionGroup) {
+ ActionGroup actionGroup,
+ boolean immutable) {
String id = tenantId
+ "-" + resourceName.replace('/', '_') // Remove the slashes so the ID can be used in a URI/URL
+ "-" + actionGroup.name;
pas.add(permAction);
}
+ if (immutable) {
+ perm.setMetadataProtection(PermissionClient.IMMUTABLE);
+ perm.setActionsProtection(PermissionClient.IMMUTABLE);
+ }
+
return perm;
}
private static Permission createWorkflowPermission(TenantBindingType tenantBinding,
ServiceBindingType serviceBinding,
String transitionVerb,
- ActionGroup actionGroup)
+ ActionGroup actionGroup,
+ boolean immutable)
{
Permission result = null;
String workFlowServiceSuffix;
+ workFlowServiceSuffix
+ transitionName;
String description = "A generated workflow permission for actiongroup " + actionGroup.name;
- result = createPermission(tenantId, resourceName, description, actionGroup);
+ result = createPermission(tenantId, resourceName, description, actionGroup, immutable);
if (logger.isDebugEnabled() == true) {
logger.debug("Generated a workflow permission: "
private static PermissionRole createPermissionRole(
Permission permission,
Role role,
- boolean enforceTenancy) throws Exception
+ boolean enforceTenancy) throws DocumentException
{
PermissionRole permRole = new PermissionRole();
+
+ //
// Check to see if the tenant ID of the permission and the tenant ID of the role match
+ //
boolean tenantIdsMatch = role.getTenantId().equalsIgnoreCase(permission.getTenantId());
if (tenantIdsMatch == false && enforceTenancy == false) {
tenantIdsMatch = true; // If we don't need to enforce tenancy then we'll just consider them matched.
}
-
+
if (tenantIdsMatch == true) {
permRole.setSubject(SubjectType.ROLE);
//
} else {
String errMsg = "The tenant ID of the role: " + role.getTenantId()
+ " did not match the tenant ID of the permission: " + permission.getTenantId();
- throw new Exception(errMsg);
+ throw new DocumentException(errMsg);
}
return permRole;
}
- private static Hashtable<String, String> getTenantNamesFromConfig(TenantBindingConfigReaderImpl tenantBindingConfigReader) {
+ private static Hashtable<String, String> getTenantNamesFromConfig(TenantBindingConfigReaderImpl tenantBindingConfigReader) {
// Note that this only handles tenants not marked as "createDisabled"
Hashtable<String, TenantBindingType> tenantBindings =
}
}
-
+ /**
+ * Creates the default Admin and Reader roles for all the configured tenants.
+ *
+ * Returns the CSID of the Spring Admin role.
+ *
+ * @param conn
+ * @param tenantInfo
+ * @param tenantAdminRoleCSIDs
+ * @param tenantReaderRoleCSIDs
+ * @return
+ * @throws SQLException
+ * @throws Exception
+ */
private static String findOrCreateDefaultRoles(Connection conn, Hashtable<String, String> tenantInfo,
Hashtable<String, String> tenantAdminRoleCSIDs, Hashtable<String, String> tenantReaderRoleCSIDs)
throws SQLException, Exception {
- // Fifth, fetch and save the default roles
+
String springAdminRoleCSID = null;
Statement stmt = null;
PreparedStatement pstmt = null;
try {
- final String querySpringRole =
- "SELECT csid from roles WHERE rolename='"+AuthN.ROLE_SPRING_ADMIN_NAME+"'";
+ //
+ // Look for the Spring Security admin role. If not found, create it.
+ //
+ final String querySpringRole = String.format("SELECT csid from roles WHERE rolename='%s'", AuthN.ROLE_SPRING_ADMIN_NAME);
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(querySpringRole);
- if(rs.next()) {
+ if (rs.next()) {
springAdminRoleCSID = rs.getString(1);
if (logger.isDebugEnabled()) {
- logger.debug("createDefaultAccounts found Spring Admin role: "
- +springAdminRoleCSID);
+ logger.debug("createDefaultAccounts found Spring Admin role: " + springAdminRoleCSID);
}
} else {
- final String insertSpringAdminRoleSQL =
- "INSERT INTO roles (csid, rolename, displayName, rolegroup, created_at, tenant_id) "
- + "VALUES ('-1', 'ROLE_SPRING_ADMIN', 'SPRING_ADMIN', 'Spring Security Administrator', now(), '0')";
+ final String insertSpringAdminRoleSQL = String.format(
+ "INSERT INTO roles (csid, rolename, displayName, rolegroup, created_at, tenant_id) VALUES ('%s', '%s', '%s', '%s', now(), '%s')",
+ AuthN.ROLE_SPRING_ADMIN_ID, AuthN.ROLE_SPRING_ADMIN_NAME, AuthN.SPRING_ADMIN_USER, AuthN.ROLE_SPRING_GROUP_NAME, AuthN.ADMIN_TENANT_ID);
stmt.executeUpdate(insertSpringAdminRoleSQL);
- springAdminRoleCSID = "-1";
- if (logger.isDebugEnabled()) {
- logger.debug("createDefaultAccounts CREATED Spring Admin role: "
- +springAdminRoleCSID);
- }
+ springAdminRoleCSID = AuthN.ROLE_SPRING_ADMIN_ID;
}
rs.close();
- final String getRoleCSIDSql =
- "SELECT csid from roles WHERE tenant_id=? and rolename=?";
- pstmt = conn.prepareStatement(getRoleCSIDSql); // create a statement
rs = null;
- for(String tId : tenantInfo.keySet()) {
- pstmt.setString(1, tId); // set tenant_id param
- pstmt.setString(2, getDefaultAdminRole(tId)); // set rolename param
+
+ //
+ // Look for and save each tenants default Admin and Reader roles
+ //
+ final String getRoleCSIDSql = "SELECT csid from roles WHERE tenant_id=? and rolename=?";
+ pstmt = conn.prepareStatement(getRoleCSIDSql); // create a statement
+ for (String tenantId : tenantInfo.keySet()) {
+ //
+ // Look for the default Admin role
+ //
+ pstmt.setString(1, tenantId);
+ pstmt.setString(2, getDefaultAdminRole(tenantId));
rs = pstmt.executeQuery();
// extract data from the ResultSet
- if(!rs.next()) {
- throw new RuntimeException("Cannot find role: "+getDefaultAdminRole(tId)
- +" for tenant id: "+tId+" in roles!");
- }
- String tenantAdminRoleCSID = rs.getString(1);
- if (logger.isDebugEnabled()) {
- logger.debug("createDefaultAccounts found role: "
- +getDefaultAdminRole(tId)+"("+tenantAdminRoleCSID
- +") for tenant id: "+tId);
+ if (!rs.next()) {
+ throw new RuntimeException("Cannot find role: " + getDefaultAdminRole(tenantId)
+ + " for tenant id: " + tenantId + " in roles!");
}
- tenantAdminRoleCSIDs.put(tId, tenantAdminRoleCSID);
- pstmt.setString(1, tId); // set tenant_id param
- pstmt.setString(2, getDefaultReaderRole(tId)); // set rolename param
+ String tenantAdminRoleCSID = rs.getString(1); // First column (#1) is the CSID
+ tenantAdminRoleCSIDs.put(tenantId, tenantAdminRoleCSID);
rs.close();
+ rs = null;
+ //
+ // Look for the default Reader role
+ //
+ pstmt.setString(1, tenantId); // set tenant_id param
+ pstmt.setString(2, getDefaultReaderRole(tenantId)); // set rolename param
rs = pstmt.executeQuery();
// extract data from the ResultSet
- if(!rs.next()) {
- throw new RuntimeException("Cannot find role: "+getDefaultReaderRole(tId)
- +" for tenant id: "+tId+" in roles!");
+ if (!rs.next()) {
+ throw new RuntimeException("Cannot find role: " + getDefaultReaderRole(tenantId)
+ + " for tenant id: " + tenantId + " in roles!");
}
String tenantReaderRoleCSID = rs.getString(1);
- if (logger.isDebugEnabled()) {
- logger.debug("createDefaultAccounts found role: "
- +getDefaultReaderRole(tId)+"("+tenantReaderRoleCSID
- +") for tenant id: "+tId);
- }
- tenantReaderRoleCSIDs.put(tId, tenantReaderRoleCSID);
+ tenantReaderRoleCSIDs.put(tenantId, tenantReaderRoleCSID);
rs.close();
}
pstmt.close();
} catch(Exception e) {
throw e;
} finally {
- if(stmt!=null)
- stmt.close();
- if(pstmt!=null)
- pstmt.close();
+ if (stmt != null) stmt.close();
+ if (pstmt != null) pstmt.close();
}
+
return springAdminRoleCSID;
}
PreparedStatement pstmt = null;
try {
String insertAccountRoleSQL;
- if (databaseProductType == DatabaseProductType.MYSQL) {
- insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_MYSQL;
- } else if (databaseProductType == DatabaseProductType.POSTGRESQL) {
+ if (databaseProductType == DatabaseProductType.POSTGRESQL) {
insertAccountRoleSQL = INSERT_ACCOUNT_ROLE_SQL_POSTGRES;
} else {
throw new Exception("Unrecognized database system.");
}
- if (logger.isDebugEnabled()) {
- logger.debug("createDefaultAccounts binding accounts to roles with SQL:\n"
- +insertAccountRoleSQL);
- }
+
pstmt = conn.prepareStatement(insertAccountRoleSQL); // create a statement
- for(String tId : tenantInfo.keySet()) {
- String adminUserId = getDefaultAdminUserID(tenantInfo.get(tId));
- if(!usersInRepo.contains(adminUserId)) {
+ for (String tId : tenantInfo.keySet()) {
+ String adminUserId = getDefaultAdminUserID(tenantInfo.get(tId));
+ if (!usersInRepo.contains(adminUserId)) {
String adminAcct = tenantAdminAcctCSIDs.get(tId);
String adminRoleId = tenantAdminRoleCSIDs.get(tId);
pstmt.setString(1, adminAcct); // set acct CSID param
pstmt.setString(2, adminUserId); // set user_id param
pstmt.setString(3, adminRoleId); // set role_id param
pstmt.setString(4, getDefaultAdminRole(tId)); // set rolename param
- if (logger.isDebugEnabled()) {
- logger.debug("createDefaultAccounts binding account: "
- +adminUserId+" to Admin role("+adminRoleId
- +") for tenant id: "+tId);
- }
pstmt.executeUpdate();
+ //
// Now add the Spring Admin Role to the admin accounts
+ //
pstmt.setString(3, springAdminRoleCSID); // set role_id param
pstmt.setString(4, AuthN.ROLE_SPRING_ADMIN_NAME); // set rolename param
- if (logger.isDebugEnabled()) {
- logger.debug("createDefaultAccounts binding account: "
- +adminUserId+" to Spring Admin role: "+springAdminRoleCSID);
- }
pstmt.executeUpdate();
}
String readerUserId = getDefaultReaderUserID(tenantInfo.get(tId));
- if(!usersInRepo.contains(readerUserId)) {
+ if (!usersInRepo.contains(readerUserId)) {
String readerAcct = tenantReaderAcctCSIDs.get(tId);
String readerRoleId = tenantReaderRoleCSIDs.get(tId);
pstmt.setString(1, readerAcct); // set acct CSID param
pstmt.setString(2, readerUserId); // set user_id param
pstmt.setString(3, readerRoleId); // set role_id param
pstmt.setString(4, getDefaultReaderRole(tId)); // set rolename param
- if (logger.isDebugEnabled()) {
- logger.debug("createDefaultAccounts binding account: "
- +readerUserId+" to Reader role("+readerRoleId
- +") for tenant id: "+tId);
- }
pstmt.executeUpdate();
}
}
} catch(Exception e) {
throw e;
} finally {
- if(pstmt!=null)
+ if (pstmt!=null) {
pstmt.close();
+ }
}
}
pstmt.setString(2, tenantManagerUserID); // set user_id param
pstmt.setString(3, tenantManagerRoleID); // set role_id param
pstmt.setString(4, tenantManagerRoleName); // set rolename param
- if (logger.isDebugEnabled()) {
- logger.debug("bindTenantManagerAccountRole binding user: "
- +tenantManagerUserID+" to Admin role("+tenantManagerRoleName+")");
- }
pstmt.executeUpdate();
+
/* At this point, tenant manager should not need the Spring Admin Role
- pstmt.setString(3, springAdminRoleCSID); // set role_id param
- pstmt.setString(4, SPRING_ADMIN_ROLE); // set rolename param
- if (logger.isDebugEnabled()) {
- logger.debug("createDefaultAccounts binding account: "
- +adminUserId+" to Spring Admin role: "+springAdminRoleCSID);
- }
- pstmt.executeUpdate();
+ pstmt.setString(3, springAdminRoleCSID); // set role_id param
+ pstmt.setString(4, SPRING_ADMIN_ROLE); // set rolename param
+ if (logger.isDebugEnabled()) {
+ logger.debug("createDefaultAccounts binding account: "
+ +adminUserId+" to Spring Admin role: "+springAdminRoleCSID);
+ }
+ pstmt.executeUpdate();
*/
+
pstmt.close();
} catch(Exception e) {
throw e;
throw e;
} finally {
try {
- if (conn != null)
+ if (conn != null) {
conn.close();
+ }
} catch (SQLException sqle) {
if (logger.isDebugEnabled()) {
logger.debug("SQL Exception closing statement/connection: " + sqle.getLocalizedMessage());
tenantAdminAcctCSIDs, tenantReaderAcctCSIDs);
boolean createdTenantMgrAccount = findOrCreateTenantManagerUserAndAccount(conn);
- if(createdTenantMgrAccount) {
+ if (createdTenantMgrAccount) {
// If we created the account, we need to create the bindings. Otherwise, assume they
// are all set (from previous initialization).
String tenantManagerRoleCSID = findTenantManagerRole(conn);
throw e;
} finally {
try {
- if (conn != null)
+ if (conn != null) {
conn.close();
+ }
} catch (SQLException sqle) {
if (logger.isDebugEnabled()) {
logger.debug("SQL Exception closing statement/connection: " + sqle.getLocalizedMessage());
}
private static String getDefaultAdminRole(String tenantId) {
- return ROLE_PREFIX+tenantId+TENANT_ADMIN_ROLE_SUFFIX;
+ return ROLE_PREFIX + tenantId + TENANT_ADMIN_ROLE_SUFFIX;
}
private static String getDefaultReaderRole(String tenantId) {
}
private static String getDefaultAdminUserID(String tenantName) {
- return TENANT_ADMIN_ACCT_PREFIX+tenantName;
+ return TENANT_ADMIN_ACCT_PREFIX + tenantName;
}
private static String getDefaultReaderUserID(String tenantName) {
- return TENANT_READER_ACCT_PREFIX+tenantName;
+ return TENANT_READER_ACCT_PREFIX + tenantName;
}
- static public PermissionAction createPermissionAction(Permission perm,
+ static private PermissionAction createPermissionAction(Permission perm,
ActionType actionType) {
PermissionAction pa = new PermissionAction();
return pa;
}
-
- static public PermissionAction update(Permission perm, PermissionAction permAction) {
- PermissionAction pa = new PermissionAction();
-
- CSpaceAction action = URIResourceImpl.getAction(permAction.getName());
- URIResourceImpl uriRes = new URIResourceImpl(perm.getTenantId(),
- perm.getResourceName(), action);
- pa.setObjectIdentity(uriRes.getHashedId().toString());
- pa.setObjectIdentityResource(uriRes.getId());
-
- return pa;
- }
private static HashSet<String> getTransitionVerbList(TenantBindingType tenantBinding, ServiceBindingType serviceBinding) {
HashSet<String> result = new HashSet<String>();
TransitionDefList result = null;
try {
String serviceObjectName = serviceBinding.getObject().getName();
- DocumentHandler docHandler = ServiceConfigUtils.createDocumentHandlerInstance(
+
+ @SuppressWarnings("rawtypes")
+ DocumentHandler docHandler = ServiceConfigUtils.createDocumentHandlerInstance(
tenantBinding, serviceBinding);
Lifecycle lifecycle = docHandler.getLifecycle(serviceObjectName);
if (lifecycle != null) {
}
/**
+ * Creates the immutable workflow permission sets for the default admin and reader roles.
*
* @param tenantBindingConfigReader
* @param databaseProductType
JPATransactionContext jpaTransactionContext,
TenantBindingConfigReaderImpl tenantBindingConfigReader,
DatabaseProductType databaseProductType,
- String cspaceDatabaseName) throws Exception //FIXME: REM - 4/11/2012 - Rename to createWorkflowPermissions
+ String cspaceDatabaseName) throws Exception
{
java.util.logging.Logger logger = java.util.logging.Logger.getAnonymousLogger();
if (prop == null ? true : Boolean.parseBoolean(prop)) {
try {
jpaTransactionContext.beginTransaction();
- TransitionDefList transitionDefList = getTransitionDefList(tenantBinding, serviceBinding);
HashSet<String> transitionVerbList = getTransitionVerbList(tenantBinding, serviceBinding);
for (String transitionVerb : transitionVerbList) {
//
// Create the permission for the admin role
- Permission adminPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionVerb, ACTIONGROUP_CRUDL);
+ Permission adminPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionVerb, ACTIONGROUP_CRUDL, true);
persist(jpaTransactionContext, adminPerm, adminRole, true, ACTIONGROUP_CRUDL);
//
// Create the permission for the read-only role
- Permission readonlyPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionVerb, ACTIONGROUP_RL);
+ Permission readonlyPerm = createWorkflowPermission(tenantBinding, serviceBinding, transitionVerb, ACTIONGROUP_RL, true);
persist(jpaTransactionContext, readonlyPerm, readonlyRole, true, ACTIONGROUP_RL); // Persist/store the permission and permrole records and related Spring Security info
}
jpaTransactionContext.commitTransaction();
public static String getPersistedMD5Hash(String tenantId, String cspaceDatabaseName) throws Exception {
String result = null;
- ArrayList<String> existingTenants = new ArrayList<String>();
// First find or create the tenants
final String queryTenantSQL = String.format("SELECT id, name, config_md5hash FROM tenants WHERE id = '%s'", tenantId);
Profiler profiler = new Profiler(AuthorizationCommon.class, 2);
profiler.start();
// Add a corresponding entry in the Spring Security Tables
- addPermissionsForUri(permission, permRole);
+ addPermissionsForUri(jpaTransactionContext, permission, permRole);
profiler.stop();
logger.debug("Finished full perm generation for "
+ ":" + permission.getTenantId()
import org.collectionspace.authentication.AuthN;
import org.collectionspace.services.authorization.AccountRoleRel;
import org.collectionspace.services.authorization.PermissionValue;
+import org.collectionspace.services.authorization.Role;
import org.collectionspace.services.authorization.RoleValue;
public class AuthorizationRoleRel {
return av;
}
+ /**
+ * Builds the role value.
+ *
+ * @param arr the arr
+ * @return the role account value
+ */
+ static public RoleValue buildRoleValue(Role role) {
+ RoleValue rv = null;
+
+ rv = new RoleValue();
+ rv.setRoleId(role.getCsid());
+ rv.setRoleName(role.getRoleName());
+ rv.setDisplayName(role.getDisplayName());
+ rv.setTenantId(role.getTenantId());
+
+ return rv;
+ }
+
/**
* Builds the role value.
*
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
-import javax.persistence.EntityManager;
-import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import org.collectionspace.services.common.document.DocumentException;
import org.collectionspace.services.common.document.DocumentNotFoundException;
-import org.collectionspace.services.common.document.TransactionException;
+import org.collectionspace.services.common.document.JaxbUtils;
+import org.collectionspace.services.common.api.Tools;
import org.collectionspace.services.common.context.ServiceContext;
import org.collectionspace.services.common.context.ServiceContextProperties;
import org.collectionspace.services.common.storage.jpa.JPATransactionContext;
import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
+import org.collectionspace.services.client.RoleClient;
+import org.collectionspace.authentication.AuthN;
+
import org.collectionspace.services.authorization.perms.ActionType;
import org.collectionspace.services.authorization.perms.EffectType;
import org.collectionspace.services.authorization.perms.Permission;
import org.collectionspace.services.authorization.perms.PermissionAction;
import org.collectionspace.services.authorization.storage.PermissionStorageConstants;
+import org.collectionspace.services.authorization.storage.RoleStorageConstants;
import org.collectionspace.services.authorization.PermissionResource;
import org.collectionspace.services.authorization.PermissionRole;
import org.collectionspace.services.authorization.PermissionRoleRel;
import org.collectionspace.services.authorization.PermissionValue;
+import org.collectionspace.services.authorization.Role;
import org.collectionspace.services.authorization.RoleValue;
import org.collectionspace.services.authorization.SubjectType;
* @param ctx the ctx
* @return the relation subject
*/
- static public SubjectType getRelationSubject(ServiceContext ctx) {
+ static public SubjectType getRelationSubject(ServiceContext<?, ?> ctx) {
Object o = ctx.getProperty(ServiceContextProperties.SUBJECT);
if (o == null) {
throw new IllegalArgumentException(ServiceContextProperties.SUBJECT
* @param pr the pr
* @return the relation subject
*/
- static public SubjectType getRelationSubject(ServiceContext ctx, PermissionRole pr) {
+ static public SubjectType getRelationSubject(ServiceContext<?, ?> ctx, PermissionRole pr) {
SubjectType subject = pr.getSubject();
if (subject == null) {
//it is not required to give subject as URI determines the subject
*
* @param pr permissionrole
* @param subject the subject
- * @param prrl persistent entities built are inserted into this list
+ * @param permRoleRelationshipList persistent entities built are inserted into this list
* @param toDelete the to delete
*/
static public void buildPermissionRoleRel(JPATransactionContext jpaTransactionContext,
PermissionRole pr,
SubjectType subject,
- List<PermissionRoleRel> prrl,
+ List<PermissionRoleRel> permRoleRelationshipList,
boolean handleDelete,
String tenantId) throws Exception {
if (subject.equals(SubjectType.ROLE)) {
List<PermissionValue> permissionValues = pr.getPermission();
- if (permissionValues != null && permissionValues.size() > 0) {
+ if (permissionValues != null && permissionValues.size() == 1) {
PermissionValue pv = permissionValues.get(0);
for (RoleValue rv : pr.getRole()) {
- PermissionRoleRel prr = buildPermissonRoleRel(jpaTransactionContext, pv, rv, subject, handleDelete, tenantId);
- prrl.add(prr);
+ PermissionRoleRel permRoleRelationship = buildPermissonRoleRel(jpaTransactionContext, pv, rv, subject, handleDelete, tenantId);
+ permRoleRelationshipList.add(permRoleRelationship);
}
+ } else {
+ String msg = "There must be one and only one Permission supplied in the payload when creating this Permission-Roles relationshiop.";
+ throw new DocumentException(msg);
}
} else if (subject.equals(SubjectType.PERMISSION)) {
List<RoleValue> roleValues = pr.getRole();
- if (roleValues != null && roleValues.size() > 0) {
+ if (roleValues != null && roleValues.size() == 1) {
RoleValue rv = roleValues.get(0);
for (PermissionValue pv : pr.getPermission()) {
PermissionRoleRel prr = buildPermissonRoleRel(jpaTransactionContext, pv, rv, subject, handleDelete, tenantId);
- prrl.add(prr);
+ permRoleRelationshipList.add(prr);
}
+ } else {
+ String msg = "There must be one and only one Role supplied in the payload when creating this Role-Permissions relationshiop.";
+ throw new DocumentException(msg);
}
}
}
static public void buildPermissionRoleRel(
- ServiceContext ctx,
+ ServiceContext<?, ?> ctx,
PermissionRole pr,
SubjectType subject,
List<PermissionRoleRel> prrl,
* Try to find a persisted Permission record using a PermissionValue instance.
*
*/
- static private Permission lookupPermission(JPATransactionContext jpaTransactionContext, PermissionValue permissionValue, String tenantId) throws TransactionException {
+ static private Permission lookupPermission(JPATransactionContext jpaTransactionContext, PermissionValue permissionValue, String tenantId) throws DocumentException {
Permission result = null;
String actionGroup = permissionValue.getActionGroup() != null ? permissionValue.getActionGroup().trim() : null;
//
if (permissionId != null && !permissionId.isEmpty()) {
try {
- result = (Permission)JpaStorageUtils.getEntity(jpaTransactionContext, permissionId, Permission.class);
+ result = (Permission)JpaStorageUtils.getEntityByDualKeys(
+ jpaTransactionContext,
+ Permission.class.getName(),
+ PermissionStorageConstants.ID, permissionId,
+ PermissionStorageConstants.TENANT_ID, tenantId);
} catch (Throwable e) {
String msg = String.format("Searched for but couldn't find a permission with CSID='%s'.",
permissionId);
logger.trace(msg);
}
- } else if ((resourceName != null && !resourceName.isEmpty()) &&
- (actionGroup != null && !actionGroup.isEmpty())) {
+ } else if (Tools.notBlank(resourceName) && Tools.notBlank(actionGroup)) {
//
// If there was no permission ID, then we can try to find the permission with the resource name and action group tuple
//
try {
- result = (Permission)JpaStorageUtils.getEntityByDualKeys(jpaTransactionContext,
+ result = (Permission)JpaStorageUtils.getEntityByDualKeys(
+ jpaTransactionContext,
Permission.class.getName(),
PermissionStorageConstants.RESOURCE_NAME, permissionValue.getResourceName(),
PermissionStorageConstants.ACTION_GROUP, permissionValue.getActionGroup(),
} else {
String errMsg = String.format("Couldn't perform lookup of permission. Not enough information provided. Lookups requires a permission CSID or a resource name and action group tuple. The provided information was permission ID='%s', resourceName='%s', and actionGroup='%s'.",
permissionId, resourceName, actionGroup);
- logger.warn(errMsg);
+ throw new DocumentException(errMsg);
+ }
+
+ if (result == null) {
+ throw new DocumentNotFoundException(String.format("Could not find Permission resource with CSID='%s', actionGroup='%s', resourceName='%s'.",
+ permissionId, actionGroup, resourceName));
}
return result;
}
+ /**
+ * Ensure the Role's permission relationships can be changed.
+ *
+ * @param role
+ * @return
+ */
+ static private boolean canRoleRelatedTo(Role role) {
+ boolean result = true;
+
+ if (RoleClient.IMMUTABLE.equals(role.getPermsProtection()) && !AuthN.get().isSystemAdmin()) {
+ result = false;
+ }
+
+ return result;
+ }
/**
* Builds a permisson role relationship for either 'create' or 'delete'
String tenantId) throws DocumentException {
PermissionRoleRel result = null;
+ Role role = lookupRole(jpaTransactionContext, roleValue, tenantId);
+ //
+ // Ensure we can change the Role's permissions-related relationships.
+ //
+ if (canRoleRelatedTo(role) == false) {
+ String msg = String.format("Role with CSID='%s' cannot have its associated permissions changed.", role.getCsid());
+ throw new DocumentException(msg);
+ }
+ //
+ // Get the permission info
+ //
Permission permission = lookupPermission(jpaTransactionContext, permissionValue, tenantId);
-
//
// If we couldn't find an existing permission and we're not processing a DELETE request, we need to create
// a new permission.
String errMsg = "Could not create new permission for new permission-role relationship.";
throw new DocumentException(errMsg);
}
+ } else if (permission == null && handleDelete == true) {
+ String msg = String.format("Could not find an existing permission that matches this: %s",
+ JaxbUtils.toString(permissionValue, PermissionValue.class));
+ throw new DocumentException(msg);
}
//
return result;
}
+
+ public static RoleValue fetchRoleValue(ServiceContext<?, ?> ctx, String roleId) throws DocumentNotFoundException {
+ RoleValue result = null;
+
+ JPATransactionContext jpaTransactionContext = (JPATransactionContext) ctx.getCurrentTransactionContext();
+ Role role = lookupRole(jpaTransactionContext, roleId, ctx.getTenantId());
+ result = AuthorizationRoleRel.buildRoleValue(role);
+
+ return result;
+ }
- private static Permission createPermission(JPATransactionContext jpaTransactionContext, Permission permission) {
+ private static Role lookupRole(JPATransactionContext jpaTransactionContext, RoleValue roleValue, String tenantId) throws DocumentNotFoundException {
+ return lookupRole(jpaTransactionContext, roleValue.getRoleId(), tenantId);
+ }
+
+ private static Role lookupRole(JPATransactionContext jpaTransactionContext, String roleId, String tenantId) throws DocumentNotFoundException {
+ Role result = null;
+
+ try {
+ result = (Role)JpaStorageUtils.getEntityByDualKeys(
+ jpaTransactionContext,
+ Role.class.getName(),
+ RoleStorageConstants.ROLE_ID, roleId,
+ RoleStorageConstants.ROLE_TENANT_ID, tenantId);
+ } catch (Throwable e) {
+ String msg = String.format("Searched for but couldn't find a role with CSID='%s'.",
+ roleId);
+ logger.trace(msg);
+ }
+
+ if (result == null) {
+ String msg = String.format("Could not find Role resource with CSID='%s'", roleId);
+ throw new DocumentNotFoundException(msg);
+ }
+
+ return result;
+ }
+
+
+ private static Permission createPermission(JPATransactionContext jpaTransactionContext, Permission permission) {
Permission result = null;
PermissionResource permissionResource = new PermissionResource(); // Get the PermissionResource singleton instance (RESTEasy ensures it is a singleton)
return result;
}
+
+ static public boolean isEmpty(PermissionRole permRole) {
+ boolean result = true;
+
+ if (permRole != null && !Tools.isEmpty(permRole.getPermission())
+ && !Tools.isEmpty(permRole.getRole()) && permRole.getSubject() != null) {
+ result = false;
+ }
+
+ return result;
+ }
/**
* Checks if is invalid tenant.
/** The logger. */
final Logger logger = LoggerFactory.getLogger(RemoteServiceContextImpl.class);
+
//input stores original content as received over the wire
/** The input. */
private IT input;
*/
@Override
public void setInput(IT input) {
- //for security reasons, do not allow to set input again (from handlers)
- if (this.input != null) {
- String msg = "Resetting or changing an context's input is not allowed.";
- logger.error(msg);
- throw new IllegalStateException(msg);
- }
+ if (logger.isDebugEnabled()) {
+ if (this.input != null) {
+ String msg = "\n#\n# Resetting or changing an context's input is not advised.\n#";
+ logger.warn(msg);
+ }
+ }
this.input = input;
}
* @return
* @throws Exception
*/
- public CollectionSpaceResource<IT, OT> getResource(ServiceContext<?, ?> ctx) throws Exception {
+ @SuppressWarnings("unchecked")
+ public CollectionSpaceResource<IT, OT> getResource(ServiceContext<?, ?> ctx) throws Exception {
CollectionSpaceResource<IT, OT> result = null;
ResourceMap resourceMap = ctx.getResourceMap();
/* (non-Javadoc)
* @see org.collectionspace.services.common.context.RemoteServiceContext#getLocalContext(java.lang.String)
*/
- @Override
+ @SuppressWarnings("unchecked")
+ @Override
public ServiceContext<IT, OT> getLocalContext(String localContextClassName) throws Exception {
ClassLoader cloader = Thread.currentThread().getContextClassLoader();
Class<?> ctxClass = cloader.loadClass(localContextClassName);
//
// If it's a shared connection, we can't close it. Just reduce the refcount by 1
//
- String warnMsg = "Attempted to release a shared storage connection. Only the originator can release the connection";
- logger.warn(warnMsg);
+ if (logger.isTraceEnabled()) {
+ String traceMsg = "Attempted to release a shared storage connection. Only the originator can release the connection";
+ logger.trace(traceMsg);
+ }
transactionConnectionRefCount--;
} else {
TransactionContext transactionCtx = getCurrentTransactionContext();
import org.collectionspace.services.common.document.ValidatorHandler;
import org.collectionspace.services.common.security.SecurityContext;
import org.collectionspace.services.common.storage.TransactionContext;
-import org.collectionspace.services.common.storage.jpa.JPATransactionContext;
+
import org.collectionspace.services.config.ClientType;
import org.collectionspace.services.config.service.ObjectPartType;
import org.collectionspace.services.config.service.ServiceBindingType;
* @param <WT>
* @param <WTL>
*/
+@SuppressWarnings({"unchecked", "rawtypes"})
public abstract class AbstractDocumentHandlerImpl<T, TL, WT, WTL>
implements DocumentHandler<T, TL, WT, WTL> {
/* (non-Javadoc)
* @see org.collectionspace.services.common.document.DocumentHandler#getServiceContext()
*/
- @Override
+ @Override
public ServiceContext getServiceContext() {
return serviceContext;
}
/* (non-Javadoc)
* @see org.collectionspace.services.common.document.DocumentHandler#complete(org.collectionspace.services.common.document.DocumentHandler.Action, org.collectionspace.services.common.document.DocumentWrapper)
*/
- @Override
+ @Override
final public void complete(Action action, DocumentWrapper<?> wrapDoc) throws Exception {
switch (action) {
case CREATE:
--- /dev/null
+package org.collectionspace.services.common.document;
+
+public class InconsistentStateException extends TransactionException {
+ private static final long serialVersionUID = 11L;
+
+ public InconsistentStateException() {
+ super(TRANSACTION_FAILED_MSG);
+ setErrorCode(HTTP_CODE);
+ }
+
+ public InconsistentStateException(String msg) {
+ super(msg);
+ }
+
+ public InconsistentStateException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public InconsistentStateException(Throwable cause) {
+ super(cause);
+ }
+
+}
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
+import javax.xml.namespace.QName;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* @param clazz class of the jaxb object
* @return
*/
- public static String toString(Object o, Class clazz) {
+ public static String toString(Object o, Class<?> clazz) {
StringWriter sw = new StringWriter();
+
try {
JAXBContext jc = JAXBContext.newInstance(clazz);
Marshaller m = jc.createMarshaller();
- m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
- Boolean.TRUE);
+ m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(o, sw);
- } catch (Exception e) {
- e.printStackTrace();
- }
+ } catch (javax.xml.bind.MarshalException e) {
+ //
+ // If the JAX-B object we're trying to marshal doesn't have an @XmlRootElement, then we need another
+ // approach.
+ //
+ return marshalWithoutRoot(o, clazz);
+ } catch (JAXBException e) {
+ logger.error(e.getMessage());
+ }
+
+ return sw.toString();
+ }
+
+ /*
+ * Use this to marshal a JAX-B object that has no @XmlRootElement
+ */
+ private static String marshalWithoutRoot(Object o, Class<?> clazz) {
+ StringWriter sw = new StringWriter();
+
+ try {
+ JAXBContext jc = JAXBContext.newInstance(clazz);
+ Marshaller marshaller = jc.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ marshaller.marshal(new JAXBElement(new QName("uri","local"), clazz, o), sw);
+ } catch (Exception e) {
+ logger.debug(e.getMessage());
+ }
+
return sw.toString();
}
*
*/
public class TransactionException extends DocumentException {
-
- /**
- *
- */
private static final long serialVersionUID = 1L;
// Custom HTTP status code, per the extensibility offered via RFC-2616
throws DocumentNotFoundException, TransactionException,
DocumentException;
+ boolean delete(ServiceContext ctx, Object entityFound, DocumentHandler handler)
+ throws DocumentNotFoundException, DocumentException;
+
}
abstract public void remove(Object entity);
abstract public Object merge(Object entity);
+
+ abstract public void flush();
+
}
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
+import javax.persistence.RollbackException;
import org.collectionspace.services.common.context.ServiceContext;
+import org.collectionspace.services.common.document.InconsistentStateException;
import org.collectionspace.services.common.document.TransactionException;
import org.collectionspace.services.common.storage.TransactionContext;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final Logger logger = LoggerFactory.getLogger(TransactionContext.class);
private int transactionRefCount = 0;
- private Boolean commitSuccessful = null;
+ private boolean aclTablesUpdatedFlag = false;
EntityManagerFactory emf;
EntityManager em;
protected EntityManager getEntityManager() {
return em;
}
+
+ /**
+ * Set to 'true' if (and only if) a change has been made AND successfully committed to the Spring Security tables.
+ *
+ * Since we can't include Spring Security table changes and JPA changes in a single transaction, we
+ * keep track of changes to the Spring Security tables here. We'll use this flag to log a critical error if
+ * we think there is a chance the JPA tables and Spring Security tables get out of sync.
+ *
+ * @param flag
+ */
+ public void setAclTablesUpdateFlag(boolean flag) {
+ aclTablesUpdatedFlag = flag;
+ }
+
+ protected boolean getAclTablesUpdateFlag() {
+ return aclTablesUpdatedFlag;
+ }
@Override
public ServiceContext getServiceContext() {
@Override
public void close() throws TransactionException {
if (em.getTransaction().isActive() == true && em.getTransaction().getRollbackOnly() == true) {
- em.getTransaction().rollback();
+ if (getAclTablesUpdateFlag() == false) {
+ //
+ // Since there were no changes committed to the Spring Security tables, we can just rollback and continue
+ //
+ em.getTransaction().rollback();
+ } else {
+ String msg = handleInconsistentState();
+ throw new InconsistentStateException(msg);
+ }
} else if (em.getTransaction().isActive() == true) {
- throw new JPATransactionException("There is an active transaction. You must commit the active transaction prior to calling this close method.");
+ markForRollback();
+ close(); // NOTE: Recursive call.
+ throw new JPATransactionException("There was an active transaction. You must commit the active transaction prior to calling this close method.");
}
-
+
+ em.close();
+ JpaStorageUtils.releaseEntityManagerFactory(emf);
+ }
+
+ private String handleInconsistentState() throws InconsistentStateException {
+ //
+ // If we've modified the Spring Tables and need to rollback this JPA transaction, we now have a potentially critical inconsistent state in the system
+ //
+ String msg = "\n#\n# CRITICAL: The Spring Security tables just became inconsistent with CollectionSpace JPA AuthN and AuthZ tables. Contact your CollectionSpace administrator immediately.\n#";
+
+ //
+ // Finish by rolling back the JPA transaction, closing the connection, and throwing an exception
+ //
+ logger.error(msg);
+ em.getTransaction().rollback();
em.close();
JpaStorageUtils.releaseEntityManagerFactory(emf);
+
+ return msg;
}
@Override
return em.merge(entity);
}
+ @SuppressWarnings("unchecked")
@Override
public Object find(Class entityClass, Object primaryKey) {
return em.find(entityClass, primaryKey);
}
+ @SuppressWarnings("unchecked")
@Override
public Object find(Class entityClass, String id) {
return em.find(entityClass, id);
public void remove(Object entity) {
em.remove(entity);
}
+
+ @Override
+ public boolean isTransactionActive() {
+ return em.getTransaction().isActive();
+ }
+
+ @Override
+ public void flush() {
+ em.flush();
+ }
@Override
public void commitTransaction() throws TransactionException {
}
if (--transactionRefCount == 0) {
em.getTransaction().commit();
- commitSuccessful = Boolean.TRUE;
}
}
-
- @Override
- public boolean isTransactionActive() {
- return em.getTransaction().isActive();
- }
}
public class JpaRelationshipStorageClient<T> extends JpaStorageClientImpl {
private final Logger logger = LoggerFactory.getLogger(JpaRelationshipStorageClient.class);
-
- public static PermissionValue createPermissionValue(Permission permission) {
- PermissionValue result = new PermissionValue();
- result.setPermissionId(permission.getCsid());
- result.setResourceName(permission.getResourceName());
- result.setActionGroup(permission.getActionGroup());
- return result;
- }
-
- public static RoleValue createRoleValue(Role role) {
- RoleValue result = new RoleValue();
- result.setRoleId(role.getCsid());
- result.setRoleName(role.getRoleName());
- return result;
- }
public JpaRelationshipStorageClient() {
//empty
try {
jpaTransactionContext.beginTransaction();
handler.prepare(Action.CREATE);
- List<T> rl = new ArrayList<T>();
- DocumentWrapper<List<T>> wrapDoc =
- new DocumentWrapperImpl<List<T>>(rl);
+ List<T> relationshipList = new ArrayList<T>();
+ DocumentWrapper<List<T>> wrapDoc = new DocumentWrapperImpl<List<T>>(relationshipList);
handler.handle(Action.CREATE, wrapDoc);
- for (T r : rl) {
- JaxbUtils.setValue(r, "setCreatedAtItem", Date.class, new Date());
- jpaTransactionContext.persist(r);
+ for (T relationship : relationshipList) {
+ JaxbUtils.setValue(relationship, "setCreatedAtItem", Date.class, new Date());
+ jpaTransactionContext.persist(relationship);
}
- handler.complete(Action.CREATE, wrapDoc);
+ handler.complete(Action.CREATE, wrapDoc);
jpaTransactionContext.commitTransaction();
- result = "-1"; // meaningless result
+ result = "0"; // meaningless result
} catch (BadRequestException bre) {
- jpaTransactionContext.markForRollback();
throw bre;
} catch (PersistenceException pe) {
- jpaTransactionContext.markForRollback();
throw pe;
+ } catch (DocumentException de) {
+ throw de;
} catch (Exception e) {
- jpaTransactionContext.markForRollback();
- if (logger.isDebugEnabled()) {
- logger.debug("Caught exception ", e);
- }
throw new DocumentException(e);
} finally {
+ if (result == null) {
+ jpaTransactionContext.markForRollback(); // If result == null, we failed and must mark the current tx for rollback
+ }
ctx.closeConnection();
}
}
String objectId = getObjectId(ctx);
- Class objectClass = getObjectClass(ctx);
DocumentFilter docFilter = handler.getDocumentFilter();
if (docFilter == null) {
docFilter = handler.createDocumentFilter();
try {
relList = q.getResultList();
} catch (NoResultException nre) {
- String msg = "get(1): " + " could not find relationships for object class="
- + objectClass.getName() + " id=" + id;
- if (logger.isDebugEnabled()) {
- logger.debug(msg, nre);
- }
- }
- if (relList.size() == 0) {
- String msg = "get(2): " + " could not find relationships for object class="
- + objectClass.getName() + " id=" + id;
- if (logger.isDebugEnabled()) {
- logger.debug(msg);
- }
+ // Quietly consume. relList will just be an empty list
}
+
DocumentWrapper<List<T>> wrapDoc = new DocumentWrapperImpl<List<T>>(relList);
handler.handle(Action.GET, wrapDoc);
handler.complete(Action.GET, wrapDoc);
try {
jpaTransactionContext.beginTransaction();
handler.prepare(Action.DELETE);
- List<T> rl = new ArrayList<T>();
- DocumentWrapper<List<T>> wrapDoc = new DocumentWrapperImpl<List<T>>(rl);
+ List<T> relationshipList = new ArrayList<T>();
+ DocumentWrapper<List<T>> wrapDoc = new DocumentWrapperImpl<List<T>>(relationshipList);
handler.handle(Action.DELETE, wrapDoc);
//
//the following could be much more efficient if done with a single sql/jql
//
- for (T r : rl) {
- jpaTransactionContext.remove(getRelationship(jpaTransactionContext, r));
+ for (T relationship : relationshipList) {
+ jpaTransactionContext.remove(getRelationship(jpaTransactionContext, relationship));
}
handler.complete(Action.DELETE, wrapDoc); // Delete from the Spring Security tables. Would be better if this was part of the earlier transaction.
jpaTransactionContext.commitTransaction();
try {
handler.handle(Action.CREATE, wrapDoc);
JaxbUtils.setValue(entity, "setCreatedAtItem", Date.class, new Date());
- jpaConnectionContext.persist(entity);
- } catch (EntityExistsException ee) {
+ jpaConnectionContext.persist(entity);
+ } catch (EntityExistsException ee) { // FIXME: No, don't allow duplicates
//
// We found an existing matching entity in the store, so we don't need to create one. Just update the transient 'entity' instance with the existing persisted entity we found.
// An entity's document handler class will throw this exception only if attempting to create (but not actually creating) duplicate is ok -e.g., Permission records.
* cost: a get before delete
* @see org.collectionspace.services.common.storage.StorageClient#delete(org.collectionspace.services.common.context.ServiceContext, java.lang.String)
*/
- @SuppressWarnings({ "rawtypes", "unchecked" })
+ @SuppressWarnings({ "rawtypes" })
@Override
public boolean delete(ServiceContext ctx, String id, DocumentHandler handler)
throws DocumentNotFoundException, DocumentException {
- boolean result = true;
+ boolean result = false;
JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection();
try {
jpaConnectionContext.beginTransaction();
- handler.prepare(Action.DELETE);
Object entityFound = getEntity(ctx, id);
if (entityFound == null) {
- jpaConnectionContext.markForRollback();
String msg = "delete(ctx, ix, handler) could not find entity with id=" + id;
logger.error(msg);
throw new DocumentNotFoundException(msg);
}
- DocumentWrapper<Object> wrapDoc = new DocumentWrapperImpl<Object>(entityFound);
+ result = delete(ctx, entityFound, handler);
+ jpaConnectionContext.commitTransaction();
+ } catch (DocumentException de) {
+ jpaConnectionContext.markForRollback();
+ throw de;
+ } catch (Exception e) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("delete(ctx, ix, handler): Caught exception ", e);
+ }
+ jpaConnectionContext.markForRollback();
+ throw new DocumentException(e);
+ } finally {
+ ctx.closeConnection();
+ }
+
+ return result;
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ @Override
+ public boolean delete(ServiceContext ctx, Object entity, DocumentHandler handler)
+ throws DocumentNotFoundException, DocumentException {
+ boolean result = false;
+
+ JPATransactionContext jpaConnectionContext = (JPATransactionContext)ctx.openConnection();
+ try {
+ jpaConnectionContext.beginTransaction();
+ handler.prepare(Action.DELETE);
+ DocumentWrapper<Object> wrapDoc = new DocumentWrapperImpl<Object>(entity);
handler.handle(Action.DELETE, wrapDoc);
- jpaConnectionContext.remove(entityFound);
+ jpaConnectionContext.remove(entity);
handler.complete(Action.DELETE, wrapDoc);
jpaConnectionContext.commitTransaction();
+ result = true;
} catch (DocumentException de) {
jpaConnectionContext.markForRollback();
throw de;
}
return result;
- }
+ }
/**
* Gets the entityReceived name.
throws DocumentNotFoundException, TransactionException {
Object entityFound = null;
- JPATransactionContext jpaTransactionConnection = (JPATransactionContext)ctx.openConnection();
+ JPATransactionContext jpaTransactionContext = (JPATransactionContext)ctx.openConnection();
try {
- entityFound = JpaStorageUtils.getEntity(jpaTransactionConnection.getEntityManager(), id, entityClazz);
+ entityFound = JpaStorageUtils.getEntity(jpaTransactionContext, id, entityClazz); // FIXME: # Should be qualifying with the tenant ID
if (entityFound == null) {
String msg = "could not find entity of type=" + entityClazz.getName()
+ " with id=" + id;
if (useTenantId == true) {
q.setParameter("tenantId", tenantId);
}
+
result = q.getSingleResult();
return result;
repoSession.setTransactionRollbackOnly();
}
}
+
+ /**
+ * Should never get called.
+ */
+ @Override
+ public boolean delete(ServiceContext ctx, Object entityFound, DocumentHandler handler)
+ throws DocumentNotFoundException, DocumentException {
+ throw new UnsupportedOperationException();
+ }
}
</xs:documentation>
<xs:appinfo>
<hj:entity>
- <orm:table name="permissions">
- <orm:unique-constraint>
- <!-- combined length should be < 1000 bytes -->
- <orm:column-name>resource_name</orm:column-name>
- <orm:column-name>action_group</orm:column-name>
- <orm:column-name>tenant_id</orm:column-name>
- </orm:unique-constraint>
- </orm:table>
+ <orm:table name="permissions" />
</hj:entity>
</xs:appinfo>
</xs:annotation>
</xs:appinfo>
</xs:annotation>
</xs:element>
- <xs:element name="actionGroup" type="xs:string" minOccurs="0"
- maxOccurs="1">
+ <xs:element name="actionGroup" type="xs:string" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:appinfo>
<hj:basic>
</xs:appinfo>
</xs:annotation>
</xs:element>
- <xs:element name="action" type="permission_action"
- minOccurs="1" maxOccurs="unbounded" />
- <xs:element name="effect" type="effect_type" minOccurs="1"
- maxOccurs="1">
+ <xs:element name="action" type="permission_action" minOccurs="1" maxOccurs="unbounded" />
+ <xs:element name="effect" type="effect_type" minOccurs="1" maxOccurs="1">
<xs:annotation>
<xs:appinfo>
<hj:basic>
</xs:appinfo>
</xs:annotation>
</xs:element>
+ <xs:element name="metadataProtection" type="xs:string" minOccurs="0" maxOccurs="1">
+ <xs:annotation>
+ <xs:appinfo>
+ <hj:basic>
+ <orm:column name="metadata_protection" nullable="true"/>
+ </hj:basic>
+ </xs:appinfo>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="actionsProtection" type="xs:string" minOccurs="0" maxOccurs="1">
+ <xs:annotation>
+ <xs:appinfo>
+ <hj:basic>
+ <orm:column name="actions_protection" nullable="true"/>
+ </hj:basic>
+ </xs:appinfo>
+ </xs:annotation>
+ </xs:element>
<xs:element name="tenant_id" type="xs:string" minOccurs="1">
<xs:annotation>
<xs:appinfo>