Skip to content

SEC-2390: Multi Factor Authentication #2603

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
spring-projects-issues opened this issue Nov 8, 2013 · 13 comments
Open

SEC-2390: Multi Factor Authentication #2603

spring-projects-issues opened this issue Nov 8, 2013 · 13 comments
Labels
type: enhancement A general enhancement type: jira An issue that was migrated from JIRA

Comments

@spring-projects-issues
Copy link

spring-projects-issues commented Nov 8, 2013

Rob Winch (Migrated from SEC-2390) said:

Include support for HMAC-Based One-time Password (HOTP) algorithm specified in RFC 4226 and the Time-based One-time Password (TOTP) algorithm specified in RFC 6238.

https://fidoalliance.org/about

See https://code.google.com/p/google-authenticator/

A simple example of U2F https://github.com/rwinch/spring-boot-security-u2f

@spring-projects-issues
Copy link
Author

Jeroen Cranendonk said:

I was looking for something like this, petty it's not here yet, building my own now :)

Has anyone given any thought already how this should be done?
My approach is having two steps, the first validates the password, pulls up the user details, and sends the OTP(SMS), the second step validates the OTP the user entered.
Each step uses a filter, the first is just UsernamePasswordAuthenticationFilter, with a custom UserDetailsService which pulls up the user, gives it a temporary role, and sends the OTP (After validating the password, to prevent OTP spam :) ). Both the OTP and the full authorities for the user are stored in the principal.
The second filter checks for the temporary role, and grabs the OTP the user entered, which is then checked by a custom AuthenticationProvider which validates the OTP, and if it matches sets the authentication of the user to those stored in the principal.

Right now I'm struggeling with setting up some proper events for all this, I rely on events for audit logging, but I'm getting two succesfull authentication events with my current setup ;)

(Oh, shouldn't there be a link to SEC-2824 from here too?)

@spring-projects-issues
Copy link
Author

Jeroen Cranendonk said:

Some related resources I found and which I based my approach on, might help someone:
https://github.com/altfatterz/two-step-login (very basic approach, and uses a MVC controller for the second step instead of a filter).
https://github.com/kyleboon/two-step-authentication-example (Closer to what I do, but goes to the user 'database' twice I think, while I reuse the principal from the first step).

@spring-projects-issues
Copy link
Author

Jeroen Cranendonk said:

Noticed a issue with the setup as I described above, sending the OTP from the UserDetailsService means sending it on a faulty password too, which isn't a great plan.

Instead I now made a wrapping provider, which I stick above the dao provider, makes for cleaner separation anyways :)

@spring-projects-issues spring-projects-issues added Open type: jira An issue that was migrated from JIRA labels Feb 5, 2016
@spring-projects-issues spring-projects-issues added this to the 4.0 Backlog milestone Feb 5, 2016
@thomasdarimont
Copy link
Contributor

the guys from projectlombok recently gave a talk about MFA with TOTP - might be a good inspiration: https://github.com/rzwitserloot/totp-example

@rwinch
Copy link
Member

rwinch commented Apr 8, 2016

Thanks @thomasdarimont!

@thomasdarimont
Copy link
Contributor

actually I even started porting this to spring security ;-)

@rwinch
Copy link
Member

rwinch commented Apr 8, 2016

@thomasdarimont Would love to see a pull request :-D or even a sample thrown together

@ynojima
Copy link
Contributor

ynojima commented Apr 2, 2018

Hi, I'm implementing AuthenticationProvider for Web Authnetication specification (https://www.w3.org/TR/webauthn/), which is successor of FIDO 2.0, and became W3C Candidate Recommendation recently.
https://github.com/ynojima/spring-security-webauthn

I implement AuthenticationProvider for Spring Security study. It is still a proof of concept, but in future, I'd like to send pull request. I'll be happy if you look into it.
(for more details about Web Authentication, see this article: https://hacks.mozilla.org/2018/01/using-hardware-token-based-2fa-with-the-webauthn-api/)

Sample application which works with Firefox Beta and FIDO-U2F device like Yubikey is provided.
(Please see the reference for instruction)

I have a favor to ask for Spring Security core to have some foundation class for multi factor authentication. It is desired to have a way to indicate a user who passed first step of multi step (factor) authentication. The status is: "not yet authenticated, but the user is identified". Since FIDO-U2F device needs keyHandle stored in server associated with user id for its authentication step, user need to be identified in the first step.
(See Section 3. Application-specific keys in https://developers.yubico.com/U2F/Protocol_details/Overview.html)

PullRequest for it: #5196

I made a new AuthenticationToken named FirstOfMultiFactorAuthenticationToken for it, and have AuthenticationTrustResolverImpl#isAnonymous return true for the token.
( At first, I tried to have the token just inherit AnonymousAuthenticationToken, but I found AnonymousAuthenticationToken is handled by HttpSessionSecurityContextRepository in a special manner,
so I had to modify Spring Security core a bit.)

I hope you enjoy the PoC.

@rwinch rwinch added type: enhancement A general enhancement and removed Open labels May 3, 2019
@ptahchiev
Copy link

Wow, I can't believe this issue is still open.

@bensiegler
Copy link

bensiegler commented Jul 29, 2021

Hi @rwinch,

As was recommended to me on Gitter, I'm reaching out here to talk about the required features for a Spring Security 2FA implementation.

So far I have a configuration that supports MFA as specified in https://datatracker.ietf.org/doc/html/rfc4226 and a interface for spring users to implement their own code sending logic.

The implementation also supports custom redirect URLs, success and failure handlers and default and custom login pages, varying code generation strategies and different code storage locations. The intermediate saving of codes and login attempts is all based on JSESSIONIDs but could be updated to be an unauthenticated token.

As of now, the configuration in a WebSecurityConfigurerAdapter looks like this:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .twoFactorLogin()
            .sendStrategy(new AwsEmailSendStrategy())
            .loginPage("/login").permitAll()
            .codeService()
                .inMemoryRepository(cache)
                .generationStrategy(new SixDigitAuthCodeGenerationStrategy())
                .expirationTime(45000)
                .and()
            .twoFactorRedirectUrl("/2FA")
            .twoFactorProcessingUrl("/2FA/authenticate")
            .failureUrl("/login?error=true")
            .twoFactorFailureUrl("/2FA?error=true")
            .defaultSuccessUrl("/")
            .userDetailsService(userDetailService)

            .and()
            .logout().permitAll()
            .and()
            .authorizeRequests()
            .anyRequest().authenticated();
}

But to make this whole system work I had to change the UserDetails interface. I added two abstract methods:

/**
	 * Indicates whether the user has activated two factor authentication. Applications that
	 * do not use two factor authentication can set this to return false always.
	 * @return <code>true</code> if the user has activated 2FA. Returns <code>false</code> otherwise
	 */
	boolean isTwoFactorAuthEnabled();

	/**
	 * Indicates where the user has specified they would like their two factor authentication codes
	 * to be sent. The integer integer key represents the preference, and the string represents either
	 * a send location or a key used to generate a TOTP code (see https://datatracker.ietf.org/doc/html/rfc4226)
	 * @return A Hashmap of where the two factor authentication code should be sent/how they should be calculated
	 */
	HashMap<Integer, TwoFactorPreference> getTwoFactorAuthPreferences();

I don't know if this is a big no no and I need to find a work around or if its cool.

I also see there are a number of a different features I have not yet considered listed above, but I'd also like some feedback on how im doing so far and what else I need to add.

@chenrujun
Copy link
Contributor

Hi, dear spring-security developers.

Do you have plan to implement the MFA feature?

@bensiegler
Copy link

@rwinch I am looking to revisit / further implement this. Any suggestions on how to proceed?

@bensiegler
Copy link

still hoping to continue working on all the above. any suggestions / ideas @rwinch @jzheaux

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement A general enhancement type: jira An issue that was migrated from JIRA
Projects
None yet
Development

No branches or pull requests

7 participants