def post(self): """POST is used when authenticating via the mobile application.""" # Validate the request. yield gen.Task(self._StartJSONRequest, 'merge_token', self.request, json_schema.MERGE_TOKEN_REQUEST, migrators=_REQUEST_MIGRATORS) # Validate the identity key. identity_key = self._request_message.dict['identity'] AuthViewfinderHandler._ValidateIdentityKey(identity_key) # Require target merge account to be logged in, so that we can get target user name, id, and device type. context = ViewfinderContext.current() if context.user is None: # This case should never happen in the mobile or web clients, since they will not offer # the option to merge if the user is not already logged in. But it could happen with a # direct API call. raise PermissionError(MERGE_REQUIRES_LOGIN) identity = yield gen.Task(Identity.Query, self._client, identity_key, None, must_exist=False) if identity is not None and identity.user_id is not None: # If "error_if_linked" is true, raise an error, since the identity is already linked to a user. if self._request_message.dict.get('error_if_linked', False): raise PermissionError( ALREADY_LINKED, account=Identity.GetDescription(identity_key)) # Send the email or SMS message in order to verify that the user controls it. yield VerifyIdBaseHandler.SendVerifyIdMessage( self._client, 'merge_token', use_short_token=self._UseShortToken(), is_mobile_app=context.IsMobileClient(), identity_key=identity_key, user_id=context.user.user_id, user_name=context.user.name) self._FinishAuthViewfinder(identity_key)
def post(self): """POST is used when authenticating via the mobile application.""" # Validate the request. yield gen.Task(self._StartJSONRequest, 'merge_token', self.request, json_schema.MERGE_TOKEN_REQUEST, migrators=_REQUEST_MIGRATORS) # Validate the identity key. identity_key = self._request_message.dict['identity'] AuthViewfinderHandler._ValidateIdentityKey(identity_key) # Require target merge account to be logged in, so that we can get target user name, id, and device type. context = ViewfinderContext.current() if context.user is None: # This case should never happen in the mobile or web clients, since they will not offer # the option to merge if the user is not already logged in. But it could happen with a # direct API call. raise PermissionError(MERGE_REQUIRES_LOGIN) identity = yield gen.Task(Identity.Query, self._client, identity_key, None, must_exist=False) if identity is not None and identity.user_id is not None: # If "error_if_linked" is true, raise an error, since the identity is already linked to a user. if self._request_message.dict.get('error_if_linked', False): raise PermissionError(ALREADY_LINKED, account=Identity.GetDescription(identity_key)) # Send the email or SMS message in order to verify that the user controls it. yield VerifyIdBaseHandler.SendVerifyIdMessage(self._client, 'merge_token', use_short_token=self._UseShortToken(), is_mobile_app=context.IsMobileClient(), identity_key=identity_key, user_id=context.user.user_id, user_name=context.user.name) self._FinishAuthViewfinder(identity_key)
def _HandleGet(self, short_url, identity_key, viewpoint_id, default_url, is_sms=False, is_first_click=True): """Invoked when a user follows a prospective user invitation URL. Sets a prospective user cookie that identifies the user and restricts access to a single viewpoint. Typically redirects the user to the corresponding website conversation page. """ identity = yield gen.Task(Identity.Query, self._client, identity_key, None, must_exist=False) # Check for rare case where the identity has been unlinked since issuing the prospective user link. if identity is None or identity.user_id is None: raise ExpiredError( 'The requested link has expired and can no longer be used.') # If the "next" query argument is specified, redirect to that, otherwise fall back on default_url. next_url = self.get_argument('next', default_url) if urlparse.urlparse(next_url).hostname is not None: raise InvalidRequestError('Cannot redirect to absolute URL: %s' % next_url) # Detect photo store redirect, as we should not set a cookie or return redirection to photo store in this case. photostore_re = re.match(r'.*/episodes/(.*)/photos/(.*)(\..)', next_url) # If the link was sent via SMS, then reset the SMS alert count (since the link was followed). if is_sms: settings = AccountSettings.CreateForUser(identity.user_id, sms_count=0) yield gen.Task(settings.Update, self._client) # A registered user can no longer use prospective user links. user = yield gen.Task(User.Query, self._client, identity.user_id, None) if user.IsRegistered(): # If not already logged in with the same user with full access, redirect to the auth page. context = ViewfinderContext.current() if context is None: current_user = None current_viewpoint_id = None else: current_user = context.user current_viewpoint_id = context.viewpoint_id if current_user is None or current_user.user_id != identity.user_id or current_viewpoint_id is not None: self.ClearUserCookie() self.redirect('/auth?%s' % urlencode(dict(next=next_url))) return else: # If this is the first time the link was clicked, then create a confirmed cookie. if is_first_click: confirm_time = util.GetCurrentTimestamp() # Update is_first_click. new_json = deepcopy(short_url.json) new_json['is_first_click'] = False short_url.json = new_json yield gen.Task(short_url.Update, self._client) else: confirm_time = None # Set the prospective user cookie. Make it a session cookie so that it will go away when # browser is closed. user_cookie_dict = self.CreateUserCookieDict( user.user_id, user.webapp_dev_id, user_name=user.name, viewpoint_id=viewpoint_id, confirm_time=confirm_time, is_session_cookie=True) # Do not set the user cookie if this is a photo view request. self.LoginUser(user, user_cookie_dict, set_cookie=photostore_re is None) # Handle photostore redirect request internally rather than returning the redirect to the # client. Email clients do not keep cookies, so it is not possible to redirect to an # authenticated URL. if photostore_re: episode_id = photostore_re.group(1) photo_id = photostore_re.group(2) suffix = photostore_re.group(3) next_url = yield PhotoStoreHandler.GetPhotoUrl( self._client, self._obj_store, episode_id, photo_id, suffix) # Redirect to the URL of the next page. self.redirect(next_url)