How do I exclude a specific controller action from needing authentication? - c#

Background
I'm adding self-checks to an API, secured by OAuth2, using Identity Server 3. I've added a MonitoringController for this, with a limited set of checks.
The main check I want to do is make sure it's possible to request a token, using fixed test credentials.
Our monitoring system can than do regular calls to this action and make sure it's possible to request a token, which is a stronger check than just a keep-alive ping (which we also have).
However
As the entirety of the API is under authentication, the MonitoringController is as well, by default.
This means my token request check isn't allowed. Having to request a token first defeats the whole purpose of this check.
How can I exclude my MonitoringController from needing authentication,
while making sure all other controllers are still checked?

You should be able to put the AllowAnonymous attribute on the controller or method.
[AllowAnonymous]
public async Task<IHttpActionResult> DoSomeMonitoring()

Related

How to force Identity Server 4 to route from /connect/authorize to my custom methods on each request?

When a user (SPA based, no MVC) tries to log in to my application (auth code flow), they go to the endpoint specified in the well known document.
https://localhost:5010/connect/authorize
?client_id=cool_client
&response_type=code
&redirect_uri=http://localhost:4200/auth&scope=openid&param=1337
It works well and the IDS4 routes over the call to the controller below with the correct value of returnUrl. I do some magic and logic in there and sign in them to the application. They are redirected to the SPA and provided with a code to be exchanged for a token. Everything works just as supposed to and a correct, working token is issued..
[HttpGet("login")]
public async Task<IActionResult> LogIn([FromQuery] string returnUrl)
{
...
await HttpContext.SignInAsync(user);
return Redirect(returnUrl);
}
When the user is signed in and attempts to authorize again, now with the access token (which they obtained using the code issued previously), they navigate to the very same endpoint with the very same query string. However, this time, the IDS4 handles the call differently. Instead of routing the call again to the method above, it automagically bounces the call to the URL from returnUrl without hitting the breaky in it.
I assumed it had to do with some optimization due to the presence of a valid access token (since the very same request after the token's expired routes me to my method again). However, I'd like to get the routing now because I need to do something with each incoming call, due to changed business requirement.
I googled the issue but found nothing (most of the material regards MVC nto SPA, anyway). I read the official docs and tried to scrutinize the quick-start application. After three days, I'm concluding that I can't find any useful info on the subject.
How can I force the routing to my custom method for each incoming request, including the ones that contain a valid access token?

AWS Cognito built-in sign in redirection issue

I am trying to incorporate Cognito built-in sign in logic into our workflow.
Here is scenario I try put to work:
I need redirect to specific URI after successful signing in through Cognito built-in UI of the user, which has been created in the User Pool. But I do not understand how to do it.
I've created User Pool, app client, configured domain, provided callback url, created a user.
I configured "Allowed OAuth Flows" to useAuthorization code grant "Allowed OAuth Scopes" is set to openid
So far - so good.
Then I came up following URL to conjure up Cognito built-in UI:
https://<my-domain>.amazoncognito.com/authorize?response_type=code&client_id=<my-client-id>&redirect_uri=https://<my-domain>.amazoncognito.com/login?client_id=<my-client-id>
Upon executing it in a browser of my choice I am hitting Cognito built-in sign in page. But upon clicking "Sign in" button I've got an error: Required String parameter 'redirect_uri' is not present
Ok, I thought to myself, let's add redirect_uri attribute at the end of the aforementioned URL and path would be cleared to success, but such optimism has been short lived. I've got dreaded: "redirect_mismatch" error. I've tried to provide multiple callback urls, but with no success. redirect_mismatch error blocking my way.
And now I have no idea how to instruct Cognito to redirect to desired url. Any ideas are welcome.
You shouldn't set the 'redirect_uri' to Cognito's Login Endpoint. It makes no sense. The 'redirect_uri' is a parameter to tell Cognito where to take the user after login, which would be your application's url.
The 'redirect_uri' should exactly match one of the Callback URIs for the app client you configured for security reasons, otherwise you will get a' redirect_mismatch' error.
To access the login endpoint:
https://mydomain.auth.us-east-1.amazoncognito.com/login?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI
For the authorize endpoint:
https://mydomain.auth.us-east-1.amazoncognito.com/oauth2/authorize?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI
The authorize endpoint firsts checks to see if you have a session cookie indicating that you're already logged in, and if you are, it automatically redirects you to the redirect_uri, otherwise it will take you to the login page via the Login Endpoint with the query strings provided to the authorize endpoint.

Ways to secure an anonymous Web API request

I have a ASP.NET MVC (NOT ASP.NET Core) single page application with angular js on the front end.
My client (browser) talks to server through ASP.NET Web APIs. Now, the web application is on https but anonymous. There is no login/ user authentication.
The web app is in the form of a wizard where user can go back and forth and add or update input fields on the web page. The form input values are then updated on the server through Web API.
I'm looking for a way to secure my Web API calls alone, especially the POST/ PUT requests. In summary, I want to prevent any user calling my Web API directly from POSTMAN or Fiddler. The Web API, though anonymous can be only called from the browser session where the request originated.
What are options do I have to achieve this?
Can I use Anti-Forgery token here (without authentication)?
One way, I can think of achieving this is to add a custom header to each request and store some kind of session key in the header. Then, validate the custom header on every request I received from client. Are any other ways of achieving this out-of-box or some proven library without going for custom solution?
If I have to go for the above custom solution, what are the pitfalls or potential issues I need to be aware of?
First of all when you remove login and there's no authentication mechanism in your application, there's really no way to secure anything, because anyone can access your APIs. I think what you want is to make sure that your APIs are called only from your own website. Unfortunately you can't completely achieve that, since your web APIs are http/https, and anyone, from anywhere (like postman, fiddler, ...) can create a http request and call your API.
All you can do is to make it harder for your API to response to requests, like using Anti-Forgery as you mentioned.
And also I suggest you add a cookie for your application and check that cookie in every request, in this case it's more complicated ( not impossible ) to call your API using Fiddler or Postman.
And last I suggest that you use CORS, so browsers would only allow your domain to call your APIs. So nobody can call your APIs in a browser from different domain.
Based on answer from #Arvin and comment from #Evk, here's how I plan to proceed:
Once, the user starts the anonymous session generate a GUID using regular Guid.NewGuid() method and save it in DB to identify the request (I'm doing this now). However, as mentioned here,
GUID can be unique but they are not cryptographically secured.
Hence, instead of using plain-text GUID, encrypt it with current timestamp as token and append it with request query string.
For every subsequent API request, read the token from query string, decrypt it and validate it as follows:
Check the timestamp. If the time difference is more than pre-defined time (i.e. token expired), reject the request
Validate the unique id (GUID) against DB
Since, I'm not using plain text GUID anymore, the URI would not easy to guess.
Additionally, with the timestamp, URI is invalidated after sometime. While theoretically it is still possible to call the API through Fiddler but this should make it very difficult for the attacker, if not impossible.
As a further security measure, I can also add Anti-Forgery token to the request
As per my understanding this helps solving my underlying problem and with this approach, I may not even need add a cookie to secure my anonymous session.
Love to hear from you all if this approach looks good and how can it be improved.
I also once had the weird need for having session functionality on WebAPI and created an OWIN Session middleware that does exactly what you're aiming for.
The library is called OwinSessionMiddleware and is available on github and NuGet.
Usage
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseSessionMiddleware();
// other middleware registrations...
app.UseWebApi();
}
}
You can also pass some options to further tweak cookie-name, add a database backed session store (instead of in-memory), add your own session id generator (instead of default id generator which is based on GUID + secure random part generated by RNGCryptoServiceProvider).
The unique session id itself is stored as a secure cookie and the session is restored automatically by the middleware on each request.
There are extension methods you can call inside your API controller to get and set session data:
public SomeApiController : ApiController
{
public IHttpActionResult MyAction()
{
var requestCount = Request.GetSessionProperty<int>("RequestCount");
Request.SetSessionProperty("RequestCount", ++requestCount);
}
}
Create Anonymous JWT token with some claims related to your scenario, Sign it with some key, Use that as in cookie (Http Only) or As bearer token. To make it little more harder further combine it with some cookies.
1)verify token signature and
2) Verify token expiry time
3) Verify Claim(skey) against cookies(skey)- no database storage required everything is in ur JWT token.

Refresh identity token from client from code

I am using the fine-uploader with an asp.net mvc backend to upload files directly to an azure blob-storage. The asp.net-server works as the azure-signature-endpoint(sas). This is all secured with an identityserver3 and here comes the problem: The identity_tokens lifetime is set to 5 minutes(as default). And I want the SAS endpoint to be only called authorized. So a user can only access its own data. But after I have the upload running for the set 5 minutes, it breaks. Of course, because it is not authorized and it returns the login-page from the identity-server(which the fine-uploader, of course, can't handle).
It would be easy to solve this problem, by either setting the lifetime from the token to something higher(but this is unreliable as the upload could take hours or days), or disable the lifetime(yeah would work. But I guess the lifetime has a reason to exist).
So my 2 ideas would be:
to just authorize the user once(when he starts the download)
or to refresh the token by code every time the signature gets generated.
First approach
Can I just set a boolean like user is authorized and if this boolean is set just skip authorization and just return the signature or how could I achieve this
Second approach
How would I do this?
Don't use the id token for API access, an instead use access token. Access tokens are for resources (APIs), whilst id_tokens are purely for authentication. The id_token is only meant to be used to provide the RP with means of knowing who the user is - hence no need for long time span. It's only there for converting into a user session (cookie/principal).
With access tokens you have several approaches for keeping a valid token at a client; either by fetching new ones using the client credentials flow or by using the refresh token approach.
I believe there are samples of both in the samples repo of IdentityServer.
Samples repo link

Microsoft.Owin.Security.Oauth Bearer Token Authorization Interception

I am in the process of implementing OAuth 2 on a web API with Microsoft.Owin.Security.Oauth.
I would like to keep the bearer token small and keep private data out of it. To do this, I'd like to store a session ID in it and then fill out the ClaimsIdentity programmatically once the session ID has been received and processed. This would also give me greater flexibility related to how logging out, role changes, and other things can be handled.
This should be a matter of intercepting the right event and adding a delegate. However, I can't find an event that gets fired on my authorization provider, a subclass of "OAuthAuthorizationServerProvider". I thought that "AuthorizeEndpoint" would do it, but it does NOT get fired for API methods decorated with the [Authorize] attribute, even though these methods clearly get checked for a valid bearer token. When I overrode "MatchEndpoint", all I found is that a call to a method that was decorated with [Authorize] showed up with "IsAuthorizeEndpoint" and "IsTokenEndpoint" both set to false. The latter makes sense to me, the former does not.
I am very confused. Can somebody who knows this library tell me what's going on and what I need to do to accomplish this seemingly simple idea?
I think you may be conflating resources marked with the AuthorizeAttribute with the OWIN Authorize endpoint. The AuthorizeEndpoint and TokenEndpoint are setup in the OWIN configuration as receivers for their respective authentication types. The Authorize Endpoint is used for web-base, user-agent authentication and is where you would expect a browser to be redirected should they be unauthorized to access a resource. The token endpoint is used instead for username-password token authentication and refreshing, and is the one you want. Assuming you are assigning both of these within your OWIN startup configuration, the event you may be looking to overload for OnValidateTokenRequest to ensure that your customizations to the token do not cause it to be invalid once the client tries to utilize it again. You would want to do your actual modifications to the token at the OnTokenEndpoint event.

Categories