def portier_login(request): """Helper to redirect client towards Portier login form.""" nonce = persist_nonce(request) form_url = '{broker_uri}/auth?{query_args}' broker_uri = portier_conf(request, 'broker_uri') query_args = urlencode({ 'login_hint': request.validated['email'], 'scope': portier_conf(request, 'requested_scope'), 'nonce': nonce, 'response_type': 'id_token', 'response_mode': 'form_post', # Get the data from the config because the request might only # have local network information and not the public facing ones. 'client_id': '{scheme}://{host}'.format( scheme=request.registry.settings['http_scheme'], host=request.registry.settings['http_host']), 'redirect_uri': request.route_url(verify.name), }) location = form_url.format(broker_uri=broker_uri, query_args=query_args) return httpexceptions.HTTPFound(location=location)
def authorized_redirect(req, **kwargs): authorized = aslist(portier_conf(req, 'webapp.authorized_domains')) if 'redirect' not in req.validated: return True domain = urlparse(req.validated['redirect']).netloc if not any((fnmatch(domain, auth) for auth in authorized)): req.errors.add('querystring', 'redirect', 'redirect URL is not authorized')
def portier_ping(request): """Verify if the portier server is ready.""" server_url = portier_conf(request, 'broker_uri') portier = None if server_url is not None: portier = False try: conf_url = urljoin(server_url, '/.well-known/openid-configuration') timeout = float(portier_conf(request, 'heartbeat_timeout_seconds')) r = requests.get(conf_url, timeout=timeout) r.raise_for_status() portier = True except requests.exceptions.HTTPError: pass return portier
def portier_verify(request): """Helper to redirect client towards Portier login form.""" broker_uri = portier_conf(request, 'broker_uri') token = request.validated['body']['id_token'] # Get the data from the config because the request might only # have local network information and not the public facing ones. audience = '{scheme}://{host}'.format( scheme=request.registry.settings['http_scheme'], host=request.registry.settings['http_host']) try: email, stored_redirect = get_verified_email( broker_url=broker_uri, token=token, audience=audience, issuer=broker_uri, cache=request.registry.cache) except ValueError as exc: error_details = 'Portier token validation failed: %s' % exc return http_error(httpexceptions.HTTPBadRequest(), errno=ERRORS.INVALID_AUTH_TOKEN, error='Invalid Auth Token', message=error_details) # Generate a random token user_token = codecs.encode(os.urandom(32), 'hex').decode('utf-8') # Encrypt the email with the token encrypted_email = encrypt(email, user_token) # Generate a user ID from the token hmac_secret = request.registry.settings['userid_hmac_secret'] userID = utils.hmac_digest(hmac_secret, user_token) # Store the encrypted user ID with the token session_ttl = portier_conf(request, 'session_ttl_seconds') request.registry.cache.set('portier:' + userID, encrypted_email, session_ttl) location = '%s%s' % (stored_redirect, user_token) return httpexceptions.HTTPFound(location=location)
def persist_nonce(request): """Persist arbitrary string in cache. It will be matched when the user returns from the OAuth server login page. """ nonce = uuid.uuid4().hex redirect_url = request.validated['redirect'] expiration = float(portier_conf(request, 'cache_ttl_seconds')) cache = request.registry.cache cache.set("portier:nonce:%s" % nonce, redirect_url, expiration) return nonce