Project

General

Profile

1
package edu.ucsb.nceas.metacat.dataone;
2

    
3
import java.io.ByteArrayInputStream;
4
import java.io.File;
5
import java.io.FileInputStream;
6
import java.io.InputStream;
7
import java.util.ArrayList;
8
import java.util.List;
9

    
10
import javax.xml.parsers.DocumentBuilder;
11
import javax.xml.parsers.DocumentBuilderFactory;
12
import javax.xml.xpath.XPath;
13
import javax.xml.xpath.XPathConstants;
14
import javax.xml.xpath.XPathExpression;
15
import javax.xml.xpath.XPathFactory;
16

    
17
import junit.framework.Test;
18
import junit.framework.TestSuite;
19

    
20
import org.dataone.client.ObjectFormatCache;
21
import org.dataone.configuration.Settings;
22
import org.dataone.service.types.v1.AccessPolicy;
23
import org.dataone.service.types.v1.AccessRule;
24
import org.dataone.service.types.v1.Identifier;
25
import org.dataone.service.types.v1.Permission;
26
import org.dataone.service.types.v1.Person;
27
import org.dataone.service.types.v1.Session;
28
import org.dataone.service.types.v1.Subject;
29
import org.dataone.service.types.v1.SubjectInfo;
30
import org.dataone.service.types.v1.SystemMetadata;
31
import org.dataone.service.util.Constants;
32
import org.junit.Before;
33
import org.w3c.dom.Document;
34
import org.w3c.dom.Node;
35
import org.w3c.dom.NodeList;
36
import org.xml.sax.InputSource;
37

    
38

    
39
/**
40
 * A test class to test the access filter mechanism for the solr query
41
 * @author tao
42
 *
43
 */
44
public class SolrQueryAccessFilterTest extends D1NodeServiceTest {
45
    
46
    private static final String SOLR = "solr";
47
    private static final String EML201NAMESPACE = "eml://ecoinformatics.org/eml-2.0.1";
48
    private static final String CREATEUSER = "CN=Christopher Jones A583,O=Google,C=US,DC=cilogon,DC=org";
49
    private static final String QUERYUSER = "CN=ben leinfelder A756,O=Google,C=US,DC=cilogon,DC=org";
50
    private static final String GROUP1 = "CN=PISCO-data-managers,DC=cilogon,DC=org";
51
    private static final String GROUP2 = "CN=dataone-coredev,DC=cilogon,DC=org";
52
    private static final String EMLFILE = "test/restfiles/knb-lter-gce.109.6.xml";
53
    private static final String IDXPATH = "//response/result/doc/str[@name='id']/text()";
54
    
55
    /**
56
     * Build the test suite
57
     * @return
58
     */
59
    public static Test suite() {
60
      
61
      TestSuite suite = new TestSuite();
62
      suite.addTest(new SolrQueryAccessFilterTest("testPublicReadable"));
63
      suite.addTest(new SolrQueryAccessFilterTest("testOnlyUserReadable"));
64
      suite.addTest(new SolrQueryAccessFilterTest("testGroupReadable"));
65
      suite.addTest(new SolrQueryAccessFilterTest("testOnlyRightHolderReadable"));
66
      
67
      return suite;
68
      
69
    }
70
    
71
    /**
72
     * Set up the test fixtures
73
     * 
74
     * @throws Exception
75
     */
76
    @Before
77
    public void setUp() throws Exception {
78
      super.setUp();
79
      // set up the configuration for d1client
80
      Settings.getConfiguration().setProperty("D1Client.cnClassName", MockCNode.class.getName());
81
    }
82
    
83
    /**
84
     * Constructor for the tests
85
     * 
86
     * @param name - the name of the test
87
     */
88
    public SolrQueryAccessFilterTest(String name) {
89
      super(name);
90
      
91
    }
92
    
93
   
94
    
95
    /**
96
     * Test to query a public readable document
97
     */
98
    public void testPublicReadable() throws Exception {
99
        Session session = getSession(CREATEUSER, null);
100
        Identifier id = generateIdentifier();
101
        String[] allowUsers = {Constants.SUBJECT_PUBLIC};
102
        File object = new File(EMLFILE);
103
        SystemMetadata sysmeta = generateSystemMetadata(id, session.getSubject(), object , allowUsers);
104
        createObject(session, id, object, sysmeta);
105
        Thread.sleep(10000);
106
        Session querySession = getSession(Constants.SUBJECT_PUBLIC, null);
107
        String resultId = query(querySession, id);
108
        assertTrue("In the testPublicReadable method, the query result should have the id "+id.getValue()+ " rather than "+resultId, resultId.equals(id.getValue()));
109
        Session querySession2 = getSession(QUERYUSER, null);
110
        String resultId2 = query(querySession2, id);
111
        assertTrue("In the testPublicReadable method, the query result should have the id "+id.getValue()+ " rather than "+resultId2, resultId2.equals(id.getValue()));
112
        archive(session, id);
113
    }
114
    
115
    
116
    /**
117
     * Test to query a document which can only be read by a specified user
118
     */
119
    public void testOnlyUserReadable() throws Exception {
120
        Thread.sleep(15000);
121
        Session session = getSession(CREATEUSER, null);
122
        Identifier id = generateIdentifier();
123
        String[] allowUsers = {QUERYUSER};
124
        File object = new File(EMLFILE);
125
        SystemMetadata sysmeta = generateSystemMetadata(id, session.getSubject(), object , allowUsers);
126
        createObject(session, id, object, sysmeta);
127
        
128
        Thread.sleep(10000);
129
        Session querySession = getSession(Constants.SUBJECT_PUBLIC, null);
130
        String resultId = query(querySession, id);
131
        assertTrue("In the testOnlyUserReadable method, the query result id should be null for the public rather than "+resultId, resultId == null);
132
        Session querySession2 = getSession(QUERYUSER, null);
133
        resultId = query(querySession2, id);
134
        assertTrue("In the testOnlyUserReadable method, the query result for the user "+QUERYUSER+" should have the id "+id.getValue()+" rather than "+resultId, resultId.equals(id.getValue()));
135
        archive(session, id);
136
    }
137
    
138
    /**
139
     * Test to query a document which can be read by a specified group
140
     */
141
    public void testGroupReadable() throws Exception {
142
        Thread.sleep(15000);
143
        Session session = getSession(CREATEUSER, null);
144
        Identifier id = generateIdentifier();
145
        String[] allowUsers = {GROUP1, GROUP2};
146
        File object = new File(EMLFILE);
147
        SystemMetadata sysmeta = generateSystemMetadata(id, session.getSubject(), object , allowUsers);
148
        createObject(session, id, object, sysmeta);
149
        Thread.sleep(10000);
150
        Session querySession = getSession(Constants.SUBJECT_PUBLIC, null);
151
        String resultId = query(querySession, id);
152
        assertTrue("In the testGroupReadable method, the query result id should be null for the public ", resultId == null);
153
        Session querySession2 = getSession(QUERYUSER, null);
154
        resultId = query(querySession2, id);
155
        assertTrue("In the testGroupReadable method, the query result for the user "+QUERYUSER+" which doesn't belong to the group should be null ", resultId == null);
156
        String[]groups = {GROUP1};
157
        Session querySession3 = getSession(QUERYUSER, groups);
158
        resultId = query(querySession3, id);
159
        assertTrue("In the testGroupReadable method, the query result for the user "+QUERYUSER+" which belong to the group should have the id "+id.getValue(), resultId.equals(id.getValue()));
160
        archive(session, id);
161
    }
162
    
163
    
164
    /**
165
     * Test to query a document which only can be read by the rightHolder
166
     */
167
    public void testOnlyRightHolderReadable() throws Exception {
168
        Thread.sleep(15000);
169
        Session session = getSession(CREATEUSER, null);
170
        Identifier id = generateIdentifier();
171
        String[] allowUsers = null;
172
        File object = new File(EMLFILE);
173
        SystemMetadata sysmeta = generateSystemMetadata(id, session.getSubject(), object , allowUsers);
174
        createObject(session, id, object, sysmeta);
175
        Thread.sleep(10000);
176
        Session querySession = getSession(Constants.SUBJECT_PUBLIC, null);
177
        String resultId = query(querySession, id);
178
        assertTrue("In the testOnlyRightHolderReadable method, the query result id should be null for the public ", resultId == null);
179
        Session querySession2 = getSession(QUERYUSER, null);
180
        resultId = query(querySession2, id);
181
        assertTrue("In the testOnlyRightHolderReadable method, the query result for the user "+QUERYUSER+" which doesn't belong to the group should be null.", resultId == null);
182
        String[]groups = {GROUP1};
183
        Session querySession3 = getSession(QUERYUSER, groups);
184
        resultId = query(querySession3, id);
185
        assertTrue("In the testOnlyRightHolderReadable method, the query result for the user "+QUERYUSER+" which belong to the group should be null.", resultId == null);
186
        Session querySession4 = getSession(CREATEUSER, groups);
187
        resultId = query(querySession4, id);
188
        assertTrue("In the testOnlyRightHolderReadable method, the query result for the creator "+CREATEUSER+" should be "+id.getValue(), id.getValue().equals(resultId));
189
        archive(session, id);
190
    }
191
    
192
    /*
193
     * constructs a "fake" session with the specified subject and groups.
194
     * If groups is not null, the session will have a subjectinfo which contains the person with the subject and is the member of the groups.
195
     * @return
196
     */
197
    private Session getSession(String subjectValue, String[]groups) throws Exception {
198
        Session session = new Session();
199
        Subject subject = new Subject();
200
        subject.setValue(subjectValue);
201
        session.setSubject(subject);
202
        if(groups != null) {
203
            Person person = new Person();
204
            person.setSubject(subject);
205
            person.setVerified(new Boolean(true));
206
            List<Subject>groupSubjects = new ArrayList<Subject>();
207
            for(String group: groups) {
208
                Subject groupSub = new Subject();
209
                groupSub.setValue(group);
210
                groupSubjects.add(groupSub);
211
            }
212
            person.setIsMemberOfList(groupSubjects);
213
            SubjectInfo subjectInfo = new SubjectInfo();
214
            subjectInfo.addPerson(person);
215
            session.setSubjectInfo(subjectInfo);
216
        }
217
        return session;
218
    }
219
    
220
    /*
221
     * Create a data object in the dataone server. 
222
     * Return the identifier of the created object
223
     */
224
    private void createObject(Session session, Identifier id, File object, SystemMetadata sysmeta) throws Exception {
225
        MNodeService.getInstance(request).create(session, id, new FileInputStream(object), sysmeta);
226
        
227
    }
228
    
229
    private Identifier generateIdentifier() {
230
        Identifier guid = new Identifier();
231
        long random = Math.round(Math.random()*10000);
232
        guid.setValue("test." + System.currentTimeMillis()+(new Long(random)).toString());
233
        return guid;
234
    }
235
    
236
    /*
237
     * Archive the given id.
238
     */
239
    private void archive(Session session, Identifier id) throws Exception {
240
        MNodeService.getInstance(request).archive(session, id);
241
    }
242
    
243
    
244
    
245
    /*
246
     * Generate system metadata for the file
247
     */
248
    private SystemMetadata generateSystemMetadata(Identifier id, Subject owner, File objectFile, String[] allowedSubjects) throws Exception{
249
        SystemMetadata sysmeta = createSystemMetadata(id, owner, new FileInputStream(objectFile));
250
        AccessPolicy accessPolicy = null;
251
        if(allowedSubjects != null && allowedSubjects.length >0) {
252
            accessPolicy = new AccessPolicy();
253
            for(int i=0; i<allowedSubjects.length; i++) {
254
                AccessRule allow = new AccessRule();
255
                allow.addPermission(Permission.READ);
256
                Subject subject =  new Subject();
257
                subject.setValue(allowedSubjects[i]);
258
                allow.addSubject(subject);
259
                accessPolicy.addAllow(allow);
260
            }
261
        }
262
        sysmeta.setAccessPolicy(accessPolicy);
263
        sysmeta.setFormatId(ObjectFormatCache.getInstance().getFormat(EML201NAMESPACE).getFormatId());
264
        return sysmeta;
265
    }
266
    
267
    /*
268
     * Query the server to find the doc which matches the specified id
269
     */
270
    private String query(Session session, Identifier id) throws Exception{
271
        String query = generateQuery(id.getValue());
272
        MNodeService service = MNodeService.getInstance(request);
273
        service.setSession(session);
274
        InputStream input = service.query(SOLR, query);
275
        return extractId(input);
276
    }
277
    
278
    /*
279
     * Extract the return id from the query result input stream
280
     */
281
    private String extractId(InputStream input ) throws Exception {
282
        String id = null;
283
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
284
        DocumentBuilder builder = factory.newDocumentBuilder();
285
        Document doc = builder.parse(new InputSource(input));
286
       
287
        XPathFactory xPathfactory = XPathFactory.newInstance();
288
        XPath xpath = xPathfactory.newXPath();
289
        XPathExpression expr = xpath.compile(IDXPATH);
290
        Object result = expr.evaluate(doc, XPathConstants.NODESET);
291
        System.out.println("================ result is "+result);
292
        if(result != null) {
293
            NodeList nodes = (NodeList) result;
294
            if(nodes != null) {
295
                System.out.println("the length of nodes is "+nodes.getLength());
296
                Node node = nodes.item(0);
297
                if(node != null) {
298
                    id = node.getNodeValue();
299
                }
300
                
301
            }
302
            
303
        }
304
       
305
        System.out.println("the id is ====== "+id);
306
        return id;
307

    
308
    
309
    }
310
    /*
311
     * Make a query string which will query "id= the specified id".
312
     * @param id
313
     * @return
314
     */
315
    private String generateQuery(String id) {
316
        String query = "q=id:"+id+"&fl=id,title";
317
        return query;
318
    }
319
}
(6-6/6)