I am dealing with a Claim-based application, with the aim to display users info after their authentication through SSO.
For a given authenticated user, I realized a .Net Web Page wherein I show all claims starting from the provided Principal (Page.User), as follows:
public partial class ClaimsPage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var claimsPrincipal = Page.User as IClaimsPrincipal;
if (claimsPrincipal != null)
{
IClaimsIdentity claimsIdentity = (IClaimsIdentity) claimsPrincipal.Identity;
// Something else...
}
}
}
And it works fine.
Now, I would like to do the same thing, but by using a .Net Web Service (SOAP), instead of the web page.
My current code is as follows:
[WebService(Namespace = "http://myapp/claims")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class ClaimsWS : System.Web.Services.WebService
{
[WebMethod]
public List<ClaimValues> GetClaims()
{
// Get Principal..
// Read claims...
}
}
My question is: how can I obtain the current Principal inside the WebService body?
Maybe you can try something along these lines. I am returning an Identity object, but you get the claims list from it also.
[WebService(Namespace = "http://myapp/claims")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[System.Web.Script.Services.ScriptService]
public class ClaimsWS : System.Web.Services.WebService
{
[WebMethod]
public List<ClaimValues> GetClaims()
{
var principal =ClaimsPrincipal.CreateFromHttpContext(HttpContext.Current);
return principal.Claims;
}
}
Related
I guess it is a stupid question but I'm havin a hard time finding something like it, so maybe someone here can push me in the right direction.
Problem:
I have a c# SoapService with lots of request/response classes, so let us say:
[WebService(Namespace = "http://fuu.bar.gov/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Main : System.Web.Services.WebService
{
[SoapHeader("authentication")]
[WebMethod(Description = "Get Foo")]
public FooResponse GetFoo(FooRequest request)
{
return new FooResponse ();
}
[SoapHeader("authentication")]
[WebMethod(Description = "Get Bar")]
public BarResponse GetBar(BarRequest request)
{
return new FooResponse ();
}
}
public class FooResponse{};
public class FooRequest{};
public class BarResponse{};
public class BarRequest{};
So when I create a WebReference named "foobarWebservice" in my client code I'll get:
foobarWebservice.FooResponse
foobarWebservice.FooRequest
foobarWebservice.BarResponse
foobarWebservice.BarRequest
class definitions.
What I'd like to is change the above into this:
public class Main : System.Web.Services.WebService
{
[SoapHeader("authentication")]
[WebMethod(Description = "Get Foo")]
public Foo.Response GetFoo(Foo.Request request)
{
return new FooResponse ();
}
[SoapHeader("authentication")]
[WebMethod(Description = "Get Bar")]
public Bar.Response GetBar(Bar.Request request)
{
return new FooResponse ();
}
}
which is easy:
namespace Foo
{
public class Response{}
public class Request{}
}
namespace Bar
{
public class Response{};
public class Request{};
}
But also the client Reference.cs should give me this:
foobarWebservice.Foo.Response
foobarWebservice.Foo.Request
foobarWebservice.Bar.Response
foobarWebservice.Bar.Request
So I'd be able to do that:
foobarWebservice.Main webservice = new foobarWebservice.Main();
foobarWebservice.Foo.Request newRequest = new foobarWebservice.Foo.Request();
foobarWebservice.Foo.Response response = webservice.GetFoo(newRequest);
Simply spoken: I want to keep my namespaces intact in the generated Reference.cs file on the client application.
Create a new assembly with the namespaces and use it in both client and server projects. In client project when adding the WCF reference check the 'use existing assemblies' option and check the added reference project/assembly.
Project A: Common classes
Project B: WCF service
Project C: WCF client. Make sure to check the reuse assemblies option.
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 have a custom Authorization attribute not getting called in my asp.net class and I can't tell what I'm missing.
My Attribute looks like this:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyAuthorize : System.Web.Http.AuthorizeAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
// ...
}
protected bool AuthorizeCore(HttpContextBase httpContext)
{
// Logic here.
return false;
}
}
And I'm calling it from inside a WebService like so:
[WebService(Namespace = "http://something/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class AccessPoint : System.Web.Services.WebService
{
[WebMethod]
[MyAuthorize]
public bool SomeWebMethod(int a)
{
//Do stuff
return false;
}
}
Each time I run it, it will fall right through and never trigger the attribute.
FYI; I used System.Web.Http.AuthorizeAttribute because System.Web.Mvc.AuthorizeAttribute was telling me that AuthorizeAttribute did not exist.
You seem to be making a terrible confusion here between ASP.NET Web API and legacy classic ASMX WebServices. You have written an ASP.NET Web API authorization attribute (designed to be used in an ASP.NET API REST service) and applied it on a legacy ASMX WebService. Those two technologies are completely different and should not be mixed together.
It's like trying to put a Lamborghini engine on a horse driven cart.
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();
}
}
}
Its possible expose many class in single asmx in Web Service C#, this for generate
one Proxy class, and consume proxy from client like: Proxy.UserService.User and Proxy.ImageService.GetImage
I try this but dont Work.
namespace ServiciosWeb
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Services : System.Web.Services.WebService
{
}
public class ImageService : Services.IService
{
[WebMethod]
public string GetImage()
{
return "Image";
}
}
public class UserService : Services.IService
{
[WebMethod]
public string User()
{
return "User";
}
}
}
A classic ASMX web service is a class that needs to derive from System.Web.Services.WebService and decorated with the [WebService] attribute. If you want to expose multiple services you might need to have multiple ASMX files. Another possibility is to simply put the two web methods inside the existing service class so that when you generate the proxy class on the client they will be visible.
no that is not possible with [WebService] and [WebMethod]s.
You can not bind multiple classes to a single asmx, what you could do however -if you want to offer a multitude of class-files- is use the same class name like partial class. Would need to check to see if each class needs to be derived from IService, but I've did this in a project and it worked.
namespace ServiciosWeb
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public partial class Services : System.Web.Services.WebService
{
}
public partial class Services : Services.IService
{
[WebMethod]
public string GetImage()
{
return "Image";
}
}
public partial class Services : Services.IService
{
[WebMethod]
public string User()
{
return "User";
}
}
}