def POST_authorize(self, authorize, client, redirect_uri, scope, state, duration, response_type): """Endpoint for OAuth2 authorization.""" if response_type == "token" and client.is_confidential(): # Prevent "confidential" clients from distributing tokens # in a non-confidential manner c.errors.add((errors.OAUTH2_INVALID_CLIENT, "client_id")) if response_type == "token" and duration != "temporary": # implicit grant -> No refresh tokens allowed c.errors.add((errors.INVALID_OPTION, "duration")) self._check_redirect_uri(client, redirect_uri) if c.errors: return self._error_response(state, redirect_uri, as_fragment=(response_type == "token")) if response_type == "code": code = OAuth2AuthorizationCode._new(client._id, redirect_uri, c.user._id36, scope, duration == "permanent") resp = {"code": code._id, "state": state} final_redirect = _update_redirect_uri(redirect_uri, resp) elif response_type == "token": token = OAuth2AccessToken._new(client._id, c.user._id36, scope) token_data = OAuth2AccessController._make_token_dict(token) token_data["state"] = state final_redirect = _update_redirect_uri(redirect_uri, token_data, as_fragment=True) return self.redirect(final_redirect, code=302)
def _access_token_code(self, code, redirect_uri): if not code: c.errors.add("NO_TEXT", field="code") if c.errors: return self.api_wrapper(self._check_for_errors()) access_token = None refresh_token = None auth_token = OAuth2AuthorizationCode.use_token( code, c.oauth2_client._id, redirect_uri) if auth_token: if auth_token.refreshable: refresh_token = OAuth2RefreshToken._new( auth_token.client_id, auth_token.user_id, auth_token.scope) g.stats.simple_event( 'oauth2.access_token_code.refresh_token_create') access_token = OAuth2AccessToken._new( auth_token.client_id, auth_token.user_id, auth_token.scope, refresh_token._id if refresh_token else "") g.stats.simple_event( 'oauth2.access_token_code.access_token_create') resp = self._make_token_dict(access_token, refresh_token) return self.api_wrapper(resp)
def _access_token_code(self, code, redirect_uri): if not code: c.errors.add("NO_TEXT", field="code") if c.errors: return self.api_wrapper(self._check_for_errors()) access_token = None refresh_token = None auth_token = OAuth2AuthorizationCode.use_token(code, c.oauth2_client._id, redirect_uri) if auth_token: if auth_token.refreshable: refresh_token = OAuth2RefreshToken._new( auth_token.client_id, auth_token.user_id, auth_token.scope) g.stats.simple_event( 'oauth2.access_token_code.refresh_token_create') access_token = OAuth2AccessToken._new( auth_token.client_id, auth_token.user_id, auth_token.scope, refresh_token._id if refresh_token else "") g.stats.simple_event( 'oauth2.access_token_code.access_token_create') resp = self._make_token_dict(access_token, refresh_token) return self.api_wrapper(resp)
def POST_authorize(self, authorize, client, redirect_uri, scope, state, duration, response_type): """Endpoint for OAuth2 authorization.""" self._check_employee_grants(client, scope) self._check_redirect_uri(client, redirect_uri) self._check_response_type_and_scope(response_type, scope) self._check_client_type_and_duration(response_type, client, duration) if c.errors: return self._error_response(state, redirect_uri, as_fragment=(response_type == "token")) if response_type == "code": code = OAuth2AuthorizationCode._new(client._id, redirect_uri, c.user._id36, scope, duration == "permanent") resp = {"code": code._id, "state": state} final_redirect = _update_redirect_uri(redirect_uri, resp) g.stats.simple_event('oauth2.POST_authorize.authorization_code_create') elif response_type == "token": token = OAuth2AccessToken._new(client._id, c.user._id36, scope) token_data = OAuth2AccessController._make_token_dict(token) token_data["state"] = state final_redirect = _update_redirect_uri(redirect_uri, token_data, as_fragment=True) g.stats.simple_event('oauth2.POST_authorize.access_token_create') # If this is the first time the user is logging in with an official # mobile app, gild them if (g.live_config.get('mobile_gild_first_login') and not c.user.has_used_mobile_app and client._id in g.mobile_auth_gild_clients): buyer = Account.system_user() admintools.adjust_gold_expiration( c.user, days=g.mobile_auth_gild_time) create_gift_gold( buyer._id, c.user._id, g.mobile_auth_gild_time, datetime.now(g.tz), signed=True, note='first_mobile_auth') subject = 'Let there be gold! Reddit just sent you Reddit gold!' message = ( "Thank you for using the Reddit mobile app! As a thank you " "for logging in during launch week, you've been gifted %s of " "Reddit Gold.\n\n" "Reddit Gold is Reddit's premium membership program, which " "grants you: \n" "An ads-free experience in Reddit's mobile apps, and\n" "Extra site features on desktop\n\n" "Discuss and get help on the features and perks at " "r/goldbenefits." ) % g.mobile_auth_gild_message message += '\n\n' + strings.gold_benefits_msg send_system_message(c.user, subject, message, add_to_sent=False) c.user.has_used_mobile_app = True c.user._commit() return self.redirect(final_redirect, code=302)
def POST_authorize(self, authorize, client, redirect_uri, scope, state, duration): """Endpoint for OAuth2 authorization.""" self._check_redirect_uri(client, redirect_uri) if not c.errors: code = OAuth2AuthorizationCode._new(client._id, redirect_uri, c.user._id36, scope, duration == "permanent") resp = {"code": code._id, "state": state} return self.redirect(redirect_uri + "?" + urlencode(resp), code=302) else: return self._error_response(state, redirect_uri)
def POST_authorize(self, authorize, client, redirect_uri, scope, state): """Endpoint for OAuth2 authorization.""" self._check_redirect_uri(client, redirect_uri) if not c.errors: code = OAuth2AuthorizationCode._new(client._id, redirect_uri, c.user._id36, scope) resp = {"code": code._id, "state": state} return self.redirect(redirect_uri+"?"+urlencode(resp), code=302) else: return self._error_response(state, redirect_uri)
def POST_authorize(self, authorize, client, redirect_uri, scope, state, duration, response_type): """Endpoint for OAuth2 authorization.""" self._check_employee_grants(client, scope) if response_type == "token" and client.is_confidential(): # Prevent "confidential" clients from distributing tokens # in a non-confidential manner c.errors.add((errors.OAUTH2_INVALID_CLIENT, "client_id")) if response_type == "token" and duration != "temporary": # implicit grant -> No refresh tokens allowed c.errors.add((errors.INVALID_OPTION, "duration")) self._check_redirect_uri(client, redirect_uri) if c.errors: return self._error_response(state, redirect_uri, as_fragment=(response_type == "token")) if response_type == "code": code = OAuth2AuthorizationCode._new(client._id, redirect_uri, c.user._id36, scope, duration == "permanent") resp = {"code": code._id, "state": state} final_redirect = _update_redirect_uri(redirect_uri, resp) elif response_type == "token": token = OAuth2AccessToken._new(client._id, c.user._id36, scope) token_data = OAuth2AccessController._make_token_dict(token) token_data["state"] = state final_redirect = _update_redirect_uri(redirect_uri, token_data, as_fragment=True) # If this is the first time the user is logging in with an official # mobile app, gild them if (g.live_config.get('mobile_gild_first_login') and not c.user.has_used_mobile_app and client._id in g.mobile_auth_gild_clients): buyer = Account.system_user() admintools.adjust_gold_expiration( c.user, days=g.mobile_auth_gild_time) create_gift_gold( buyer._id, c.user._id, g.mobile_auth_gild_time, datetime.now(g.tz), signed=True, note='first_mobile_auth') subject = 'Let there be gold! %s just sent you reddit gold!' % ( buyer.name) message = "Thank you for using the reddit mobile app! For your "\ "participation, you've been gifted %s of reddit gold." % ( g.mobile_auth_gild_message) message += '\n\n' + strings.gold_benefits_msg send_system_message(c.user, subject, message, add_to_sent=False) c.user.has_used_mobile_app = True c.user._commit() return self.redirect(final_redirect, code=302)
def POST_authorize(self, authorize, client, redirect_uri, scope, state, duration): """Endpoint for OAuth2 authorization.""" self._check_redirect_uri(client, redirect_uri) if not c.errors: code = OAuth2AuthorizationCode._new(client._id, redirect_uri, c.user._id36, scope, duration == "permanent") resp = {"code": code._id, "state": state} final_redirect = _update_redirect_uri(redirect_uri, resp) return self.redirect(final_redirect, code=302) else: return self._error_response(state, redirect_uri)
def POST_authorize(self, authorize, client, redirect_uri, scope, state): """Endpoint for OAuth2 authorization.""" self._check_redirect_uri(client, redirect_uri) resp = {} if state: resp["state"] = state if not c.errors: code = OAuth2AuthorizationCode._new(client._id, redirect_uri, c.user._id, scope) resp["code"] = code._id else: self._error_response(resp) return self.redirect(redirect_uri+"?"+urlencode(resp), code=302)
def POST_access_token(self, grant_type, code, redirect_uri): """ Exchange an [OAuth 2.0](http://oauth.net/2/) authorization code (from [/api/v1/authorize](#api_method_authorize)) for an access token. On success, returns a URL-encoded dictionary containing **access_token**, **token_type**, **expires_in**, and **scope**. If there is a problem, an **error** parameter will be returned instead. Must be called using SSL, and must contain a HTTP `Authorization:` header which contains the application's client identifier as the username and client secret as the password. (The client id and secret are visible on the [app preferences page](/prefs/apps).) Per the OAuth specification, **grant_type** must be ``authorization_code`` and **redirect_uri** must exactly match the value that was used in the call to [/api/v1/authorize](#api_method_authorize). """ resp = {} if not c.errors: auth_token = OAuth2AuthorizationCode.use_token(code, c.oauth2_client._id, redirect_uri) if auth_token: access_token = OAuth2AccessToken._new(auth_token.user_id, auth_token.scope) resp["access_token"] = access_token._id resp["token_type"] = access_token.token_type resp["expires_in"] = access_token._ttl resp["scope"] = auth_token.scope else: resp["error"] = "invalid_grant" else: if (errors.INVALID_OPTION, "grant_type") in c.errors: resp["error"] = "unsupported_grant_type" elif (errors.INVALID_OPTION, "scope") in c.errors: resp["error"] = "invalid_scope" else: resp["error"] = "invalid_request" return self.api_wrapper(resp)
def POST_access_token(self, grant_type, code, redirect_uri): """ Exchange an [OAuth 2.0](http://oauth.net/2/) authorization code (from [/api/v1/authorize](#api_method_authorize)) for an access token. On success, returns a URL-encoded dictionary containing **access_token**, **token_type**, **expires_in**, and **scope**. If there is a problem, an **error** parameter will be returned instead. Must be called using SSL, and must contain a HTTP `Authorization:` header which contains the application's client identifier as the username and client secret as the password. (The client id and secret are visible on the [app preferences page](/prefs/apps).) Per the OAuth specification, **grant_type** must be ``authorization_code`` and **redirect_uri** must exactly match the value that was used in the call to [/api/v1/authorize](#api_method_authorize). """ resp = {} if not c.errors: auth_token = OAuth2AuthorizationCode.use_token(code, c.oauth2_client._id, redirect_uri) if auth_token: access_token = OAuth2AccessToken._new(auth_token.client_id, auth_token.user_id, auth_token.scope) resp["access_token"] = access_token._id resp["token_type"] = access_token.token_type resp["expires_in"] = access_token._ttl resp["scope"] = auth_token.scope else: resp["error"] = "invalid_grant" else: if (errors.INVALID_OPTION, "grant_type") in c.errors: resp["error"] = "unsupported_grant_type" elif (errors.INVALID_OPTION, "scope") in c.errors: resp["error"] = "invalid_scope" else: resp["error"] = "invalid_request" return self.api_wrapper(resp)
def _access_token_code(self, code, redirect_uri): if not code: c.errors.add("NO_TEXT", field="code") if c.errors: return self.api_wrapper(self._check_for_errors()) access_token = None refresh_token = None client = c.oauth2_client auth_token = OAuth2AuthorizationCode.use_token(code, client._id, redirect_uri) if auth_token: if auth_token.refreshable: refresh_token = OAuth2RefreshToken._new( client_id=auth_token.client_id, user_id=auth_token.user_id, scope=auth_token.scope, ) g.stats.simple_event( 'oauth2.access_token_code.refresh_token_create') device_id = get_device_id(client) access_token = OAuth2AccessToken._new( client_id=auth_token.client_id, user_id=auth_token.user_id, scope=auth_token.scope, refresh_token=refresh_token._id if refresh_token else "", device_id=device_id, ) g.stats.simple_event( 'oauth2.access_token_code.access_token_create') resp = self._make_new_token_response(access_token, refresh_token) return self.api_wrapper(resp)
def POST_authorize(self, authorize, client, redirect_uri, scope, state, duration, response_type): """Endpoint for OAuth2 authorization.""" self._check_employee_grants(client, scope) self._check_redirect_uri(client, redirect_uri) self._check_response_type_and_scope(response_type, scope) self._check_client_type_and_duration(response_type, client, duration) if c.errors: return self._error_response(state, redirect_uri, as_fragment=(response_type == "token")) if response_type == "code": code = OAuth2AuthorizationCode._new(client._id, redirect_uri, c.user._id36, scope, duration == "permanent") resp = {"code": code._id, "state": state} final_redirect = _update_redirect_uri(redirect_uri, resp) g.stats.simple_event('oauth2.POST_authorize.authorization_code_create') elif response_type == "token": device_id = get_device_id(client) token = OAuth2AccessToken._new( client_id=client._id, user_id=c.user._id36, scope=scope, device_id=device_id, ) resp = OAuth2AccessController._make_new_token_response(token) resp["state"] = state final_redirect = _update_redirect_uri(redirect_uri, resp, as_fragment=True) g.stats.simple_event('oauth2.POST_authorize.access_token_create') # If this is the first time the user is logging in with an official # mobile app, gild them if (g.live_config.get('mobile_gild_first_login') and not c.user.has_used_mobile_app and client._id in g.mobile_auth_gild_clients): buyer = Account.system_user() admintools.adjust_gold_expiration( c.user, days=g.mobile_auth_gild_time) create_gift_gold( buyer._id, c.user._id, g.mobile_auth_gild_time, datetime.now(g.tz), signed=True, note='first_mobile_auth') subject = 'Let there be gold! Reddit just sent you Reddit gold!' message = ( "Thank you for using the Reddit mobile app! As a thank you " "for logging in during launch week, you've been gifted %s of " "Reddit Gold.\n\n" "Reddit Gold is Reddit's premium membership program, which " "grants you: \n" "An ads-free experience in Reddit's mobile apps, and\n" "Extra site features on desktop\n\n" "Discuss and get help on the features and perks at " "r/goldbenefits." ) % g.mobile_auth_gild_message message += '\n\n' + strings.gold_benefits_msg send_system_message(c.user, subject, message, add_to_sent=False) c.user.has_used_mobile_app = True c.user._commit() return self.redirect(final_redirect, code=302)
def POST_access_token(self, grant_type, code, refresh_token, redirect_uri): """ Exchange an [OAuth 2.0](http://oauth.net/2/) authorization code or refresh token (from [/api/v1/authorize](#api_method_authorize)) for an access token. On success, returns a URL-encoded dictionary containing **access_token**, **token_type**, **expires_in**, and **scope**. If an authorization code for a permanent grant was given, a **refresh_token** will be included. If there is a problem, an **error** parameter will be returned instead. Must be called using SSL, and must contain a HTTP `Authorization:` header which contains the application's client identifier as the username and client secret as the password. (The client id and secret are visible on the [app preferences page](/prefs/apps).) Per the OAuth specification, **grant_type** must be ``authorization_code`` for the initial access token or ``refresh_token`` for renewing the access token. In either case, **redirect_uri** must exactly match the value that was used in the call to [/api/v1/authorize](#api_method_authorize) that created this grant. """ resp = {} if not (code or refresh_token): c.errors.add("NO_TEXT", field=("code", "refresh_token")) if not c.errors: access_token = None if grant_type == "authorization_code": auth_token = OAuth2AuthorizationCode.use_token( code, c.oauth2_client._id, redirect_uri) if auth_token: if auth_token.refreshable: refresh_token = OAuth2RefreshToken._new( auth_token.client_id, auth_token.user_id, auth_token.scope) access_token = OAuth2AccessToken._new( auth_token.client_id, auth_token.user_id, auth_token.scope, refresh_token._id if refresh_token else None) elif grant_type == "refresh_token" and refresh_token: access_token = OAuth2AccessToken._new( refresh_token.client_id, refresh_token.user_id, refresh_token.scope, refresh_token=refresh_token._id) if access_token: resp["access_token"] = access_token._id resp["token_type"] = access_token.token_type resp["expires_in"] = int(access_token._ttl) if access_token._ttl else None resp["scope"] = access_token.scope if refresh_token: resp["refresh_token"] = refresh_token._id else: resp["error"] = "invalid_grant" else: if (errors.INVALID_OPTION, "grant_type") in c.errors: resp["error"] = "unsupported_grant_type" elif (errors.INVALID_OPTION, "scope") in c.errors: resp["error"] = "invalid_scope" else: resp["error"] = "invalid_request" return self.api_wrapper(resp)
def POST_access_token(self, grant_type, code, refresh_token, redirect_uri): """ Exchange an [OAuth 2.0](http://oauth.net/2/) authorization code or refresh token (from [/api/v1/authorize](#api_method_authorize)) for an access token. On success, returns a URL-encoded dictionary containing **access_token**, **token_type**, **expires_in**, and **scope**. If an authorization code for a permanent grant was given, a **refresh_token** will be included. If there is a problem, an **error** parameter will be returned instead. Must be called using SSL, and must contain a HTTP `Authorization:` header which contains the application's client identifier as the username and client secret as the password. (The client id and secret are visible on the [app preferences page](/prefs/apps).) Per the OAuth specification, **grant_type** must be ``authorization_code`` for the initial access token or ``refresh_token`` for renewing the access token. In either case, **redirect_uri** must exactly match the value that was used in the call to [/api/v1/authorize](#api_method_authorize) that created this grant. """ resp = {} if not (code or refresh_token): c.errors.add("NO_TEXT", field=("code", "refresh_token")) if not c.errors: access_token = None if grant_type == "authorization_code": auth_token = OAuth2AuthorizationCode.use_token( code, c.oauth2_client._id, redirect_uri) if auth_token: if auth_token.refreshable: refresh_token = OAuth2RefreshToken._new( auth_token.client_id, auth_token.user_id, auth_token.scope) access_token = OAuth2AccessToken._new( auth_token.client_id, auth_token.user_id, auth_token.scope, refresh_token._id if refresh_token else None) elif grant_type == "refresh_token" and refresh_token: access_token = OAuth2AccessToken._new( refresh_token.client_id, refresh_token.user_id, refresh_token.scope, refresh_token=refresh_token._id) if access_token: resp["access_token"] = access_token._id resp["token_type"] = access_token.token_type resp["expires_in"] = int( access_token._ttl) if access_token._ttl else None resp["scope"] = access_token.scope if refresh_token: resp["refresh_token"] = refresh_token._id else: resp["error"] = "invalid_grant" else: if (errors.INVALID_OPTION, "grant_type") in c.errors: resp["error"] = "unsupported_grant_type" elif (errors.INVALID_OPTION, "scope") in c.errors: resp["error"] = "invalid_scope" else: resp["error"] = "invalid_request" return self.api_wrapper(resp)