Authorization for HttpEndpoints - elsa-workflows

"Elsa" Version="2.8.1"
"Elsa.Activities.Http" Version="2.8.1"
"Elsa.Server.Api" Version="2.8.1"
I am trying to enable HttpEndpoint authorization for workflows which are started by an HTTP call.
Even if I enable the Authorize setting in Security tab of the incoming HTTP request activity, that seems to have no impact as I can still start the workflow without a Bearer token when calling the endpoint.
Screenshot of HttpActivity.
If I create a sample controller in the same project and add an [Authorize] attribute to it, it works as expected (401 Error on invalid/missing token).
Sample controller:
[HttpGet("auth-test")]
[Authorize]
public async Task<IActionResult> TestAuth()
{
return Ok();
}
Authentication & authorization setup:
builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration, "AzureAd");
<..>
builder.Services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.AddRequirements(new MyApiRequirement())
.Build();
});
I even tried specifying an non-existing policy name for the Policy input field, to check if that would fail some evaluations - no errors, accessible without any tokens.
Could someone please help identifying what am I missing?

Related

How to skip Azure active directory authentication in Web API depends on Url request header value

How to skip the [Authorization](Azure AD authentication) from Web Api controller depends on the value from header request?
[Authorize]
public class ExampleController : ApiController
{
//code
private string _clientid;
var req = Request.Headers;
_clientid = string.IsNullOrEmpty(req.GetValues("clientid").First())
? null :
req.GetValues("clientid").First();
}
The above mentioned _clientid is a header value, I want to skip authentication for some _clientid values.
In my opinion you essentially have an alternative way of authentication.
It would make the most sense to define your own authentication scheme that checks that header and creates a user principal based on that.
Then you can keep on using [Authorize] as usual.
Writing an example would be quite time-consuming, the best I can offer at the moment is the Security repo, which contains all of the built-in authentication schemes, like JWT Bearer here: https://github.com/aspnet/Security/blob/dev/src/Microsoft.AspNetCore.Authentication.JwtBearer/JwtBearerHandler.cs Check those for examples on how to implement an authentication handler.
You can create a custom authentication handler similar to the one here .
Then, where you add authorization in Startup.cs, you can add a custom policy like this:
services.AddAuthorization(
o =>
{
// create a policy called ApiKeyPolicy which requires a Role defined in
// ApiKeyAuthenticationOptions.
// The policy is used by the API controllers.
o.AddPolicy(
"ApiKeyPolicy", builder =>
{
builder.AddAuthenticationSchemes(
ApiKeyAuthenticationOptions.AuthenticationSchemeName);
});
});
and add the scheme to the services.AddAuthentication builder:
builder.AddScheme<ApiKeyAuthenticationOptions, ApiKeyAuthenticationHandler>(
"ApiKey", "ApiKey", o =>
{
o.AllowedApiKeys = config["Api:AllowedApiKeys"];
o.ApiKeyHeaderName = config["Api:ApiKeyHeaderName"];
});
In my example, I have an ApiKeyAuthenticationOptions class that is configured with some API keys and the http header name to check. In your case, you would probably want the valid client IDs.
Finally, you need to tell the [Authorize] attribute which policy is needed:
[Authorize(Policy = "ApiKeyPolicy")]
In your case, you want to be able to handle both the client IDs and regular auth, so you could add the regular auth scheme to the policy builder expression (the first snippet above).

What is a good way to pass additional information to the http response when issuing access token with Owin middleware in Asp Net Web Api?

I am using Owin middleware to implement token-based security for my application. When issuing the access token to the client I would also like to pass User Id along with the token, so that, the client application will know the User Id and will be able to call GetUserById (one of the methods inside UserController) in order to show the user his starting page. The best solution I could come up with so far is just adding User Id to the response header. Take a look at my OAuthAuthorizationServerProvider class, in GrantResourceOwnerCredentialsmethod I am adding User Id to the header, using context.Response.Headers.Add("User-Id", new string[] { "1" })
Here is the implementation of my OAuthAuthorizationServerProviderclass
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
//The actual credential check will be added later
if (context.UserName=="user" && context.Password=="user")
{
identity.AddClaim(new Claim("Id", "1"));
context.Validated(identity);
//Here I am adding User Id to the response header
context.Response.Headers.Add("User-Id", new string[] { "1" });
}
else
{
context.SetError("invalid_grant","The credentials provided are not valid");
return;
}
}
}
Basically the client then will have to read User-Id from the header. Is this a good solution I came up with or there is a better one? Also what if I want to pass the whole User object with all its properties to the response is it possible and how to do this?
Since you store the ID already in the claims, why don't you just decode your token on the client and read out the user id like that? Passing it through the headers could allow tampering with it (security).
Have a look on how you could achieve to decode your token and read the claims. This is a c# example https://contos.io/peeking-inside-your-jwt-tokens-using-c-bf6a729d06c8 but this could also be done even through javascript.
This, assuming you use the JWT-format as token (was not specified in your initial question).
Bad way to store UserID as a response header back to client side. This is a huge security concern.
The best way would be to store it as a Claims.
It is very easy to achieve this and get back the claims in the client side.
In your controller, call this and remember to reference
using Microsoft.AspNet.Identity;
var userId = User.Identity.GetUserId();

How to customize WebApi OAuth token validation?

Context
I have a working WebApi2 application, which uses the out of the box bearer token validation, just as was in the original Visual Studio project template.
I would like to add a custom data to the generated token, then check against that custom data when the subsequent api calls happen what are presenting this token.
For the sake of example say I would like to store the IP address of the caller when the token was created, then when validating the token check if the call which is uses the token have the very same IP.
I found the custom class
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
in my project and I also see that OAuthOptions is configured to use that custom class in start up.
I suppose where to add my custom token data (the ip):
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
here I can add it to the ticket properties as custom data.
Question
However I can not find out in what method to check against the token has this data, and it matches to the actual call's ip, and if not, then regard the token invalid?
You are absolutely right when you decided to implement OAuthAuthorizationServerProvider . Now you need to add something like this:
private ClaimsIdentity CreateIdentity(User user, string authenticationType)
{
var identity = new ClaimsIdentity(authenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, user.Login));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.UserID.ToString())); // or ip instead of user.UserID if you need
return identity;
}
And then use it in your Grant... method (for instance GrantResourceOwnerCredentials) like this:
ClaimsIdentity identity = CreateIdentity(user, context.Options.AuthenticationType);
context.Validated(identity);
Then when request come to your webapi controller you can check your data in your custom Attribute:
Claim userIdClaim = ((ClaimsIdentity)actionContext.ControllerContext.RequestContext.Principal.Identity)
.Claims
.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);
hope it helps.

Https and Http only on .net webapi v2 actions

I have been working on a project with webapi 2 using oauth 2 (openid connect to be precise) bearer tokens to grant access. Now the whole idea is that the bearer tokens are only secure if used with a secure connection.
Until now I have simply not allowed http calls to the webserver which kinda worked since no one could do a http call with a bearer token.
We now have some endpoints that need to be avaible over http (no bearer token/authenticaiton required) and we are going to enable http of course. Now my question is, what is normal in these situations?
Would I have an attribute that I can put on all actions that only accept https?
Can I make that the default behaviour and only put attribute on those that are okay on http?
What is the advice on, is it our responsibility that no one use a oauth token over a non secure line or is the user of the api ?
I believe the right way to do this is to add global action filter which forces you to use HTTPs on all controllers/actions on your Web API. The implementation for this HTTPs action filter can be as the below:
public class ForceHttpsAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
var request = actionContext.Request;
if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
{
var html = "<p>Https is required</p>";
if (request.Method.Method == "GET")
{
actionContext.Response = request.CreateResponse(HttpStatusCode.Found);
actionContext.Response.Content = new StringContent(html, Encoding.UTF8, "text/html");
UriBuilder httpsNewUri = new UriBuilder(request.RequestUri);
httpsNewUri.Scheme = Uri.UriSchemeHttps;
httpsNewUri.Port = 443;
actionContext.Response.Headers.Location = httpsNewUri.Uri;
}
else
{
actionContext.Response = request.CreateResponse(HttpStatusCode.NotFound);
actionContext.Response.Content = new StringContent(html, Encoding.UTF8, "text/html");
}
}
}
}
Now you want to register this globally on WebApiConfig class as the below:
config.Filters.Add(new ForceHttpsAttribute());
As I understand from your question, the number of controllers you want to call them over https are greater than controllers over http, so you want to add override attribute to those http controllers [OverrideActionFiltersAttribute]
Do not forget to attribute your anonymous controllers with [AllowAnonymous] attribute.
But my recommendation is to keep all the communication over https and you just allow anonymos calls.
You can read more about enforcing https on my blog here: http://bitoftech.net/2013/12/03/enforce-https-asp-net-web-api-basic-authentication/
Hope this helps.
Firstly I think you definitely have to make best efforts to ensure the security of that token and so the server should enforce SSL.
We are using web api v1 (infrastructure restrictions :() and we have a global DelegatingHandler that enforces SSL on all requests except for certain uris that are on a whitelist (not the prettiest solution but it works for now).
In web api 2 I reckon you could have a global FilterAttribute to enforce the SSL connectivity and then use the new attribute override feature http://dotnet.dzone.com/articles/new-filter-overrides-feature to create your exceptions - all theory though ! :)
Hope that helps
Garrett

Returning HTTP 403 substatus from Asp.Net WebApi controller

I'd like to return Http 403 errors from my Asp.Net WebApi controllers when the user does not have permission to perform certain tasks.
However, I'd like to use a substatus on this to give further details about the error, along with the error message.
At the moment, what I get is
HTTP/1.1 403 Read access forbidden
but what I'd like to see is
HTTP/1.1 403.2 Read access forbidden
The code I'm using currently:
[HttpGet]
public EnrollmentDetail Details(int id)
{
var enrollmentDetail = _context.GetEnrollmentDetail(id);
if (!enrollmentDetail.R)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Forbidden)
{
ReasonPhrase = "Read access forbidden"
});
}
return enrollmentDetail;
}
I can't find any information any where on how to add these sub-statuses to the response. Is there any way it can be done with the built-in classes? If not, is there a way to write a custom HttpException which could do this for me?
That's because sub-statuses are not part of the HTTP spec and should not be used. If you want to send more details about the problem you encountered, take a look at Json-problem

Resources