CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-python3-openid

OpenID support for modern servers and consumers with comprehensive authentication functionality.

Pending
Overview
Eval results
Files

discovery.mddocs/

OpenID Discovery

Complete OpenID service discovery implementation that enables consumers to discover OpenID service endpoints from user identifiers. The discovery system supports both Yadis-based XRDS discovery and HTML-based discovery with automatic fallback mechanisms, handling OpenID 1.0, 1.1, and 2.0 protocols.

Core Imports

from openid.consumer.discover import (
    discover,
    OpenIDServiceEndpoint,
    normalizeURL,
    normalizeXRI,
    discoverYadis,
    discoverXRI,
    discoverURI,
    discoverNoYadis,
    findOPLocalIdentifier,
    arrangeByType,
    getOPOrUserServices,
    OPENID_1_0_NS,
    OPENID_IDP_2_0_TYPE,
    OPENID_2_0_TYPE,
    OPENID_1_1_TYPE,
    OPENID_1_0_TYPE
)

Capabilities

Primary Discovery Interface

The main discovery function that handles both XRI and URL identifiers with automatic protocol detection.

def discover(identifier):
    """
    Discover OpenID service endpoints for a user identifier.
    
    Parameters:
    - identifier: str, user's OpenID identifier (URL or XRI)
    
    Returns:
    tuple: (claimed_id, services) where:
        - claimed_id: str, normalized claimed identifier
        - services: list of OpenIDServiceEndpoint objects, ordered by preference
        
    Raises:
    DiscoveryFailure: when discovery fails for any reason
    """

Service Endpoint Representation

Core class representing an OpenID service endpoint with methods for protocol compatibility and extension support.

class OpenIDServiceEndpoint:
    def __init__(self):
        """
        Initialize an empty OpenID service endpoint.
        
        Attributes:
        - claimed_id: str or None, the claimed identifier
        - server_url: str or None, the OpenID server endpoint URL
        - type_uris: list, supported OpenID type URIs
        - local_id: str or None, the local identifier at the server
        - canonicalID: str or None, canonical XRI identifier
        - used_yadis: bool, whether this endpoint was discovered via Yadis
        - display_identifier: str or None, identifier for display purposes
        """

    def usesExtension(self, extension_uri):
        """
        Check if this endpoint supports a specific extension.
        
        Parameters:
        - extension_uri: str, extension type URI to check
        
        Returns:
        bool: True if extension is supported
        """

    def preferredNamespace(self):
        """
        Get the preferred OpenID namespace for this endpoint.
        
        Returns:
        str: OPENID_2_0_MESSAGE_NS or OPENID_1_0_MESSAGE_NS
        """

    def supportsType(self, type_uri):
        """
        Check if this endpoint supports a specific OpenID type.
        
        Parameters:
        - type_uri: str, OpenID type URI to check
        
        Returns:
        bool: True if type is supported (considers server endpoints as supporting signon)
        """

    def compatibilityMode(self):
        """
        Check if this endpoint requires OpenID 1.x compatibility mode.
        
        Returns:
        bool: True if OpenID 1.x compatibility is needed
        """

    def isOPIdentifier(self):
        """
        Check if this is an OP Identifier endpoint (OpenID 2.0 server type).
        
        Returns:
        bool: True if this is an OP Identifier endpoint
        """

    def getLocalID(self):
        """
        Get the identifier to send as openid.identity parameter.
        
        Returns:
        str: local identifier or claimed identifier if no local ID
        """

    def getDisplayIdentifier(self):
        """
        Get the identifier for display purposes.
        
        Returns:
        str: display identifier or claimed identifier with fragment removed
        """

Service Endpoint Creation Methods

Factory methods for creating OpenID service endpoints from various sources.

@classmethod
def fromBasicServiceEndpoint(cls, endpoint):
    """
    Create OpenIDServiceEndpoint from a basic Yadis service endpoint.
    
    Parameters:
    - endpoint: BasicServiceEndpoint object from Yadis discovery
    
    Returns:
    OpenIDServiceEndpoint or None if endpoint is not OpenID-compatible
    """

@classmethod
def fromHTML(cls, uri, html):
    """
    Parse HTML document for OpenID link rel discovery.
    
    Parameters:
    - uri: str, the document URI
    - html: str, HTML document content
    
    Returns:
    list: OpenIDServiceEndpoint objects found in HTML
    """

@classmethod
def fromXRDS(cls, uri, xrds):
    """
    Parse XRDS document for OpenID service endpoints.
    
    Parameters:
    - uri: str, the document URI  
    - xrds: str, XRDS document content
    
    Returns:
    list: OpenIDServiceEndpoint objects found in XRDS
    
    Raises:
    XRDSError: when XRDS document cannot be parsed
    """

@classmethod
def fromDiscoveryResult(cls, discoveryResult):
    """
    Create endpoints from a Yadis DiscoveryResult object.
    
    Parameters:
    - discoveryResult: DiscoveryResult object from Yadis discovery
    
    Returns:
    list: OpenIDServiceEndpoint objects
    
    Raises:
    XRDSError: when XRDS document cannot be parsed
    """

@classmethod
def fromOPEndpointURL(cls, op_endpoint_url):
    """
    Create OP Identifier endpoint for a known OP endpoint URL.
    
    Parameters:
    - op_endpoint_url: str, the OP endpoint URL
    
    Returns:
    OpenIDServiceEndpoint: OP Identifier endpoint
    """

URL and XRI Normalization

Utility functions for normalizing identifiers before discovery.

def normalizeURL(url):
    """
    Normalize a URL identifier for OpenID discovery.
    
    Parameters:
    - url: str, URL to normalize
    
    Returns:
    str: normalized URL with fragment removed
    
    Raises:
    DiscoveryFailure: when URL normalization fails
    """

def normalizeXRI(xri):
    """
    Normalize an XRI identifier by removing xri:// scheme if present.
    
    Parameters:
    - xri: str, XRI identifier to normalize
    
    Returns:
    str: normalized XRI without scheme
    """

Discovery Protocol Implementations

Specific discovery methods for different protocols and fallback scenarios.

def discoverYadis(uri):
    """
    Perform Yadis-based OpenID discovery with HTML fallback.
    
    Parameters:
    - uri: str, normalized identity URL
    
    Returns:
    tuple: (claimed_id, services) where:
        - claimed_id: str, discovered claimed identifier
        - services: list of OpenIDServiceEndpoint objects
        
    Raises:
    DiscoveryFailure: when discovery fails
    """

def discoverXRI(iname):
    """
    Perform XRI resolution for OpenID discovery.
    
    Parameters:
    - iname: str, XRI identifier to resolve
    
    Returns:
    tuple: (claimed_id, services) where:
        - claimed_id: str, the normalized XRI
        - services: list of OpenIDServiceEndpoint objects with canonicalID set
        
    Raises:
    XRDSError: when XRI resolution fails
    """

def discoverURI(uri):
    """
    Perform OpenID discovery for URI identifiers.
    
    Parameters:
    - uri: str, URI identifier (may need http:// prefix)
    
    Returns:
    tuple: (claimed_id, services) where:
        - claimed_id: str, normalized claimed identifier
        - services: list of OpenIDServiceEndpoint objects
        
    Raises:
    DiscoveryFailure: when URI scheme is invalid or discovery fails
    """

def discoverNoYadis(uri):
    """
    Perform HTML-only OpenID discovery without Yadis.
    
    Parameters:
    - uri: str, identity URL
    
    Returns:
    tuple: (claimed_id, services) where:
        - claimed_id: str, final URL after redirects
        - services: list of OpenIDServiceEndpoint objects from HTML
        
    Raises:
    DiscoveryFailure: when HTTP request fails
    """

Service Processing Utilities

Utility functions for processing and ordering discovered services.

def arrangeByType(service_list, preferred_types):
    """
    Reorder services by type preference.
    
    Parameters:
    - service_list: list, OpenIDServiceEndpoint objects to reorder
    - preferred_types: list, type URIs in order of preference
    
    Returns:
    list: reordered services with preferred types first
    """

def getOPOrUserServices(openid_services):
    """
    Extract OP Identifier services or return user services ordered by preference.
    
    Parameters:
    - openid_services: list, OpenIDServiceEndpoint objects
    
    Returns:
    list: OP Identifier services if found, otherwise user services ordered by type preference
    """

def findOPLocalIdentifier(service_element, type_uris):
    """
    Find OP-Local Identifier from XRDS service element.
    
    Parameters:
    - service_element: ElementTree.Node, xrd:Service element
    - type_uris: list, xrd:Type values for this service
    
    Returns:
    str or None: OP-Local Identifier if present
    
    Raises:
    DiscoveryFailure: when multiple conflicting LocalID tags are found
    """

Usage Examples

Basic Discovery

from openid.consumer.discover import discover

try:
    claimed_id, services = discover("https://example.com/user")
    
    if services:
        # Use the first (highest priority) service
        service = services[0]
        print(f"Server URL: {service.server_url}")
        print(f"OpenID Version: {'2.0' if not service.compatibilityMode() else '1.x'}")
        print(f"OP Identifier: {service.isOPIdentifier()}")
    else:
        print("No OpenID services found")
        
except DiscoveryFailure as e:
    print(f"Discovery failed: {e}")

XRI Discovery

from openid.consumer.discover import discoverXRI

try:
    claimed_id, services = discoverXRI("=example*user")
    
    for service in services:
        print(f"Canonical ID: {service.canonicalID}")
        print(f"Server: {service.server_url}")
        print(f"Local ID: {service.getLocalID()}")
        
except XRDSError as e:
    print(f"XRI resolution failed: {e}")

Service Endpoint Analysis

from openid.consumer.discover import discover, OPENID_2_0_TYPE

claimed_id, services = discover("https://example.com/user")

for service in services:
    # Check OpenID version support
    if service.supportsType(OPENID_2_0_TYPE):
        print("Supports OpenID 2.0")
    
    # Check for extensions
    if service.usesExtension("http://openid.net/extensions/sreg/1.1"):
        print("Supports Simple Registration extension")
    
    # Get appropriate namespace
    namespace = service.preferredNamespace()
    print(f"Preferred namespace: {namespace}")

HTML Link Discovery

from openid.consumer.discover import OpenIDServiceEndpoint

html_content = '''
<html>
<head>
    <link rel="openid2.provider" href="https://example.com/openid">
    <link rel="openid2.local_id" href="https://example.com/user/local">
</head>
</html>
'''

services = OpenIDServiceEndpoint.fromHTML("https://example.com/user", html_content)

for service in services:
    print(f"Provider: {service.server_url}")
    print(f"Local ID: {service.local_id}")

Constants

# OpenID Namespace URIs
OPENID_1_0_NS = 'http://openid.net/xmlns/1.0'

# OpenID Type URIs (in preference order)
OPENID_IDP_2_0_TYPE = 'http://specs.openid.net/auth/2.0/server'      # OP Identifier
OPENID_2_0_TYPE = 'http://specs.openid.net/auth/2.0/signon'          # User Identifier  
OPENID_1_1_TYPE = 'http://openid.net/signon/1.1'                     # OpenID 1.1
OPENID_1_0_TYPE = 'http://openid.net/signon/1.0'                     # OpenID 1.0

# OpenIDServiceEndpoint class constants
openid_type_uris = [
    OPENID_IDP_2_0_TYPE,
    OPENID_2_0_TYPE, 
    OPENID_1_1_TYPE,
    OPENID_1_0_TYPE
]

Types

# Discovery result tuple
DiscoveryResult = tuple[str, list[OpenIDServiceEndpoint]]

# Exception types
class DiscoveryFailure(Exception):
    """Raised when OpenID discovery fails."""
    
class XRDSError(Exception):
    """Raised when XRDS parsing fails."""

Install with Tessl CLI

npx tessl i tessl/pypi-python3-openid

docs

association-management.md

consumer-auth.md

discovery.md

extensions.md

index.md

message-processing.md

server-implementation.md

storage-backends.md

utilities.md

tile.json