/// <summary> /// Processes an incoming authorization-granted message from an SP and obtains an access token. /// </summary> /// <param name="openIdAuthenticationResponse">The OpenID authentication response that may be carrying an authorized request token.</param> /// <returns> /// The access token, or null if OAuth authorization was denied by the user or service provider. /// </returns> /// <remarks> /// The access token, if granted, is automatically stored in the <see cref="ConsumerBase.TokenManager"/>. /// The token manager instance must implement <see cref="IOpenIdOAuthTokenManager"/>. /// </remarks> public AuthorizedTokenResponse ProcessUserAuthorization(IAuthenticationResponse openIdAuthenticationResponse) { Requires.NotNull(openIdAuthenticationResponse, "openIdAuthenticationResponse"); Requires.ValidState(this.TokenManager is IOpenIdOAuthTokenManager); var openidTokenManager = this.TokenManager as IOpenIdOAuthTokenManager; ErrorUtilities.VerifyOperation(openidTokenManager != null, OAuthStrings.OpenIdOAuthExtensionRequiresSpecialTokenManagerInterface, typeof(IOpenIdOAuthTokenManager).FullName); // The OAuth extension is only expected in positive assertion responses. if (openIdAuthenticationResponse.Status != AuthenticationStatus.Authenticated) { return null; } // Retrieve the OAuth extension var positiveAuthorization = openIdAuthenticationResponse.GetExtension<AuthorizationApprovedResponse>(); if (positiveAuthorization == null) { return null; } // Prepare a message to exchange the request token for an access token. // We are careful to use a v1.0 message version so that the oauth_verifier is not required. var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint, Protocol.V10.Version) { RequestToken = positiveAuthorization.RequestToken, ConsumerKey = this.ConsumerKey, }; // Retrieve the access token and store it in the token manager. openidTokenManager.StoreOpenIdAuthorizedRequestToken(this.ConsumerKey, positiveAuthorization); var grantAccess = this.Channel.Request<AuthorizedTokenResponse>(requestAccess); this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, positiveAuthorization.RequestToken, grantAccess.AccessToken, grantAccess.TokenSecret); // Provide the caller with the access token so it may be associated with the user // that is logging in. return grantAccess; }
/// <summary> /// Analyzes an incoming request message payload to discover what kind of /// message is embedded in it and returns the type, or null if no match is found. /// </summary> /// <param name="recipient">The intended or actual recipient of the request message.</param> /// <param name="fields">The name/value pairs that make up the message payload.</param> /// <returns> /// A newly instantiated <see cref="IProtocolMessage"/>-derived object that this message can /// deserialize to. Null if the request isn't recognized as a valid protocol message. /// </returns> /// <remarks> /// The request messages are: /// UnauthorizedTokenRequest /// AuthorizedTokenRequest /// UserAuthorizationRequest /// AccessProtectedResourceRequest /// </remarks> public virtual IDirectedProtocolMessage GetNewRequestMessage(MessageReceivingEndpoint recipient, IDictionary<string, string> fields) { MessageBase message = null; Protocol protocol = Protocol.V10; // default to assuming the less-secure 1.0 instead of 1.0a until we prove otherwise. string token; fields.TryGetValue("oauth_token", out token); try { if (fields.ContainsKey("oauth_consumer_key") && !fields.ContainsKey("oauth_token")) { protocol = fields.ContainsKey("oauth_callback") ? Protocol.V10a : Protocol.V10; message = new UnauthorizedTokenRequest(recipient, protocol.Version); } else if (fields.ContainsKey("oauth_consumer_key") && fields.ContainsKey("oauth_token")) { // Discern between RequestAccessToken and AccessProtectedResources, // which have all the same parameters, by figuring out what type of token // is in the token parameter. bool tokenTypeIsAccessToken = this.tokenManager.GetTokenType(token) == TokenType.AccessToken; if (tokenTypeIsAccessToken) { message = (MessageBase)new AccessProtectedResourceRequest(recipient, protocol.Version); } else { // Discern between 1.0 and 1.0a requests by checking on the consumer version we stored // when the consumer first requested an unauthorized token. protocol = Protocol.Lookup(this.tokenManager.GetRequestToken(token).ConsumerVersion); message = new AuthorizedTokenRequest(recipient, protocol.Version); } } else { // fail over to the message with no required fields at all. if (token != null) { protocol = Protocol.Lookup(this.tokenManager.GetRequestToken(token).ConsumerVersion); } // If a callback parameter is included, that suggests either the consumer // is following OAuth 1.0 instead of 1.0a, or that a hijacker is trying // to attack. Either way, if the consumer started out as a 1.0a, keep it // that way, and we'll just ignore the oauth_callback included in this message // by virtue of the UserAuthorizationRequest message not including it in its // 1.0a payload. message = new UserAuthorizationRequest(recipient, protocol.Version); } if (message != null) { message.SetAsIncoming(); } return message; } catch (KeyNotFoundException ex) { throw ErrorUtilities.Wrap(ex, OAuthStrings.TokenNotFound); } }
public async Task VerifyAuthenticationFailsIfAccessTokenIsInvalid() { // Arrange var endpoint = new MessageReceivingEndpoint("http://live.com/path/?a=b", HttpDeliveryMethods.GetRequest); var request = new AuthorizedTokenRequest(endpoint, new Version("1.0")); var webWorker = new Mock<IOAuthWebWorker>(MockBehavior.Strict); webWorker.Setup(w => w.ProcessUserAuthorizationAsync(It.IsAny<HttpContextBase>(), CancellationToken.None)).Returns(Task.FromResult<AccessTokenResponse>(null)).Verifiable(); var client = new MockOAuthClient(webWorker.Object); var context = new Mock<HttpContextBase>(); // Act AuthenticationResult result = await client.VerifyAuthenticationAsync(context.Object); // Assert webWorker.Verify(); Assert.False(result.IsSuccessful); }
public void VerifyAuthenticationFailsIfAccessTokenIsInvalid() { // Arrange var endpoint = new MessageReceivingEndpoint("http://live.com/path/?a=b", HttpDeliveryMethods.GetRequest); var request = new AuthorizedTokenRequest(endpoint, new Version("1.0")); var response = new AuthorizedTokenResponse(request) { AccessToken = "invalid token" }; var webWorker = new Mock<IOAuthWebWorker>(MockBehavior.Strict); webWorker.Setup(w => w.ProcessUserAuthorization()).Returns(response).Verifiable(); var client = new MockOAuthClient(webWorker.Object); var context = new Mock<HttpContextBase>(); // Act AuthenticationResult result = client.VerifyAuthentication(context.Object); // Assert webWorker.Verify(); Assert.False(result.IsSuccessful); }
/// <summary> /// Obtains an access token for a new account at the Service Provider via 2-legged OAuth. /// </summary> /// <param name="requestParameters">Any applicable parameters to include in the query string of the token request.</param> /// <returns>The access token.</returns> /// <remarks> /// The token secret is stored in the <see cref="TokenManager"/>. /// </remarks> public string RequestNewClientAccount(IDictionary<string, string> requestParameters = null) { // Obtain an unauthorized request token. Assume the OAuth version given in the service description. var token = new UnauthorizedTokenRequest(this.ServiceProvider.RequestTokenEndpoint, this.ServiceProvider.Version) { ConsumerKey = this.ConsumerKey, }; var tokenAccessor = this.Channel.MessageDescriptions.GetAccessor(token); tokenAccessor.AddExtraParameters(requestParameters); var requestTokenResponse = this.Channel.Request<UnauthorizedTokenResponse>(token); this.TokenManager.StoreNewRequestToken(token, requestTokenResponse); var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint, this.ServiceProvider.Version) { RequestToken = requestTokenResponse.RequestToken, ConsumerKey = this.ConsumerKey, }; var grantAccess = this.Channel.Request<AuthorizedTokenResponse>(requestAccess); this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, requestTokenResponse.RequestToken, grantAccess.AccessToken, grantAccess.TokenSecret); return grantAccess.AccessToken; }
/// <summary> /// Exchanges a given request token for access token. /// </summary> /// <param name="requestToken">The request token that the user has authorized.</param> /// <param name="verifier">The verifier code.</param> /// <returns> /// The access token assigned by the Service Provider. /// </returns> protected AuthorizedTokenResponse ProcessUserAuthorization(string requestToken, string verifier) { Contract.Requires<ArgumentException>(!String.IsNullOrEmpty(requestToken)); Contract.Ensures(Contract.Result<AuthorizedTokenResponse>() != null); var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint, this.ServiceProvider.Version) { RequestToken = requestToken, VerificationCode = verifier, ConsumerKey = this.ConsumerKey, }; var grantAccess = this.Channel.Request<AuthorizedTokenResponse>(requestAccess); this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, requestToken, grantAccess.AccessToken, grantAccess.TokenSecret); return grantAccess; }
/// <summary> /// Prepares and sends an access token to a Consumer, and invalidates the request token. /// </summary> /// <param name="request">The Consumer's message requesting an access token.</param> /// <returns>The HTTP response to actually send to the Consumer.</returns> public AuthorizedTokenResponse PrepareAccessTokenMessage(AuthorizedTokenRequest request) { Requires.NotNull(request, "request"); ErrorUtilities.VerifyProtocol(this.TokenManager.IsRequestTokenAuthorized(request.RequestToken), OAuthStrings.AccessTokenNotAuthorized, request.RequestToken); string accessToken = this.TokenGenerator.GenerateAccessToken(request.ConsumerKey); string tokenSecret = this.TokenGenerator.GenerateSecret(); this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(request.ConsumerKey, request.RequestToken, accessToken, tokenSecret); var grantAccess = new AuthorizedTokenResponse(request) { AccessToken = accessToken, TokenSecret = tokenSecret, }; return grantAccess; }
public async Task VerifyAuthenticationSucceeds() { // Arrange var endpoint = new MessageReceivingEndpoint("http://live.com/path/?a=b", HttpDeliveryMethods.GetRequest); var request = new AuthorizedTokenRequest(endpoint, new Version("1.0")); var webWorker = new Mock<IOAuthWebWorker>(MockBehavior.Strict); webWorker .Setup(w => w.ProcessUserAuthorizationAsync(It.IsAny<HttpContextBase>(), CancellationToken.None)) .Returns(Task.FromResult(new AccessTokenResponse("ok", "secret", new NameValueCollection()))).Verifiable(); var client = new MockOAuthClient(webWorker.Object); var context = new Mock<HttpContextBase>(); // Act AuthenticationResult result = await client.VerifyAuthenticationAsync(context.Object); // Assert webWorker.Verify(); Assert.True(result.IsSuccessful); Assert.AreEqual("mockoauth", result.Provider); Assert.AreEqual("12345", result.ProviderUserId); Assert.AreEqual("super", result.UserName); Assert.IsNotNull(result.ExtraData); Assert.AreEqual("ok", result.ExtraData["accesstoken"]); }
/// <summary> /// Exchanges a given request token for access token. /// </summary> /// <param name="requestToken">The request token that the user has authorized.</param> /// <returns>The access token assigned by the Service Provider.</returns> protected AuthorizedTokenResponse ProcessUserAuthorization(string requestToken) { var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint) { RequestToken = requestToken, ConsumerKey = this.ConsumerKey, }; var grantAccess = this.Channel.Request<AuthorizedTokenResponse>(requestAccess); this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, requestToken, grantAccess.AccessToken, grantAccess.TokenSecret); return grantAccess; }
/// <summary> /// Prepares and sends an access token to a Consumer, and invalidates the request token. /// </summary> /// <param name="request">The Consumer's message requesting an access token.</param> /// <returns>The HTTP response to actually send to the Consumer.</returns> public AuthorizedTokenResponse PrepareAccessTokenMessage(AuthorizedTokenRequest request) { if (request == null) { throw new ArgumentNullException("request"); } if (!this.TokenManager.IsRequestTokenAuthorized(request.RequestToken)) { throw new ProtocolException( string.Format( CultureInfo.CurrentCulture, OAuthStrings.AccessTokenNotAuthorized, request.RequestToken)); } string accessToken = this.TokenGenerator.GenerateAccessToken(request.ConsumerKey); string tokenSecret = this.TokenGenerator.GenerateSecret(); this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(request.ConsumerKey, request.RequestToken, accessToken, tokenSecret); var grantAccess = new AuthorizedTokenResponse(request) { AccessToken = accessToken, TokenSecret = tokenSecret, }; return grantAccess; }
/// <summary> /// Initializes a new instance of the <see cref="AuthorizedTokenResponse"/> class. /// </summary> /// <param name="originatingRequest">The originating request.</param> protected internal AuthorizedTokenResponse(AuthorizedTokenRequest originatingRequest) : base(MessageProtections.None, originatingRequest) { }
/// <summary> /// Obtains an access token for a new account at the Service Provider via 2-legged OAuth. /// </summary> /// <param name="requestParameters">Any applicable parameters to include in the query string of the token request.</param> /// <returns>The access token.</returns> /// <remarks> /// The token secret is stored in the <see cref="TokenManager"/>. /// </remarks> public string RequestNewClientAccount(IDictionary<string, string> requestParameters = null) { // Obtain an unauthorized request token. Force use of OAuth 1.0 (not 1.0a) so that // we are not expected to provide an oauth_verifier which doesn't apply in 2-legged OAuth. var token = new UnauthorizedTokenRequest(this.ServiceProvider.RequestTokenEndpoint, Protocol.V10.Version) { ConsumerKey = this.ConsumerKey, }; var tokenAccessor = this.Channel.MessageDescriptions.GetAccessor(token); tokenAccessor.AddExtraParameters(requestParameters); var requestTokenResponse = this.Channel.Request<UnauthorizedTokenResponse>(token); this.TokenManager.StoreNewRequestToken(token, requestTokenResponse); var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint, Protocol.V10.Version) { RequestToken = requestTokenResponse.RequestToken, ConsumerKey = this.ConsumerKey, }; var grantAccess = this.Channel.Request<AuthorizedTokenResponse>(requestAccess); this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, requestTokenResponse.RequestToken, grantAccess.AccessToken, grantAccess.TokenSecret); return grantAccess.AccessToken; }
/// <summary> /// Exchanges a given request token for access token. /// </summary> /// <param name="requestToken">The request token that the user has authorized.</param> /// <param name="verifier">The verifier code.</param> /// <returns> /// The access token assigned by the Service Provider. /// </returns> protected AuthorizedTokenResponse ProcessUserAuthorization(string requestToken, string verifier) { Requires.NotNullOrEmpty(requestToken, "requestToken"); var requestAccess = new AuthorizedTokenRequest(this.ServiceProvider.AccessTokenEndpoint, this.ServiceProvider.Version) { RequestToken = requestToken, VerificationCode = verifier, ConsumerKey = this.ConsumerKey, }; var grantAccess = this.Channel.Request<AuthorizedTokenResponse>(requestAccess); this.TokenManager.ExpireRequestTokenAndStoreNewAccessToken(this.ConsumerKey, requestToken, grantAccess.AccessToken, grantAccess.TokenSecret); return grantAccess; }
/// <summary> /// Initializes a new instance of the <see cref="AuthorizedTokenResponse"/> class. /// </summary> /// <param name="originatingRequest">The originating request.</param> protected internal AuthorizedTokenResponse(AuthorizedTokenRequest originatingRequest) : base(MessageProtections.None, originatingRequest, originatingRequest.Version) { }
public void VerifyAuthenticationSucceeds() { // Arrange var endpoint = new MessageReceivingEndpoint("http://live.com/path/?a=b", HttpDeliveryMethods.GetRequest); var request = new AuthorizedTokenRequest(endpoint, new Version("1.0")); var response = new AuthorizedTokenResponse(request) { AccessToken = "ok" }; var webWorker = new Mock<IOAuthWebWorker>(MockBehavior.Strict); webWorker.Setup(w => w.ProcessUserAuthorization()).Returns(response).Verifiable(); var client = new MockOAuthClient(webWorker.Object); var context = new Mock<HttpContextBase>(); // Act AuthenticationResult result = client.VerifyAuthentication(context.Object); // Assert webWorker.Verify(); Assert.True(result.IsSuccessful); Assert.AreEqual("mockoauth", result.Provider); Assert.AreEqual("12345", result.ProviderUserId); Assert.AreEqual("super", result.UserName); Assert.IsNotNull(result.ExtraData); Assert.IsTrue(result.ExtraData.ContainsKey("accesstoken")); Assert.AreEqual("ok", result.ExtraData["accesstoken"]); }