def verify(self, assoc_handle, sig, signed_pairs): """Verify that the signature for some data is valid. @param assoc_handle: The handle of the association used to sign the data. @type assoc_handle: str @param sig: The base-64 encoded signature to check. @type sig: str @param signed_pairs: The data to check, an ordered list of key-value pairs. The keys should be as they are in the request's C{signed} list, without any C{"openid."} prefix. @type signed_pairs: list of pairs @returns: C{True} if the signature is valid, C{False} if not. @returntype: bool """ assoc = self.getAssociation(assoc_handle, dumb=True) if not assoc: oidutil.log("failed to get assoc with handle %r to verify sig %r" % (assoc_handle, sig)) return False # Not using Association.checkSignature here is intentional; # Association should not know things like "the list of signed pairs is # in the request's 'signed' parameter and it is comma-separated." expected_sig = oidutil.toBase64(assoc.sign(signed_pairs)) return sig == expected_sig
def verifyReturnTo(realm_str, return_to, _vrfy=getAllowedReturnURLs): """Verify that a return_to URL is valid for the given realm. This function builds a discovery URL, performs Yadis discovery on it, makes sure that the URL does not redirect, parses out the return_to URLs, and finally checks to see if the current return_to URL matches the return_to. @raises DiscoveryFailure: When Yadis discovery fails @returns: True if the return_to URL is valid for the realm @since: 2.1.0 """ realm = TrustRoot.parse(realm_str) if realm is None: # The realm does not parse as a URL pattern return False try: allowable_urls = _vrfy(realm.buildDiscoveryURL()) except RealmVerificationRedirected as err: oidutil.log(str(err)) return False if returnToMatches(allowable_urls, return_to): return True else: oidutil.log("Failed to validate return_to %r for realm %r, was not " "in %s" % (return_to, realm_str, allowable_urls)) return False
def getAssociationFilename(self, server_url, handle): """Create a unique filename for a given server url and handle. This implementation does not assume anything about the format of the handle. The filename that is returned will contain the domain name from the server URL for ease of human inspection of the data directory. (str, str) -> str """ if server_url.find('://') == -1: raise ValueError('Bad server URL: %r' % server_url) proto, rest = server_url.split('://', 1) domain = _filenameEscape(rest.split('/', 1)[0]) url_hash = _safe64(server_url) if handle: handle_hash = _safe64(handle) else: handle_hash = '' filename = '%s-%s-%s-%s' % (proto, domain, url_hash, handle_hash) oidutil.log('filename for %s %s is %s' % (server_url, handle, filename)) return os.path.join(self.association_dir, filename)
def _allAssocs(self): all_associations = [] association_filenames = [os.path.join(self.association_dir, filename) for filename in os.listdir(self.association_dir)] for association_filename in association_filenames: try: association_file = file(association_filename, 'rb') except IOError as why: if why.errno == ENOENT: oidutil.log("%s disappeared during %s._allAssocs" % ( association_filename, self.__class__.__name__)) else: raise else: try: assoc_s = association_file.read() finally: association_file.close() # Remove expired or corrupted associations try: association = Association.deserialize(assoc_s) except ValueError: _removeIfPresent(association_filename) else: all_associations.append( (association_filename, association)) return all_associations
def try_login(self, identity_url, ask_for=None): """This tries to login with the given identity URL. This function must be called from the login_handler. The `ask_for` parameter can be a set of values to be asked from the openid provider. The following strings can be used in the `ask_for` parameter: ``aim``, ``blog``, ``country``, ``dob`` (date of birth), ``email``, ``fullname``, ``gender``, ``icq``, ``image``, ``jabber``, ``language``, ``msn``, ``nickname``, ``phone``, ``postcode``, ``skype``, ``timezone``, ``website``, ``yahoo`` """ if ask_for and __debug__: for key in ask_for: if key not in ALL_KEYS: raise ValueError('invalid key %r' % key) try: oidutil.log("self.store_factory() :" + str(self.store_factory)) consumer = Consumer(SessionWrapper(self), self.store_factory()) auth_request = consumer.begin(identity_url) if ask_for: self.attach_reg_info(auth_request, ask_for) except discover.DiscoveryFailure: self.signal_error(u'The OpenID was invalid') return redirect(self.get_current_url()) trust_root = request.host_url return redirect(auth_request.redirectURL(request.host_url, self.get_success_url()))
def discoverXRI(iname): endpoints = [] iname = normalizeXRI(iname) try: canonicalID, services = xrires.ProxyResolver().query( iname, OpenIDServiceEndpoint.openid_type_uris) if canonicalID is None: raise XRDSError('No CanonicalID found for XRI %r' % (iname,)) flt = filters.mkFilter(OpenIDServiceEndpoint) for service_element in services: endpoints.extend(flt.getServiceEndpoints(iname, service_element)) except XRDSError: oidutil.log('xrds error on ' + iname) for endpoint in endpoints: # Is there a way to pass this through the filter to the endpoint # constructor instead of tacking it on after? endpoint.canonicalID = canonicalID endpoint.claimed_id = canonicalID endpoint.display_identifier = iname # FIXME: returned xri should probably be in some normal form return iname, getOPOrUserServices(endpoints)
def discoverXRI(iname): endpoints = [] iname = normalizeXRI(iname) try: canonicalID, services = xrires.ProxyResolver().query( iname, OpenIDServiceEndpoint.openid_type_uris) if canonicalID is None: raise XRDSError('No CanonicalID found for XRI %r' % (iname, )) flt = filters.mkFilter(OpenIDServiceEndpoint) for service_element in services: endpoints.extend(flt.getServiceEndpoints(iname, service_element)) except XRDSError: oidutil.log('xrds error on ' + iname) for endpoint in endpoints: # Is there a way to pass this through the filter to the endpoint # constructor instead of tacking it on after? endpoint.canonicalID = canonicalID endpoint.claimed_id = canonicalID endpoint.display_identifier = iname # FIXME: returned xri should probably be in some normal form return iname, getOPOrUserServices(endpoints)
def _allAssocs(self): all_associations = [] association_filenames = map( lambda filename: os.path.join(self.association_dir, filename), os.listdir(self.association_dir)) for association_filename in association_filenames: try: association_file = file(association_filename, 'rb') except IOError, why: if why.errno == ENOENT: oidutil.log( "%s disappeared during %s._allAssocs" % (association_filename, self.__class__.__name__)) else: raise else: try: assoc_s = association_file.read() finally: association_file.close() # Remove expired or corrupted associations try: association = Association.deserialize(assoc_s) except ValueError: _removeIfPresent(association_filename) else: all_associations.append( (association_filename, association))
def getAssociation(self, assoc_handle, dumb): """Get the association with the specified handle. @type assoc_handle: str @param dumb: Is this association used with dumb mode? @type dumb: bool @returns: the association, or None if no valid association with that handle was found. @returntype: L{openid.association.Association} """ # Hmm. We've created an interface that deals almost entirely with # assoc_handles. The only place outside the Signatory that uses this # (and thus the only place that ever sees Association objects) is # when creating a response to an association request, as it must have # the association's secret. if assoc_handle is None: raise ValueError("assoc_handle must not be None") if dumb: key = self._dumb_key else: key = self._normal_key assoc = self.store.getAssociation(key, assoc_handle) if assoc is not None and assoc.expiresIn <= 0: oidutil.log("requested %sdumb key %r is expired (by %s seconds)" % ((not dumb) and 'not-' or '', assoc_handle, assoc.expiresIn)) self.store.removeAssociation(key, assoc_handle) assoc = None return assoc
def getAssociation(self, assoc_handle, dumb): """Get the association with the specified handle. @type assoc_handle: str @param dumb: Is this association used with dumb mode? @type dumb: bool @returns: the association, or None if no valid association with that handle was found. @returntype: L{openid.association.Association} """ # Hmm. We've created an interface that deals almost entirely with # assoc_handles. The only place outside the Signatory that uses this # (and thus the only place that ever sees Association objects) is # when creating a response to an association request, as it must have # the association's secret. if assoc_handle is None: raise ValueError("assoc_handle must not be None") if dumb: key = self._dumb_key else: key = self._normal_key assoc = self.store.getAssociation(key, assoc_handle) if assoc is not None and assoc.expiresIn <= 0: oidutil.log( "requested %sdumb key %r is expired (by %s seconds)" % ((not dumb) and 'not-' or '', assoc_handle, assoc.expiresIn)) self.store.removeAssociation(key, assoc_handle) assoc = None return assoc
def _parseAssociation(self, results, assoc_session, server_url): try: assoc_type = results['assoc_type'] assoc_handle = results['assoc_handle'] expires_in_str = results['expires_in'] except KeyError, e: fmt = 'Getting association: missing key in response from %s: %s' oidutil.log(fmt % (server_url, e[0])) return None
def _getAssociation(self, filename): oidutil.log('getting association from file %s' % filename) try: assoc_file = file(filename, 'rb') except IOError, why: if why.errno == ENOENT: # No association exists for that URL and handle return None else: raise
def _processCheckAuthResponse(self, response, server_url): is_valid = response.get('is_valid', 'false') invalidate_handle = response.get('invalidate_handle') if invalidate_handle is not None: self.store.removeAssociation(server_url, invalidate_handle) if is_valid == 'true': return True else: oidutil.log('Server responds that checkAuth call is not valid') return False
def _discoverAndVerify(self, claimed_id, to_match_endpoints): oidutil.log("Performing discovery on %s" % (claimed_id,)) if not claimed_id.startswith("https://www.google.com/accounts/"): # want to get a service endpoint for the domain, but keep the # original claimed_id so tests during verify pass g_claimed_id = "https://www.google.com/accounts/o8/user-xrds?uri=" + claimed_id _, services = self._discover(g_claimed_id) services[0].claimed_id = claimed_id else: _, services = self._discover(claimed_id) if not services: raise DiscoveryFailure("No OpenID information found at %s" % (claimed_id,), None) return self._verifyDiscoveredServices(claimed_id, services, to_match_endpoints)
def _discoverAndVerify(self, claimed_id, to_match_endpoints): oidutil.log('Performing discovery on %s' % (claimed_id,)) if not claimed_id.startswith('https://www.google.com/accounts/'): # want to get a service endpoint for the domain, but keep the # original claimed_id so tests during verify pass g_claimed_id = "https://www.google.com/accounts/o8/user-xrds?uri="+claimed_id _, services = self._discover(g_claimed_id) services[0].claimed_id = claimed_id else: _, services = self._discover(claimed_id) if not services: raise DiscoveryFailure('No OpenID information found at %s' % (claimed_id,), None) return self._verifyDiscoveredServices(claimed_id, services, to_match_endpoints)
def _createCheckAuthRequest(self, query): signed = query.get('openid.signed') if signed is None: oidutil.log('No signature present; checkAuth aborted') return None # Arguments that are always passed to the server and not # included in the signature. whitelist = ['assoc_handle', 'sig', 'signed', 'invalidate_handle'] signed = signed.split(',') + whitelist check_args = dict([(k, v) for k, v in query.iteritems() if k.startswith('openid.') and k[7:] in signed]) check_args['openid.mode'] = 'check_authentication' return check_args
def _getAssociation(self, server_url): if self.store.isDumb(): return None assoc = self.store.getAssociation(server_url) if assoc is None or assoc.expiresIn <= 0: assoc_session, args = self._createAssociateRequest(server_url) try: response = self._makeKVPost(args, server_url) except fetchers.HTTPFetchingError, why: oidutil.log('openid.associate request failed: %s' % (str(why),)) assoc = None else: assoc = self._parseAssociation( response, assoc_session, server_url)
def discoverXRI(iname): endpoints = [] try: canonicalID, services = xrires.ProxyResolver().query( iname, OpenIDServiceEndpoint.openid_type_uris) flt = filters.mkFilter(OpenIDServiceEndpoint) for service_element in services: endpoints.extend(flt.getServiceEndpoints(iname, service_element)) except XRDSError: oidutil.log('xrds error on ' + iname) for endpoint in endpoints: # Is there a way to pass this through the filter to the endpoint # constructor instead of tacking it on after? endpoint.canonicalID = canonicalID # FIXME: returned xri should probably be in some normal form return iname, endpoints
def getAssociation(self, server_url, handle=None): """Retrieve an association. If no handle is specified, return the association with the latest expiration. (str, str or NoneType) -> Association or NoneType """ oidutil.log('getting association %s for url %s' % (handle, server_url)) if handle is None: handle = '' # The filename with the empty handle is a prefix of all other # associations for the given server URL. filename = self.getAssociationFilename(server_url, handle) if handle: return self._getAssociation(filename) else: association_files = os.listdir(self.association_dir) matching_files = [] # strip off the path to do the comparison name = os.path.basename(filename) for association_file in association_files: if association_file.startswith(name): matching_files.append(association_file) matching_associations = [] # read the matching files and sort by time issued for name in matching_files: full_name = os.path.join(self.association_dir, name) association = self._getAssociation(full_name) if association is not None: matching_associations.append( (association.issued, association)) matching_associations.sort() # return the most recently issued one. if matching_associations: (_, assoc) = matching_associations[-1] return assoc else: return None
def _default_store_factory(self): """Default store factory that creates a filesystem store from the configuration. """ print "in _default_store_factory - current_app:", current_app app = self.app if self.app is not None else current_app if 'OPENID_FS_STORE_PATH' not in app.config: self.init_app(app) from warnings import warn warn(DeprecationWarning('init_app not called for this ' 'application. This is deprecated functionality')) else: if app.config['OPENID_FS_STORE_PATH'] == 'datastore': oidutil.log("in _default_store_factory - return datastore object" + str(DatastoreStore())) return DatastoreStore() path = app.config['OPENID_FS_STORE_PATH'] or self.fs_store_path if path is None: path = os.path.join(tempfile.gettempdir(), 'flask-openid') return FileOpenIDStore(path)
def verifyReturnTo(realm_str, return_to, _vrfy=getAllowedReturnURLs): """Verify that a return_to URL is valid for the given realm. This function builds a discovery URL, performs Yadis discovery on it, makes sure that the URL does not redirect, parses out the return_to URLs, and finally checks to see if the current return_to URL matches the return_to. @raises DiscoveryFailure: When Yadis discovery fails @returns: True if the return_to URL is valid for the realm @since: 2.1.0 """ realm = TrustRoot.parse(realm_str) if realm is None: # The realm does not parse as a URL pattern return False try: allowable_urls = _vrfy(realm.buildDiscoveryURL()) except RealmVerificationRedirected, err: oidutil.log(str(err)) return False
def _verifyDiscoveryResultsOpenID2(self, resp_msg, endpoint): to_match = OpenIDServiceEndpoint() to_match.type_uris = [OPENID_2_0_TYPE] to_match.claimed_id = resp_msg.getArg(OPENID2_NS, 'claimed_id') to_match.local_id = resp_msg.getArg(OPENID2_NS, 'identity') # Raises a KeyError when the op_endpoint is not present to_match.server_url = resp_msg.getArg( OPENID2_NS, 'op_endpoint', no_default) # claimed_id and identifier must both be present or both # be absent if (to_match.claimed_id is None and to_match.local_id is not None): raise consumer.ProtocolError( 'openid.identity is present without openid.claimed_id') elif (to_match.claimed_id is not None and to_match.local_id is None): raise consumer.ProtocolError( 'openid.claimed_id is present without openid.identity') # This is a response without identifiers, so there's really no # checking that we can do, so return an endpoint that's for # the specified `openid.op_endpoint' elif to_match.claimed_id is None: return OpenIDServiceEndpoint.fromOPEndpointURL(to_match.server_url) # The claimed ID doesn't match, so we have to do discovery # again. This covers not using sessions, OP identifier # endpoints and responses that didn't match the original # request. if to_match.server_url.startswith(u'https://www.google.com/a/'): import urllib claimed_id = u'https://www.google.com/accounts/o8/user-xrds?uri=%s' % urllib.quote_plus(to_match.claimed_id) else: claimed_id = to_match.claimed_id if not endpoint: oidutil.log('No pre-discovered information supplied.') endpoint = self._discoverAndVerify(claimed_id, [to_match]) else: # The claimed ID matches, so we use the endpoint that we # discovered in initiation. This should be the most common # case. try: self._verifyDiscoverySingle(endpoint, to_match) except consumer.ProtocolError, e: oidutil.log( "Error attempting to use stored discovery information: " + str(e)) oidutil.log("Attempting discovery to verify endpoint") endpoint = self._discoverAndVerify( claimed_id, [to_match])
def _makeKVPost(self, args, server_url): mode = args['openid.mode'] body = urllib.urlencode(args) resp = fetchers.fetch(server_url, body=body) if resp is None: fmt = 'openid.mode=%s: failed to fetch URL: %s' oidutil.log(fmt % (mode, server_url)) return None response = kvform.kvToDict(resp.body) if resp.status == 400: server_error = response.get('error', '<no message from server>') fmt = 'openid.mode=%s: error returned from server %s: %s' oidutil.log(fmt % (mode, server_url, server_error)) return None elif resp.status != 200: fmt = 'openid.mode=%s: bad status code from server %s: %s' oidutil.log(fmt % (mode, server_url, resp.status)) return None return response
) from six import string_types __all__ = [ 'TeamsRequest', 'TeamsResponse', 'ns_uri', 'supportsTeams', ] ns_uri = 'http://ns.launchpad.net/2007/openid-teams' try: registerNamespaceAlias(ns_uri, 'lp') except NamespaceAliasRegistrationError as e: oidutil.log( 'registerNamespaceAlias(%r, %r) failed: %s' % (ns_uri, 'lp', str(e))) def supportsTeams(endpoint): """Does the given endpoint advertise support for Launchpad Teams? @param endpoint: The endpoint object as returned by OpenID discovery @type endpoint: openid.consumer.discover.OpenIDEndpoint @returns: Whether an lp type was advertised by the endpoint @rtype: bool """ return endpoint.usesExtension(ns_uri) class TeamsNamespaceError(ValueError):
ns_uri_1_0 = 'http://openid.net/sreg/1.0' # URI in the draft specification for simple registration 1.1 # <http://openid.net/specs/openid-simple-registration-extension-1_1-01.html> ns_uri_1_1 = 'http://openid.net/extensions/sreg/1.1' # This attribute will always hold the preferred URI to use when adding # sreg support to an XRDS file or in an OpenID namespace declaration. ns_uri = ns_uri_1_1 try: registerNamespaceAlias(ns_uri_1_1, 'sreg') except NamespaceAliasRegistrationError, e: oidutil.log('registerNamespaceAlias(%r, %r) failed: %s' % ( ns_uri_1_1, 'sreg', str(e), )) def supportsSReg(endpoint): """Does the given endpoint advertise support for simple registration? @param endpoint: The endpoint object as returned by OpenID discovery @type endpoint: openid.consumer.discover.OpenIDEndpoint @returns: Whether an sreg type was advertised by the endpoint @rtype: bool """ return (endpoint.usesExtension(ns_uri_1_1)
args.update(assoc_session.getRequest()) return assoc_session, args def _parseAssociation(self, results, assoc_session, server_url): try: assoc_type = results['assoc_type'] assoc_handle = results['assoc_handle'] expires_in_str = results['expires_in'] except KeyError, e: fmt = 'Getting association: missing key in response from %s: %s' oidutil.log(fmt % (server_url, e[0])) return None if assoc_type != 'HMAC-SHA1': fmt = 'Unsupported assoc_type returned from server %s: %s' oidutil.log(fmt % (server_url, assoc_type)) return None try: expires_in = int(expires_in_str) except ValueError, e: fmt = 'Getting Association: invalid expires_in field: %s' oidutil.log(fmt % (e[0],)) return None session_type = results.get('session_type') if session_type != assoc_session.session_type: if session_type is None: oidutil.log('Falling back to plain text association ' 'session from %s' % assoc_session.session_type) assoc_session = PlainTextConsumerSession()
def verifyReturnTo(realm_str, return_to, _vrfy=getAllowedReturnURLs): """Verify that a return_to URL is valid for the given realm. This function builds a discovery URL, performs Yadis discovery on it, makes sure that the URL does not redirect, parses out the return_to URLs, and finally checks to see if the current return_to URL matches the return_to. @raises DiscoveryFailure: When Yadis discovery fails @returns: True if the return_to URL is valid for the realm @since: 2.1.0 """ realm = TrustRoot.parse(realm_str) if realm is None: # The realm does not parse as a URL pattern return False try: allowable_urls = _vrfy(realm.buildDiscoveryURL()) except RealmVerificationRedirected, err: oidutil.log(str(err)) return False if returnToMatches(allowable_urls, return_to): return True else: oidutil.log("Failed to validate return_to %r for realm %r, was not " "in %s" % (return_to, realm_str, allowable_urls)) return False
def err(msg): formatted = 'seqToKV warning: %s: %r' % (msg, seq) if strict: raise KVFormError(formatted) else: oidutil.log(formatted)
NamespaceAliasRegistrationError) from openid.extension import Extension from openid import oidutil try: basestring except NameError: # For Python 2.2 basestring = (str, unicode) ns_uri = "http://specs.openid.net/extensions/oauth/1.0" # try: registerNamespaceAlias(ns_uri, 'oauth') except NamespaceAliasRegistrationError, e: oidutil.log('registerNamespaceAlias(%r, %r) failed: %s' % (ns_uri, 'oauth', str(e),)) class OAuthRequest(Extension): ns_alias = 'oauth' def __init__(self, consumer=None, scope=None, oauth_ns_uri=ns_uri): Extension.__init__(self) self.consumer = consumer self.scope = scope self.ns_uri = oauth_ns_uri def fromOpenIDRequest(cls, request): self = cls()
assoc_file = file(filename, 'rb') except IOError, why: if why.errno == ENOENT: # No association exists for that URL and handle return None else: raise else: try: assoc_s = assoc_file.read() finally: assoc_file.close() try: association = Association.deserialize(assoc_s) oidutil.log('got association %s' % association) except ValueError: _removeIfPresent(filename) return None # Clean up expired associations if association.getExpiresIn() == 0: _removeIfPresent(filename) oidutil.log('association expired') return None else: return association def removeAssociation(self, server_url, handle): """Remove an association if it exists. Do nothing if it does not.
# URI used in the wild for Yadis documents advertising simple # registration support ns_uri_1_0 = 'http://openid.net/sreg/1.0' # URI in the draft specification for simple registration 1.1 # <http://openid.net/specs/openid-simple-registration-extension-1_1-01.html> ns_uri_1_1 = 'http://openid.net/extensions/sreg/1.1' # This attribute will always hold the preferred URI to use when adding # sreg support to an XRDS file or in an OpenID namespace declaration. ns_uri = ns_uri_1_1 try: registerNamespaceAlias(ns_uri_1_1, 'sreg') except NamespaceAliasRegistrationError, e: oidutil.log('registerNamespaceAlias(%r, %r) failed: %s' % (ns_uri_1_1, 'sreg', str(e),)) def supportsSReg(endpoint): """Does the given endpoint advertise support for simple registration? @param endpoint: The endpoint object as returned by OpenID discovery @type endpoint: openid.consumer.discover.OpenIDEndpoint @returns: Whether an sreg type was advertised by the endpoint @rtype: bool """ return (endpoint.usesExtension(ns_uri_1_1) or endpoint.usesExtension(ns_uri_1_0)) class SRegNamespaceError(ValueError):
'MacaroonResponse', ] from openid import oidutil from openid.extension import Extension from openid.message import ( NamespaceAliasRegistrationError, registerNamespaceAlias, ) MACAROON_NS = 'http://ns.login.ubuntu.com/2016/openid-macaroon' try: registerNamespaceAlias(MACAROON_NS, 'macaroon') except NamespaceAliasRegistrationError as e: oidutil.log('registerNamespaceAlias(%r, %r) failed: %s' % (MACAROON_NS, 'macaroon', e)) def get_macaroon_ns(message): """Extract the macaroon namespace URI from the given OpenID message. @param message: The OpenID message from which to parse the macaroon. This may be a request or response message. @type message: C{L{openid.message.Message}} @returns: the macaroon namespace URI for the supplied message. The message may be modified to define a macaroon namespace. @rtype: C{str} @raise ValueError: when using OpenID 1 if the message defines the 'macaroon' alias to be something other than a macaroon type.
def err(msg): formatted = 'kvToSeq warning: %s: %r' % (msg, data) if strict: raise KVFormError(formatted) else: oidutil.log(formatted)
def err(msg): formatted = 'seqToKV warning: %s: %r' % (msg, seq) if strict: raise ValueError(formatted) else: oidutil.log(formatted)
def err(msg): formatted = 'kvToSeq warning: %s: %r' % (msg, data) if strict: raise ValueError(formatted) else: oidutil.log(formatted)
# -*- test-case-name: openid.test.test_discover -*- from urljr import fetchers from openid import oidutil # If the Yadis library is available, use it. Otherwise, only use # old-style discovery. try: import yadis except ImportError: yadis_available = False oidutil.log('Consumer operating without Yadis support ' '(failed to import Yadis library)') class DiscoveryFailure(RuntimeError): """A failure to discover an OpenID server. When the C{yadis} package is available, this is C{yadis.discover.DiscoveryFailure}.""" else: yadis_available = True from yadis.etxrd import nsTag, XRDSError from yadis.services import applyFilter as extractServices from yadis.discover import discover as yadisDiscover from yadis.discover import DiscoveryFailure from yadis import xrires, filters from openid.consumer.parse import openIDDiscover as parseOpenIDLinkRel from openid.consumer.parse import ParseError
from openid import oidutil try: basestring # pylint:disable-msg=W0104 except NameError: # For Python 2.2 basestring = (str, unicode) # pylint:disable-msg=W0622 __all__ = ["TeamsRequest", "TeamsResponse", "ns_uri", "supportsTeams"] ns_uri = "http://ns.launchpad.net/2007/openid-teams" try: registerNamespaceAlias(ns_uri, "lp") except NamespaceAliasRegistrationError, e: oidutil.log("registerNamespaceAlias(%r, %r) failed: %s" % (ns_uri, "lp", str(e))) def supportsTeams(endpoint): """Does the given endpoint advertise support for Launchpad Teams? @param endpoint: The endpoint object as returned by OpenID discovery @type endpoint: openid.consumer.discover.OpenIDEndpoint @returns: Whether an lp type was advertised by the endpoint @rtype: bool """ return endpoint.usesExtension(ns_uri) class TeamsNamespaceError(ValueError):