Skip to content

Commit

Permalink
Merge pull request galaxyproject#17274 from uwwint/oidc/add-backend-s…
Browse files Browse the repository at this point in the history
…chema

Add OIDC backend configuration schema and validation
  • Loading branch information
nuwang authored Jan 15, 2024
2 parents 03f01da + eb36ad3 commit f7018e4
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 2 deletions.
5 changes: 4 additions & 1 deletion lib/galaxy/authnz/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
string_as_bool,
unicodify,
)
from galaxy.util.resources import files
from .custos_authnz import (
CustosAuthFactory,
KEYCLOAK_BACKENDS,
Expand All @@ -34,6 +35,8 @@
Strategy,
)

OIDC_BACKEND_SCHEMA = files("galaxy.authnz.xsd") / "oidc_backends_config.xsd"

log = logging.getLogger(__name__)

# Note: This if for backward compatibility. Icons can be specified in oidc_backends_config.xml.
Expand Down Expand Up @@ -105,7 +108,7 @@ def _parse_oidc_backends_config(self, config_file):
self.oidc_backends_config = {}
self.oidc_backends_implementation = {}
try:
tree = parse_xml(config_file)
tree = parse_xml(config_file, OIDC_BACKEND_SCHEMA)
root = tree.getroot()
if root.tag != "OIDC":
raise etree.ParseError(
Expand Down
151 changes: 151 additions & 0 deletions lib/galaxy/authnz/xsd/oidc_backends_config.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" elementFormDefault="qualified" vc:minVersion="1.1">
<xs:element name="OIDC">
<xs:complexType>
<xs:annotation>
<xs:documentation>
Root element for OpenID Connect (OIDC) configurations, encompassing multiple identity providers.
</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="provider" maxOccurs="unbounded">
<xs:complexType>
<xs:annotation>
<xs:documentation>
Configuration for a specific OIDC Identity Provider (IdP).
</xs:documentation>
</xs:annotation>
<xs:all>
<xs:element name="client_id" minOccurs="1" type="xs:string">
<xs:annotation>
<xs:documentation>
Client ID obtained from the IdP at client registration.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="client_secret" minOccurs="1" type="xs:string">
<xs:annotation>
<xs:documentation>
Secret generated by the IdP for the client upon registration.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="redirect_uri" minOccurs="1" type="xs:anyURI">
<xs:annotation>
<xs:documentation>
URI where the IdP will send the authentication response.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="prompt" minOccurs="0" type="xs:string">
<xs:annotation>
<xs:documentation>
Determines whether the IdP should prompt the user for re-authorization and consent.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="icon" minOccurs="0" type="xs:string">
<xs:annotation>
<xs:documentation>
URL to an icon representing the IdP.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="extra_scopes" minOccurs="0" type="xs:string">
<xs:annotation>
<xs:documentation>
Additional scopes requested from the IdP.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="require_create_confirmation" minOccurs="0" type="xs:boolean">
<xs:annotation>
<xs:documentation>
Indicates whether a confirmation page is shown for new user creation.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="ca_bundle" minOccurs="0" type="xs:string">
<xs:annotation>
<xs:documentation>
Path to a CA bundle file or directory for SSL certificate verification.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="well_known_oidc_config_uri" minOccurs="0" type="xs:anyURI">
<xs:annotation>
<xs:documentation>
Override the default OIDC configuration URI.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="allowed_idp" minOccurs="0" type="xs:string">
<xs:annotation>
<xs:documentation>
Restricts the list of allowed identity providers for authentication.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="enable_idp_logout" minOccurs="0" type="xs:boolean">
<xs:annotation>
<xs:documentation>
Enable logout from the IdP when logging out of the application.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="label" minOccurs="0" type="xs:string">
<xs:annotation>
<xs:documentation>
Custom label for the IdP in the user interface.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="url" minOccurs="0" type="xs:anyURI">
<xs:annotation>
<xs:documentation>
URL of the IdP.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="api_url" minOccurs="0" type="xs:anyURI">
<xs:annotation>
<xs:documentation>
API URL for the IdP, if different from the main URL.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="pkce_support" minOccurs="0" type="xs:boolean">
<xs:annotation>
<xs:documentation>
Indicates support for Proof Key for Code Exchange (PKCE).
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="idphint" minOccurs="0" type="xs:string">
<xs:annotation>
<xs:documentation>
Hint to preselect the IdP during authentication.
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="accepted_audiences" minOccurs="0" type="xs:string">
<xs:annotation>
<xs:documentation>
Specifies the accepted audiences for authentication tokens.
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="name" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>
Name of the Identity Provider (IdP).
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
3 changes: 3 additions & 0 deletions lib/galaxy/config/sample/oidc_backends_config.xml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ Please mind `http` and `https`.
<!-- <icon>https://path/to/icon</icon> -->
<!-- (Optional) Enable PKCE for this IDP -->
<!-- <pkce_support>false</pkce_support> -->
<!-- (Optional) the audiences accepted on teh access-token for this IDP.
<!-- <accepted_audiences>galaxy</accepted_audiences> -->

</provider>

<!-- Documentation: https://galaxyproject.org/authnz/config/oidc/idps/elixir-aai -->
Expand Down
16 changes: 15 additions & 1 deletion lib/galaxy/util/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,13 +294,22 @@ def unique_id(KEY_SIZE=128):
return md5(random_bits).hexdigest()


def parse_xml(fname: StrPath, strip_whitespace=True, remove_comments=True) -> ElementTree:
def parse_xml(
fname: StrPath, schemafname: Union[StrPath, None] = None, strip_whitespace=True, remove_comments=True
) -> ElementTree:
"""Returns a parsed xml tree"""
parser = None
schema = None
if remove_comments and LXML_AVAILABLE:
# If using stdlib etree comments are always removed,
# but lxml doesn't do this by default
parser = etree.XMLParser(remove_comments=remove_comments)

if LXML_AVAILABLE and schemafname:
with open(str(schemafname), "rb") as schema_file:
schema_root = etree.XML(schema_file.read())
schema = etree.XMLSchema(schema_root)

try:
tree = etree.parse(str(fname), parser=parser)
root = tree.getroot()
Expand All @@ -310,6 +319,8 @@ def parse_xml(fname: StrPath, strip_whitespace=True, remove_comments=True) -> El
elem.text = elem.text.strip()
if elem.tail is not None:
elem.tail = elem.tail.strip()
if schema:
schema.assertValid(tree)
except OSError as e:
if e.errno is None and not os.path.exists(fname):
# lxml doesn't set errno
Expand All @@ -318,6 +329,9 @@ def parse_xml(fname: StrPath, strip_whitespace=True, remove_comments=True) -> El
except etree.ParseError:
log.exception("Error parsing file %s", fname)
raise
except etree.DocumentInvalid as e:
log.exception(f"Validation of file %s failed with error {e}" % fname)
raise
return tree


Expand Down

0 comments on commit f7018e4

Please sign in to comment.