KeyCloak Visual Studio - c#

I am getting an error when I login using KeyCloak.
The error I get is "Both the access token and the refresh token have expired"
I have followed the example detailed here;
https://github.com/dylanplecki/KeycloakOwinAuthentication/wiki/ASP.NET-MVC-Tutorial
The code works as far as the login page. I enter my login ID and Password, press the Login button and immediately get the above error on a yellow screen.
I have created the client in the Master realm and based all the settings according to what is in the web page above.
Does anyone know what I need to do to fix this?

This was confirmed as a bug:
https://github.com/dylanplecki/KeycloakOwinAuthentication/issues/35#issuecomment-204128345
Are you still having issues?

Here is what you need to do in order to resolve this, and use Keycloak normally:
Since it is reported as a bug, and The Library Author/maintainer is not working on it anymore, you'll have to fix your local copy, and use it instead of the NuGet package.
Background:
Keycloak uses UTC time in all attributes that require time reference, like for example the Token's nbf or exp. Since the Access token is usually valid for 5 minutes, so unless if the machine happens to be in a time zone that matches UTC time, you'll never be able to make the 5 minute limit.
The problem with the library is that it compares the time in the token with DateTime.Now you need to change that manually into DateTime.UtcNow
Implementation:
You can download a copy of the Library Code from GitHub here and browse through the first project in the solution: KeycloakIdentityModel to the file where the task is located: KeycloakIdentity.cs.
Go to line 443, that's the beginning of comparison task GetClaimsAsync.
inside the task, there is an if statement, you'll change all DateTime.Now within into DateTime.UtcNow. the result should look like this:
// Check to update cached claims, but not if refresh token is missing (as in bearer mode)
if ((_kcClaims == null || _accessToken.ValidTo <= DateTime.UtcNow) && _refreshToken != null)
{
// Validate refresh token expiration
if (_refreshToken.ValidTo <= DateTime.UtcNow)
throw new Exception("Both the access token and the refresh token have expired");
// Load new identity from token endpoint via refresh token
await RefreshIdentity(_refreshToken.RawData);
}
changes took place in lines 439 and 442.
after that rebuild the solution, and browse to the physical folders of the solution to ~\src\Owin.Security.Keycloak\bin\Debug, Make sure that the date modified on both of them resembles the actual time and copy both files
KeycloakIdentityModel.dll and Owin.Security.Keycloak.dll to an easy directory to reach (this is not necessary, but recommended for simplicity).
Then from your solution, delete both from the references and add the new ones by right clicking on the reference node in the solution explorer and selecting Add reference. Browse to where you saved them, add them and it should function correctly this way.

Related

DocuSign C# API - USER_LACKS_MEMBERSHIP error for every token-authenticated request

We had a working application, we went through the go-live process, and everything was running live for several days. Then we started getting SSL errors, and we saw that the nuget package for the DocuSign package had an update (I believe this was all for the 11/13/2019 2019 certificates auto-update), so we updated our code, but now every request returns the USER_LACKS_MEMBERSHIP error for every token-authenticated request.
Things I can confirm are not the issue:
We have authenticated the app via account.docusign.com and the oauth signature impersonation scope, and the testing and live paths are in the API approved Redirect URIs.
We have the correct base path in the configuration (https://na3.docusign.net, as shown on our Apps and Keys page)
The base path did not change after we get the token back (The BaseUri on the Account object matches what we started with)
We are using the correct user for the configuration (The value labeled "API Username" in the Apps and Keys page is entered as "IMPERSONATED_USER_GUID" in appsettings.json and successfully used in creating the token as parameter UserID, which also matches our user account's ID shown in the backend, so we are not confusing it with TARGET_ACCOUNT_ID or CLIENT_ID, and shuffling those around causes errors much earlier at the token generation step).
We only have one user: the administrator of the DocuSign account. Their ID appears in the API configuration labeled as "API Username". The DocuSign administration backend doesn't display a membership tab anywhere for us to correct any possible issues with a user lacking membership. As far as I can tell, Membership is a higher tier account option than what we're paying for, so I'm confused how we could be having problems with a feature we haven't bought.
We get this error for checking envelope status. We get this error for trying to create new envelopes. We get this error for trying to get Account information. The only thing we can do is get an authentication token, but then that token can't be used to make any further authenticated requests.
Is there anything I'm missing that could be causing this other than some database error on DocuSign that I can't correct through the tools available to me? The package update changed the order of which class constructor accepts the ApiClient object, and there's a new AccessToken field on the Configuration class (which I filled out, but doesn't seem to have any effect, since we're still adding the Authorization/Bearer header manually). I'm out of ideas on what to try next.
Are you using the production environment or the demo environment?
I suspect that what's happening is that you are getting them mixed. As the baseUrl should not be demo.docusign.net etc. if you're using production (as indicated by your na3.docusign.net address) but you must ensure that the same account/user from production is also used.
So, the 4 things to check:
userId
accountId.
baseURI
authURI (account-d.docusign.com vs. account.docusign.com)
All of these should match and be for the same account in the same env.

Asp.Net Identity with 2FA: List of Trusted Browsers

I'm working on a project with Asp.Net MVC 5 and Asp.Net Identity and I'm using two factor authentication. For the login I use:
var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, isPersistent: model.RememberMe, rememberBrowser: model.RememberBrowser);
which is the default code that came with the new project. However, I also need the ability for a user to "trust" or "remember" a browser, similar to how banks can indicate if this was the first time you have signed in from a particular browser/pc.
My question is around the RememberBrowser property on the sign in method and what .NET Identity does with this data. I want the list of saved browsers and the ability to revoke access to one/and-or all of them. Is that possible within the Identity framework? Also, can I tell if a browser has been "trusted" before by some type of lookup?
Edit:
Maybe it's a good idea to save the browser info in the database and check on login instead of the cookie? That way it can be shown as a list with the ability to delete it. What I'm looking for is what to save and how to integrate it with the Asp.Net Identity without having a security risk.
Edit 2
Here's an example from a website that is already using this:
Edit 3
Maybe this can be implemented as another step for authentication. So basically we'll have a 3 factor authentication:
First user logs in with user/pass
Then we'll check if the 2FA is enabled and get the code if necessary
We get the user's aser agent and IP and check the database if it's new. Then notify if necessary.
So I'm guessing an new cookie should be added to save browser's info. However, we should be able to invalidate this cookie along with the 2FA cookie.
RememberBrowser sets a cookie that allows the 2FA step to be skipped. There is no central way to track this though it would be easy enough to log, however the results may not be accurate because people can delete cookies manually. There's no way to invalidate it I believe but it doesn't really matter as you can invalidate their session and the user is will be required to login with their password again.
Not sure whether saving browser info adds value as browser info is gonna be same for different users (using same browser and version) unless you save requestor IP as well; and saving requestor IP has too many complications.
How about adding a custom claim to the token if user has set RememberBrowser and then do your logic based on this custom claim? For eg, set a custom claim your_claim_name and set a Guid.NewGuid() to it if RememberBrowser is true. Also save the username, this guid and status flag in database . When a request comes, check whether your custom claim is present, if yes query the table with the custom claim value and username to check whether the entry is still active.
You can either delete the entry or soft delete (set the status) the entry for an user so that when next request comes you can perform your required logic.

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

Webapi oauth accestoken invalid expiration date

We are building a frontend application that is making extensive use of an webapi backend.
In this application we are using oauth to log a user in and store all of the claims that belong to that user inside off access tokens.
On the frontend we are using sentry error logging (http://www.getsentry.com) to log all of our javascript errors. This includes any webapi calls that somehow went wrong or do not return the result we are expecting. With every error we recieve we also log the cookie information along with it, which includes the access tokens that that specific user was using at that time.
Right now we are seeing alot of webapi calls that went wrong because the calls they made are forbidden. I checked some of their access tokens and immeadiately i noticed that the information was way out of date and should have been refreshed a long time ago because the access token should have expired already.
By using :
var ticket = Startup.OAuthOptions.AccessTokenFormat.Unprotect("tokenhere");
on my localhost machine inside the debugger i can unprotect the access tokens and view the information inside of them.
Like i said the information inside some of these tokens contains invalid information and should have been refreshed already..
Then i noticed that the reason they are not refreshed yet is because the ExpiresUtc is more than 2 years bigger than the IssuedUtc. In other words; The token wont expire until after 2 years.
Here is some example information of one of these tokens
IssuedUtc: { 20/02/2016 03:04:40 +00:00}
ExpiresUtc: {16/11/2018 03:04:40 +00:00}
We are using the default expire time from oauth (20 minutes) and somehow in the pipeline it is setting it to be bigger than 2 years. The only way a user can now refresh their claims is if he logs out and back in again, and obviously until they do so it is creating alot of errors on the frontend side.
By debugging my own tokens i can verify that it is setting it to 20 minutes and have never managed to reproduce it myself.
Solved, we had an controller method hidden somewhere that was issueing access tokens with an expiry date of 2 years.. Doh

Clear before logging

For my application I want to clear the cache before logging.
However, if someone logs with different account, I want to clear the cache so that the page is refreshed and doesn't keep the previous user's values.
How do I do this in C#?
Create an if condition to check log in accounts. Then use the code in this reference to clear the cache if it satisfy the condition.
Using this Code you can clear the browser cache.
You can also use it on LogOut of your site instead of login.
Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
Or you can do this way
https://stackoverflow.com/a/2876701/2218635
You can define a cache by this way
HttpContextBase httpContext = filterContext.HttpContext;
httpContext.Response.AddCacheItemDependency("Pages");
and setup a cache when login
protected void Application_Start()
{
HttpRuntime.Cache.Insert("Pages", DateTime.Now);
}
and clear cache when logout
HttpRuntime.Cache.Insert("Pages", DateTime.Now);
more details
Clearing Page Cache in ASP.NET
You cannot write code to clear the client browser cache. All you can do it set control cache policy for data when you send the date to the browser in the first place.
E.g., if you initially have an image file, with expiration set to midnight when the browser retrieves it, the browser will not remove the file from its cache before midnight. If you need to immediate force the browser to fetch a different version of the file, the URI must change -- i.e., rename the file to a new (version 2) name.
You can only control cache policy of item sent to the browser (or the intervening proxy server, or both). The browser can ignore the policy (if it wants to be a really bad browser), but you CAN NOT send anything that will clear pre-existing browser cache.
Policy (in the http header), set things like expiration time (GMT), relative time (i.e., cache duraction), as well as no-cache directives. You can set this for the browser cache (or proxy and shared cache). But once it goes over the wire, you can not clear it.
ADDED
Took me a while to find this article explaining how browser caching works. Easier to understand than the W3C explanation of browser caching

Categories