001/* 002 * Licensed to DuraSpace under one or more contributor license agreements. 003 * See the NOTICE file distributed with this work for additional information 004 * regarding copyright ownership. 005 * 006 * DuraSpace licenses this file to you under the Apache License, 007 * Version 2.0 (the "License"); you may not use this file except in 008 * compliance with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.fcrepo.integration.http.api; 019 020import static javax.ws.rs.core.Response.Status.CREATED; 021import static javax.ws.rs.core.Response.Status.NO_CONTENT; 022import static javax.ws.rs.core.Response.Status.OK; 023import static javax.ws.rs.core.Response.Status.PRECONDITION_FAILED; 024import static org.junit.Assert.assertEquals; 025import static org.junit.Assert.assertNotNull; 026 027import java.io.IOException; 028 029import org.apache.http.client.methods.CloseableHttpResponse; 030import org.apache.http.client.methods.HttpGet; 031import org.apache.http.client.methods.HttpHead; 032import org.apache.http.client.methods.HttpPatch; 033import org.apache.http.client.methods.HttpPut; 034import org.apache.http.entity.StringEntity; 035import org.junit.Test; 036import org.springframework.test.context.TestExecutionListeners; 037 038/** 039 * @author dbernstein 040 */ 041@TestExecutionListeners( 042 listeners = { TestIsolationExecutionListener.class }, 043 mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS) 044public class StateTokensIT extends AbstractResourceIT { 045 046 private static final String X_STATE_TOKEN_HEADER = "X-State-Token"; 047 private static final String X_IF_STATE_TOKEN_HEADER = "X-If-State-Token"; 048 049 @Test 050 public void testGetHasStateTokenRDFSource() throws IOException { 051 final String id = getRandomUniqueId(); 052 createObjectAndClose(id); 053 try (final CloseableHttpResponse response = execute(new HttpGet(serverAddress + id))) { 054 assertEquals(OK.getStatusCode(), getStatus(response)); 055 assertNotNull(X_STATE_TOKEN_HEADER, response.getFirstHeader(X_STATE_TOKEN_HEADER).getValue()); 056 } 057 } 058 059 @Test 060 public void testHeadHasStateTokenRDFSource() throws IOException { 061 final String id = getRandomUniqueId(); 062 createObjectAndClose(id); 063 try (final CloseableHttpResponse response = execute(new HttpHead(serverAddress + id))) { 064 assertEquals(OK.getStatusCode(), getStatus(response)); 065 assertNotNull(X_STATE_TOKEN_HEADER, response.getFirstHeader(X_STATE_TOKEN_HEADER).getValue()); 066 } 067 } 068 069 @Test 070 public void testAclGetHasStateTokenRDFSource() throws IOException { 071 final String id = getRandomUniqueId(); 072 createObjectAndClose(id); 073 final String aclPid = id + "/fcr:acl"; 074 075 final HttpPut method = putObjMethod(aclPid, "text/turtle", 076 "<#auth> a <http://www.w3.org/ns/auth/acl#Authorization> ."); 077 078 try (final CloseableHttpResponse response = execute(method)) { 079 assertEquals(CREATED.getStatusCode(), getStatus(response)); 080 } 081 082 try (final CloseableHttpResponse response = execute(new HttpGet(serverAddress + aclPid))) { 083 assertEquals(OK.getStatusCode(), getStatus(response)); 084 assertNotNull(X_STATE_TOKEN_HEADER, response.getFirstHeader(X_STATE_TOKEN_HEADER).getValue()); 085 } 086 } 087 088 @Test 089 public void testAclHeadHasStateTokenRDFSource() throws IOException { 090 final String id = getRandomUniqueId(); 091 createObjectAndClose(id); 092 final String aclPid = id + "/fcr:acl"; 093 094 final HttpPut method = putObjMethod(aclPid, "text/turtle", 095 "<#auth> a <http://www.w3.org/ns/auth/acl#Authorization> ."); 096 097 try (final CloseableHttpResponse response = execute(method)) { 098 assertEquals(CREATED.getStatusCode(), getStatus(response)); 099 } 100 101 try (final CloseableHttpResponse response = execute(new HttpHead(serverAddress + aclPid))) { 102 assertEquals(OK.getStatusCode(), getStatus(response)); 103 assertNotNull(X_STATE_TOKEN_HEADER, response.getFirstHeader(X_STATE_TOKEN_HEADER).getValue()); 104 } 105 } 106 107 @Test 108 public void testLdpcvGetHasStateTokenRDFSource() throws IOException { 109 final String id = getRandomUniqueId(); 110 createObjectAndClose(id); 111 try (final CloseableHttpResponse response = execute(new HttpGet(serverAddress + id + "/fcr:versions"))) { 112 assertEquals(OK.getStatusCode(), getStatus(response)); 113 assertNotNull(X_STATE_TOKEN_HEADER, response.getFirstHeader(X_STATE_TOKEN_HEADER).getValue()); 114 } 115 } 116 117 @Test 118 public void testLdpcvHeadHasStateTokenRDFSource() throws IOException { 119 final String id = getRandomUniqueId(); 120 createObjectAndClose(id); 121 try (final CloseableHttpResponse response = execute(new HttpHead(serverAddress + id + "/fcr:versions"))) { 122 assertEquals(OK.getStatusCode(), getStatus(response)); 123 assertNotNull(X_STATE_TOKEN_HEADER, response.getFirstHeader(X_STATE_TOKEN_HEADER).getValue()); 124 } 125 } 126 127 @Test 128 public void testGetHasStateTokenNonRDFSource() throws IOException { 129 final String id = getRandomUniqueId(); 130 final String location = serverAddress + id + "/binary"; 131 final HttpPut method = putDSMethod(id, "binary", "foo"); 132 try (final CloseableHttpResponse response = execute(method)) { 133 assertEquals(CREATED.getStatusCode(), getStatus(response)); 134 } 135 136 try (final CloseableHttpResponse response = execute(new HttpGet(location))) { 137 assertEquals(OK.getStatusCode(), getStatus(response)); 138 assertNotNull(X_STATE_TOKEN_HEADER, response.getFirstHeader(X_STATE_TOKEN_HEADER).getValue()); 139 } 140 } 141 142 @Test 143 public void testHeadHasStateTokenNonRDFSource() throws IOException { 144 final String id = getRandomUniqueId(); 145 final String location = serverAddress + id + "/binary"; 146 final HttpPut method = putDSMethod(id, "binary", "foo"); 147 try (final CloseableHttpResponse response = execute(method)) { 148 assertEquals(CREATED.getStatusCode(), getStatus(response)); 149 } 150 151 try (final CloseableHttpResponse response = execute(new HttpHead(location))) { 152 assertEquals(OK.getStatusCode(), getStatus(response)); 153 assertNotNull(X_STATE_TOKEN_HEADER, response.getFirstHeader(X_STATE_TOKEN_HEADER).getValue()); 154 } 155 } 156 157 @Test 158 public void testPutWithStateTokenOnNonRDFSource() throws IOException { 159 final String id = getRandomUniqueId(); 160 final String location = serverAddress + id + "/binary"; 161 //create a binary 162 final HttpPut method = putDSMethod(id, "binary", "foo"); 163 try (final CloseableHttpResponse response = execute(method)) { 164 assertEquals(CREATED.getStatusCode(), getStatus(response)); 165 } 166 167 //get state token 168 final String stateToken; 169 try (final CloseableHttpResponse response = execute(new HttpHead(location))) { 170 assertEquals(OK.getStatusCode(), getStatus(response)); 171 stateToken = response.getFirstHeader(X_STATE_TOKEN_HEADER).getValue(); 172 } 173 174 //perform put with valid X-If-State-Token 175 final HttpPut validPut = putDSMethod(id, "binary", "bar"); 176 validPut.addHeader(X_IF_STATE_TOKEN_HEADER, stateToken); 177 try (final CloseableHttpResponse response = execute(validPut)) { 178 assertEquals(NO_CONTENT.getStatusCode(), getStatus(response)); 179 } 180 181 //perform put with an invalid X-If-State-Token 182 final HttpPut invalidPut = putDSMethod(id, "binary", "boo"); 183 invalidPut.addHeader(X_IF_STATE_TOKEN_HEADER, "invalid_token"); 184 try (final CloseableHttpResponse response = execute(invalidPut)) { 185 assertEquals(PRECONDITION_FAILED.getStatusCode(), getStatus(response)); 186 } 187 188 } 189 190 @Test 191 public void testPatchWithStateTokenOnRDFSource() throws IOException { 192 final String id = getRandomUniqueId(); 193 final String location = serverAddress + id; 194 //create a resource 195 final HttpPut method = putObjMethod(id); 196 try (final CloseableHttpResponse response = execute(method)) { 197 assertEquals(CREATED.getStatusCode(), getStatus(response)); 198 } 199 200 //get state token 201 final String stateToken; 202 try (final CloseableHttpResponse response = execute(new HttpHead(location))) { 203 assertEquals(OK.getStatusCode(), getStatus(response)); 204 stateToken = response.getFirstHeader(X_STATE_TOKEN_HEADER).getValue(); 205 } 206 207 //perform patch with an invalid X-If-State-Token 208 final HttpPatch invalidPatch = patchObjMethod(id); 209 invalidPatch.addHeader(X_IF_STATE_TOKEN_HEADER, "invalid_token"); 210 invalidPatch.setHeader("Content-Type", "application/sparql-update"); 211 invalidPatch.setEntity(new StringEntity("INSERT { <> a <http://example.org/test> } WHERE {}")); 212 213 try (final CloseableHttpResponse response = execute(invalidPatch)) { 214 assertEquals(PRECONDITION_FAILED.getStatusCode(), getStatus(response)); 215 } 216 217 218 //perform patch with valid X-If-State-Token 219 final HttpPatch validPatch = patchObjMethod(id); 220 validPatch.addHeader(X_IF_STATE_TOKEN_HEADER, stateToken); 221 validPatch.setHeader("Content-Type", "application/sparql-update"); 222 validPatch.setEntity(new StringEntity("INSERT { <> a <http://example.org/test> } WHERE {}")); 223 try (final CloseableHttpResponse response = execute(validPatch)) { 224 assertEquals(NO_CONTENT.getStatusCode(), getStatus(response)); 225 } 226 } 227 228 @Test 229 public void testPatchWithStateTokenOnAcl() throws IOException { 230 final String id = getRandomUniqueId(); 231 createObjectAndClose(id); 232 final String aclPid = id + "/fcr:acl"; 233 final String location = serverAddress + aclPid; 234 final HttpPut method = putObjMethod(aclPid, "text/turtle", 235 "<#auth> a <http://www.w3.org/ns/auth/acl#Authorization> ."); 236 237 try (final CloseableHttpResponse response = execute(method)) { 238 assertEquals(CREATED.getStatusCode(), getStatus(response)); 239 } 240 241 final String stateToken; 242 try (final CloseableHttpResponse response = execute(new HttpHead(location))) { 243 assertEquals(OK.getStatusCode(), getStatus(response)); 244 stateToken = response.getFirstHeader(X_STATE_TOKEN_HEADER).getValue(); 245 } 246 247 //perform patch with an invalid X-If-State-Token 248 final HttpPatch invalidPatch = patchObjMethod(aclPid); 249 invalidPatch.addHeader(X_IF_STATE_TOKEN_HEADER, "invalid_token"); 250 invalidPatch.setHeader("Content-Type", "application/sparql-update"); 251 invalidPatch.setEntity(new StringEntity("INSERT { <> a <http://example.org/test> } WHERE {}")); 252 253 try (final CloseableHttpResponse response = execute(invalidPatch)) { 254 assertEquals(PRECONDITION_FAILED.getStatusCode(), getStatus(response)); 255 } 256 257 //perform patch with valid X-If-State-Token 258 final HttpPatch validPatch = patchObjMethod(aclPid); 259 validPatch.addHeader(X_IF_STATE_TOKEN_HEADER, stateToken); 260 validPatch.setHeader("Content-Type", "application/sparql-update"); 261 validPatch.setEntity(new StringEntity("INSERT { <> a <http://example.org/test> } WHERE {}")); 262 try (final CloseableHttpResponse response = execute(validPatch)) { 263 assertEquals(NO_CONTENT.getStatusCode(), getStatus(response)); 264 } 265 } 266}