//-----------------------------------------------------------------------
//
// 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) {
Requires.NotNull(accessTokenAnalyzer, "accessTokenAnalyzer");
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) {
Requires.NotNull(httpRequestInfo, "httpRequestInfo");
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) {
Requires.NotNull(request, "request");
Requires.NotNull(requestUri, "requestUri");
return this.VerifyAccess(new HttpRequestInfo(request, requestUri), out principal);
}
}
}