Skip to content

Commit

Permalink
Allow sending info.json XHR with Authorization header (#574)
Browse files Browse the repository at this point in the history
Web browser clients implementing IIIF Authentication API 1.0 may send
info.json requests with an Authorization header via XMLHttpRequest
(XHR). Such requests are "pre-flighted", and the pre-flight response
must explicitly state that the Authorization header is allowed in order
for the browser to proceed with the request.
  • Loading branch information
Mark A. Matney, Jr authored and ksclarke committed Aug 16, 2024
1 parent 47b96bb commit 768b4c0
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 57 deletions.
56 changes: 0 additions & 56 deletions .github/workflows/ci.yml.orig

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,10 @@ public void doHEAD() throws Exception {
doGET();
}

final void doOPTIONS() {
/**
* May be overridden by implementations that support {@literal OPTIONS}.
*/
protected void doOPTIONS() {
Method[] methods = getSupportedMethods();
if (methods.length > 0) {
response.setStatus(Status.NO_CONTENT.getCode());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package edu.illinois.library.cantaloupe.resource.iiif.v1;

import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import edu.illinois.library.cantaloupe.http.Method;
import edu.illinois.library.cantaloupe.http.Status;
Expand All @@ -18,6 +20,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;

/**
* Handles IIIF Image API 1.x information requests.
*
Expand All @@ -42,6 +46,21 @@ public Method[] getSupportedMethods() {
return SUPPORTED_METHODS;
}

@Override
protected final void doOPTIONS() {
HttpServletResponse response = getResponse();
Method[] methods = getSupportedMethods();
if (methods.length > 0) {
response.setStatus(Status.NO_CONTENT.getCode());
response.setHeader("Access-Control-Allow-Headers", "Authorization");
response.setHeader("Allow", Arrays.stream(methods)
.map(Method::toString)
.collect(Collectors.joining(",")));
} else {
response.setStatus(Status.METHOD_NOT_ALLOWED.getCode());
}
}

/**
* Writes a JSON-serialized {@link Information} instance to the response.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package edu.illinois.library.cantaloupe.resource.iiif.v2;

import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import edu.illinois.library.cantaloupe.http.Method;
import edu.illinois.library.cantaloupe.http.Status;
Expand All @@ -20,6 +22,7 @@
import org.slf4j.LoggerFactory;

import javax.script.ScriptException;
import javax.servlet.http.HttpServletResponse;

/**
* Handles information requests.
Expand All @@ -45,6 +48,21 @@ public Method[] getSupportedMethods() {
return SUPPORTED_METHODS;
}

@Override
protected final void doOPTIONS() {
HttpServletResponse response = getResponse();
Method[] methods = getSupportedMethods();
if (methods.length > 0) {
response.setStatus(Status.NO_CONTENT.getCode());
response.setHeader("Access-Control-Allow-Headers", "Authorization");
response.setHeader("Allow", Arrays.stream(methods)
.map(Method::toString)
.collect(Collectors.joining(",")));
} else {
response.setStatus(Status.METHOD_NOT_ALLOWED.getCode());
}
}

/**
* Writes a JSON-serialized {@link Information} instance to the response.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package edu.illinois.library.cantaloupe.resource.iiif.v3;

import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import edu.illinois.library.cantaloupe.http.Method;
import edu.illinois.library.cantaloupe.http.Status;
Expand All @@ -20,6 +22,7 @@
import org.slf4j.LoggerFactory;

import javax.script.ScriptException;
import javax.servlet.http.HttpServletResponse;

/**
* Handles IIIF Image API 3.x information requests.
Expand All @@ -45,6 +48,21 @@ public Method[] getSupportedMethods() {
return SUPPORTED_METHODS;
}

@Override
protected final void doOPTIONS() {
HttpServletResponse response = getResponse();
Method[] methods = getSupportedMethods();
if (methods.length > 0) {
response.setStatus(Status.NO_CONTENT.getCode());
response.setHeader("Access-Control-Allow-Headers", "Authorization");
response.setHeader("Allow", Arrays.stream(methods)
.map(Method::toString)
.collect(Collectors.joining(",")));
} else {
response.setStatus(Status.METHOD_NOT_ALLOWED.getCode());
}
}

/**
* Writes a JSON-serialized {@link Information} instance to the response.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,11 @@ void testOPTIONSWhenEnabled() throws Exception {
assertEquals(2, methods.size());
assertTrue(methods.contains("GET"));
assertTrue(methods.contains("OPTIONS"));

List<String> allowedHeaders =
List.of(StringUtils.split(headers.getFirstValue("Access-Control-Allow-Headers"), ", "));
assertEquals(1, allowedHeaders.size());
assertTrue(allowedHeaders.contains("Authorization"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,11 @@ void testOPTIONSWhenEnabled() throws Exception {
assertEquals(2, methods.size());
assertTrue(methods.contains("GET"));
assertTrue(methods.contains("OPTIONS"));

List<String> allowedHeaders =
List.of(StringUtils.split(headers.getFirstValue("Access-Control-Allow-Headers"), ", "));
assertEquals(1, allowedHeaders.size());
assertTrue(allowedHeaders.contains("Authorization"));
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,11 @@ void testOPTIONSWhenEnabled() throws Exception {
assertEquals(2, methods.size());
assertTrue(methods.contains("GET"));
assertTrue(methods.contains("OPTIONS"));

List<String> allowedHeaders =
List.of(StringUtils.split(headers.getFirstValue("Access-Control-Allow-Headers"), ", "));
assertEquals(1, allowedHeaders.size());
assertTrue(allowedHeaders.contains("Authorization"));
}

@Test
Expand Down

0 comments on commit 768b4c0

Please sign in to comment.