New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comparing phase 02 and 01 #1

Open
wants to merge 2 commits into
base: phase/01
from
Jump to file or symbol
Failed to load files and symbols.
+170 −15
Diff settings

Always

Just for now

@@ -0,0 +1,15 @@
using System.Runtime.Serialization;
namespace simpleWCFApp.Models
{
[DataContract]
public enum ACCESS_LEVEL
{
[EnumMember(Value = "admin")]
ADMIN = 2,
[EnumMember(Value = "user")]
USER = 1,
[EnumMember(Value = "public")]
PUBLIC = 0
}
}
@@ -8,6 +8,6 @@ namespace simpleWCFApp.Models
{
public interface IContext
{
User CurentUser { get; }
User CurrentUser { get; set; }
}
}
Copy path View file
@@ -6,12 +6,20 @@ namespace simpleWCFApp.Models
[DataContract]
public class User
{
public User()
{
this.Level = ACCESS_LEVEL.USER;
}
[DataMember(Name="id", IsRequired=true)]
public Guid? Uuid { get; set; }
[DataMember(Name="login", IsRequired=true)]
public string Login { get; set; }
[DataMember(Name = "level", IsRequired = false)]
public ACCESS_LEVEL Level { get; set; }
[IgnoreDataMember]
public string Password { get; set; }
@@ -41,6 +41,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ACCESS_LEVEL.cs" />
<Compile Include="IContext.cs" />
<Compile Include="PagingList.cs" />
<Compile Include="PagingListOption.cs" />
@@ -65,5 +65,21 @@ public string Authenticate(string login, string password)
}
return null;
}
public User FromToken(string token)
{
try
{
IDictionary<string, Object> properties = new JwtBuilder()
.WithSecret(Properties.Settings.Default.JWTSecret)
.MustVerifySignature()
.Decode<IDictionary<string, Object>>(token);
return this.GetSingle(Guid.Parse(properties["guid"].ToString()));
}
catch (Exception)
{
return null;
}
}
}
}
@@ -19,6 +19,7 @@ private void Populate()
List<User> list = (List<User>)this.Users;
list.Add(new User() {
Uuid = Guid.NewGuid(),
Level = ACCESS_LEVEL.ADMIN,
Login = "user01",
Name = "Dylan",
Password = "123456789"
@@ -0,0 +1,15 @@
using simpleWCFApp.Models;
using System;
namespace simpleWCFApp.WebService.Attributes
{
public class OperationAccessAttribute : Attribute
{
public OperationAccessAttribute()
{
this.RequiredAccessLevel = ACCESS_LEVEL.PUBLIC;
}
public ACCESS_LEVEL RequiredAccessLevel { get; set; }
}
}
@@ -0,0 +1,96 @@
using simpleWCFApp.Services;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Web;
using System.Linq;
using simpleWCFApp.Models;
using System.ServiceModel.Web;
using System.Net;
namespace simpleWCFApp.WebService.Attributes
{
[AttributeUsage(AttributeTargets.Class)]
public class ServiceContractSecurityAttribute : Attribute, IParameterInspector, IServiceBehavior
{
private WebService webService;
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{ }
public object BeforeCall(string operationName, object[] inputs)
{
Object currentWebService = OperationContext.Current.InstanceContext.GetServiceInstance();
if (currentWebService != null)
{
this.webService = currentWebService as WebService;
MethodInfo method = currentWebService.GetType().GetMethod(operationName);
this.webService.Context.CurrentUser = this.GetCurrentUser();
this.Apply(method);
}
return null;
}
private Models.User GetCurrentUser()
{
string token = HttpContext.Current.Request.Headers["Authorization"];
if (string.IsNullOrEmpty(token) == false)
{
UserService userService = new UserService();
return userService.FromToken(token);
}
return null;
}
private void Apply(MethodInfo method)
{
if (method != null)
{
IEnumerable<Attribute> attributes = Attribute.GetCustomAttributes(method, typeof(OperationAccessAttribute), true);
IEnumerable<ACCESS_LEVEL> levels = (from attr in attributes select (attr as OperationAccessAttribute).RequiredAccessLevel);
if (levels.Contains(ACCESS_LEVEL.PUBLIC))
{
return;
}
else if (levels.Count((level) => level > this.webService.Context.CurrentUser.Level) > 0)
{
this.webService.Context.Forbiden("You don't have the permissions to do this");
}
return;
}
}
public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{ }
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
if (channelDispatcher == null)
{
continue;
}
foreach (EndpointDispatcher endpoint in channelDispatcher.Endpoints)
{
if (endpoint == null)
{
continue;
}
foreach (var operation in endpoint.DispatchRuntime.Operations)
{
operation.ParameterInspectors.Add(this);
}
}
}
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{ }
}
}
@@ -1,5 +1,6 @@
using simpleWCFApp.Models;
using simpleWCFApp.Services;
using simpleWCFApp.WebService.Attributes;
using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
@@ -11,6 +12,7 @@ namespace simpleWCFApp.WebService
public class User : WebService
{
[OperationContract]
[OperationAccess(RequiredAccessLevel=ACCESS_LEVEL.USER)]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest, UriTemplate = "/users")]
public PagingList<Models.User> GetList()
{
@@ -27,6 +29,7 @@ public PagingList<Models.User> GetList()
}
[OperationContract]
[OperationAccess(RequiredAccessLevel = ACCESS_LEVEL.ADMIN)]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, UriTemplate = "/users")]
public Models.User Add(Models.User user)
{
@@ -43,6 +46,7 @@ public Models.User Add(Models.User user)
}
[OperationContract]
[OperationAccess(RequiredAccessLevel = ACCESS_LEVEL.USER)]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest, UriTemplate = "/users/{id}")]
public Models.User GetSingle(string id)
{
@@ -65,6 +69,7 @@ public Models.User GetSingle(string id)
}
[OperationContract]
[OperationAccess(RequiredAccessLevel = ACCESS_LEVEL.ADMIN)]
[WebInvoke(Method = "DELETE", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest, UriTemplate = "/users/{id}")]
public Models.User Delete(string id)
{
@@ -81,6 +86,7 @@ public Models.User Delete(string id)
}
[OperationContract]
[OperationAccess(RequiredAccessLevel = ACCESS_LEVEL.ADMIN)]
[WebInvoke(Method = "PUT", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest, UriTemplate = "/users/{id}")]
public Models.User Update(string id, Models.User user)
{
@@ -100,6 +106,7 @@ public Models.User Update(string id, Models.User user)
}
}
[OperationContract]
[OperationAccess]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, UriTemplate = "/auth")]
public string Authenticate(string login, string password)
{
@@ -1,10 +1,12 @@
using System.ServiceModel;
using simpleWCFApp.WebService.Attributes;
using System.ServiceModel;
using System.ServiceModel.Activation;
namespace simpleWCFApp.WebService
{
[ServiceBehavior(IncludeExceptionDetailInFaults=true, InstanceContextMode=InstanceContextMode.PerCall, ConcurrencyMode=ConcurrencyMode.Multiple)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceContractSecurity]
public class WebService
{
private IWebServiceContext context;
@@ -15,27 +15,19 @@ public WebServiceContext()
public void NotFound(string message = "Not found")
{
this.response.StatusCode = HttpStatusCode.NotFound;
this.response.StatusDescription = message;
throw new WebFaultException<string>(message, HttpStatusCode.NotFound);
}
public void ServerError(string message = "Server error")
{
this.response.StatusCode = HttpStatusCode.InternalServerError;
this.response.StatusDescription = message;
throw new WebFaultException<string>(message, HttpStatusCode.InternalServerError);
}
public void Forbiden(string message = "Cannot access")
{
this.response.StatusCode = HttpStatusCode.Forbidden;
this.response.StatusDescription = message;
}
public Models.User CurentUser
{
get {
return null;
}
throw new WebFaultException<string>(message, HttpStatusCode.Forbidden);
}
public Models.User CurrentUser { get; set; }
}
}
@@ -67,6 +67,8 @@
</Content>
</ItemGroup>
<ItemGroup>
<Compile Include="Attributes\OperationAccessAttribute.cs" />
<Compile Include="Attributes\ServiceContractSecurityAttribute.cs" />
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
ProTip! Use n and p to navigate between commits in a pull request.