diff --git a/build_date.as b/build_date.as
index ab73fe4..86caa49 100644
--- a/build_date.as
+++ b/build_date.as
@@ -1 +1 @@
-public var build_date:String='2020_12_29';
+public var build_date:String='2024_06_05';
diff --git a/com/adobe/protocols/oauth2/OAuth2.as b/com/adobe/protocols/oauth2/OAuth2.as
new file mode 100644
index 0000000..92f9942
--- /dev/null
+++ b/com/adobe/protocols/oauth2/OAuth2.as
@@ -0,0 +1,551 @@
+package com.adobe.protocols.oauth2
+{
+ import com.adobe.protocols.oauth2.event.GetAccessTokenEvent;
+ import com.adobe.protocols.oauth2.event.RefreshAccessTokenEvent;
+ import com.adobe.protocols.oauth2.grant.AuthorizationCodeGrant;
+ import com.adobe.protocols.oauth2.grant.IGrantType;
+ import com.adobe.protocols.oauth2.grant.ImplicitGrant;
+ import com.adobe.protocols.oauth2.grant.ResourceOwnerCredentialsGrant;
+ import com.adobe.serialization.json.JSONParseError;
+
+ import flash.events.ErrorEvent;
+ import flash.events.Event;
+ import flash.events.EventDispatcher;
+ import flash.events.IOErrorEvent;
+ import flash.events.LocationChangeEvent;
+ import flash.events.SecurityErrorEvent;
+ import flash.net.URLLoader;
+ import flash.net.URLRequest;
+ import flash.net.URLRequestMethod;
+ import flash.net.URLVariables;
+
+ import org.as3commons.logging.api.ILogger;
+ import org.as3commons.logging.api.LOGGER_FACTORY;
+ import org.as3commons.logging.api.getLogger;
+ import org.as3commons.logging.setup.LevelTargetSetup;
+ import org.as3commons.logging.setup.LogSetupLevel;
+ import org.as3commons.logging.setup.target.TraceTarget;
+
+ /**
+ * Event that is broadcast when results from a getAccessToken request are received.
+ *
+ * @eventType com.adobe.protocols.oauth2.event.GetAccessTokenEvent.TYPE
+ *
+ * @see #getAccessToken()
+ * @see com.adobe.protocols.oauth2.event.GetAccessTokenEvent
+ */
+ [Event(name="getAccessToken", type="com.adobe.protocols.oauth2.event.GetAccessTokenEvent")]
+
+ /**
+ * Event that is broadcast when results from a refreshAccessToken request are received.
+ *
+ * @eventType com.adobe.protocols.oauth2.event.RefreshAccessTokenEvent.TYPE
+ *
+ * @see #refreshAccessToken()
+ * @see com.adobe.protocols.oauth2.event.RefreshAccessTokenEvent
+ */
+ [Event(name="refreshAccessToken", type="com.adobe.protocols.oauth2.event.RefreshAccessTokenEvent")]
+
+ /**
+ * Utility class the encapsulates APIs for interaction with an OAuth 2.0 server.
+ * Implemented against the OAuth 2.0 v2.15 specification.
+ *
+ * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15
+ *
+ * @author Charles Bihis (www.whoischarles.com)
+ */
+ public class OAuth2 extends EventDispatcher
+ {
+ private static const log:ILogger = getLogger(OAuth2);
+
+ private var grantType:IGrantType;
+ private var authEndpoint:String;
+ private var tokenEndpoint:String;
+ private var traceTarget:TraceTarget = new TraceTarget();
+
+
+ /**
+ * Constructor to create a valid OAuth2 client object.
+ *
+ * @param authEndpoint The authorization endpoint used by the OAuth 2.0 server
+ * @param tokenEndpoint The token endpoint used by the OAuth 2.0 server
+ * @param logLevel (Optional) The new log level for the logger to use
+ */
+ public function OAuth2(authEndpoint:String, tokenEndpoint:String, logLevel:LogSetupLevel = null)
+ {
+ // save endpoint properties
+ this.authEndpoint = authEndpoint;
+ this.tokenEndpoint = tokenEndpoint;
+
+ // set up logging
+ traceTarget = new TraceTarget();
+ traceTarget.format = "{date} {time} [{logLevel}] {name} {message}";
+ LOGGER_FACTORY.setup = new LevelTargetSetup(traceTarget, (logLevel == null) ? LogSetupLevel.NONE : logLevel);
+ } // OAuth2
+
+ /**
+ * Initiates the access token request workflow with the proper context as
+ * described by the passed-in grant-type object. Upon completion, will
+ * dispatch a GetAccessTokenEvent event.
+ *
+ * @param grantType An IGrantType object which represents the desired workflow to use when requesting an access token
+ *
+ * @see com.adobe.protocols.oauth2.grant.IGrantType
+ * @see com.adobe.protocols.oauth2.event.GetAccessTokenEvent#TYPE
+ */
+ public function getAccessToken(grantType:IGrantType):void
+ {
+ if (grantType is AuthorizationCodeGrant)
+ {
+ log.info("Initiating getAccessToken() with authorization code grant type workflow");
+ getAccessTokenWithAuthorizationCodeGrant(grantType as AuthorizationCodeGrant);
+ } // if statement
+ else if (grantType is ImplicitGrant)
+ {
+ log.info("Initiating getAccessToken() with implicit grant type workflow");
+ getAccessTokenWithImplicitGrant(grantType as ImplicitGrant);
+ } // else-if statement
+ else if (grantType is ResourceOwnerCredentialsGrant)
+ {
+ log.info("Initiating getAccessToken() with resource owner credentials grant type workflow");
+ getAccessTokenWithResourceOwnerCredentialsGrant(grantType as ResourceOwnerCredentialsGrant);
+ } // else-if statement
+ } // getAccessToken
+
+ /**
+ * Initiates request to refresh a given access token. Upon completion, will dispatch
+ * a RefreshAccessTokenEvent event. On success, a new refresh token may
+ * be issues, at which point the client should discard the old refresh token with the
+ * new one.
+ *
+ * @param refreshToken A valid refresh token received during last request for an access token
+ * @param clientId The client identifier
+ * @param clientSecret The client secret
+ *
+ * @see com.adobe.protocols.oauth2.event.RefreshAccessTokenEvent#TYPE
+ */
+ public function refreshAccessToken(refreshToken:String, clientId:String, clientSecret:String, scope:String = null):void
+ {
+ // create result event
+ var refreshAccessTokenEvent:RefreshAccessTokenEvent = new RefreshAccessTokenEvent();
+
+ // set up URL request
+ var urlRequest:URLRequest = new URLRequest(tokenEndpoint);
+ var urlLoader:URLLoader = new URLLoader();
+ urlRequest.method = URLRequestMethod.POST;
+
+ // define POST parameters
+ var urlVariables : URLVariables = new URLVariables();
+ urlVariables.grant_type = OAuth2Const.GRANT_TYPE_REFRESH_TOKEN;
+ urlVariables.client_id = clientId;
+ urlVariables.client_secret = clientSecret;
+ urlVariables.refresh_token = refreshToken;
+
+ // define optional scope parameter only when scope not null
+ if(scope !== null)
+ {
+ urlVariables.scope = scope;
+ }
+
+ urlRequest.data = urlVariables;
+
+ // attach event listeners
+ urlLoader.addEventListener(Event.COMPLETE, onRefreshAccessTokenResult);
+ urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onRefreshAccessTokenError);
+ urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onRefreshAccessTokenError);
+
+ // make the call
+ try
+ {
+ urlLoader.load(urlRequest);
+ } // try statement
+ catch (error:Error)
+ {
+ log.error("Error loading token endpoint \"" + tokenEndpoint + "\"");
+ } // catch statement
+
+ function onRefreshAccessTokenResult(event:Event):void
+ {
+ try
+ {
+ var response:Object = com.adobe.serialization.json.JSON.decode(event.target.data);
+ log.debug("Access token: " + response.access_token);
+ refreshAccessTokenEvent.parseAccessTokenResponse(response);
+ } // try statement
+ catch (error:JSONParseError)
+ {
+ refreshAccessTokenEvent.errorCode = "com.adobe.serialization.json.JSONParseError";
+ refreshAccessTokenEvent.errorMessage = "Error parsing output from refresh access token response";
+ } // catch statement
+
+ dispatchEvent(refreshAccessTokenEvent);
+ } // onRefreshAccessTokenResult
+
+ function onRefreshAccessTokenError(event:Event):void
+ {
+ log.error("Error encountered during refresh access token request: " + event);
+
+ try
+ {
+ var error:Object = com.adobe.serialization.json.JSON.decode(event.target.data);
+ refreshAccessTokenEvent.errorCode = error.error;
+ refreshAccessTokenEvent.errorMessage = error.error_description;
+ } // try statement
+ catch (error:JSONParseError)
+ {
+ refreshAccessTokenEvent.errorCode = "Unknown";
+ refreshAccessTokenEvent.errorMessage = "Error encountered during refresh access token request. Unable to parse error message.";
+ } // catch statement
+
+ dispatchEvent(refreshAccessTokenEvent);
+ } // onRefreshAccessTokenError
+ } // refreshAccessToken
+
+ /**
+ * Modifies the log level of the logger at runtime.
+ *
+ *
By default, logging is turned off. Passing in any value will modify the logging level + * of the application. This method can accept any of the following values...
+ * + *getAccessToken
+ * request are received.
+ *
+ * @author Charles Bihis (www.whoischarles.com)
+ */
+ public class GetAccessTokenEvent extends Event implements IOAuth2Event
+ {
+ /**
+ * Event type for this event which encapsulates the response from
+ * a getAccessToken request.
+ *
+ * @eventType getAccessToken
+ */
+ public static const TYPE:String = "getAccessToken";
+
+ private var _errorCode:String;
+ private var _errorMessage:String;
+ private var _accessToken:String;
+ private var _tokenType:String;
+ private var _expiresIn:int;
+ private var _refreshToken:String;
+ private var _scope:String;
+ private var _state:String;
+ private var _response:Object;
+
+ /**
+ * Constructor.
+ *
+ * @param bubbles (Optional) Parameter indicating whether or not the event bubbles
+ * @param cancelable (Optional Parameter indicating whether or not the event is cancelable
+ */
+ public function GetAccessTokenEvent(bubbles:Boolean = false, cancelable:Boolean = false)
+ {
+ super(TYPE, bubbles, cancelable);
+ } // GetAccessTokenEvent
+
+ /**
+ * Convenience function that will take a getAccessToken response
+ * and parse its values.
+ *
+ * @param response An object representing the response from a getAccessToken request
+ */
+ public function parseAccessTokenResponse(response:Object):void
+ {
+ // required
+ _accessToken = response.access_token;
+ _tokenType = response.token_type;
+
+ // optional
+ _expiresIn = int(response.expires_in);
+ _refreshToken = response.refresh_token;
+ _scope = response.scope;
+ _state = response.state;
+
+ // extra
+ _response = response;
+ }
+
+ /**
+ * Override of the clone function.
+ *
+ * @return A new GetAccessTokenEvent object.
+ */
+ public override function clone():Event
+ {
+ return new GetAccessTokenEvent();
+ } // clone
+
+ /**
+ * Error code for error after a failed getAccessToken request.
+ */
+ public function get errorCode():String
+ {
+ return _errorCode;
+ } // errorCode
+
+ /**
+ * @private
+ */
+ public function set errorCode(errorCode:String):void
+ {
+ _errorCode = errorCode;
+ } // errorCode
+
+ /**
+ * Error message for error after a failed getAccessToken request.
+ */
+ public function get errorMessage():String
+ {
+ return _errorMessage;
+ } // errorMessage
+
+ /**
+ * @private
+ */
+ public function set errorMessage(errorMessage:String):void
+ {
+ _errorMessage = errorMessage;
+ } // errorMessage
+
+ /**
+ * The access token issues by the authorization server.
+ */
+ public function get accessToken():String
+ {
+ return _accessToken;
+ } // accessToken
+
+ /**
+ * The type of the token issued as described in the OAuth 2.0
+ * v2.15 specification, section 7.1, "Access Token Types".
+ *
+ * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-7.1
+ */
+ public function get tokenType():String
+ {
+ return _tokenType;
+ } // tokenType
+
+ /**
+ * The duration in seconds of the access token lifetime. For example,
+ * the value "3600" denotes that the access token will expire one hour
+ * from the time the response was generated.
+ */
+ public function get expiresIn():int
+ {
+ return _expiresIn;
+ } // expiresIn
+
+ /**
+ * The refresh token which can be used ot obtain new access tokens using
+ * the same authorization grant as described in the OAuth 2.0
+ * v2.15 specification, section 6, "Refreshing an Access Token".
+ *
+ * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-6
+ */
+ public function get refreshToken():String
+ {
+ return _refreshToken;
+ } // refreshToken
+
+ /**
+ * The scope of the access request expressed as a list of space-delimited,
+ * case-sensitive strings.
+ */
+ public function get scope():String
+ {
+ return _scope;
+ } // scope
+
+ /**
+ * An opaque value used by the client to maintain state between the request
+ * and callback.
+ */
+ public function get state():String
+ {
+ return _state;
+ } // state
+
+ /**
+ * Response object to contain all returned response data after a successfull access token request.
+ */
+ public function get response():Object
+ {
+ return _response;
+ } // response
+ } // class declaration
+} // package
\ No newline at end of file
diff --git a/com/adobe/protocols/oauth2/event/IOAuth2Event.as b/com/adobe/protocols/oauth2/event/IOAuth2Event.as
new file mode 100644
index 0000000..3002690
--- /dev/null
+++ b/com/adobe/protocols/oauth2/event/IOAuth2Event.as
@@ -0,0 +1,16 @@
+package com.adobe.protocols.oauth2.event
+{
+ /**
+ * Interface describing generic OAuth 2.0 events.
+ *
+ * @author Charles Bihis (www.whoischarles.com)
+ */
+ public interface IOAuth2Event
+ {
+ function get errorCode():String;
+ function set errorCode(errorCode:String):void;
+
+ function get errorMessage():String;
+ function set errorMessage(errorMessage:String):void;
+ } // interface declaration
+} // package
\ No newline at end of file
diff --git a/com/adobe/protocols/oauth2/event/RefreshAccessTokenEvent.as b/com/adobe/protocols/oauth2/event/RefreshAccessTokenEvent.as
new file mode 100644
index 0000000..868251b
--- /dev/null
+++ b/com/adobe/protocols/oauth2/event/RefreshAccessTokenEvent.as
@@ -0,0 +1,173 @@
+package com.adobe.protocols.oauth2.event
+{
+ import flash.events.Event;
+
+ /**
+ * Event that is broadcast when results from a refreshAccessToken
+ * request are received.
+ *
+ * @author Charles Bihis (www.whoischarles.com)
+ */
+ public class RefreshAccessTokenEvent extends Event implements IOAuth2Event
+ {
+ /**
+ * Event type for this event which encapsulates the response from
+ * a refreshAccessToken request.
+ *
+ * @eventType refreshAccessToken
+ */
+ public static const TYPE:String = "refreshAccessToken";
+
+ private var _errorCode:String;
+ private var _errorMessage:String;
+ private var _accessToken:String;
+ private var _tokenType:String;
+ private var _expiresIn:int;
+ private var _refreshToken:String;
+ private var _scope:String;
+ private var _state:String;
+ private var _response:Object;
+
+ /**
+ * Constructor.
+ *
+ * @param bubbles (Optional) Parameter indicating whether or not the event bubbles
+ * @param cancelable (Optional Parameter indicating whether or not the event is cancelable
+ */
+ public function RefreshAccessTokenEvent(bubbles:Boolean = false, cancelable:Boolean = false)
+ {
+ super(TYPE, bubbles, cancelable);
+ } // RefreshAccessTokenEvent
+
+ /**
+ * Convenience function that will take a refreshAccessToken response
+ * and parse its values.
+ *
+ * @param response An object representing the response from a refreshAccessToken request
+ */
+ public function parseAccessTokenResponse(response:Object):void
+ {
+ // required
+ _accessToken = response.access_token;
+ _tokenType = response.token_type;
+
+ // optional
+ _expiresIn = int(response.expires_in);
+ _refreshToken = response.refresh_token;
+ _scope = response.scope;
+ _state = response.state;
+
+ // extra
+ _response = response;
+ }
+
+ /**
+ * Override of the clone function.
+ *
+ * @return A new RefreshAccessTokenEvent object.
+ */
+ public override function clone():Event
+ {
+ return new GetAccessTokenEvent();
+ } // clone
+
+ /**
+ * Error code for error after a failed refreshAccessToken request.
+ */
+ public function get errorCode():String
+ {
+ return _errorCode;
+ } // errorCode
+
+ /**
+ * @private
+ */
+ public function set errorCode(errorCode:String):void
+ {
+ _errorCode = errorCode;
+ } // errorCode
+
+ /**
+ * Error message for error after a failed refreshAccessToken request.
+ */
+ public function get errorMessage():String
+ {
+ return _errorMessage;
+ } // errorMessage
+
+ /**
+ * @private
+ */
+ public function set errorMessage(errorMessage:String):void
+ {
+ _errorMessage = errorMessage;
+ } // errorMessage
+
+ /**
+ * The access token issues by the authorization server.
+ */
+ public function get accessToken():String
+ {
+ return _accessToken;
+ } // accessToken
+
+ /**
+ * The type of the token issued as described in the OAuth 2.0
+ * v2.15 specification, section 7.1, "Access Token Types".
+ *
+ * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-7.1
+ */
+ public function get tokenType():String
+ {
+ return _tokenType;
+ } // tokenType
+
+ /**
+ * The duration in seconds of the access token lifetime. For example,
+ * the value "3600" denotes that the access token will expire one hour
+ * from the time the response was generated.
+ */
+ public function get expiresIn():int
+ {
+ return _expiresIn;
+ } // expiresIn
+
+ /**
+ * The refresh token which can be used ot obtain new access tokens using
+ * the same authorization grant as described in the OAuth 2.0
+ * v2.15 specification, section 6, "Refreshing an Access Token".
+ *
+ * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-6
+ */
+ public function get refreshToken():String
+ {
+ return _refreshToken;
+ } // refreshToken
+
+ /**
+ * The scope of the access request expressed as a list of space-delimited,
+ * case-sensitive strings.
+ */
+ public function get scope():String
+ {
+ return _scope;
+ } // scope
+
+ /**
+ * An opaque value used by the client to maintain state between the request
+ * and callback.
+ */
+ public function get state():String
+ {
+ return _state;
+ } // state
+
+ /**
+ * Response object to contain all returned response data after a successfull access token request.
+ */
+ public function get response():Object
+ {
+ return _response;
+ } // response
+ } // class declaration
+} // package
\ No newline at end of file
diff --git a/com/adobe/protocols/oauth2/grant/AuthorizationCodeGrant.as b/com/adobe/protocols/oauth2/grant/AuthorizationCodeGrant.as
new file mode 100644
index 0000000..3115196
--- /dev/null
+++ b/com/adobe/protocols/oauth2/grant/AuthorizationCodeGrant.as
@@ -0,0 +1,140 @@
+package com.adobe.protocols.oauth2.grant
+{
+ import com.adobe.protocols.oauth2.OAuth2Const;
+
+ import flash.media.StageWebView;
+
+ /**
+ * Class to encapsulate all of the relevant properties used during
+ * a get-access-token request using the authorization code grant type.
+ *
+ * @author Charles Bihis (www.whoischarles.com)
+ */
+ public class AuthorizationCodeGrant implements IGrantType
+ {
+ private var _stageWebView:StageWebView;
+ private var _clientId:String;
+ private var _clientSecret:String;
+ private var _redirectUri:String;
+ private var _scope:String;
+ private var _state:Object;
+ private var _queryParams:Object;
+
+ /**
+ * Constructor.
+ *
+ * @param stageWebView The StageWebView object for which to display the user-consent page
+ * @param clientId The client identifier
+ * @param clientSecret The client secret
+ * @param redirectUri The redirect URI to return to after the authorization process has completed
+ * @param scope (Optional) The scope of the access request expressed as a list of space-delimited, case-sensitive strings
+ * @param state (Optional) An opaque value used by the client to maintain state between the request and callback
+ * @param queryParams (Optional) Additional query parameters that can be passed to the authorization URL
+ */
+ public function AuthorizationCodeGrant(stageWebView:StageWebView, clientId:String, clientSecret:String, redirectUri:String, scope:String = null, state:Object = null, queryParams:Object = null)
+ {
+ _stageWebView = stageWebView;
+ _clientId = clientId;
+ _clientSecret = clientSecret;
+ _redirectUri = redirectUri;
+ _scope = scope;
+ _state = state;
+ _queryParams = queryParams;
+ } // AuthorizationCodeGrant
+
+ /**
+ * The StageWebView object for which to display the user-consent page.
+ */
+ public function get stageWebView():StageWebView
+ {
+ return _stageWebView;
+ } // stageWebView
+
+ /**
+ * The client identifier as described in the OAuth spec v2.15,
+ * section 3, Client Authentication.
+ *
+ * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-3
+ */
+ public function get clientId():String
+ {
+ return _clientId;
+ } // clientId
+
+ /**
+ * The client secret.
+ */
+ public function get clientSecret():String
+ {
+ return _clientSecret;
+ } // clientSecret
+
+ /**
+ * The redirect endpoint for the client as described in the OAuth
+ * spec v2.15, section 3.1.2, Redirection Endpoint.
+ *
+ * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-20#section-3.1.2
+ */
+ public function get redirectUri():String
+ {
+ return _redirectUri;
+ } // redirectUri
+
+ /**
+ * The scope of the access request expressed as a list of space-delimited,
+ * case-sensitive strings.
+ */
+ public function get scope():String
+ {
+ return _scope;
+ } // scope
+
+ /**
+ * An opaque value used by the client to maintain state between the request
+ * and callback.
+ */
+ public function get state():Object
+ {
+ return _state;
+ } // state
+
+ /**
+ * Additional query parameters that can be passed to the authorization URL.
+ */
+ public function get queryParams():Object
+ {
+ return _queryParams;
+ } // queryParams
+
+ /**
+ * Convenience method for getting the full authorization URL.
+ */
+ public function getFullAuthUrl(authEndpoint:String):String
+ {
+ var url:String = authEndpoint + "?response_type=" + OAuth2Const.RESPONSE_TYPE_AUTHORIZATION_CODE + "&client_id=" + clientId + "&redirect_uri=" + redirectUri;
+
+ // scope is optional
+ if (scope != null && scope.length > 0)
+ {
+ url += "&scope=" + scope;
+ } // if statement
+
+ // state is optional
+ if (state != null)
+ {
+ url += "&state=" + state;
+ } // if statement
+
+ // add additional optional query params, if any
+ if (queryParams != null)
+ {
+ for (var queryParam:String in queryParams)
+ {
+ url += "&" + queryParam + "=" + queryParams[queryParam];
+ } // for loop
+ } // if statement
+
+ return url;
+ } // getFullAuthUrl
+ } // class declaration
+} // package
\ No newline at end of file
diff --git a/com/adobe/protocols/oauth2/grant/IGrantType.as b/com/adobe/protocols/oauth2/grant/IGrantType.as
new file mode 100644
index 0000000..0576ad8
--- /dev/null
+++ b/com/adobe/protocols/oauth2/grant/IGrantType.as
@@ -0,0 +1,17 @@
+package com.adobe.protocols.oauth2.grant
+{
+ /**
+ * Interface used as a marker to signify whether a class
+ * encapsulates the properties of any of the supported
+ * OAuth 2.0 grant types, as described by the v2.15
+ * specification.
+ *
+ * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-4
+ *
+ * @author Charles Bihis (www.whoischarles.com)
+ */
+ public interface IGrantType
+ {
+ function get clientId():String;
+ } // interface declaration
+} // package
\ No newline at end of file
diff --git a/com/adobe/protocols/oauth2/grant/ImplicitGrant.as b/com/adobe/protocols/oauth2/grant/ImplicitGrant.as
new file mode 100644
index 0000000..e427f34
--- /dev/null
+++ b/com/adobe/protocols/oauth2/grant/ImplicitGrant.as
@@ -0,0 +1,129 @@
+package com.adobe.protocols.oauth2.grant
+{
+ import com.adobe.protocols.oauth2.OAuth2Const;
+
+ import flash.media.StageWebView;
+
+ /**
+ * Class to encapsulate all of the relevant properties used during
+ * a get-access-token request using the implicit grant type.
+ *
+ * @author Charles Bihis (www.whoischarles.com)
+ */
+ public class ImplicitGrant implements IGrantType
+ {
+ private var _stageWebView:StageWebView;
+ private var _clientId:String;
+ private var _redirectUri:String;
+ private var _scope:String;
+ private var _state:Object;
+ private var _queryParams:Object;
+
+ /**
+ * Constructor.
+ *
+ * @param stageWebView The StageWebView object for which to display the user-consent page
+ * @param clientId The client identifier
+ * @param redirectUri The redirect URI to return to after the authorization process has completed
+ * @param scope (Optional) The scope of the access request expressed as a list of space-delimited, case-sensitive strings
+ * @param state (Optional) An opaque value used by the client to maintain state between the request and callback
+ * @param queryParams (Optional) Additional query parameters that can be passed to the authorization URL
+ */
+ public function ImplicitGrant(stageWebView:StageWebView, clientId:String, redirectUri:String, scope:String = null, state:Object = null, queryParams:Object = null)
+ {
+ _stageWebView = stageWebView;
+ _clientId = clientId;
+ _redirectUri = redirectUri;
+ _scope = scope;
+ _state = state;
+ _queryParams = queryParams;
+ } // ImplicitGrant
+
+ /**
+ * The StageWebView object for which to display the user-consent page.
+ */
+ public function get stageWebView():StageWebView
+ {
+ return _stageWebView;
+ } // stageWebView
+
+ /**
+ * The client identifier as described in the OAuth spec v2.15,
+ * section 3, Client Authentication.
+ *
+ * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-3
+ */
+ public function get clientId():String
+ {
+ return _clientId;
+ } // clientId
+
+ /**
+ * The redirect endpoint for the client as described in the OAuth
+ * spec v2.15, section 3.1.2, Redirection Endpoint.
+ *
+ * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-20#section-3.1.2
+ */
+ public function get redirectUri():String
+ {
+ return _redirectUri;
+ } // redirectUri
+
+ /**
+ * The scope of the access request expressed as a list of space-delimited,
+ * case-sensitive strings.
+ */
+ public function get scope():String
+ {
+ return _scope;
+ } // scope
+
+ /**
+ * An opaque value used by the client to maintain state between the request
+ * and callback.
+ */
+ public function get state():Object
+ {
+ return _state;
+ } // state
+
+ /**
+ * Additional query parameters that can be passed to the authorization URL.
+ */
+ public function get queryParams():Object
+ {
+ return _queryParams;
+ } // queryParams
+
+ /**
+ * Convenience method for getting the full authorization URL.
+ */
+ public function getFullAuthUrl(endpoint:String):String
+ {
+ var url:String = endpoint + "?response_type=" + OAuth2Const.RESPONSE_TYPE_IMPLICIT + "&client_id=" + clientId + "&redirect_uri=" + redirectUri;
+
+ // scope is optional
+ if (scope != null && scope.length > 0)
+ {
+ url += "&scope=" + scope;
+ } // if statement
+
+ // state is optional
+ if (state != null)
+ {
+ url += "&state=" + state;
+ } // if statement
+
+ // add additional optional query params, if any
+ if (queryParams != null)
+ {
+ for (var queryParam:String in queryParams)
+ {
+ url += "&" + queryParam + "=" + queryParams[queryParam];
+ } // for loop
+ } // if statement
+
+ return url;
+ } // getFullAuthUrl
+ } // class declaration
+} // package
\ No newline at end of file
diff --git a/com/adobe/protocols/oauth2/grant/ResourceOwnerCredentialsGrant.as b/com/adobe/protocols/oauth2/grant/ResourceOwnerCredentialsGrant.as
new file mode 100644
index 0000000..cabc1b5
--- /dev/null
+++ b/com/adobe/protocols/oauth2/grant/ResourceOwnerCredentialsGrant.as
@@ -0,0 +1,80 @@
+package com.adobe.protocols.oauth2.grant
+{
+ /**
+ * Class to encapsulate all of the relevant properties used during
+ * a get-access-token request using the resource owner password
+ * credentials grant type.
+ *
+ * @author Charles Bihis (www.hoischarles.com)
+ */
+ public class ResourceOwnerCredentialsGrant implements IGrantType
+ {
+ private var _clientId:String;
+ private var _clientSecret:String;
+ private var _username:String;
+ private var _password:String;
+ private var _scope:String;
+
+ /**
+ * Constructor.
+ *
+ * @param clientId The client identifier
+ * @param clientSecret The client secret
+ * @param username The resource owner's username for the authorization server
+ * @param password The resource owner's password for the authorization server
+ * @param scope (Optional) The scope of the access request expressed as a list of space-delimited, case-sensitive strings
+ */
+ public function ResourceOwnerCredentialsGrant(clientId:String, clientSecret:String, username:String, password:String, scope:String = null)
+ {
+ _clientId = clientId;
+ _clientSecret = clientSecret;
+ _username = username;
+ _password = password;
+ _scope = scope;
+ } // ResourceOwnserCredentialsGrant
+
+ /**
+ * The client identifier as described in the OAuth spec v2.15,
+ * section 3, Client Authentication.
+ *
+ * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-3
+ */
+ public function get clientId():String
+ {
+ return _clientId;
+ } // clientId
+
+ /**
+ * The client secret.
+ */
+ public function get clientSecret():String
+ {
+ return _clientSecret;
+ } // clientSecret
+
+ /**
+ * The resource owners username.
+ */
+ public function get username():String
+ {
+ return _username;
+ } // username
+
+ /**
+ * The resource owner password.
+ */
+ public function get password():String
+ {
+ return _password;
+ } // password
+
+ /**
+ * The scope of the access request expressed as a list of space-delimited,
+ * case-sensitive strings.
+ */
+ public function get scope():String
+ {
+ return _scope;
+ } // scope
+ } // class declaration
+} // package
\ No newline at end of file
diff --git a/lib/as3commons-logging-2.7.swc b/lib/as3commons-logging-2.7.swc
new file mode 100644
index 0000000..0266508
Binary files /dev/null and b/lib/as3commons-logging-2.7.swc differ
diff --git a/lib/iotashan-oath.swc b/lib/iotashan-oath.swc
deleted file mode 100644
index 28d6030..0000000
Binary files a/lib/iotashan-oath.swc and /dev/null differ
diff --git a/net/systemeD/halcyon/WayUI.as b/net/systemeD/halcyon/WayUI.as
index b2e231d..55eec1a 100644
--- a/net/systemeD/halcyon/WayUI.as
+++ b/net/systemeD/halcyon/WayUI.as
@@ -588,7 +588,7 @@ package net.systemeD.halcyon {
var t1:Number = (pathlength/2 - tf.width/2) / pathlength; var p1:Array=pointAt(t1);
var t2:Number = (pathlength/2 + tf.width/2) / pathlength; var p2:Array=pointAt(t2);
- var mult:Number = (Capabilities.playerType == "Desktop") ? Number(nameformat.size)*1.8 : 1;
+ var mult:Number = (Capabilities.playerType == "Desktop") ? Number(nameformat.size) : 1;
var angleOffset:Number; // so we can do a 180ยบ if we're running backwards
var offsetSign:Number; // -1 if we're starting at t2
diff --git a/net/systemeD/halcyon/connection/Connection.as b/net/systemeD/halcyon/connection/Connection.as
index bf66a51..04df4ec 100644
--- a/net/systemeD/halcyon/connection/Connection.as
+++ b/net/systemeD/halcyon/connection/Connection.as
@@ -39,11 +39,6 @@ package net.systemeD.halcyon.connection {
public function set apiBase(api:String):void { apiBaseURL = api; }
public function get apiDomain():String { return apiBaseURL.replace(/(^https?:\/\/.+?\/).+$/, "$1"); }
- // OAuth getters
- public function get oauthRequestToken():String { return apiDomain+"oauth/request_token"; }
- public function get oauthAccessToken():String { return apiDomain+"oauth/access_token"; }
- public function get oauthAuthURL():String { return apiDomain+"oauth/authorize"; }
-
// connection events
public static var LOAD_STARTED:String = "load_started";
public static var LOAD_COMPLETED:String = "load_completed";
@@ -640,21 +635,22 @@ package net.systemeD.halcyon.connection {
top:Number, bottom:Number):void {
}
public function loadEntityByID(type:String, id:Number):void {}
- public function setAuthToken(id:Object):void {}
- public function deleteAuthToken():void {}
- public function setAccessToken(key:String, secret:String):void {}
public function createChangeset(tags:Object):void {}
public function closeChangeset(callback:Function=null):void {}
public function uploadChanges(closeAfterwards:Boolean=false):* {}
public function fetchUserTraces(refresh:Boolean=false):void {}
public function fetchTrace(id:Number, callback:Function):void {}
- public function hasAccessToken():Boolean { return false; }
public function fetchHistory(entity:Entity, callback:Function):void {}
-
public function loadEntity(entity:Entity):void {
loadEntityByID(entity.getType(),entity.id);
}
-
+
+ // OAuth2 support
+ public var oauthAccessToken:String; // Access token, should be set either from SharedObject (cookie) or from osm.org response
+ public function setAccessToken(token:String):void {}
+ public function hasAccessToken():Boolean { return false; }
+ public function getAccessToken():String { return ""; }
+ public function deleteAccessToken():void {}
}
}
diff --git a/net/systemeD/halcyon/connection/XMLBaseConnection.as b/net/systemeD/halcyon/connection/XMLBaseConnection.as
index 967e143..97e8e08 100644
--- a/net/systemeD/halcyon/connection/XMLBaseConnection.as
+++ b/net/systemeD/halcyon/connection/XMLBaseConnection.as
@@ -4,7 +4,6 @@ package net.systemeD.halcyon.connection {
import flash.system.Security;
import flash.net.*;
- import org.iotashan.oauth.*;
import net.systemeD.halcyon.MapEvent;
import net.systemeD.halcyon.connection.bboxes.*;
diff --git a/net/systemeD/halcyon/connection/XMLConnection.as b/net/systemeD/halcyon/connection/XMLConnection.as
index 07d8c1d..92f8f7d 100644
--- a/net/systemeD/halcyon/connection/XMLConnection.as
+++ b/net/systemeD/halcyon/connection/XMLConnection.as
@@ -5,7 +5,6 @@ package net.systemeD.halcyon.connection {
import mx.rpc.events.*;
import flash.system.Security;
import flash.net.*;
- import org.iotashan.oauth.*;
import net.systemeD.halcyon.AttentionEvent;
import net.systemeD.halcyon.MapEvent;
@@ -95,55 +94,12 @@ package net.systemeD.halcyon.connection {
private function mapLoadStatus(event:HTTPStatusEvent):void {
}
- protected var appID:OAuthConsumer;
- protected var authToken:OAuthToken;
- override public function setAuthToken(id:Object):void {
- authToken = OAuthToken(id);
- }
-
- override public function deleteAuthToken():void {
- authToken = null;
- var obj:SharedObject = SharedObject.getLocal("access_token","/");
- obj.setProperty("oauth_token", null);
- obj.setProperty("oauth_token_secret", null);
- try { obj.flush(); } catch (e:Error) {}
- }
-
- override public function hasAccessToken():Boolean {
- return !(getAccessToken() == null);
- }
-
- override public function setAccessToken(key:String, secret:String):void {
- if (key && secret) {
- authToken = new OAuthToken(key, secret);
- }
- }
-
- /* Get the stored access token, or try setting it up from loader params */
- private function getAccessToken():OAuthToken {
- if (authToken == null) {
- var key:String = getParam("oauth_token", null);
- var secret:String = getParam("oauth_token_secret", null);
-
- if ( key != null && secret != null ) {
- authToken = new OAuthToken(key, secret);
- }
- }
- return authToken;
- }
-
- private function getConsumer():OAuthConsumer {
- if (appID == null) {
- var key:String = getParam("oauth_consumer_key", null);
- var secret:String = getParam("oauth_consumer_secret", null);
-
- if ( key != null && secret != null ) {
- appID = new OAuthConsumer(key, secret);
- }
- }
- return appID;
- }
+ // OAuth2 config
+ override public function setAccessToken(token:String):void { oauthAccessToken = token; }
+ override public function hasAccessToken():Boolean { return oauthAccessToken != null; }
+ override public function getAccessToken():String { return oauthAccessToken; }
+ override public function deleteAccessToken():void { oauthAccessToken = null; } // note you may need to blank the SharedObject too
private var httpStatus:int = 0;
@@ -207,21 +163,14 @@ package net.systemeD.halcyon.connection {
dispatchEvent(new AttentionEvent(AttentionEvent.ALERT, null, "Couldn't close changeset", 1));
}
- private function signedOAuthURL(url:String, method:String):String {
- // method should be PUT, GET, POST or DELETE
- var sig:IOAuthSignatureMethod = new OAuthSignatureMethod_HMAC_SHA1();
- var oauthRequest:OAuthRequest = new OAuthRequest(method, url, null, getConsumer(), authToken);
- var urlStr:Object = oauthRequest.buildRequest(sig, OAuthRequest.RESULT_TYPE_URL_STRING);
- return String(urlStr);
- }
-
private function sendOAuthPut(url:String, xml:XML, onComplete:Function, onError:Function, onStatus:Function):void {
// build the request
- var urlReq:URLRequest = new URLRequest(signedOAuthURL(url, "PUT"));
+ var urlReq:URLRequest = new URLRequest(url);
urlReq.method = "POST";
if (xml) { urlReq.data = xml.toXMLString(); } else { urlReq.data = true; }
urlReq.contentType = "application/xml";
- urlReq.requestHeaders = [ new URLRequestHeader("X-HTTP-Method-Override", "PUT"),
+ urlReq.requestHeaders = [ new URLRequestHeader("Authorization", "Bearer "+oauthAccessToken),
+ new URLRequestHeader("X-HTTP-Method-Override", "PUT"),
new URLRequestHeader("X-Error-Format", "XML") ];
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, onComplete);
@@ -231,8 +180,9 @@ package net.systemeD.halcyon.connection {
}
private function sendOAuthGet(url:String, onComplete:Function, onError:Function, onStatus:Function):void {
- var urlReq:URLRequest = new URLRequest(signedOAuthURL(url, "GET"));
+ var urlReq:URLRequest = new URLRequest(url);
urlReq.method = "GET";
+ urlReq.requestHeaders = [ new URLRequestHeader("Authorization", "Bearer "+oauthAccessToken) ];
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, onComplete);
loader.addEventListener(IOErrorEvent.IO_ERROR, onError);
@@ -266,9 +216,9 @@ package net.systemeD.halcyon.connection {
// build the actual request
var serv:HTTPService=new HTTPService();
serv.method="POST";
- serv.url=signedOAuthURL(url, "POST");
+ serv.url=url;
serv.contentType = "text/xml";
- serv.headers={'X-Error-Format':'xml'};
+ serv.headers={'X-Error-Format':'xml', "Authorization": "Bearer "+oauthAccessToken};
serv.request=" ";
serv.resultFormat="e4x";
serv.requestTimeout=0;
diff --git a/net/systemeD/potlatch2/dialogs/OptionsDialog.mxml b/net/systemeD/potlatch2/dialogs/OptionsDialog.mxml
index 57177fe..6b652ea 100644
--- a/net/systemeD/potlatch2/dialogs/OptionsDialog.mxml
+++ b/net/systemeD/potlatch2/dialogs/OptionsDialog.mxml
@@ -57,11 +57,11 @@