Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support public read / auth write #3481

6 changes: 1 addition & 5 deletions src/stashcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,6 @@ def generate_cache_scitokens(global_data: GlobalData, fqdn: str, suppress_errors

for vo_name, stashcache_obj in vos_data.stashcache_by_vo_name.items():
for namespace in stashcache_obj.namespaces.values(): # type: Namespace
if namespace.is_public():
continue
if not namespace_allows_cache_resource(namespace, cache_resource):
continue
if not resource_allows_namespace(cache_resource, namespace):
Expand Down Expand Up @@ -486,8 +484,6 @@ def generate_origin_scitokens(global_data: GlobalData, fqdn: str, suppress_error

for vo_name, stashcache_obj in vos_data.stashcache_by_vo_name.items():
for namespace in stashcache_obj.namespaces.values():
if namespace.is_public():
continue
if not namespace_allows_origin_resource(namespace, origin_resource):
continue
if not resource_allows_namespace(origin_resource, namespace):
Expand Down Expand Up @@ -562,7 +558,7 @@ def _namespace_dict(ns: Namespace):
nsdict = {
"path": ns.path,
"readhttps": not ns.is_public(),
"usetokenonread": any(isinstance(a, SciTokenAuth) for a in ns.authz_list),
"usetokenonread": not ns.is_public() and any(isinstance(a, SciTokenAuth) for a in ns.authz_list),
"writebackhost": ns.writeback,
"dirlisthost": ns.dirlist,
"caches": [],
Expand Down
5 changes: 5 additions & 0 deletions src/tests/data/testvo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,18 @@ DataFederations:
- Path: /testvo/PUBLIC
Authorizations:
- PUBLIC
- SciTokens:
Issuer: https://test.wisc.edu
Base Path: /testvo
Map Subject: False
AllowedOrigins:
# sc-origin.test.wisc.edu
- TEST_STASHCACHE_ORIGIN
# sc-origin2000.test.wisc.edu
- TEST_STASHCACHE_ORIGIN_2000
AllowedCaches:
- ANY
Writeback: "https://sc-origin.test.wisc.edu:1095"

- Path: /testvo/itb/helm-origin/PUBLIC
Authorizations:
Expand Down
41 changes: 40 additions & 1 deletion src/tests/test_stashcache.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
EMPTY_LINE_REGEX = re.compile(r'^\s*(#|$)') # Empty or comment-only lines
I2_TEST_CACHE = "osg-sunnyvale-stashcache.nrp.internet2.edu"
# ^^ one of the Internet2 caches; these serve both public and LIGO data
# fake origins in our test data:
TEST_ITB_HELM_ORIGIN = "helm-origin.osgdev.test.io"
# ^^ a fake origin that's in our test data
TEST_SC_ORIGIN = "sc-origin.test.wisc.edu"


# Some DNs I can use for testing and the hashes they map to.
Expand Down Expand Up @@ -127,6 +128,44 @@ def test_scitokens_issuer_sections(self, client: flask.Flask):
print(f"Generated origin scitokens.conf text:\n{origin_scitokens_conf}\n", file=sys.stderr)
raise

def test_scitokens_issuer_public_read_auth_write_namespaces_info(self, client: flask.Flask):
test_global_data = get_test_global_data(global_data)

namespaces_json = stashcache.get_namespaces_info(test_global_data)
namespaces = namespaces_json["namespaces"]
testvo_PUBLIC_namespace_list = [
ns for ns in namespaces if ns.get("path") == "/testvo/PUBLIC"
]
assert testvo_PUBLIC_namespace_list, "/testvo/PUBLIC namespace not found"
ns = testvo_PUBLIC_namespace_list[0]
assert ns["usetokenonread"] is False, \
"usetokenonread is wrong for public namespace"
assert ns["readhttps"] is False, \
"readhttps is wrong for public namespace"
assert ns["writebackhost"] == f"https://{TEST_SC_ORIGIN}:1095", \
"writebackhost is wrong for namespace with auth write"

def test_scitokens_issuer_public_read_auth_write_scitokens_conf(self, client: flask.Flask):
test_global_data = get_test_global_data(global_data)

origin_scitokens_conf = stashcache.generate_origin_scitokens(
test_global_data, TEST_SC_ORIGIN)
assert origin_scitokens_conf.strip(), "Generated scitokens.conf empty"

cp = ConfigParser()
cp.read_string(origin_scitokens_conf, "origin_scitokens.conf")
try:
assert "Global" in cp, "Missing Global section"
assert "Issuer https://test.wisc.edu" in cp, \
"Expected issuer missing"
assert "base_path" in cp["Issuer https://test.wisc.edu"], \
"'Issuer https://test.wisc.edu' section missing expected attribute"
assert cp["Issuer https://test.wisc.edu"]["base_path"] == "/testvo", \
"'Issuer https://test.wisc.edu' section has wrong base path"
except AssertionError:
print(f"Generated origin scitokens.conf text:\n{origin_scitokens_conf}\n", file=sys.stderr)
raise

def test_None_fdqn_isnt_error(self, client: flask.Flask):
stashcache.generate_cache_authfile(global_data, None)

Expand Down
7 changes: 2 additions & 5 deletions src/webapp/data_federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def __init__(
self.credential_generation = credential_generation

def is_public(self) -> bool:
return self.authz_list and self.authz_list[0].is_public
return any(x for x in self.authz_list if x.is_public)


def _parse_authz_scitokens(attributes: Dict, authz: Dict) -> Tuple[AuthMethod, Optional[str]]:
Expand Down Expand Up @@ -392,8 +392,5 @@ def parse_authz_list(self, path: str, unparsed_authz_list: List[Union[str, Dict]
if err:
self.errors.add(f"Namespace {path}: {err}")
continue
if parsed_authz.is_public:
return [parsed_authz]
else:
authz_list.append(parsed_authz)
authz_list.append(parsed_authz)
return authz_list