Closed RonRademaker closed 4 years ago
Do the admin UI and the API share the same firewall? If not, would it be possible to give each one its own firewall? Would make things much easier. Ideally, please share your security.yaml
so I get a better idea how your application works.
A question that I can already anwer.
How can I config the same provider twice (I want to use a different server_name and issuer for each interface)
You can't. You could try to do some dependency-injection magic and inject different values into scheb_two_factor.security.google_totp_factory
depending on the context. Or duplicate all the code for the Google Authenticator provider as a custom provider. But then it would be not the same Google Authenticator provider, you'd need to have it configured twice for each user, one for the UI, another one for the API.
Thanks for the quick reply, I use two firewalls:
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
admin:
pattern: ^/admin
anonymous: ~
form_login:
login_path: /admin/inloggen
check_path: /admin/login_check
default_target_path: /admin
logout:
path: /admin/logout
target: easyadmin
two_factor:
auth_form_path: 2fa_login
check_path: 2fa_login_check
guard:
authenticators:
- ConnectHolland\UserBundle\Security\UserBundleAuthenticator
api_login:
pattern: ^/api/users/authenticate
stateless: true
anonymous: true
provider: app_user_provider
json_login:
check_path: /api/users/authenticate
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
api:
pattern: ^/api
stateless: true
anonymous: true
provider: app_user_provider
json_login:
check_path: /api/users/authenticate
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: lexik_jwt_authentication.handler.authentication_failure
require_previous_session: false
guard:
authenticators:
- lexik_jwt_authentication.jwt_token_authenticator
I see a problem there: your API has stateless security. To do two-factor authentication you have to keep some state between requests, because you have to know if the user has already passed 2fa or not. Normally, this is done through security token/session management.
There is no easy way to do this. I had a discussion a while ago on the same issue: https://github.com/scheb/two-factor-bundle/issues/141
As an outcome of this discussion, some new configuration options for custom handlers have been added to the bundle. They allow you to customize the handlers so that they return an API response instead of doing the default behavior (redirecting).
# config/packages/security.yaml
security:
firewalls:
yourFirewallName:
two_factor:
success_handler: acme.custom_success_handler # Use a custom success handler instead of the default one
failure_handler: acme.custom_failure_handler # Use a custom failure handler instead of the default one
# Use a custom authentication required handler instead of the default one
# This can be used to modify the default behavior of the bundle, which is always redirecting to the
# two-factor authentication form, when two-factor authentication is required.
authentication_required_handler: acme.custom_auth_reqired_handler
And you should also replace lexik_jwt_authentication.handler.authentication_success
with a custom implementation that checks if a TwoFactorToken
is present. In that case return the "you have to do 2fa" API response, otherwise fall-back to the behavior of lexik_jwt_authentication.handler.authentication_success
.
The tricky part is in fact how to restore TwoFactorToken
in suceeding requests as long as the 2fa hasn't been completed yet. That's the thing you'd need to find out, maybe this post no 2) works for you?
Would be curious to learn if that approach works. I'd like to write a little "how-to" for stateless firewalls, because that question is coming up every once in a while.
Thanks for the solution direction, I'll let you know if I can get things to work.
I got 2FA on JWT working, but took a different approach.
I create a security provider (as described in https://symfony.com/doc/current/security/custom_authentication_provider.html) that:
@RonRademaker Could you please share your solution?
Hello @tumbochka, I plan to open source our solution next week
@RonRademaker Could you please share your solution?
I've made an open source bundle that has several options to make JWT more secure, including a 2FA implementation, at https://github.com/ConnectHolland/secure-jwt-bundle
Bundle version: v4.14.0 Symfony version: 4.4.7
Description I have an application that has two interfaces, a traditional (twig based) admin and an API (powered by API platform and lexik JWT for authentication). I want to add two factor authentication to both interfaces, preferably both with Google Authenticator. Now, for the admin interface this is pretty straight forward, but it gets complex for the API. A few of my issues:
Thanks!