Is there a way to customize laravel auth in order to verify if a user is previally stored in a old table? - authentication

I'm refactoring a pure PHP application to Laravel. I've already made Laravel auth. It works. However, I need a way of migrate old users and passwords to the new table. My idea is, at the login POST, verify if the user is stored on old table, if yes, insert that user on new table and procede with laravel auth. Can I override the login's method in LoginController to make these changes? Is It possible?

I had to override the login methods, adding the function migrationUserModelInternet($request).
protected function login(Request $request) {
$this->validateLogin($request);
$this->migrationUserModelInternet($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}

Related

How do I enforce 2FA in .Net Core Identity?

Question: How can I enforce existing users to set up 2FA in .Net Core 3.1 Identity?
I have seen a couple of answers here already, but I have issues with them as follows:
Redirect user to set up 2FA page on login if they do not have it set up. Problem with this is that the user can simply jump to a different url to avoid this, therefore it is not actually enforced.
Have some on executing filter that checks if the user has 2FA enbaled or not and if not redirect them to MFA set up page. The issue I have with this is that on every single navigation the server must go to the database to check whether the user has this field enabled, thus creating a significant performance hit on each request. I know one trip to the database may not sound like much but I have worked with applications where this was the norm and other things used this method, causing a pile up of pre action db queries. I want to avoid this kind of behavior unless absolutely necessary.
My current idea is to on login:
Check the users credentials but NOT log them in
userManager.CheckPasswordAsync(....)
If the credentials pass, check if the user has 2FA enabled or not. If they do, continue through login flow, if not:
Generate a user token:
userManager.GenerateUserTokenAsync(.......)
and store this along with the username in a server side cache. Then pass a key to the cached items with a redirect to the 2FA setup page, which will not have the [authorize] attribute set, allowing users not logged in to access it.
Before doing anything on the 2FA set up page, retrieve the cached items with the provied key andverify the token and username:
userManager.VerifyUserTokenAsync(......)
If this doesn't pass, return Unauthorized otherwise continue and get the current user from the supplied UserName in the url that was passed via a cache key. Also dump the cached items and key so that should the url be snatched by a dodgy browser extension it can't be used again.
Continue to pass a new cache key to new user tokens and usernames to each 2FA page to authenticate the user as they navigate.
Is this an appropriate use of user tokens? And is this approach secure enough? I'm concerned that having the user not logged in presents security issues, but I think it is necessary in order to avoid the previously mention problem of going to the database on every request to check 2FA, as with this method trying to navigate away will just redirect to login.
I implemented this via a Filter Method
I have a BasePageModel which all my pages inherit
public override async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next)
{
if (!User.Identity.IsAuthenticated)
{
await next.Invoke();
return;
}
var user = await UserManager.GetUserAsync(User);
var allowedPages = new List<string>
{
"Areas_Identity_Pages_Account_ConfirmEmail",
"Areas_Identity_Pages_Account_ConfirmEmailChange",
"Areas_Identity_Pages_Account_Logout",
"Areas_Identity_Pages_Account_Manage_EnableAuthenticator",
"Areas_Identity_Pages_Account_ResetPassword",
"Pages_AllowedPageX",
"Pages_AllowedPageY",
"Pages_Privacy"
};
var page = context.ActionDescriptor.PageTypeInfo.Name;
if (!user.TwoFactorEnabled && allowedPages.All(p => p != page))
{
context.Result = RedirectToPage("/Account/Manage/EnableAuthenticator", new { area = "Identity" });
}
else
{
await next.Invoke();
}
}
I then changed both the Disable2fa and ResetAuthenticator pages to redirect to the main 2fa page
public IActionResult OnGet() => RedirectToPage("./TwoFactorAuthentication");
And removed the reset/disable links from that page
I chose to implement a more modern and OAuth friendly solution (which is inline with .Net Core Identity).
Firstly, I created a custom claims principal factory that extends UserClaimsPrincipalFactory.
This allows us to add claims to the user when the runtime user object is built (I'm sorry I don't know the official name for this, but its the same thing as the User property you see on controllers).
In here I added a claim 'amr' (which is the standard name for authentication method as described in RFC 8176). That will either be set to pwd or mfa depending on whether they simply used a password or are set up with mfa.
Next, I added a custom authorize attribute that checks for this claim. If the claim is set to pwd, the authorization handler fails. This attribute is then set on all controllers that aren't to do with MFA, that way the user can still get in to set up MFA, but nothing else.
The only downside with this technique is the dev needs to remember to add that attribute to every non MFA controller, but aside from that, it works quite well as the claims are stored in the users' cookie (which isn't modifiable), so the performance hit is very small.
Hope this helps someone else, and this is what I read as a base for my solution:
https://damienbod.com/2019/12/16/force-asp-net-core-openid-connect-client-to-require-mfa/
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/mfa?view=aspnetcore-5.0#force-aspnet-core-openid-connect-client-to-require-mfa

How to use IdentityServer4 to authenticate local user from local database?

I'm creating SSO solution for multiple existing projects. Most of the applications already use same database, so same users and I use these users in IdentityServer. But there is one app which has its own users DB and login screen. Users from this table are used in one of the tables in this app (FK).
My idea is to leave existing users DB as is. Add a column MasterUserGuid to Users table that will contain "master" user Guid (so the user that IdentityServer uses for authentication) and implement following flow:
User opens the app and is not signed in
User is redirected to IdentityServer and uses global credentials
User is redirected back to the app which gets global user GUID from claims and authenticates local user (with this GUID in the MasterUserGuid column), instead of using global user
The problem is that I don't know how to implement step 3 or if it's even possible/supported in IdentityServer4. At the moment I'm redirected to IdentityServer, am authenticated and redirected back, but then the app tries to use this external user.
While researching I've read that users should be in one table, so maybe this approach is totally wrong and it would be better to remove local users and break FK for mentioned table and do some manual migration of users.
Is the scenario described in the steps I provided possible and sane?
You need to adjust your application to authenticate via IdentityServer first. Remove all the ASP.NET Core Identity logic related to registration, login etc. assuming all of that will be done on IdentityServer side. Then implement the instance of IClaimsTransformation which will either replace your current ClaimsPrincipalor add additional identities to it if needed with the claim values you want (populated from local database). Here is the example:
public class MyClaimsTransformer : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
var claims = new List<Claim>();
claims.Add(new Claim(...)); // put here your claim type and value
var identity = new ClaimsIdentity(claims);
principal.AddIdentity(identity);
return principal;
}
}
Then register your claims transformer in IOC in Startup.ConfigureServices method:
services.AddTransient<IClaimsTransformation, MyClaimsTransformer>();

Thinktecture Implicit Flow: Signout/Logout a user

I followed this example to get the implicit flow working.
http://weblogs.thinktecture.com/cweyer/2012/11/oauth2-in-thinktecture-identityserver-v2-implicit-grant-flow-with-javascript.html
My question is, how would I signout a user? I'm hoping someone out there knows, because I haven't been able to find any examples. Right now I can trigger the authorize window and process it all correctly and use the access token for my requests, but I don't know how to make it so I can switch users.
To logout you have to create custom controller with logout method.
public void Logout()
{
// You should be able to revoke thinktecture token like this. (haven't tested this out)
var sam = FederatedAuthentication.SessionAuthenticationModule;
sam.SignOut();
// Or you should be able to logoff like this when using a membership provider. (this way works for me)
//_yourMembership.Logout();
Thread.CurrentPrincipal = null;
HttpContext.Current.User = null;
}
Here is a sample of token revocation:
https://github.com/brockallen/BrockAllen.MembershipReboot/blob/master/src/BrockAllen.MembershipReboot/Authentication/SamAuthenticationService.cs

Problems configuring user authentication by external API on Symfony2

I have a problem authenticating users for my new Symfony2 application.
This applications gets all the info through an API, so no database is used. When a user goes to login page, he introduce the user and password in the login form. Then, I have to authenticate him using an API call. This API call returns "false" if it's not a user, and return a token key and a token secret if its a correct user. With this token key and secret, during the user session, I can make all the API requests I need for rendering all the pages of the application. Once the user session is over and token key and secret are erased, the user has to login again.
I don't know really how ti implement that. I read this http://symfony.com/doc/current/cookbook/security/custom_provider.html and that http://symfony.com/doc/current/cookbook/security/custom_authentication_provider.html, and I'm still so lost... :(
Can any one help me?
Thank you so much :)
If you want to write custom authentication you have found the correct links. As an example you can see the implementation of the OAuth authorization HWIOAuthBundle. But keep in mind that this type of authentication creates a user on your system. If you do not use a database, you must make a request to the API every time user send a request.
First you need to understand that there is no magic. On every request symfony checks if url matches one of the specified firewalls (see secutity.yml). Listener that fired you can see in the firewall factory. If matches are found, the action switches to the corresponding AuthenticationListener. Listener attempts to authenticate the credewntials by creating Token, which is sended to AuthenticationProvider
$this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
in AuthenticationProvider
public function authenticate(TokenInterface $token) {
...
}
AuthenticationProvider try to get user via UserProvider. In case of success, Token stored in the session. On subsequent requests, ContextListener comes into play first, checks the session, extract token and send it to AuthenticationProvider similar.
In general terms, the scheme looks like that. More info you can find examining the source code of Symfony Security component.
Really good starting point is a UsernamePasswordFormAuthenticationListener. It just take login and password from request and make simplest UsernamePasswordToken.
protected function attemptAuthentication(Request $request)
{
...
}
Good luck!

Cakephp with OpenID and User Authentication

I have a table "users" and I want to enable my visitors to login with their openID Account. For this I use the OpenId Component for Cakephp and it works fine (When I login with the Google URL I receive the "successfully authenticated!" notification).
But now I'm kind of stuck because I don't know how to go on from there.
Do I have to create a User-Entry for every user which has a new entry in the "oid_associations" table (I save all OpenId interaction in the mysql database)?
Do I have to authenticate the User after the login (or is the OpenID-component doing that automatically?).
Am I completely misunderstanding the concept?
No, you don't have to access the "oid_associations" table, it is a table which is only used by the OpenID library.
Instead, you can use the identity_url to figure out whether it is a new user. If that's the case, you can then create an entry in your "users" table. For example (assuming your "users" table has an "openid" column):
$response = $this->Openid->getResponse($returnTo);
if ($response->status == Auth_OpenID_SUCCESS) {
$user = $this->User->findByOpenid($response->identity_url);
if ($user) {
// existing user
} else {
// new user -> create user entry in the database
}
}
I'm not sure I understand your second question correctly. If someone logs in with an OpenID and you get an Auth_OpenID_SUCESS response, then this means this user was sucessfully authenticated. How you use this information in your application is up to you.
I hope this answers your questions.