//----------------------------------------------------------------------- // // Copyright (c) Andrew Arnott. All rights reserved. // //----------------------------------------------------------------------- namespace DotNetOpenAuth.OAuth2 { using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Diagnostics.Contracts; using System.Linq; using System.Net; using System.Security.Principal; using System.ServiceModel.Channels; using System.Text; using System.Text.RegularExpressions; using System.Web; using ChannelElements; using Messages; using Messaging; /// /// Provides services for validating OAuth access tokens. /// public class ResourceServer { /// /// Initializes a new instance of the class. /// /// The access token analyzer. public ResourceServer(IAccessTokenAnalyzer accessTokenAnalyzer) { Contract.Requires(accessTokenAnalyzer != null); this.AccessTokenAnalyzer = accessTokenAnalyzer; this.Channel = new OAuth2ResourceServerChannel(); } /// /// Gets the access token analyzer. /// /// The access token analyzer. public IAccessTokenAnalyzer AccessTokenAnalyzer { get; private set; } /// /// Gets the channel. /// /// The channel. internal OAuth2ResourceServerChannel Channel { get; private set; } /// /// Discovers what access the client should have considering the access token in the current request. /// /// The name on the account the client has access to. /// The set of operations the client is authorized for. /// An error to return to the client if access is not authorized; null if access is granted. [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "0#", Justification = "Try pattern")] [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "Try pattern")] public OutgoingWebResponse VerifyAccess(out string userName, out HashSet scope) { return this.VerifyAccess(this.Channel.GetRequestFromContext(), out userName, out scope); } /// /// Discovers what access the client should have considering the access token in the current request. /// /// The HTTP request info. /// The name on the account the client has access to. /// The set of operations the client is authorized for. /// /// An error to return to the client if access is not authorized; null if access is granted. /// [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "Try pattern")] [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#", Justification = "Try pattern")] public virtual OutgoingWebResponse VerifyAccess(HttpRequestInfo httpRequestInfo, out string userName, out HashSet scope) { Contract.Requires(httpRequestInfo != null); AccessProtectedResourceRequest request = null; try { if (this.Channel.TryReadFromRequest(httpRequestInfo, out request)) { if (this.AccessTokenAnalyzer.TryValidateAccessToken(request, request.AccessToken, out userName, out scope)) { // No errors to return. return null; } throw ErrorUtilities.ThrowProtocol("Bad access token"); } else { var response = new UnauthorizedResponse(new ProtocolException("Missing access token")); userName = null; scope = null; return this.Channel.PrepareResponse(response); } } catch (ProtocolException ex) { var response = request != null ? new UnauthorizedResponse(request, ex) : new UnauthorizedResponse(ex); userName = null; scope = null; return this.Channel.PrepareResponse(response); } } /// /// Discovers what access the client should have considering the access token in the current request. /// /// The HTTP request info. /// The principal that contains the user and roles that the access token is authorized for. /// /// An error to return to the client if access is not authorized; null if access is granted. /// [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "Try pattern")] public virtual OutgoingWebResponse VerifyAccess(HttpRequestInfo httpRequestInfo, out IPrincipal principal) { string username; HashSet scope; var result = this.VerifyAccess(httpRequestInfo, out username, out scope); principal = result == null ? new OAuth.ChannelElements.OAuthPrincipal(username, scope != null ? scope.ToArray() : new string[0]) : null; return result; } /// /// Discovers what access the client should have considering the access token in the current request. /// /// HTTP details from an incoming WCF message. /// The URI of the WCF service endpoint. /// The principal that contains the user and roles that the access token is authorized for. /// /// An error to return to the client if access is not authorized; null if access is granted. /// [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "Try pattern")] [SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "2#", Justification = "Try pattern")] public virtual OutgoingWebResponse VerifyAccess(HttpRequestMessageProperty request, Uri requestUri, out IPrincipal principal) { Contract.Requires(request != null); Contract.Requires(requestUri != null); return this.VerifyAccess(new HttpRequestInfo(request, requestUri), out principal); } } }