When I activate the OWIN logout-everywhere feature via security stamps and use the OnValidateIdentity-Callback of the CookieAuthenticationProvider with the SecurityStampValidator-class, the user is logged out every time he closes the browser.
provider.OnValidateIdentity =
SecurityStampValidator.OnValidateIdentity<MyUserManager, MyUser>(
System.TimeSpan.FromSeconds(10),(manager, user) => {
return user.GenerateUserIdentityAsync(manager);
});
However, when I do the plumbing myself (lookup and comparison of the security stamps, rejecting or renewing the identity) in the OnValidateIdentity-callback, everything seems to work fine.
Is this a known bug, or do I miss here something? Or is there a good documentation about the CookieAuthenticationProvider and the use of OnValidateIdentity?
Digging with google only shows me some simple samples, but gives no further insight.
Additional information
I use an own implementation of the UserStorage which saves all the
data in a database
I noted that every page request calls two times the
GetSecurityStampAsync of the UserStorage, wheras when I use my
implementation, only one call is done.
Installed Identity Version is 2.0.1
This is basically a bug, the regeneration of the cookie should respect the current Remember Me option on the cookie. As a workaround, you can copy the OnValidateIdentity code and feed in the current context properties to flow the Persistent mode through:
context.OwinContext.Authentication.SignIn(context.Properties, identity);
This is resolved in ASP.NET Identity 2.2. See https://aspnetidentity.codeplex.com/workitem/2319
I have found the following code in the disassembly of SecurityStampValidator.OnValidateIdentity:
// .. some other code
// ...
ClaimsIdentity claimsIdentity = await regenerateIdentityCallback(userManager, tUser);
if (claimsIdentity != null){
context.get_OwinContext().get_Authentication().SignIn(new ClaimsIdentity[]
{
claimsIdentity
});
}
It seems to me, that the SignIn-operation is incomplete and should set the remember-me option? Therefore I assume that the implementation of SecurityStampValidator is buggy.
Related
I'm integrating SustainSys.Saml2, with Gluu server as my IdP. I'm using the scaffolded Identity pages out of the box. When I run in localhost, and I view the console log everything seems to work with the SAML communication, and I even see a couple lines that read:
Sustainsys.Saml2.AspNetCore2.Saml2Handler[0]
Successfully processed SAML response Microsoft.IdentityModel.Tokens.Saml2.Saml2Id and authenticated
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[10]
AuthenticationScheme: Identity.External signed in.
Unless I'm mistaken, that indicates everything's good on the SAML end of things. But what I don't then understand is why, in ExternalLogin.OnGetCallbackAsync, the command
var info = await _signInManager.GetExternalLoginInfoAsync();
finds info set to null.
For the record, in Startup.cs, I have:
services.AddAuthentication()
.AddSaml2(options =>
{
options.SPOptions.EntityId = new EntityId("{entityId}");
options.IdentityProviders.Add(
new IdentityProvider(new EntityId("{entityId}"), options.SPOptions)
{
Metadatalocation = "{metadataURL}",
});
options.Validate();
});
I was able to figure this out based on this GitHub issue, and Anders' notes in there.
I'll link to my comment there. Read Anders' comment above that for explanation. https://github.com/Sustainsys/Saml2/issues/1030#issuecomment-616842796
recently in one of my applications I needed to access currently logged-in user data for saving in another model (something like the author of a book or owner of a book). in my googling, I encountered these references but none of them was useful.
https://github.com/strongloop/loopback/issues/1495
https://docs.strongloop.com/display/public/LB/Using+current+context
...
all of them have this problem about accessing context or req object. after three days I decided to switch to afterRemote remote hook and add Owner or Author on that stage.
but something was wrong with this solution.
in strongloop's documentations (https://docs.strongloop.com/display/public/LB/Remote+hooks) there is a variable as ctx.req.accessToken that saves current logged-in user access token. but in the application this variable is undefined.
instead, I found accessToken in ctx.req.query.access_token and it was currently access_token variable that is sent to the server.
here is my problem:
is this variable (ctx.req.query.access_token) always available or
it's just because loopback-explorer send access_token as GET
variable?
in production mode do applications need to send access_token as
GET variable or it should be sent as Authorization in the header?
why ctx.req.accessToken is undefined?
could these things change over time? cause most of users encounter this problem due to deprecation of app.getCurrentContext()
Is this variable (ctx.req.query.access_token) always available or
it's just because loopback-explorer send access_token as GET
variable?
Well if your application always sends in the querystring, then it'll be always available for you, but it also sent in the header, or cookie or in the request body, but I don't suggest using it because it if the user logged in and the access token is valid and ctx.req.accessToken should be available and you can use it.
In production mode do applications need to send access_token as
GET variable or it should be sent as Authorization in the header?
I believe Authorization header is preferred, as if you send it in a GET variable, well it'll be visible in the logs and someone with the access to the logs can access the session(well unless you trust everyone), other than this it's fine to have it in a GET variable. Though I believe loopback client SDKs(Angular, Android, iOS) all send it via Authorization header by default, so you might have to configure them(maybe not possible).
Why ctx.req.accessToken is undefined?
Sometimes the context is lost thanks to the database drivers connection pooling, or the context req is lost(ctx.req) and they are null.
Assuming ctx.req is defined(because sometimes it's not), then probably that means the user is not logged it, or it's access token wasn't valid(expired or not in database). Also it could be a bug(maybe misconfiguration on your side), which also means for you that you will authentication problems.
Could these things change over time? cause most of users encounter this problem due to deprecation of app.getCurrentContext()
app.getCurrentContext is risky to use and I don't suggest unless you have no other solution. If you use it and it works, it might stop working if the database driver changes or in some corner cases that you haven't tested it, it might not work.
In the updated doc https://loopback.io/doc/en/lb3/Using-current-context.html
add this in your remoting metadata
"accepts": [
{"arg": "options", "type": "object", "http": "optionsFromRequest"}
]
then
MyModel.methodName = function(options) {
const token = options && options.accessToken;
const userId = token.userId
}
but it says
In LoopBack 2.x, this feature is disabled by default for compatibility reasons. To enable, add "injectOptionsFromRemoteContext": true to your model JSON file.
so add "injectOptionsFromRemoteContext": true on your model.json file
For our new project we want to leverage as much of the asp.net mvc 5 as we can. This includes making use of the AspNet.Identity toolset for our user administration.
We are using the following version(s):
"Microsoft.AspNet.Identity.Core" version="2.2.1" targetFramework="net46"
"Microsoft.AspNet.Identity.EntityFramework" version="2.2.1" targetFramework="net46"
In our previous roll-your-own applications we made sure that reset links can be used only once, and that they expire within a day or so.
Does does AspNet.Identiy support something similar? I could not find it in the documentation.
To pass our security checks the link should at least expire.
How to make this happen?
to control the lifetime of the token, go to IdentityConfig.cs, next, and the end of the Create function, within the last if related to dataProtectionProvider you can set the time, look:
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>(
dataProtectionProvider.Create("ASP.NET Identity")){
**TokenLifespan = TimeSpan.FromMinutes(1)**
};
}
Use the TokenLifespan = TimeSpan.FromMinutes(1) (or the time that you need)
ASP.NET Identity by default generates reset tokens based on existing user properties. This means that when those properties change, the reset token is automatically invalidated. This will meet your one time use requirement (when they use the token and reset their password, the token will no longer be valid).
Reset token expiration can be set when you assign an IUserTokenProvider to the UserTokenProvider property of your UserManager.
A good example of IUserTokenProvider is DataProtectorTokenProvider found in the Microsoft.AspNet.Identity.Owin package. This class uses the previously mentioned security stamp based tokens and allows for expiration times to be set using the TokenLifespan property. For info on how to implement this check out this answer.
By default the token is valid for one day. However, you can change that by customizing the Create method in App_Start\IdentityConfig.cs file
if (dataProtectionProvider != null)
{
manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser>
(dataProtectionProvider.Create("ASP.NET Identity"))
{
TokenLifespan = TimeSpan.FromHours(3)
};
}
With the code above, the forgotten password and the email confirmation tokens will expire in 3 hours.
Do make sure that your application has a way for users to regenerate token. I had added a Resend Link button. It links to the function that regenerates the token and sends link to the user.
You will more details here: http://www.asp.net/identity/overview/features-api/account-confirmation-and-password-recovery-with-aspnet-identity
I have ServiceStack v4 service but when I call the auth/logout route (using either POST or GET) to logout the currently logged-in user, I get an error:
400 Not Empty
User Name cannot be empty
Password Cannot be empty
As I wouldn't expect users to enter credentials when logging out, I am surely missing something?
I have the AuthFeature registered during host initialisation, and I am using CredentialsAuthProvider. I have taken the code from Github so I can see how it works.
My Client Code:
var rest = Restangular.one('auth/logout').get();
//var result = rest.post({userName: userName});
this.requestTracker.addPromise(rest);
return rest;
After a lot of digging, this happens when you are using CredentialsAuthProvider. Within this class, a validator is defined that validates all instances of the Authenticate request. As the logout route uses the Authenticate request, this validator is fired.
I got round it by modifying the validator to:
RuleFor(x => x.UserName).NotEmpty().When(d => d.provider != "logout");
RuleFor(x => x.Password).NotEmpty().When(d => d.provider != "logout");
This is probably not the most elegant way of fixing long term, but got me up and running.
I know this question is old, but I recently have been struggling with the same thing. What occurs is that before the Authenticate.Post function is called, the validation cache is checked and the CredentialsAuthProvider which has the mentioned validator fails unless username and password are not empty.
Now, i'm not sure if it makes a difference if you only have that provider enabled or not - I've not tested. I actually have my own custom provider that subclasses CredentialsAuthProvider and it's the only one I register.
The only way currently is to either pass a non-empty (but useless) password and username, or modify your own custom provider, overriding the Authenticate function and using a modified version of the validator as mentioned above.
I am using the Spring Security Core plugin and can successfully log users in and out of my application. However, when the user successfully signs up, I don't understand how to set that user's security context on the signup postback so that they can be redirected to a secure page without having to log in again. Any help is welcome. Thanks.
The other link you reference is 2 years old. Since then I've added a reauthenticate method to SpringSecurityService. See section "6.2 SpringSecurityService" in the docs:
http://grails-plugins.github.com/grails-spring-security-core/docs/
I eventually came upon this link, which does the trick: https://stackoverflow.com/a/7112838/469106
Here are the contents of that link:
If you don't have the password, you can load the user via
def user = User.findByUsername(username)
and setting the authority array in the 3-parameter constructor. Create the auths via
GrantedAuthority[] auths = user.authorities.collect { new GrantedAuthorityImpl(it.authority) }
Then you can omit the call to authenticate() and use:
SecurityContextHolder.context.authentication = new UsernamePasswordAuthenticationToken(username, 'unknown', auths)