I'm writting WCF REST Data Service. I need to add authorization system basing on login and password given by url addres(https).
In every url should be login and password:
https://myservice.svc/Products()?$orderby=name&login=user_login&pass=user_pass
And on the service side I want to make authorization. There should be checked if user has permission to access the data. In this scenario there should checked if user has Role to read table Products. The Roles are stored in database.
Is there any opportunity to make it?
Implement OnStartProcessingRequest method.
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class ServiceODataAFR : EntityFrameworkDataService<PortalContext>
{
public static void InitializeService(DataServiceConfiguration config)
{
ValidarAcesso();
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
}
protected override void OnStartProcessingRequest(ProcessRequestArgs args)
{
ValidarAcesso();
base.OnStartProcessingRequest(args);
}
private static void ValidarAcesso()
{
using (var context = new PortalWeb())
{
if (!context.UsuarioEstaNoGrupo(EnumGrupoPermissao.AdministradorAFR.GetTitle()))
{
throw new AddressAccessDeniedException();
}
}
}
Related
I created WCF service and calling it from the android studio and its working fine, but after implementing WCF perSession functionality it is working for a single user at a time.
Problem:
My problem is when i am hitting WCF url with multiple user my sessionID get overwrite by the latest logged in user, So how to maintain session for multiple user like we do in web application.
I used this to creste session in WCF:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
and this is my method to create sessionid within services class
public class MyService : IMyService
{
static string currentSessionID = string.Empty;
public string createSession()
{
currentSessionID = DateTime.Now.Ticks.ToString();
return currentSessionID;
}
public string Login()
{
var mysessionId = createSession();
return mysessionId;
}
public string Mymethods(string data)
{
string response = "";
if(data.StartsWith("01"))
response = Login();
return response;
}
}
and am hitting this createSession() method only in login function.
Please help me out of this.....
Thanks in advnance.
We are developing an application with Windows Authentication that is used internally at a company. We have looked at ADFS but at the moment this is not an option. The problem is our test servers are entirely cloud based on Azure. I have been trying to find a way to activate a user but have not found a good solution.
My first idea was to turn off authentication completely. This works good but we have some resources that checks for user roles so I had to abandon that idea.
<system.web>
<authentication mode="None" />
</system.web>
Example method that returns 401 Unauthorized with authentication mode="None", obviously:
[Authorize(Roles = "Administrator")]
[HttpGet]
[Route("TestMethod")]
public IHttpActionResult TestMethod()
{
return Ok("It works!");
}
My second thought was to edit the WebApiConfig and try to add authentication headers in every request server side. However when I started looking at the NTLM Authentication Scheme for HTTP and the 4-way handshake I realized this would probably be impossible.
NTLM Authentication Scheme for HTTP
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Other code for WebAPI registerations here
config.MessageHandlers.Add(new AuthenticationHandler());
}
}
class AuthenticationHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// Add authentication to every request...
return base.SendAsync(request, cancellationToken);
}
}
Since there is no Owin (Katana) I can not edit the standard App_Start -> Startup.Auth.cs -> public void ConfigureAuth(IAppBuilder app) and try something there. I don't know how I would build up the "user object" anyway.
Is there anything we can do about this or do we have to test everything locally? If we could impersonate one user to be logged in for every request this would be fine in the test environment.
In terms of faking the authentication and authorisation you should be able to set a generic user principal with the appropriate roles using a FilterAttribute.
public class TestIdentityFilter : FilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
filterContext.Principal = new GenericPrincipal(
new GenericIdentity(),
new string [] {"Administrator"});
}
}
You will need to set <authentication mode="None" /> as you did previously otherwise this code will never be hit in your test environment.
Adding this as a Global filter will override any other existing authentication system (for example if you deploy it to an authenticated environment by mistake). Obviously you will need to be very careful about only using this in your test system.
This example is based on MVC, I think there are some very small differences with WebApi but the basic principal applies.
Big thanks to #ste-fu for pointing me in the right direction. Complete code:
public class AppSettingsDynamicRolesAuthorizeAttribute : AuthorizeAttribute
{
public AppSettingsDynamicRolesAuthorizeAttribute(params string[] roleKeys)
{
List<string> roles = new List<string>(roleKeys.Length);
foreach (var roleKey in roleKeys)
{
roles.Add(WebConfigurationManager.AppSettings[roleKey]);
}
this.Roles = string.Join(",", roles);
}
public override void OnAuthorization(HttpActionContext filterContext)
{
if (Convert.ToBoolean(WebConfigurationManager.AppSettings["IsTestEnvironment"]))
{
filterContext.RequestContext.Principal = new GenericPrincipal(
new GenericIdentity("Spoofed-Oscar"),
new string[] { WebConfigurationManager.AppSettings[Role.Administrator] });
}
base.OnAuthorization(filterContext);
}
}
public static class Role
{
public const string Administrator = "Administrator";
public const string OtherRole = "OtherRole";
}
Can then be used like this:
[AppSettingsDynamicRolesAuthorize(Role.Administrator, Role.OtherRole)]
[HttpGet]
[Route("Test")]
public IHttpActionResult Get()
{
var userName = RequestContext.Principal.Identity.Name;
var user = HttpContext.Current.User.Identity;
return Ok("It works!");
}
I've got a web application created with ASP.NET and a windows native client program written in c#.
The windows native program needs to send and fetch data from the ASP.NET web application.
I guess in the web application I'll need a controller for the external calls. And in the client Software I somehow Need to call them.
Is there a way to achieve calls with complex data types (lists of classes) as parameters?
How do I secure the calls from the client? Simple http-logon?
for example I'd like to transfer an instance of this class to or from the ASP.NET web application:
public class Address
{
public String Street {get;set;}
public String City {get;set;}
}
public class CustomerInformation
{
public String No {get;set;}
public String Name {get;set;}
public List<Address> Addresses {get;set;}
}
Of course the Windows client is running somewhere local while the ASP.NET Service is running in the web.
I would add API controller and put some methods there. For instance
// Addresses API
public class AddressController : ApiController
{
private readonly IRepository<Address> _repository;
public AddressController(IRepository<Address> repository)
{
_repository = repository;
}
[BasicAuthorize]
public IList<Address> GetList()
{
return _repository.GetAll();
}
}
// Constomer information API
public class CustomerInformationController : ApiController
{
private readonly IRepository<CustomerInformation> _repository;
public CustomerInformationController(IRepository<CustomerInformation> repository)
{
_repository = repository;
}
[BasicAuthorize]
public IList<CustomerInformation> GetList()
{
return _repository.GetAll();
}
}
To secure those methods you can use Basic authentication. This means that you can add authorization header for each request:
For example how it looks for user "myuser" with password "test"
Authorization: basic bXl1c2VyOnRlc3Q=
// Custom attribute for Basic authentication
public class BasicAuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
private readonly string[] _permissionNames;
public BasicAuthorizeAttribute()
{
}
public BasicAuthorizeAttribute(params string[] permissionNames)
{
_permissionNames = permissionNames;
}
protected override bool IsAuthorized(HttpActionContext actionContext)
{
// check if user has been already authorized
if (base.IsAuthorized(actionContext))
return true;
var user = AuthenticateUser(actionContext);
// here you can check roles and permissions
return user != null;
}
private IUser AuthenticateUser(HttpActionContext context)
{
var request = context.Request;
AuthenticationHeaderValue authHeader = request.Headers.Authorization;
if (authHeader != null)
{
// RFC 2617 sec 1.2, "scheme" name is case-insensitive
if (authHeader.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) && authHeader.Parameter != null)
return AuthenticateUser(authHeader.Parameter);
}
return null;
}
private IUser AuthenticateUser(string credentials)
{
try
{
// parse values
var encoding = Encoding.GetEncoding("iso-8859-1");
credentials = encoding.GetString(Convert.FromBase64String(credentials));
var credentialsArray = credentials.Split(':');
var username = credentialsArray[0];
var password = credentialsArray[1];
// authentication
var membershipService = new IMembershipService();
return membershipService.ValidateUser(username, password);
}
catch (Exception)
{
// Credentials were not formatted correctly.
return null;
}
}
}
On client side you can use HttpClient to send async request
public async Task<Address[]> GetAddresses() {
var client = new HttpClient {BaseAddress = new Uri(_settingsService.GetHost())};
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var base64 = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "myuser", "test")));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",base64);
HttpResponseMessage response = await client.GetAsync("api/addresses");
if (response.StatusCode != HttpStatusCode.OK)
throw new Exception(response.ReasonPhrase);
string content = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Address[]>(content);
}
Is there a way to achieve calls with complex data types (lists of classes) as parameters?
Yes, The server application as ASP.NET or ASP.NET MVC or (preferably) ASP.NET WEB API can provide services with complex data types. In fact there is no limitation in declaring methods.
How do I secure the calls from the client? Simple http-logon?
There are wide ranage of authentication and authorization mechanism in ASP.NET (MVC, WEB API) which give you opportunity to choose one them.
The data transfers between your client and server via XML or JSON.
The "WebClient" class provides everything that you need to make a call from client to server.
More information:
http://www.codeproject.com/Articles/33798/HTTP-GET-with-NET-WebClient
How to post data to specific URL using WebClient in C#
How do I log into a site with WebClient?
I want to allow two types of authentication on my site :
* Forms authentication: The user login using his/her details in the form. The authentication should be made using cookies.
* Bearer: When calling WebAPI's (for mobile), the authentication should be made only by using bearer tokens.
I've relayed on the SPA template and some questions in SO and did successful made it available.
The only problem I'm facing is the ClaimsIdentity: I wish to use custom identity class. However, I'm being able to do so only in forms authentication, not in bearer WebAPI requests.
My custom identity:
public class MyIdentity : ClaimsIdentity, IMyIdentity
{
#region IMyIdentity
private Account _account = null;
public Account Account
{
get
{
if (_account == null)
{
if (this.IsAuthenticated)
{
Guid claimedAccountId = Guid.Parse(this.FindFirst(ClaimTypes.NameIdentifier).Value);
var accountService = ServiceLocator.SharedInstance.GetInstance<IAccountService>();
_account = accountService.Where(
a => a.Id == claimedAccountId
).FirstOrDefault();
}
_account = _account ?? Membership.Account.GuestAccount;
}
return _account;
}
}
#endregion
}
In Global.asax, I've overridden the Application_OnPostAuthenticateRequest method in order to set the custom identity, and it does working good - but only in forms, not in WebAPI.
In addition, I do set in WebApiConfig.cs
config.SuppressDefaultHostAuthentication();
so it does make sense that MyIdentity being nulled and User.Identity resets back to ClaimsIdentity.
So to sum up my question - is there a way to define which Identity class will be used, so I can set MyIdentity instead of ClaimsIdentity?
For Web API, you could try hooking into the OWIN authentication pipeline, and implement your own Authentication Filter, and use it to change the current principal to your own:
public class MyAuthenticationFilter : ActionFilterAttribute, IAuthenticationFilter
{
public Task AuthenticateAsync(HttpAuthenticationContext context, System.Threading.CancellationToken cancellationToken)
{
if (context.Principal != null && context.Principal.Identity.IsAuthenticated)
{
CustomPrincipal myPrincipal = new CustomPrincipal();
// Do work to setup custom principal
context.Principal = myPrincipal;
}
return Task.FromResult(0);
}
And register the filter:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new MyAuthenticationFilter());
...
Authorization and authentication in MVC application
I have an internal web app developed in C# using MVC 2. I want to use AD roles/groups to do authorization. Thus I have 3 access group Admin, Basic, Readonly. The access to the application will be controlled through these groups.
Now when I hit an action/page of my MVC app, the requirements are:
1) Check level of access (is in either group Admin, Basic or Readonly)
2) If in a group - serve the page.
If not - serve the 401 Unauthorized page.
I am probably confusing myself with the concepts authorization/authentication, but this is how it is set up so far (from answers, google and my own efforts flowing from this question:
public static class AuthorizationModule
{
public static bool Authorize(HttpContext httpContext, string roles)
{
...
//Check Configuration.AppSettings for the roles to check
//using httpContext.User check .IsInRole for each role and return true if they are
...
//other wise throw new HttpException(401,.....)
}
...
}
public class AuthorizeByConfigurationAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//Essentially at the moment this is pretty much the same as AuthorizationModule.Authorize(HttpContext httpContext, string roles)
}
}
//This code from http://paulallen.com.jm/blog/aspnet-mvc-redirect-unauthorized-access-page-401-page
public class RequiresAuthenticationAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result = new ViewResult {ViewName = "AccessDenied"};
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}
The problems with this are that I seem to need to decorate my action methods twice now, ala:
[AuthorizeByConfiguration(Roles = "Admin, Basic, Readonly")]
[RequiresAuthentication(Roles = "Admin, Basic, Readonly")]
public ActionResult Index(string msg)
{
...
}
And the next problem is that it seems I have three separate methods all trying to do the same thing. I am overriding methods based on advice and not entirely sure how they were meant to work originally. How could I go about implementing my requirements?
edit: Since this is an IntrAnet app, all users who sign on with their network accounts will be able to access this app. I need to restrict the access so that only those who belong to certain Active Directory security groups can access this app
I have wrapped all the methods concerning auth with the interface IAuthorization.
Here is an example custom attrbiute you would need to add the Roles property and your own implementaion.
Attribute calls the filter itself for testability reasons.
public class SomeAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
var filter = new SomeAuthorizeFilter(DependencyLookup.Resolve<IAuthorization>());
filter.OnAuthorization(filterContext);
}
}
public class SomeAuthorizeFilter : IAuthorizationFilter
{
private readonly IAuthorization _authorization;
public SomeAuthorizeFilter(IAuthorization authorization)
{
_authorization = authorization;
}
protected virtual ActionResult ResultWhenNotAuthenticated(AuthorizationContext filterContext)
{
//snip..
//default
RouteValueDictionary redirectTargetDictionary = new RouteValueDictionary
{
{"action", "Index"},
{"controller", "Home"}
};
return new RedirectToRouteResult(redirectTargetDictionary);
}
#region IAuthorizationFilter Members
public void OnAuthorization(AuthorizationContext filterContext)
{
if (!_authorization.GetCurrentUserIdentity().IsAuthenticated)
{
filterContext.Result = ResultWhenNotAuthenticated(filterContext);
}
}
#endregion
}