umbraco / UmbracoIdentityExtensions

Code files & installation that enables easy extensibility points for ASP.Net Identity and the Umbraco back office
MIT License
38 stars 23 forks source link

Allow Two-Factor Local Authentication available in .NET Identity #4

Closed warrenbuckley closed 9 years ago

warrenbuckley commented 9 years ago

Allow for Local Two Factor Identity so that a SMS or TOTP (Time Based One Time Passcodes) aka Google Authenticator Application & even email (even though it's not secure/ideal)

Normal .NET Identity allows this to be done but from what I could see, I was not able to do this. I have been reading articles on this on how to implement, but I am having little luck & seen comments in the codebase then you may or may not support it.

Ideally I would like to implement the TOTP style Local Two Factor auth as shown here http://www.jerriepelser.com/blog/using-google-authenticator-asp-net-identity

I have a badly drawn/thought out UI in terms of using/enabling two factor auth as shown here: https://www.dropbox.com/s/qzm5xqvgcty4tu6/Screenshot%202015-06-18%2016.51.27.png?dl=0

The login screen after prompting for the username & password would need to hide these current fields/form & ask for the two factor auth code.

The codebase in the 7.3 beta core is conflicting if this will be implemented or not. https://github.com/umbraco/Umbraco-CMS/blob/a3d4ccc062b94859e446b1206bf21f334577a35c/src/Umbraco.Core/Security/BackOfficeUserManager.cs#L106

Here in the comment it is mentioned that I need my own UserStore this seems a lot of work for me as a dev to reimplement a user store to fetch, check passwords etc which is already done just to tack on support for two factor auth.

However further down in the UserManager object/class there is a TODO comment of saying to support this for the SupportsUserTwoFactor. https://github.com/umbraco/Umbraco-CMS/blob/a3d4ccc062b94859e446b1206bf21f334577a35c/src/Umbraco.Core/Security/BackOfficeUserManager.cs#L158

Can some clarification be made on this please.

Shazwazza commented 9 years ago

Mate... unfortunately we are not going to build this into the core. You CAN implement it on your own, you will have to implement a custom user manager and implement your own db tables. Any implementation of 2 factor auth will be different and different providers will probably make you store custom data. Our recommendataion is: 2 factor auth is done already by tons of third party programs (like google). You can very easily use identity with a 3rd party provider to support 2 factor auth (i.e. again, Google... as shown by niels in his keynote).

However, if you really really really want to do this yourself, you are going to have to write the custom code to support it. We're happy to perhaps modify the core codebase if there are real barriers to making this happen but you should be able to implement this yourself by extending the identity implementation that we supply.

Shazwazza commented 9 years ago

Yes... it will be a lot of work, that is the nature of implementing custom authentication. Integrating with SMS providers, etc... will be done differently per provider, i don't think there's just a super easy single OOTB solution that we should provide that will work for everyone. No matter what you are going to have to do some work and code to make this happen.

Shazwazza commented 9 years ago

And you don't implement an entire user store/user manager, you just extend the one that we already give you.

warrenbuckley commented 9 years ago

I may bug you for advice/pointers on how to do this, but obviously a GitHub issue is probably not the best place for this to happen. But obviously with me wanting to implement my own two factor auth, would require some UI changes in the backoffice, hence me asking more broadly for support.

As no matter on the delivery method of the token/code (sent out via email, SMS, carrier pigeon, morse code) I would still need the login UI to help support this.

Regardless of that, is the best place to ask for advice using/hacking this to my needs is the best place to ask for help, here on issues, the forum or via email?

Cheers

warrenbuckley commented 9 years ago

I agree most 3rd party Google, Microsoft obviously offer this, but there are some clients & corporates that may not be using any of these 3rd party providers or Active Directory. Hence the idea of providing two factor auth for local based accounts not linked/connected to a 3rd party identity.

Shazwazza commented 9 years ago

Here is a good place for that convo.

Yup i understand the need for it, but the core cannot cater for all cases, so we need to be able to support people being able to extend the core to support their needs. It will be an interesting process.

For much of the UI, it will be best to have the form fields, etc... to redirect to your own UI so you can accept and process the input however you like. The trick will be how we wire up the redirects. ... but we need to map out how the process can work

warrenbuckley commented 9 years ago

OK thanks for being so helpful mate. Expect more questions as I find time to hack, play & learn more about Identity along the way.

I can understand the core's stance on this, like you say 1001 options for this.

The UI needs the following:

But first thing is first as a starting point how would I got about extending the UserManager you use? Do I create my own that inherits a class of your own?

Cheers!

warrenbuckley commented 9 years ago

OK started hacking/exploring with this. Got a simple controller that gets the UserManager then I can check if its enabled & set it to be enabled. However obviously the UserManager does not support this, plus if it did the UserStore has no way of knowing what to do either. IE what to insert into the DB.

So I assume for the userstore part I need to do something similar & implement this interface for the userStore?

public class MyUserStore : IUserTwoFactorStore<BackOfficeIdentityUser, int>
{
    public Task<bool> GetTwoFactorEnabledAsync(BackOfficeIdentityUser user)
    {
        throw new NotImplementedException();
    }

    public Task SetTwoFactorEnabledAsync(BackOfficeIdentityUser user, bool enabled)
    {
        throw new NotImplementedException();
    }

    public Task CreateAsync(BackOfficeIdentityUser user)
    {
        throw new NotImplementedException();
    }

    public Task DeleteAsync(BackOfficeIdentityUser user)
    {
        throw new NotImplementedException();
    }

    public Task<BackOfficeIdentityUser> FindByIdAsync(int userId)
    {
        throw new NotImplementedException();
    }

    public Task<BackOfficeIdentityUser> FindByNameAsync(string userName)
    {
        throw new NotImplementedException();
    }

    public Task UpdateAsync(BackOfficeIdentityUser user)
    {
        throw new NotImplementedException();
    }

    public void Dispose()
    {
        throw new NotImplementedException();
    }
}

Do I need to implement all methods @Shazwazza or just the Get & Set methods?

warrenbuckley commented 9 years ago

OK when trying to write something for the GetTwoFactorEnabledAsync method. I noticed the BackOfficeIdentityUserhas a property for TwoFactorEnabled which its inheriting from IdentityUser class

https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Core/Models/Identity/IdentityUser.cs#L73

Is this POCO class mapping the majority of the properties back to the DB table, but as there is no column in the DB for this this would never get set?

I suppose I am asking should these properties on IdentityUser be here @Shazwazza ?

warrenbuckley commented 9 years ago

My mess & experimenting to better understand Identity & my current efforts will be in this repo https://github.com/warrenbuckley/Umbraco-Identity-Playground

This will give a bit of better context than fragments here & there

Shazwazza commented 9 years ago

I'll have to find some time this week to reply to all of this mate. You should inherit from the current umbraco user store and implement the IUserTwoFactorStore. Then replace the current user store with your new overriding user store. For any additional columns in the db that you need you should create a new db table with a 1:1 relationship.

warrenbuckley commented 9 years ago

Thanks for replying to this thread of my muddled thoughts, questions & problems I come across as I hack & explore this.

Yeh I have managed to figure out how that I need to inherit from IUserTwoFactorStore https://github.com/warrenbuckley/Umbraco-Identity-Playground/blob/master/Umbraco.Identity.TwoFactor/Identity/TwoFactorUserStore.cs

Next I am trying to get the UserManager to use my custom store and I see that I need to override the OWIN startup app.ConfigureUserManagerForUmbracoBackOffice() method. I presume by me specifying it in the UmbracoStandardOwinStartup class and that last one in wins as this class inherits from UmbracoDefaultOwinStartup which has the ConfigureUserManagerForUmbracoBackOffice() method in it.

However when trying to pass in the last parameter to this method for the customStore it expects an object of BackOfficeUserStore but my TwoFactorUserStore I am not sure how I would pass this in as the last param? Does it need to inherit some other interface or do I need to convert/cast it to this object?

Again thanks for all the pointers & advice on this!

Shazwazza commented 9 years ago

As mentioned before, the purpose of the UmbracoCustomOwinStartup, is to be able to modify these things, the 'Standard' won't work for this. Also, i didn't mean just inherit from IUserTwoFactorStore, you need to inherit from the user manager that we ship with so you get all of the other stuff already coded in there (otherwise nothing will work), then you also need to implement IUserTwoFactorStore

warrenbuckley commented 9 years ago

Sorry mate if I am being really dumb. OK yes I can see the example in the UmbracoCustomOwinStartup for ConfigureUserManagerForUmbracoBackOffice

When you say inherit from the userManager that you ship, it's that what I am currently struggling with on how to do. As I would have thought I would need to inherit from your BackOfficeUserStore which has the logic for looking up users, finding them etc. As it was my understanding the userManager has no understanding of the store underneath to do the CRUD operations.

If you can provide a snippet or brief example to point me in the right direction that would be fantastic mate.

Shazwazza commented 9 years ago

Yo, sorry I haven't had time to get back to all of this, we are super busy trying to get the remaining 7.3 stuff done for beta2.

In the meantime, you'll be happy to know that I'm currently working on a solution that will allow developers to plugin in a little to the UI pipeline for auth ... which might also work for the 2 factor auth 2nd screen. This is a requirement currently for this issue: http://issues.umbraco.org/issue/U4-6753

warrenbuckley commented 9 years ago

Hey @Shazwazza no problem now have equally become busy, but would like to eventually finish this, with a little help with some pointers from you.

Its good to hear the UI will support these type of customisations :+1:

akeilox commented 7 years ago

Stumbled across this page while researching TOTP (google authenticator) support for Umbraco back-office login.

Are there any changes/updates in the latest 7.5.8 or planned anytime soon?

cheers!

Shazwazza commented 7 years ago

@akeilox In Umbraco 7.6 Core we've added better support for being able to integrate custom 2FA, I'll try to post some docs once we're closer to release time and find time to write them, it will still require a lot of custom integration but options have been enabled to allow you to provide a custom 2FA login model screen.

ruant commented 7 years ago

@Shazwazza 7.6 is out now right? 😃

Shazwazza commented 7 years ago

Yes 7.6 is out, just need to write up docs on how to do it