def propertysheet(self): if self._sheet is not None: return self._sheet # build sheet from identities pdata = dict(id=self.userid) cfgs_providers = authomatic_cfg() for provider_name in cfgs_providers: identity = self.identity(provider_name) if identity is None: continue logger.debug(identity) cfg = cfgs_providers[provider_name] for akey, pkey in cfg.get('propertymap', {}).items(): # Always search first on the user attributes, then on the raw # data this guaratees we do not break existing configurations ainfo = identity.get(akey, identity['data'].get(akey, None)) if ainfo is None: continue if isinstance(pkey, dict): for k, v in pkey.items(): pdata[k] = ainfo.get(v) else: pdata[pkey] = ainfo self._sheet = UserPropertySheet(**pdata) return self._sheet
def __call__(self): cfg = authomatic_cfg() if cfg is None: return "Authomatic is not configured" if not ( ISiteRoot.providedBy(self.context) or INavigationRoot.providedBy(self.context) ): # callback url is expected on either navigationroot or site root # so bevor going on redirect root = api.portal.get_navigation_root(self.context) self.request.response.redirect( "{0}/authomatic-handler/{1}".format( root.absolute_url(), getattr(self, 'provider', '') ) ) return "redirecting" if not hasattr(self, 'provider'): return self.template() if self.provider not in cfg: return "Provider not supported" if not self.is_anon: if self.provider in self._provider_names: raise ValueError( 'Provider {0} is already connected to current ' 'user.'.format(self.provider) ) # TODO: some sort of CSRF check might be needed, so that # not an account got connected by CSRF. Research needed. pass auth = Authomatic( cfg, secret=authomatic_settings().secret.encode('utf8') ) result = auth.login( ZopeRequestAdapter(self), self.provider ) if not result: logger.info('return from view') # let authomatic do its work return if result.error: return result.error.message display = cfg[self.provider].get('display', {}) provider_name = display.get('title', self.provider) if not self.is_anon: # now we delegate to PAS plugin to add the identity self._add_identity(result, provider_name) self.request.response.redirect( "{0}".format(self.context.absolute_url()) ) else: # now we delegate to PAS plugin in order to login self._remember_identity(result, provider_name) self.request.response.redirect( "{0}/login_success".format(self.context.absolute_url()) ) return "redirecting"
def __call__(self): cfg = authomatic_cfg() if cfg is None: return "Authomatic is not configured" if not ( ISiteRoot.providedBy(self.context) or INavigationRoot.providedBy(self.context) ): # callback url is expected on either navigationroot or site root # so bevor going on redirect root = api.portal.get_navigation_root(self.context) self.request.response.redirect( "{0}/authomatic-handler/{1}".format( root.absolute_url(), getattr(self, 'provider', '') ) ) return "redirecting" if not hasattr(self, 'provider'): return self.template() if self.provider not in cfg: return "Provider not supported" if not self.is_anon: if self.provider in self._provider_names: raise ValueError( 'Provider {0} is already connected to current ' 'user.'.format(self.provider) ) # TODO: some sort of CSRF check might be needed, so that # not an account got connected by CSRF. Research needed. pass secret = authomatic_settings().secret if six.PY2 and isinstance(secret, six.text_type): secret = secret.encode('utf8') auth = Authomatic(cfg, secret=secret) result = auth.login(ZopeRequestAdapter(self), self.provider) if not result: logger.info('return from view') # let authomatic do its work return if result.error: return result.error.message display = cfg[self.provider].get('display', {}) provider_name = display.get('title', self.provider) if not self.is_anon: # now we delegate to PAS plugin to add the identity self._add_identity(result, provider_name) self.request.response.redirect( "{0}".format(self.context.absolute_url()) ) else: # now we delegate to PAS plugin in order to login self._remember_identity(result, provider_name) if api.env.plone_version() < '5.2': self.request.response.redirect( "{0}/login_success".format(self.context.absolute_url()) ) else: self.request.response.redirect(self.context.absolute_url()) return "redirecting"
def providers(self) -> dict: """Return Authomatic providers.""" providers = self._providers if not providers: try: providers = authomatic_cfg() except KeyError: # Authomatic is not configured providers = {} except ModuleNotFoundError: # Bad configuration providers = {} return providers
def __call__(self): cfg = authomatic_cfg() if cfg is None: return "Authomatic is not configured" if not (ISiteRoot.providedBy(self.context) or INavigationRoot.providedBy(self.context)): # callback url is expected on either navigationroot or site root # so bevor going on redirect root = api.portal.get_navigation_root(self.context) self.request.response.redirect("{}/authomatic-handler/{}".format( root.absolute_url(), getattr(self, "provider", ""))) return "redirecting" if not getattr(self, "provider", None): return self.template() if self.provider not in cfg: return "Provider not supported" if not self.is_anon: if self.provider in self._provider_names: logger.warn( "Provider %s is already connected to current " "user.", self.provider) return self._redirect() # TODO: some sort of CSRF check might be needed, so that # not an account got connected by CSRF. Research needed. pass secret = authomatic_settings().secret auth = Authomatic(cfg, secret=secret) result = auth.login(ZopeRequestAdapter(self), self.provider) if not result: logger.info("return from view") # let authomatic do its work return if result.error: return result.error.message display = cfg[self.provider].get("display", {}) provider_name = display.get("title", self.provider) if not self.is_anon: # now we delegate to PAS plugin to add the identity self._add_identity(result, provider_name) else: # now we delegate to PAS plugin in order to login self._remember_identity(result, provider_name) return self._redirect()
def providers(self): cfgs = authomatic_cfg() if not cfgs: raise ValueError("Authomatic configuration has errors.") for identifier, cfg in cfgs.items(): entry = cfg.get('display', {}) cssclasses = entry.get('cssclasses', {}) record = { 'identifier': identifier, 'title': entry.get('title', identifier), 'iconclasses': cssclasses.get( 'icon', 'glypicon glyphicon-log-in' ), 'buttonclasses': cssclasses.get( 'button', 'plone-btn plone-btn-default' ), 'as_form': entry.get('as_form', False), } yield record
def providers(self): cfgs = authomatic_cfg() if not cfgs: raise ValueError("Authomatic configuration has errors.") for identifier, cfg in cfgs.items(): entry = cfg.get("display", {}) cssclasses = entry.get("cssclasses", {}) record = { "identifier": identifier, "title": entry.get("title", identifier), "iconclasses": cssclasses.get("icon", "glypicon glyphicon-log-in"), "buttonclasses": cssclasses.get("button", "plone-btn plone-btn-default"), "as_form": entry.get("as_form", False), } yield record
def list_plugins() -> List[Dict]: """List all configured Authomatic plugins. :returns: List of login options. """ try: providers = authomatic_cfg() except KeyError: # Authomatic is not configured providers = {} plugins = [] for provider_id, provider in providers.items(): entry = provider.get("display", {}) title = entry.get("title", provider_id) plugins.append( dict( id=provider_id, plugin="authomatic", title=title, )) return plugins
def credentials(self): cfg = authomatic_cfg() return Credentials.deserialize(cfg, self.user['credentials'])
def _provider_names(self): cfgs = authomatic_cfg() if not cfgs: raise ValueError("Authomatic configuration has errors.") return cfgs.keys()
def __call__(self): # callback url is expected on site root if not ISiteRoot.providedBy(self.context): root = api.portal.get() self.request.response.redirect("{0}/authomatic-handler/{1}".format( root.absolute_url(), getattr(self, 'provider', ''))) return "redirecting" self.authopas = authomatic_plugin() self.cfgs = authomatic_cfg() if self.cfgs is None: return "Authomatic is not configured" self.is_anon = api.user.is_anonymous() if not self.is_anon: self.user = api.user.get_current() self.user_providers = self.authopas._useridentities_by_userid.get( self.user.id).providers() # Validate provider if not hasattr(self, 'provider'): return self.template() if self.provider not in self.cfgs: return "Provider not supported" if not self.is_anon and self.provider in self.user_providers: action = self.request.form.get('action', None) if action == 'unlink': alsoProvides(self.request, IDisableCSRFProtection) self.authopas.remove_identity(self.user.id, self.provider) api.portal.show_message( _('Unlink account with {provider} provider', mapping={'provider': self.provider}), self.request) return self.template() #Any other action ? else: api.portal.show_message( _('Provider {provider} is already connected to current user', mapping={'provider': self.provider}), self.request) return self.template() # TODO: some sort of CSRF check might be needed, so that # not an account got connected by CSRF. Research needed. #Authomatic login auth = Authomatic(self.cfgs, secret=authomatic_settings().secret.encode('utf8')) result = auth.login(ZopeRequestAdapter(self), self.provider) if not result: logger.info('return from view') # let authomatic do its work return if result.error: return result.error.message # fetch provider specific user-data result.user.update() display = self.cfgs[self.provider].get('display', {}) provider_name = display.get('title', self.provider) if not self.is_anon: # now we delegate to PAS plugin to add the identity self._add_identity(result, provider_name) self.request.response.redirect("{0}".format( self.context.absolute_url())) else: # now we delegate to PAS plugin in order to login self._remember_identity(result, provider_name) redirect = self.cfgs[self.provider].get( 'redirect_url', "${portal_url}/login_success") redirect = redirect.replace("${portal_url}", api.portal.get().absolute_url()) self.request.response.redirect(redirect) return "redirecting"
def __call__(self): cfg = authomatic_cfg() if cfg is None: return "Authomatic is not configured" if not (ISiteRoot.providedBy(self.context) or INavigationRoot.providedBy(self.context)): # callback url is expected on either navigationroot or site root # so bevor going on redirect root = api.portal.get_navigation_root(self.context) self.request.response.redirect( "{0}/authomatic-handler/{1}{2}".format( root.absolute_url(), getattr(self, 'provider', ''), ('?' + self.request.QUERY_STRING if self.request.QUERY_STRING else ''))) return "redirecting" if not hasattr(self, 'provider'): return self.template() if self.provider not in cfg: return "Provider not supported" if not self.is_anon: if self.provider in self._provider_names: raise ValueError( 'Provider {0} is already connected to current ' 'user.'.format(self.provider)) # TODO: some sort of CSRF check might be needed, so that # not an account got connected by CSRF. Research needed. pass auth = Authomatic(cfg, secret=authomatic_settings().secret.encode('utf8')) additional_params = {} for key in ('came_from', 'next'): if key in self.request.form: additional_params[key] = self.request.form[key] # TODO: expire after 1800s (30m) # TODO: single cookie for next and came_from ? self.request.response.setCookie( 'authomatic_{0}'.format(key), self.request.form[key], http_only=True, path=api.portal.get().absolute_url_path()) del (self.request.form[key]) # TODO: expire cookie(s) after successful login, not here. elif self.request.cookies.get('authomatic_{0}'.format(key)): additional_params[key] = self.request.cookies.get( 'authomatic_{0}'.format(key)) self.request.response.expireCookie( 'authomatic_{0}'.format(key), path=api.portal.get().absolute_url_path()) result = auth.login(ZopeRequestAdapter(self), self.provider) if not result: logger.info('return from view') return if result.error: return result.error.message display = cfg[self.provider].get('display', {}) provider_name = display.get('title', self.provider) if not self.is_anon: # now we delegate to PAS plugin to add the identity logger.info('add_identity %s', additional_params) self._add_identity(result, provider_name) self.request.response.redirect( additional_params.get('came_from', self.context.absolute_url())) else: # now we delegate to PAS plugin in order to login logger.info('remember_identity %s', additional_params) self._remember_identity(result, provider_name) if additional_params: self.request.response.redirect("{0}/logged_in?{1}".format( self.context.absolute_url(), urlencode(additional_params))) else: self.request.response.redirect("{0}/login_success".format( self.context.absolute_url())) return "redirecting"