/* Copyright (c) 2009 Yahoo! Inc. All rights reserved. The copyrights embodied in the content of this file are licensed under the BSD (revised) open source license */ package com.yahoo.social.methodgroups { import com.yahoo.net.Connection; import com.yahoo.oauth.OAuthConsumer; import com.yahoo.oauth.OAuthRequest; import com.yahoo.oauth.OAuthToken; import com.yahoo.social.YahooSession; import com.yahoo.social.events.YahooResultEvent; import com.yahoo.social.utils.YahooURL; import flash.net.URLRequest; import flash.net.URLRequestHeader; import flash.net.URLRequestMethod; import flash.net.navigateToURL; /** * Dispatched when the getRequestToken request executes successfully. */ [Event(name="getRequestTokenSuccess", type="YahooResultEvent")] /** * Dispatched when the getRequestToken request encounters an error. */ [Event(name="getRequestTokenFailure", type="YahooResultEvent")] /** * Dispatched when the getAccessToken request executes successfully. */ [Event(name="getAccessTokenSuccess", type="YahooResultEvent")] /** * Dispatched when the getAccessToken request encounters an error. */ [Event(name="getAccessTokenFailure", type="YahooResultEvent")] /** * A wrapper over the OAuth authorization APIs for Yahoo!. * * Allows for the full authorization flow to occur inside an application. (Most useful for AIR applications) * * @author zachg * @see http://developer.yahoo.com/oauth * @see http://developer.yahoo.com/oauth/guide/ * * @example * * var _session:YahooSession = new YahooSession('consumerKey', 'consumerSecret','appId'); * var _user:YahooUser; * * var _token:OAuthToken; * * var _callbackUrl = "http://myapp.com/"; * * _session.auth.addEventListener(YahooResultEvent.GET_REQUEST_TOKEN_SUCCESS, handleRequestTokenSuccess); * _session.auth.getRequestToken(_callbackUrl); * * function handleRequestTokenSuccess(event:YahooResultEvent):void * { * // save the request token and use it to send the user to the authorize page * // then after the user has finished, use it again to request an access token. * * _token = event.data as OAuthToken; * _session.auth.sendToAuthorization(_token); * } * * // call userAuthFinish after the user has indicated that they have finished the authorization process * * function userAuthFinish():void * { * // fetch the oauth_verifier. this string may be typed * // into your application by the user or returned via the callback url. * var verifier:String = "abc123"; * * // reuse the request token to request an access token. * * _session.auth.addEventListener(YahooResultEvent.GET_ACCESS_TOKEN_SUCCESS, handleAccessTokenSuccess); * _session.auth.getAccessToken(_token, verifier); * } * * function handleAccessTokenSuccess(event:YahooResultEvent):void * { * // save the access token and create a new session. * _token = event.data as OAuthToken; * * // set the sessions token. * _session.setAccessToken(_token); * * _user = _session.getSessionedUser(); * } * * */ public class AuthorizationRequest extends YOSMethodBase { /** * The OAuth Language Preference. (xoauth_lang_pref, OAuth 1.0) * * Set to null if your service provider does not not accept this argument. */ public var oAuthLang:String = "en_US"; /** * Out-of-band * * OAuth 1.0 'Rev A' parameter indicating a consumer cannot recieve callbacks. */ protected static const OUT_OF_BAND:String = "oob"; /** * Creates a new AuthenticationRequest object. * */ public function AuthorizationRequest() { super(null); this.$oauthRequestType = OAuthRequest.OAUTH_REQUEST_TYPE_POST; this.$hostname = YOSMethodBase.OAUTH_HOSTNAME; this.$version = "v2"; } /** * Sends a request to fetch a request token. * @param callbackUrl An optional callback url used after the user has authorized the application. */ public function getRequestToken(callbackUrl:String=null):void { var url:YahooURL = new YahooURL("https", this.$hostname); url.rawResource("oauth"); url.rawResource(this.$version); url.rawResource("get_request_token"); var httpMethod:String = URLRequestMethod.POST; var args:Object = new Object(); // adding oauth_callback per OAuth Core 1.0 Rev A args.oauth_callback = (callbackUrl) ? callbackUrl : OUT_OF_BAND; if(oAuthLang) { args.xoauth_lang_pref = this.oAuthLang; } var callback:Object = new Object(); callback.success = handleRequestTokenSuccess; callback.failure = handleRequestTokenFailure; callback.security = handleSecurityError; this.sendRequest(httpMethod, url.toString(), callback, args); } /** * Generates an authorization url and navigates the browser to the page. * @param token A request token object. * @param window The window of the browser to open the URL in. */ public function sendToAuthorization(token:OAuthToken, window:String="_blank"):void { flash.net.navigateToURL(new URLRequest(this.createAuthorizationUrl(token)), window); } /** * Returns a URL to be used to send a user to the OAuth authorization page. * @param requestToken An OAuthToken object containing a token key and secret. * @return * */ public function createAuthorizationUrl(requestToken:OAuthToken):String { if(!requestToken.key) { throw new Error("Value of OAuth request token key must not be null."); } var url:YahooURL = new YahooURL("https", this.$hostname); url.rawResource("oauth"); url.rawResource(this.$version); url.rawResource("request_auth"); var args:Object = new Object(); args.oauth_token = requestToken.key; url.queryParameters = args; return url.toString(); } /** * Sends a request to fetch an access token. * @param token A request token to be authorized. * @param verifier The oauth_verifier returned to the application by the service provider. */ public function getAccessToken(token:OAuthToken, verifier:String=null):void { this.token = token; var url:YahooURL = new YahooURL("https", this.$hostname); url.rawResource("oauth"); url.rawResource(this.$version); url.rawResource("get_token"); var httpMethod:String = URLRequestMethod.POST; var args:Object = new Object(); if(verifier) { // adding oauth_verifier per OAuth Core 1.0 Rev A args.oauth_verifier = verifier; } if(token.sessionHandle) { args.oauth_session_handle = token.sessionHandle; } var callback:Object = new Object(); callback.success = handleAccessTokenSuccess; callback.failure = handleAccessTokenFailure; callback.security = handleSecurityError; var headers:Array = [new URLRequestHeader("Content-Type","application/x-www-form-urlencoded")]; this.sendRequest(httpMethod, url.toString(), callback, args, headers); } ///////////////////////////// // Private callback methods ///////////////////////////// /** * Handles the request token success event. * @private * @param response * */ private function handleRequestTokenSuccess(response:Object):void { if(!this.getResponseStatusOk(response.status)) { handleRequestTokenFailure(response); } else { var token:OAuthToken = this.parseRequestToken(response.responseText); var event:YahooResultEvent = new YahooResultEvent(YahooResultEvent.GET_REQUEST_TOKEN_SUCCESS, token); this.dispatchEvent(event); } } /** * Handles the request token failure event. * @private * @param response * */ private function handleRequestTokenFailure(response:Object):void { this.dispatchEvent(new YahooResultEvent(YahooResultEvent.GET_REQUEST_TOKEN_FAILURE, response)); } /** * Handles the access token success event. * @private * @param response * */ private function handleAccessTokenSuccess(response:Object):void { if(!this.getResponseStatusOk(response.status)) { handleRequestTokenFailure(response); } else { var token:OAuthToken = parseAccessToken(response.responseText); if(token) { var event:YahooResultEvent = new YahooResultEvent(YahooResultEvent.GET_ACCESS_TOKEN_SUCCESS, token); this.dispatchEvent(event); } } } /** * Handles the access token failure event. * @private * @param response * */ private function handleAccessTokenFailure(response:Object):void { this.dispatchEvent(new YahooResultEvent(YahooResultEvent.GET_ACCESS_TOKEN_FAILURE, response)); } ///////////////////////////// // Protected methods ///////////////////////////// /** * Parses an OAuth get_token response into a valid OAuthToken object. * @private * @param responseText The responseText from the request. * @return * */ protected function parseAccessToken(responseText:String):OAuthToken { var data:Object = Connection.parse_query(responseText); var token:OAuthToken = new OAuthToken(); token.key = decodeURIComponent(data["oauth_token"]); // decode the token token.secret = data["oauth_token_secret"]; // extensions token.guid = data["xoauth_yahoo_guid"]; token.sessionHandle = data["oauth_session_handle"]; token.consumer = this.$consumer.key; if(data["oauth_expires_in"]) { var now:Number = new Date().getTime(); var expires:Number = (data["oauth_expires_in"]*1000); token.tokenExpires = now+expires; } return token; } /** * Parses an OAuth get_request_token response into a new OAuthToken object. * @private * @param responseText The responseText from the request. * @return * */ protected function parseRequestToken(responseText:String):OAuthToken { var data:Object = Connection.parse_query(responseText); var token:OAuthToken = new OAuthToken(); token.key = data["oauth_token"]; token.secret = data["oauth_token_secret"]; // extensions token.requestAuthUrl = decodeURIComponent(data["xoauth_request_auth_url"]); token.callbackConfirmed = Boolean(data["oauth_callback_confirmed"]); // 1.0a Draft 3 if(data["oauth_expires_in"]) { var now:Number = new Date().getTime(); var expires:Number = (data["oauth_expires_in"]*1000); token.tokenExpires = now+expires; } return token; } ///////////////////////////// // Public static functions ///////////////////////////// /** * Converts a native object containing request token values into a new OAuthToken object. * * Most useful in AIR you are storing the request token in a File and * need to turn in back into an OAuthToken after reading the file contents. * * @param data * @return * */ public static function toRequestToken(data:Object):OAuthToken { var token:OAuthToken = new OAuthToken(); token.key = data["key"]; token.secret = data["secret"]; // extensions token.requestAuthUrl = data["requestAuthUrl"]; token.tokenExpires = data["tokenExpires"]; token.callbackConfirmed = data["callbackConfirmed"]; return token; } /** * Converts a native object containing access token values into a new OAuthToken object. * * Most useful in AIR you are storing the access token in a File and * need to turn the Object back into an OAuthToken after reading the file contents. * * @param data * @return * */ public static function toAccessToken(data:Object):OAuthToken { var token:OAuthToken = new OAuthToken(); token.key = data["key"]; token.secret = data["secret"]; // extensions token.guid = data["guid"]; token.consumer = data["consumer"]; token.sessionHandle = data["sessionHandle"]; token.tokenExpires = data["tokenExpires"]; return token; } /** * Checks if a token is about to expire (up to 30 seconds). * * Returns true if expired. * * @param token An OAuthToken containing a token key, secret and a tokenExpires property. * @param buffer The total amount of seconds to pad the expires time with. * @return * */ public static function checkExpires(token:OAuthToken, buffer:int=30):Boolean { var expired:Boolean=false; if(token.tokenExpires) { var now:Number = (new Date().getTime()); expired = ((token.tokenExpires >= 0) && (token.tokenExpires-now) < buffer); } return expired; } /** * Generates a new AuthorizationRequest object using the OAuth consumer credentials from a YahooSession instance. * * @param session * @return * */ public static function fromSession(session:YahooSession):AuthorizationRequest { var consumer:OAuthConsumer = session.getConsumer(); if(consumer.empty) return null; var auth:AuthorizationRequest = new AuthorizationRequest(); auth.consumer = consumer; return auth; } } }