Skip to content

Support WebAuthn #5238

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
rwinch opened this issue Apr 16, 2018 · 13 comments
Open

Support WebAuthn #5238

rwinch opened this issue Apr 16, 2018 · 13 comments
Assignees
Labels
in: web An issue in web modules (web, webmvc) theme: mfa Related to multi-factor authentication, & building blocks for MFA (such as WebAuthN & passkeys) type: enhancement A general enhancement

Comments

@rwinch
Copy link
Member

rwinch commented Apr 16, 2018

Summary

https://www.w3.org/TR/webauthn

Work on this was started in gh-6842 but stalled. The work is still in https://github.com/rwinch/spring-security-webauthn

@ynojima
Copy link
Contributor

ynojima commented Apr 17, 2018

Hello @rwinch,
As I've commented on #2603 (comment), I'm implementing WebAuthn for spring-security (https://github.com/ynojima/spring-security-webauthn).
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.

@rwinch
Copy link
Member Author

rwinch commented Apr 17, 2018

@ynojima Thank you for reaching out (again) and pointing me to your comment! Sorry I had missed your comment. Let's move all of the discussion to here going forward.

I'd love for you to send a pull request. I will review your proof of concept and pull request this week.

Thanks again!

@rwinch rwinch added the status: waiting-for-triage An issue we've not yet triaged label Apr 17, 2018
@rwinch rwinch self-assigned this Apr 17, 2018
@ynojima
Copy link
Contributor

ynojima commented Apr 19, 2018

Thank you for your reply, and here is a separate pull request to make a foundation for multi-factor authentication in spring security: #5196
My spring-security-webauthn is built on the top of it, and other kind multi-factor(step) authentication provider may utilize it to indicate a user who passed the first authentication.

@rwinch
Copy link
Member Author

rwinch commented Apr 19, 2018

Thanks! I'm taking a look at your sample now.

@rwinch
Copy link
Member Author

rwinch commented Apr 19, 2018

Thank you for putting this together. I have tried the sample in both FireFox and Chrome.

In Chrome 65.0.3325.181 with Web Authentication API I attempt to register my U2F FIDO key on the register page and it gives me the following error in my Boot application:

2018-04-19 17:00:22.195 ERROR 9086 --- [nio-8080-exec-8] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.webauthn4j.exception.NotImplementedException] with root cause

com.webauthn4j.exception.NotImplementedException: null
        at com.webauthn4j.context.validator.attestation.FIDOU2FAttestationStatementValidator.validateTrustworthiness(FIDOU2FAttestationStatementValidator.java:58)
        at com.webauthn4j.context.validator.attestation.AbstractAttestationStatementValidator.validate(AbstractAttestationStatementValidator.java:15)
        at com.webauthn4j.context.validator.WebAuthnRegistrationContextValidator.validateAttestationStatement(WebAuthnRegistrationContextValidator.java:117)
        at com.webauthn4j.context.validator.WebAuthnRegistrationContextValidator.validate(WebAuthnRegistrationContextValidator.java:105)
        at net.sharplab.springframework.security.webauthn.WebAuthnRegistrationRequestValidator.validate(WebAuthnRegistrationRequestValidator.java:27)
        at net.sharplab.springframework.security.webauthn.sample.app.web.helper.AuthenticatorHelper.lambda$validateAuthenticators$0(AuthenticatorHelper.java:46)
        at java.util.stream.MatchOps$1MatchSink.accept(MatchOps.java:90)
        at java.util.ArrayList$ArrayListSpliterator.tryAdvance(ArrayList.java:1359)
        at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
        at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:498)
        at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485)
        at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
        at java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:230)
        at java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:196)
        at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.util.stream.ReferencePipeline.allMatch(ReferencePipeline.java:454)
        at net.sharplab.springframework.security.webauthn.sample.app.web.helper.AuthenticatorHelper.validateAuthenticators(AuthenticatorHelper.java:43)
        at net.sharplab.springframework.security.webauthn.sample.app.web.SignupController.create(SignupController.java:68)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:870)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:776)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:978)
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:881)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:855)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.terasoluna.gfw.web.exception.ExceptionLoggingFilter.doFilter(ExceptionLoggingFilter.java:100)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:127)
        at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at net.sharplab.springframework.security.webauthn.metadata.MetadataEndpointFilter.doFilter(MetadataEndpointFilter.java:67)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:124)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)

In FireFox 60.0b13 I am able to register the key, but then upon trying to use it to log in a modal dialog pops up very quickly and then disappears. I also see the following error the console

Credential Management API is not supported.
loginViewModel.js:127
LoginViewModel.prototype.tryLoginWithSavedPasswordCredential/<
loginViewModel.js:127

Can you please help me try to sort out these issues?

@ynojima
Copy link
Contributor

ynojima commented Apr 20, 2018

Hi Rob, it seems Chrome 65.0.3325.181 has not implemented AttestationConveyancePreference(https://www.w3.org/TR/webauthn/#attestation-convey), which is used in the sample. Because of it, chrome 65 provides full authenticator attestation, which is optional in WebAuthn Candidate Recomendation, but my PoC cannot validate it for now.

Chrome 66, which was released very recently(https://chromereleases.googleblog.com/2018/04/stable-channel-update-for-desktop.html), has implemented AttestationConveyancePreference.
Please update Chrome to latest stable version and try again.

Regarding FireFox 60.0b13, which button in the login page did you use, "Login" or "Password-less Login"? For FIDO-U2F key, "Password-less Login" button doesn't work. It is for user verifying authenticator like finger print sensor.
If you are using the "Login" button but still facing the trouble, could you close the Firefox Developer Tools and try again?
I'm not sure the reason why, but it interfer login page to work.

@ynojima
Copy link
Contributor

ynojima commented Apr 21, 2018

Thank you so much for your review to my pull request. I understand the importance of backward-compatibility. I made change to my patch to keep the existing interface as is.
I opened a new pull request within my forked spring-security repository for review (not for merge).
https://github.com/ynojima/spring-security/pull/3/files

Could you check the design again? I agree with you that it is not appropriate time to merge the pull request since the user facing code is not ready, but spring-security-webauthn is built on the top of the pull request, I'd like to fix the design to handle multi factor authentication flow.

@ynojima
Copy link
Contributor

ynojima commented Jul 26, 2018

Hi @rwinch,
I'd like to reboot this thread.

After your review comment, I made a lot of changes to my project (spring-security-webauthn).

  • The patch to spring-security project has changed not to break existing interface.

  • Registration flow and authentication flows are explained in the reference document.

  • Improved code quality by measuring with SonarQube

  • lots of bugfix

There is still room to be improved in the sample application, but the library itself is feature complete for the initial release. I appreciate if you review spring-security-webauthn and the patch again.

@rwinch rwinch removed their assignment Jul 29, 2019
@rwinch rwinch added in: web An issue in web modules (web, webmvc) type: enhancement A general enhancement Epic and removed status: waiting-for-triage An issue we've not yet triaged Epic labels Nov 7, 2019
@hohwille
Copy link

hohwille commented Aug 7, 2020

@ynojima
Copy link
Contributor

ynojima commented Aug 7, 2020

https://github.com/webauthn4j/webauthn4j-spring-security is a playground to test new design.
For implentation that intended to be merged into spring-security upstream, I'll keep using
https://github.com/ynojima/spring-security-webauthn or
https://github.com/ynojima/spring-security

@asaikali
Copy link

Example implementation of WebAuthn and Spring Security using the Yubico libs https://github.com/asaikali/devnexus-2022/tree/main/webauthn-basics

@rwinch rwinch self-assigned this Jun 30, 2023
@sjohnr sjohnr added theme: mfa Related to multi-factor authentication, & building blocks for MFA (such as WebAuthN & passkeys) and removed theme-proposal: emerging-standards labels Jul 6, 2023
@guycall
Copy link

guycall commented Oct 8, 2024

I found the https://github.com/rwinch/spring-security-webauthn project via the recent Spring One presentation. The readme mentions "... eventually be merged into Spring Security."

The youtube comments of the Spring One presentation had a comment, possibly from @marcusdacoregio, that it might be ready for Spring Security 6.4. Is that the plan or will it more likely be 7.0?

@JohnNiang
Copy link
Contributor

@guycall , I found #13305 was closed by b0e8730. And the feature was released into 6.4.0-RC1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web An issue in web modules (web, webmvc) theme: mfa Related to multi-factor authentication, & building blocks for MFA (such as WebAuthN & passkeys) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

8 participants