diff --git a/HawkNet.WCF/HawkAuthenticationManager.cs b/HawkNet.WCF/HawkAuthenticationManager.cs new file mode 100644 index 0000000..476ee1a --- /dev/null +++ b/HawkNet.WCF/HawkAuthenticationManager.cs @@ -0,0 +1,79 @@ +using System; +using System.Diagnostics; +using System.Collections.ObjectModel; +using System.Collections.Generic; +using System.ServiceModel.Channels; +using System.IdentityModel.Claims; +using System.IdentityModel.Policy; +using System.Security.Principal; +using System.ServiceModel; +using System.ServiceModel.Security; +using System.ServiceModel.Web; +using System.Security; +using System.Web; +using System.Linq; + +namespace HawkNet.WCF +{ + class HawkAuthenticationManager : ServiceAuthenticationManager + { + const string HawkScheme = "Hawk"; + + static TraceSource TraceSource = new TraceSource("HawkNet.WCF"); + + Func credentials; + int timeskewInSeconds; + string schemeOverride; + + public HawkAuthenticationManager(Func credentials, int timeskewInSeconds, string schemeOverride) + : base() + { + this.credentials = credentials; + this.timeskewInSeconds = timeskewInSeconds; + this.schemeOverride = schemeOverride; + + if (Trace.CorrelationManager.ActivityId == Guid.Empty) + Trace.CorrelationManager.ActivityId = Guid.NewGuid(); + } + + public override ReadOnlyCollection Authenticate(ReadOnlyCollection authPolicy, Uri listenUri, ref Message requestMessage) + { + IPrincipal principal = ExtractCredentials(requestMessage); + var policies = new List(); + policies.Add(new HawkPrincipalAuthorizationPolicy()); + + if (principal != null) + { + requestMessage.Properties["Principal"] = principal; + } + + return policies.AsReadOnly(); + } + + private IPrincipal ExtractCredentials(Message requestMessage) + { + var request = (HttpRequestMessageProperty)requestMessage.Properties[HttpRequestMessageProperty.Name]; + + var authHeader = request.Headers["Authorization"]; + if (authHeader != null && authHeader.StartsWith(HawkScheme, StringComparison.InvariantCultureIgnoreCase)) + { + var hawk = authHeader.Substring(HawkScheme.Length).Trim(); + + TraceSource.TraceInformation(string.Format("{0} - Received Auth header: {1}", + Trace.CorrelationManager.ActivityId, hawk)); + + var uri = new Uri(HttpUtility.UrlDecode(requestMessage.Properties.Via.AbsoluteUri)); + + var principal = Hawk.Authenticate(hawk, + request.Headers["host"], + request.Method, + new UriBuilder (uri) { Scheme = (!string.IsNullOrEmpty(schemeOverride)) ? schemeOverride : uri.Scheme }.Uri, + this.credentials, + this.timeskewInSeconds); + + return principal; + } + return null; + } + } +} diff --git a/HawkNet.WCF/HawkAuthorizationManager.cs b/HawkNet.WCF/HawkAuthorizationManager.cs new file mode 100644 index 0000000..4b10f16 --- /dev/null +++ b/HawkNet.WCF/HawkAuthorizationManager.cs @@ -0,0 +1,45 @@ +using System; +using System.Linq; +using System.ServiceModel; +using System.ServiceModel.Channels; +using System.IdentityModel.Claims; +using System.Net; + +namespace HawkNet.WCF +{ + class HawkAuthorizationManager : ServiceAuthorizationManager + { + public bool SendChallenge { get; set; } + + public HawkAuthorizationManager(bool sendChallenge) : base() + { + SendChallenge = sendChallenge; + } + + protected override bool CheckAccessCore(OperationContext operationContext) + { + if (!operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets.Any()) + { + if (SendChallenge) + { + var newReply = Message.CreateMessage(MessageVersion.None, null); + var responseProperty = new HttpResponseMessageProperty() { StatusCode = HttpStatusCode.Unauthorized }; + + var ts = Hawk.ConvertToUnixTimestamp(DateTime.Now).ToString(); + var challenge = string.Format("ts=\"{0}\" ntp=\"{1}\"", + ts, "pool.ntp.org"); + + responseProperty.Headers.Add("WWW-Authenticate", challenge); + + newReply.Properties[HttpResponseMessageProperty.Name] = responseProperty; + + //overwrite the original reply with the unauthorized message. + operationContext.RequestContext.Reply(newReply); + } + return false; + } + + return base.CheckAccessCore(operationContext); + } + } +} diff --git a/HawkNet.WCF/HawkNet.WCF.csproj b/HawkNet.WCF/HawkNet.WCF.csproj index 279d8a7..f6fd04f 100644 --- a/HawkNet.WCF/HawkNet.WCF.csproj +++ b/HawkNet.WCF/HawkNet.WCF.csproj @@ -45,10 +45,6 @@ false - - ..\packages\HawkNet.1.4.4.0\lib\net45\HawkNet.dll - True - ..\packages\Microsoft.ServiceModel.Web.1.0.1\lib\net35\Microsoft.ServiceModel.Web.dll @@ -66,13 +62,23 @@ + + + + + + + {f997ce59-eee3-42e4-b41a-b32985994603} + HawkNet + +