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

extensions.mddocs/

OpenID Extensions

Implementation of standard OpenID extensions including Simple Registration (SREG) for basic profile data and Attribute Exchange (AX) for flexible attribute sharing between consumers and servers.

Capabilities

Simple Registration Extension (SREG)

Standard extension for requesting and sharing basic profile information between OpenID consumers and servers.

class SRegRequest:
    """Simple Registration extension request."""
    
    def __init__(self, required=None, optional=None, policy_url=None, sreg_ns_uri=ns_uri):
        """
        Initialize SREG request.
        
        Parameters:
        - required: list, required field names
        - optional: list, optional field names  
        - policy_url: str, privacy policy URL
        - sreg_ns_uri: str, SREG namespace URI
        """

    @classmethod
    def fromOpenIDRequest(cls, request):
        """
        Create SREG request from OpenID authentication request.
        
        Parameters:
        - request: AuthRequest object
        
        Returns:
        SRegRequest object or None if no SREG data
        """

    def parseExtensionArgs(self, args, strict=False):
        """
        Parse extension arguments from OpenID message.
        
        Parameters:
        - args: dict, extension arguments
        - strict: bool, whether to enforce strict validation
        """

    def requestField(self, field_name, required=False, strict=False):
        """
        Request a single profile field.
        
        Parameters:
        - field_name: str, field name (e.g., 'nickname', 'email')
        - required: bool, whether field is required
        - strict: bool, whether to enforce strict validation
        """

    def requestFields(self, field_names, required=False, strict=False):
        """
        Request multiple profile fields.
        
        Parameters:
        - field_names: list, field names to request
        - required: bool, whether fields are required
        - strict: bool, whether to enforce strict validation
        """

    def getExtensionArgs(self):
        """
        Get extension arguments for OpenID message.
        
        Returns:
        dict, extension arguments
        """

    def allRequestedFields(self):
        """
        Get all requested fields (required and optional).
        
        Returns:
        list, all requested field names
        """

    def wereFieldsRequested(self):
        """
        Check if any fields were requested.
        
        Returns:
        bool, True if fields were requested
        """

class SRegResponse:
    """Simple Registration extension response."""
    
    def __init__(self, data=None, sreg_ns_uri=ns_uri):
        """
        Initialize SREG response.
        
        Parameters:
        - data: dict, profile data
        - sreg_ns_uri: str, SREG namespace URI
        """

    @classmethod
    def extractResponse(cls, request, data):
        """
        Extract SREG response data matching request.
        
        Parameters:
        - request: SRegRequest object
        - data: dict, available profile data
        
        Returns:
        SRegResponse object with matching fields
        """

    @classmethod  
    def fromSuccessResponse(cls, success_response, signed_only=True):
        """
        Create SREG response from successful OpenID response.
        
        Parameters:
        - success_response: SuccessResponse object
        - signed_only: bool, whether to only include signed fields
        
        Returns:
        SRegResponse object or None if no SREG data
        """

    def getExtensionArgs(self):
        """
        Get extension arguments for OpenID message.
        
        Returns:
        dict, extension arguments
        """

    def get(self, field_name, default=None):
        """
        Get profile field value.
        
        Parameters:
        - field_name: str, field name
        - default: default value if field not present
        
        Returns:
        str or default, field value
        """

    def items(self):
        """
        Get all profile data as key-value pairs.
        
        Returns:
        list, [(field_name, value), ...] tuples
        """

    def keys(self):
        """
        Get all profile field names.
        
        Returns:
        list, field names
        """

    def values(self):
        """
        Get all profile field values.
        
        Returns:
        list, field values  
        """

Attribute Exchange Extension (AX)

Flexible extension for exchanging structured attribute data with support for multiple values and custom attribute types.

class AttrInfo:
    """Attribute information for AX requests."""
    
    def __init__(self, type_uri, count=1, required=False, alias=None):
        """
        Initialize attribute information.
        
        Parameters:
        - type_uri: str, attribute type URI
        - count: int or 'unlimited', number of values requested
        - required: bool, whether attribute is required
        - alias: str, attribute alias (auto-generated if None)
        """

    def wantsUnlimitedValues(self):
        """
        Check if unlimited values are requested.
        
        Returns:
        bool, True if unlimited values wanted
        """

class FetchRequest:
    """AX fetch request for retrieving attributes."""
    
    def __init__(self, update_url=None):
        """
        Initialize fetch request.
        
        Parameters:
        - update_url: str, URL for attribute updates
        """

    def add(self, attribute):
        """
        Add attribute to fetch request.
        
        Parameters:
        - attribute: AttrInfo object
        """

    @classmethod
    def fromOpenIDRequest(cls, openid_request):
        """
        Create fetch request from OpenID authentication request.
        
        Parameters:
        - openid_request: AuthRequest object
        
        Returns:
        FetchRequest object or None if no AX data
        """

    def parseExtensionArgs(self, ax_args):
        """
        Parse AX extension arguments.
        
        Parameters:
        - ax_args: dict, AX extension arguments
        """

    def getExtensionArgs(self):
        """
        Get extension arguments for OpenID message.
        
        Returns:
        dict, extension arguments
        """

    def getRequiredAttrs(self):
        """
        Get required attributes.
        
        Returns:
        list, AttrInfo objects for required attributes
        """

    def iterAttrs(self):
        """
        Iterate over all requested attributes.
        
        Returns:
        iterator, AttrInfo objects
        """

class FetchResponse:
    """AX fetch response with attribute data."""
    
    def __init__(self, request=None, update_url=None):
        """
        Initialize fetch response.
        
        Parameters:
        - request: FetchRequest object (optional)
        - update_url: str, URL for attribute updates
        """

    @classmethod
    def fromSuccessResponse(cls, success_response, signed=True):
        """
        Create fetch response from successful OpenID response.
        
        Parameters:
        - success_response: SuccessResponse object
        - signed: bool, whether to only include signed attributes
        
        Returns:
        FetchResponse object or None if no AX data
        """

    def getExtensionArgs(self):
        """
        Get extension arguments for OpenID message.
        
        Returns:
        dict, extension arguments
        """

    def parseExtensionArgs(self, ax_args):
        """
        Parse AX extension arguments.
        
        Parameters:
        - ax_args: dict, AX extension arguments
        """

class StoreRequest:
    """AX store request for sending attributes to server."""
    
    def __init__(self, aliases=None):
        """
        Initialize store request.
        
        Parameters:
        - aliases: dict, attribute type URI to alias mapping
        """

    def getExtensionArgs(self):
        """
        Get extension arguments for OpenID message.
        
        Returns:
        dict, extension arguments
        """

class StoreResponse:
    """AX store response indicating success or failure."""
    
    def __init__(self, succeeded=True, error_message=None):
        """
        Initialize store response.
        
        Parameters:
        - succeeded: bool, whether store operation succeeded
        - error_message: str, error message if failed
        """

    def succeeded(self):
        """
        Check if store operation succeeded.
        
        Returns:
        bool, True if succeeded
        """

    def getExtensionArgs(self):
        """
        Get extension arguments for OpenID message.
        
        Returns:
        dict, extension arguments
        """

AX Base Classes

Base classes providing common functionality for AX message handling.

class AXMessage:
    """Abstract base class for AX messages."""
    
    def getExtensionArgs(self):
        """Get extension arguments."""

class AXKeyValueMessage(AXMessage):
    """Base class for AX messages with key-value data."""
    
    def addValue(self, type_uri, value):
        """
        Add single value for attribute type.
        
        Parameters:
        - type_uri: str, attribute type URI
        - value: str, attribute value
        """

    def setValues(self, type_uri, values):
        """
        Set multiple values for attribute type.
        
        Parameters:
        - type_uri: str, attribute type URI
        - values: list, attribute values
        """

    def getSingle(self, type_uri, default=None):
        """
        Get single value for attribute type.
        
        Parameters:
        - type_uri: str, attribute type URI
        - default: default value if not found
        
        Returns:
        str or default, attribute value
        """

    def get(self, type_uri):
        """
        Get all values for attribute type.
        
        Parameters:
        - type_uri: str, attribute type URI
        
        Returns:
        list, attribute values
        """

    def count(self, type_uri):
        """
        Count values for attribute type.
        
        Parameters:
        - type_uri: str, attribute type URI
        
        Returns:
        int, number of values
        """

Extension Utilities

Utility functions for working with OpenID extensions.

def checkFieldName(field_name):
    """
    Validate SREG field name.
    
    Parameters:
    - field_name: str, field name to validate
    
    Raises:
    ValueError: if field name is invalid
    """

def getSRegNS(message):
    """
    Get SREG namespace URI from OpenID message.
    
    Parameters:
    - message: Message object
    
    Returns:
    str, SREG namespace URI or None
    """

def supportsSReg(endpoint):
    """
    Check if endpoint supports SREG extension.
    
    Parameters:
    - endpoint: OpenIDServiceEndpoint object
    
    Returns:
    bool, True if SREG is supported
    """

def checkAlias(alias):
    """
    Validate AX attribute alias.
    
    Parameters:
    - alias: str, alias to validate
    
    Raises:
    ValueError: if alias is invalid
    """

def toTypeURIs(namespace_map, alias_list_s):
    """
    Convert comma-separated alias list to type URIs.
    
    Parameters:
    - namespace_map: dict, alias to type URI mapping
    - alias_list_s: str, comma-separated alias list
    
    Returns:
    list, type URIs
    """

Usage Examples

SREG Consumer Usage

from openid.extensions import sreg
from openid.consumer import consumer

# Create consumer and start authentication
openid_consumer = consumer.Consumer({}, store)
auth_request = openid_consumer.begin(user_url)

# Add SREG request
sreg_request = sreg.SRegRequest(
    required=['nickname', 'email'],  # Required fields
    optional=['fullname', 'dob'],    # Optional fields
    policy_url="https://mysite.com/privacy"
)
auth_request.addExtension(sreg_request)

# Redirect user to identity provider
redirect_url = auth_request.redirectURL(realm, return_to)

# Handle response
response = openid_consumer.complete(query, current_url)
if response.status == consumer.SUCCESS:
    sreg_response = sreg.SRegResponse.fromSuccessResponse(response)
    if sreg_response:
        nickname = sreg_response.get('nickname')
        email = sreg_response.get('email')
        fullname = sreg_response.get('fullname')
        
        # Use profile data
        create_user_account(nickname, email, fullname)

SREG Server Usage

from openid.extensions import sreg

def handle_checkid_request(openid_request):
    # Check for SREG request
    sreg_request = sreg.SRegRequest.fromOpenIDRequest(openid_request)
    
    if sreg_request:
        # Get user profile data
        user_profile = get_user_profile(user_id)
        
        # Create SREG response with requested fields
        sreg_response = sreg.SRegResponse.extractResponse(
            sreg_request, 
            user_profile
        )
        
        # Create positive OpenID response
        openid_response = openid_request.answer(allow=True, ...)
        openid_response.addExtension(sreg_response)
        
        return openid_response

AX Consumer Usage

from openid.extensions import ax

# Create AX fetch request
ax_request = ax.FetchRequest()

# Add specific attributes
ax_request.add(ax.AttrInfo(
    'http://schema.openid.net/contact/email',
    required=True,
    alias='email'
))
ax_request.add(ax.AttrInfo(
    'http://schema.openid.net/namePerson/friendly',
    required=False,
    alias='nickname'
))
ax_request.add(ax.AttrInfo(
    'http://schema.openid.net/contact/web/homepage',
    count='unlimited',  # Allow multiple URLs
    alias='website'
))

# Add to authentication request
auth_request.addExtension(ax_request)

# Handle response
response = openid_consumer.complete(query, current_url)
if response.status == consumer.SUCCESS:
    ax_response = ax.FetchResponse.fromSuccessResponse(response)
    if ax_response:
        email = ax_response.getSingle('http://schema.openid.net/contact/email')
        nickname = ax_response.getSingle('http://schema.openid.net/namePerson/friendly')
        websites = ax_response.get('http://schema.openid.net/contact/web/homepage')

AX Server Usage

from openid.extensions import ax

def handle_ax_fetch_request(openid_request):
    ax_request = ax.FetchRequest.fromOpenIDRequest(openid_request)
    
    if ax_request:
        ax_response = ax.FetchResponse()
        
        # Process each requested attribute
        for attr_info in ax_request.iterAttrs():
            if attr_info.type_uri == 'http://schema.openid.net/contact/email':
                if user_allows_email_sharing():
                    ax_response.addValue(attr_info.type_uri, user.email)
            
            elif attr_info.type_uri == 'http://schema.openid.net/namePerson/friendly':
                ax_response.addValue(attr_info.type_uri, user.nickname)
            
            elif attr_info.type_uri == 'http://schema.openid.net/contact/web/homepage':
                # Multiple values supported
                for website in user.websites:
                    ax_response.addValue(attr_info.type_uri, website)
        
        # Add to OpenID response
        openid_response = openid_request.answer(allow=True, ...)
        openid_response.addExtension(ax_response)
        
        return openid_response

Types

# SREG namespace URIs
ns_uri_1_0 = 'http://openid.net/sreg/1.0'
ns_uri_1_1 = 'http://openid.net/extensions/sreg/1.1'
ns_uri = ns_uri_1_1  # Preferred namespace

# SREG data fields
data_fields = {
    'nickname': 'Any UTF-8 string that the End User wants to use as a nickname.',
    'email': 'The email address of the End User as specified in section 3.4.1 of [RFC2822]',
    'fullname': 'UTF-8 string free text representation of the End User\'s full name.',
    'dob': 'The End User\'s date of birth as YYYY-MM-DD.',
    'gender': 'The End User\'s gender, "M" for male, "F" for female.',
    'postcode': 'UTF-8 string free text that SHOULD conform to the End User\'s country\'s postal system.',
    'country': 'The End User\'s country of residence as specified by ISO3166.',
    'language': 'End User\'s preferred language as specified by ISO639.',
    'timezone': 'ASCII string from TimeZone database'
}

# AX constants
UNLIMITED_VALUES = "unlimited"
MINIMUM_SUPPORTED_ALIAS_LENGTH = 32

# Common AX attribute type URIs
AX_SCHEMA_ATTRS = {
    'email': 'http://schema.openid.net/contact/email',
    'nickname': 'http://schema.openid.net/namePerson/friendly', 
    'fullname': 'http://schema.openid.net/namePerson',
    'first_name': 'http://schema.openid.net/namePerson/first',
    'last_name': 'http://schema.openid.net/namePerson/last',
    'website': 'http://schema.openid.net/contact/web/homepage',
    'image': 'http://schema.openid.net/media/image/aspect11',
    'country': 'http://schema.openid.net/contact/country/home',
    'language': 'http://schema.openid.net/pref/language',
    'timezone': 'http://schema.openid.net/pref/timezone'
}

# Exception types
class SRegNamespaceError(Exception):
    """SREG namespace error."""

class AXError(Exception):
    """AX extension error."""

class NotAXMessage(Exception):
    """Message is not an AX message."""

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