summaryrefslogtreecommitdiffstats
path: root/src/DotNetOpenAuth.OAuth2.AuthorizationServer
diff options
context:
space:
mode:
Diffstat (limited to 'src/DotNetOpenAuth.OAuth2.AuthorizationServer')
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/DotNetOpenAuth.OAuth2.AuthorizationServer.csproj41
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs258
-rw-r--r--src/DotNetOpenAuth.OAuth2.AuthorizationServer/Properties/AssemblyInfo.cs54
3 files changed, 353 insertions, 0 deletions
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/DotNetOpenAuth.OAuth2.AuthorizationServer.csproj b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/DotNetOpenAuth.OAuth2.AuthorizationServer.csproj
new file mode 100644
index 0000000..e28c158
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/DotNetOpenAuth.OAuth2.AuthorizationServer.csproj
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.props))\EnlistmentInfo.props" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.props))' != '' " />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ </PropertyGroup>
+ <Import Project="$(ProjectRoot)tools\DotNetOpenAuth.props" />
+ <PropertyGroup>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{99BB7543-EA16-43EE-A7BC-D7A25A3B22F6}</ProjectGuid>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <AssemblyName>DotNetOpenAuth.OAuth2.AuthorizationServer</AssemblyName>
+ </PropertyGroup>
+ <Import Project="$(ProjectRoot)tools\DotNetOpenAuth.Product.props" />
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="OAuth2\AuthorizationServer.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\DotNetOpenAuth.Core\DotNetOpenAuth.Core.csproj">
+ <Project>{60426312-6AE5-4835-8667-37EDEA670222}</Project>
+ <Name>DotNetOpenAuth.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\DotNetOpenAuth.OAuth2\DotNetOpenAuth.OAuth2.csproj">
+ <Project>{56459A6C-6BA2-4BAC-A9C0-27E3BD961FA6}</Project>
+ <Name>DotNetOpenAuth.OAuth2</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\DotNetOpenAuth.OAuth\DotNetOpenAuth.OAuth.csproj">
+ <Project>{A288FCC8-6FCF-46DA-A45E-5F9281556361}</Project>
+ <Name>DotNetOpenAuth.OAuth</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(ProjectRoot)tools\DotNetOpenAuth.targets" />
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))\EnlistmentInfo.targets" Condition=" '$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), EnlistmentInfo.targets))' != '' " />
+</Project> \ No newline at end of file
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs
new file mode 100644
index 0000000..73c2bd6
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/OAuth2/AuthorizationServer.cs
@@ -0,0 +1,258 @@
+//-----------------------------------------------------------------------
+// <copyright file="AuthorizationServer.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+namespace DotNetOpenAuth.OAuth2 {
+ using System;
+ using System.Collections.Generic;
+ using System.Diagnostics.Contracts;
+ using System.Linq;
+ using System.Security.Cryptography;
+ using System.Text;
+ using DotNetOpenAuth.Messaging;
+ using DotNetOpenAuth.OAuth2.ChannelElements;
+ using DotNetOpenAuth.OAuth2.Messages;
+
+ /// <summary>
+ /// Authorization Server supporting the web server flow.
+ /// </summary>
+ public class AuthorizationServer {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="AuthorizationServer"/> class.
+ /// </summary>
+ /// <param name="authorizationServer">The authorization server.</param>
+ public AuthorizationServer(IAuthorizationServer authorizationServer) {
+ Requires.NotNull(authorizationServer, "authorizationServer");
+ this.OAuthChannel = new OAuth2AuthorizationServerChannel(authorizationServer);
+ }
+
+ /// <summary>
+ /// Gets the channel.
+ /// </summary>
+ /// <value>The channel.</value>
+ public Channel Channel {
+ get { return this.OAuthChannel; }
+ }
+
+ /// <summary>
+ /// Gets the authorization server.
+ /// </summary>
+ /// <value>The authorization server.</value>
+ public IAuthorizationServer AuthorizationServerServices {
+ get { return this.OAuthChannel.AuthorizationServer; }
+ }
+
+ /// <summary>
+ /// Gets the channel.
+ /// </summary>
+ internal OAuth2AuthorizationServerChannel OAuthChannel { get; private set; }
+
+ /// <summary>
+ /// Reads in a client's request for the Authorization Server to obtain permission from
+ /// the user to authorize the Client's access of some protected resource(s).
+ /// </summary>
+ /// <param name="request">The HTTP request to read from.</param>
+ /// <returns>The incoming request, or null if no OAuth message was attached.</returns>
+ /// <exception cref="ProtocolException">Thrown if an unexpected OAuth message is attached to the incoming request.</exception>
+ public EndUserAuthorizationRequest ReadAuthorizationRequest(HttpRequestInfo request = null) {
+ if (request == null) {
+ request = this.Channel.GetRequestFromContext();
+ }
+
+ EndUserAuthorizationRequest message;
+ if (this.Channel.TryReadFromRequest(request, out message)) {
+ if (message.ResponseType == EndUserAuthorizationResponseType.AuthorizationCode) {
+ // Clients with no secrets can only request implicit grant types.
+ var client = this.AuthorizationServerServices.GetClientOrThrow(message.ClientIdentifier);
+ ErrorUtilities.VerifyProtocol(!String.IsNullOrEmpty(client.Secret), Protocol.unauthorized_client);
+ }
+ }
+
+ return message;
+ }
+
+ /// <summary>
+ /// Approves an authorization request and sends an HTTP response to the user agent to redirect the user back to the Client.
+ /// </summary>
+ /// <param name="authorizationRequest">The authorization request to approve.</param>
+ /// <param name="userName">The username of the account that approved the request (or whose data will be accessed by the client).</param>
+ /// <param name="scopes">The scope of access the client should be granted. If <c>null</c>, all scopes in the original request will be granted.</param>
+ /// <param name="callback">The Client callback URL to use when formulating the redirect to send the user agent back to the Client.</param>
+ public void ApproveAuthorizationRequest(EndUserAuthorizationRequest authorizationRequest, string userName, IEnumerable<string> scopes = null, Uri callback = null) {
+ Requires.NotNull(authorizationRequest, "authorizationRequest");
+
+ var response = this.PrepareApproveAuthorizationRequest(authorizationRequest, userName, scopes, callback);
+ this.Channel.Respond(response);
+ }
+
+ /// <summary>
+ /// Rejects an authorization request and sends an HTTP response to the user agent to redirect the user back to the Client.
+ /// </summary>
+ /// <param name="authorizationRequest">The authorization request to disapprove.</param>
+ /// <param name="callback">The Client callback URL to use when formulating the redirect to send the user agent back to the Client.</param>
+ public void RejectAuthorizationRequest(EndUserAuthorizationRequest authorizationRequest, Uri callback = null) {
+ Requires.NotNull(authorizationRequest, "authorizationRequest");
+
+ var response = this.PrepareRejectAuthorizationRequest(authorizationRequest, callback);
+ this.Channel.Respond(response);
+ }
+
+ /// <summary>
+ /// Checks the incoming HTTP request for an access token request and prepares a response if the request message was found.
+ /// </summary>
+ /// <param name="response">The formulated response, or <c>null</c> if the request was not found..</param>
+ /// <returns>A value indicating whether any access token request was found in the HTTP request.</returns>
+ /// <remarks>
+ /// This method assumes that the authorization server and the resource server are the same and that they share a single
+ /// asymmetric key for signing and encrypting the access token. If this is not true, use the <see cref="ReadAccessTokenRequest"/> method instead.
+ /// </remarks>
+ public bool TryPrepareAccessTokenResponse(out IDirectResponseProtocolMessage response) {
+ return this.TryPrepareAccessTokenResponse(this.Channel.GetRequestFromContext(), out response);
+ }
+
+ /// <summary>
+ /// Checks the incoming HTTP request for an access token request and prepares a response if the request message was found.
+ /// </summary>
+ /// <param name="httpRequestInfo">The HTTP request info.</param>
+ /// <param name="response">The formulated response, or <c>null</c> if the request was not found..</param>
+ /// <returns>A value indicating whether any access token request was found in the HTTP request.</returns>
+ /// <remarks>
+ /// This method assumes that the authorization server and the resource server are the same and that they share a single
+ /// asymmetric key for signing and encrypting the access token. If this is not true, use the <see cref="ReadAccessTokenRequest"/> method instead.
+ /// </remarks>
+ public bool TryPrepareAccessTokenResponse(HttpRequestInfo httpRequestInfo, out IDirectResponseProtocolMessage response) {
+ Requires.NotNull(httpRequestInfo, "httpRequestInfo");
+ Contract.Ensures(Contract.Result<bool>() == (Contract.ValueAtReturn<IDirectResponseProtocolMessage>(out response) != null));
+
+ var request = this.ReadAccessTokenRequest(httpRequestInfo);
+ if (request != null) {
+ response = this.PrepareAccessTokenResponse(request);
+ return true;
+ }
+
+ response = null;
+ return false;
+ }
+
+ /// <summary>
+ /// Reads the access token request.
+ /// </summary>
+ /// <param name="requestInfo">The request info.</param>
+ /// <returns>The Client's request for an access token; or <c>null</c> if no such message was found in the request.</returns>
+ public AccessTokenRequestBase ReadAccessTokenRequest(HttpRequestInfo requestInfo = null) {
+ if (requestInfo == null) {
+ requestInfo = this.Channel.GetRequestFromContext();
+ }
+
+ AccessTokenRequestBase request;
+ this.Channel.TryReadFromRequest(requestInfo, out request);
+ return request;
+ }
+
+ /// <summary>
+ /// Prepares a response to inform the Client that the user has rejected the Client's authorization request.
+ /// </summary>
+ /// <param name="authorizationRequest">The authorization request.</param>
+ /// <param name="callback">The Client callback URL to use when formulating the redirect to send the user agent back to the Client.</param>
+ /// <returns>The authorization response message to send to the Client.</returns>
+ public EndUserAuthorizationFailedResponse PrepareRejectAuthorizationRequest(EndUserAuthorizationRequest authorizationRequest, Uri callback = null) {
+ Requires.NotNull(authorizationRequest, "authorizationRequest");
+ Contract.Ensures(Contract.Result<EndUserAuthorizationFailedResponse>() != null);
+
+ if (callback == null) {
+ callback = this.GetCallback(authorizationRequest);
+ }
+
+ var response = new EndUserAuthorizationFailedResponse(callback, authorizationRequest);
+ return response;
+ }
+
+ /// <summary>
+ /// Approves an authorization request.
+ /// </summary>
+ /// <param name="authorizationRequest">The authorization request to approve.</param>
+ /// <param name="userName">The username of the account that approved the request (or whose data will be accessed by the client).</param>
+ /// <param name="scopes">The scope of access the client should be granted. If <c>null</c>, all scopes in the original request will be granted.</param>
+ /// <param name="callback">The Client callback URL to use when formulating the redirect to send the user agent back to the Client.</param>
+ /// <returns>The authorization response message to send to the Client.</returns>
+ public EndUserAuthorizationSuccessResponseBase PrepareApproveAuthorizationRequest(EndUserAuthorizationRequest authorizationRequest, string userName, IEnumerable<string> scopes = null, Uri callback = null) {
+ Requires.NotNull(authorizationRequest, "authorizationRequest");
+ Requires.NotNullOrEmpty(userName, "userName");
+ Contract.Ensures(Contract.Result<EndUserAuthorizationSuccessResponseBase>() != null);
+
+ if (callback == null) {
+ callback = this.GetCallback(authorizationRequest);
+ }
+
+ var client = this.AuthorizationServerServices.GetClientOrThrow(authorizationRequest.ClientIdentifier);
+ EndUserAuthorizationSuccessResponseBase response;
+ switch (authorizationRequest.ResponseType) {
+ case EndUserAuthorizationResponseType.AccessToken:
+ var accessTokenResponse = new EndUserAuthorizationSuccessAccessTokenResponse(callback, authorizationRequest);
+ accessTokenResponse.Lifetime = this.AuthorizationServerServices.GetAccessTokenLifetime(authorizationRequest);
+ response = accessTokenResponse;
+ break;
+ case EndUserAuthorizationResponseType.AuthorizationCode:
+ response = new EndUserAuthorizationSuccessAuthCodeResponse(callback, authorizationRequest);
+ break;
+ default:
+ throw ErrorUtilities.ThrowInternal("Unexpected response type.");
+ }
+
+ response.AuthorizingUsername = userName;
+
+ // Customize the approved scope if the authorization server has decided to do so.
+ if (scopes != null) {
+ response.Scope.ResetContents(scopes);
+ }
+
+ return response;
+ }
+
+ /// <summary>
+ /// Prepares the response to an access token request.
+ /// </summary>
+ /// <param name="request">The request for an access token.</param>
+ /// <param name="includeRefreshToken">If set to <c>true</c>, the response will include a long-lived refresh token.</param>
+ /// <returns>The response message to send to the client.</returns>
+ public virtual IDirectResponseProtocolMessage PrepareAccessTokenResponse(AccessTokenRequestBase request, bool includeRefreshToken = true) {
+ Requires.NotNull(request, "request");
+
+ var tokenRequest = (IAuthorizationCarryingRequest)request;
+ var response = new AccessTokenSuccessResponse(request) {
+ Lifetime = this.AuthorizationServerServices.GetAccessTokenLifetime(request),
+ HasRefreshToken = includeRefreshToken,
+ };
+ response.Scope.ResetContents(tokenRequest.AuthorizationDescription.Scope);
+ return response;
+ }
+
+ /// <summary>
+ /// Gets the redirect URL to use for a particular authorization request.
+ /// </summary>
+ /// <param name="authorizationRequest">The authorization request.</param>
+ /// <returns>The URL to redirect to. Never <c>null</c>.</returns>
+ /// <exception cref="ProtocolException">Thrown if no callback URL could be determined.</exception>
+ protected Uri GetCallback(EndUserAuthorizationRequest authorizationRequest) {
+ Requires.NotNull(authorizationRequest, "authorizationRequest");
+ Contract.Ensures(Contract.Result<Uri>() != null);
+
+ var client = this.AuthorizationServerServices.GetClientOrThrow(authorizationRequest.ClientIdentifier);
+
+ // Prefer a request-specific callback to the pre-registered one (if any).
+ if (authorizationRequest.Callback != null) {
+ // The OAuth channel has already validated the callback parameter against
+ // the authorization server's whitelist for this client.
+ return authorizationRequest.Callback;
+ }
+
+ // Since the request didn't include a callback URL, look up the callback from
+ // the client's preregistration with this authorization server.
+ Uri defaultCallback = client.DefaultCallback;
+ ErrorUtilities.VerifyProtocol(defaultCallback != null, OAuthStrings.NoCallback);
+ return defaultCallback;
+ }
+ }
+}
diff --git a/src/DotNetOpenAuth.OAuth2.AuthorizationServer/Properties/AssemblyInfo.cs b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..54db6cf
--- /dev/null
+++ b/src/DotNetOpenAuth.OAuth2.AuthorizationServer/Properties/AssemblyInfo.cs
@@ -0,0 +1,54 @@
+//-----------------------------------------------------------------------
+// <copyright file="AssemblyInfo.cs" company="Andrew Arnott">
+// Copyright (c) Andrew Arnott. All rights reserved.
+// </copyright>
+//-----------------------------------------------------------------------
+
+// We DON'T put an AssemblyVersionAttribute in here because it is generated in the build.
+
+using System;
+using System.Diagnostics.Contracts;
+using System.Net;
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Security.Permissions;
+using System.Web.UI;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("DotNetOpenAuth OAuth 2.0")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("DotNetOpenAuth")]
+[assembly: AssemblyCopyright("Copyright © 2008")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: NeutralResourcesLanguage("en-US")]
+[assembly: CLSCompliant(true)]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("7d73990c-47c0-4256-9f20-a893add9e289")]
+
+[assembly: ContractVerification(true)]
+
+#if StrongNameSigned
+// See comment at top of this file. We need this so that strong-naming doesn't
+// keep this assembly from being useful to shared host (medium trust) web sites.
+[assembly: AllowPartiallyTrustedCallers]
+
+[assembly: InternalsVisibleTo("DotNetOpenAuth.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100AD093C3765257C89A7010E853F2C7C741FF92FA8ACE06D7B8254702CAD5CF99104447F63AB05F8BB6F51CE0D81C8C93D2FCE8C20AAFF7042E721CBA16EAAE98778611DED11C0ABC8900DC5667F99B50A9DADEC24DBD8F2C91E3E8AD300EF64F1B4B9536CEB16FB440AF939F57624A9B486F867807C649AE4830EAB88C6C03998")]
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
+#else
+[assembly: InternalsVisibleTo("DotNetOpenAuth.Test")]
+[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
+#endif