-
Notifications
You must be signed in to change notification settings - Fork 6.1k
WebAuthn support #6842
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
WebAuthn support #6842
Changes from all commits
6e0527c
6a85631
d7981e3
e7ba6bf
be92253
b430a71
ca07572
c9411eb
ba25a7e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Copyright 2002-2018 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.security.config.annotation.authentication.configurers.mfa; | ||
|
||
import org.springframework.security.authentication.*; | ||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter; | ||
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder; | ||
|
||
/** | ||
* Allows configuring a {@link MultiFactorAuthenticationProvider} | ||
* | ||
* @param <B> the type of the {@link ProviderManagerBuilder} | ||
* | ||
* @author Yoshikazu Nojima | ||
*/ | ||
public class MultiFactorAuthenticationProviderConfigurer<B extends ProviderManagerBuilder<B>> | ||
extends SecurityConfigurerAdapter<AuthenticationManager, B> { | ||
|
||
//~ Instance fields | ||
// ================================================================================================ | ||
private AuthenticationProvider authenticationProvider; | ||
private MFATokenEvaluator mfaTokenEvaluator = new MFATokenEvaluatorImpl(); | ||
|
||
/** | ||
* Constructor | ||
* @param authenticationProvider {@link AuthenticationProvider} to be delegated | ||
*/ | ||
public MultiFactorAuthenticationProviderConfigurer(AuthenticationProvider authenticationProvider) { | ||
this.authenticationProvider = authenticationProvider; | ||
} | ||
|
||
|
||
public static MultiFactorAuthenticationProviderConfigurer multiFactorAuthenticationProvider(AuthenticationProvider authenticationProvider){ | ||
return new MultiFactorAuthenticationProviderConfigurer(authenticationProvider); | ||
} | ||
|
||
@Override | ||
public void configure(B builder) { | ||
MultiFactorAuthenticationProvider multiFactorAuthenticationProvider = new MultiFactorAuthenticationProvider(authenticationProvider, mfaTokenEvaluator); | ||
multiFactorAuthenticationProvider = postProcess(multiFactorAuthenticationProvider); | ||
builder.authenticationProvider(multiFactorAuthenticationProvider); | ||
} | ||
|
||
public MultiFactorAuthenticationProviderConfigurer<B> mfaTokenEvaluator(MFATokenEvaluator mfaTokenEvaluator) { | ||
this.mfaTokenEvaluator = mfaTokenEvaluator; | ||
return this; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* | ||
* Copyright 2002-2018 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.security.authentication; | ||
|
||
import org.springframework.security.core.Authentication; | ||
|
||
/** | ||
* Evaluates <code>Authentication</code> tokens | ||
* | ||
* @author Yoshikazu Nojima | ||
*/ | ||
public interface MFATokenEvaluator { | ||
|
||
/** | ||
* Indicates whether the passed <code>Authentication</code> token represents a | ||
* user in the middle of multi factor authentication process. | ||
* | ||
* @param authentication to test (may be <code>null</code> in which case the method | ||
* will always return <code>false</code>) | ||
* | ||
* @return <code>true</code> the passed authentication token represented a principal | ||
* in the middle of multi factor authentication process, <code>false</code> otherwise | ||
*/ | ||
boolean isMultiFactorAuthentication(Authentication authentication); | ||
|
||
/** | ||
* Indicates whether the principal associated with the <code>Authentication</code> | ||
* token is allowed to login with only single factor. | ||
* | ||
* @param authentication to test (may be <code>null</code> in which case the method | ||
* will always return <code>false</code>) | ||
* | ||
* @return <code>true</code> the principal associated with thepassed authentication | ||
* token is allowed to login with only single factor, <code>false</code> otherwise | ||
*/ | ||
boolean isSingleFactorAuthenticationAllowed(Authentication authentication); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The APIs need to consider that multi factor authentication is really an authorization requirement. It isn't sufficient to be able to answer if single factor authentication allowed. There needs to be the ability to answer: Does any specific part of the application require another authentication factor? If so, we need to be able to request that specific factor from the user. There might be different types of factors that are triggered at different places within the application. A page that uses a credit card might require that the user has submitted their password again recently, a user with settings enabled for MFA may require the user to enter a code sent over SMS to access any part of the application, an administrator may require FIDO2 to access administrative parts of the applications, etc. A possibility is that we should set these rules using granted authorities. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The objective of this API is to check the user is allowed to login with single authentication factor or not. To realize access-controll based on authentication level, yes, we should use granted authority. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
/* | ||
* Copyright 2002-2018 the original author or authors. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.springframework.security.authentication; | ||
|
||
import org.springframework.security.core.Authentication; | ||
import org.springframework.security.core.userdetails.MFAUserDetails; | ||
|
||
/** | ||
* Basic implementation of {@link MFATokenEvaluator}. | ||
* <p> | ||
* Makes trust decisions based on whether the passed <code>Authentication</code> is an | ||
* instance of a defined class. | ||
* <p> | ||
* If {@link #multiFactorClass} is <code>null</code>, the | ||
* corresponding method will always return <code>false</code>. | ||
* | ||
* @author Yoshikazu Nojima | ||
*/ | ||
public class MFATokenEvaluatorImpl implements MFATokenEvaluator { | ||
|
||
private Class<? extends Authentication> multiFactorClass = MultiFactorAuthenticationToken.class; | ||
private boolean singleFactorAuthenticationAllowed = true; | ||
|
||
@Override | ||
public boolean isMultiFactorAuthentication(Authentication authentication) { | ||
if ((multiFactorClass == null) || (authentication == null)) { | ||
return false; | ||
} | ||
|
||
return multiFactorClass.isAssignableFrom(authentication.getClass()); | ||
} | ||
|
||
@Override | ||
public boolean isSingleFactorAuthenticationAllowed(Authentication authentication) { | ||
if (singleFactorAuthenticationAllowed && authentication.getPrincipal() instanceof MFAUserDetails) { | ||
MFAUserDetails webAuthnUserDetails = (MFAUserDetails) authentication.getPrincipal(); | ||
return webAuthnUserDetails.isSingleFactorAuthenticationAllowed(); | ||
} | ||
return false; | ||
} | ||
|
||
Class<? extends Authentication> getMultiFactorClass() { | ||
return multiFactorClass; | ||
} | ||
|
||
public void setMultiFactorClass(Class<? extends Authentication> multiFactorClass) { | ||
this.multiFactorClass = multiFactorClass; | ||
} | ||
|
||
/** | ||
* Check if single factor authentication is allowed | ||
* | ||
* @return true if single factor authentication is allowed | ||
*/ | ||
public boolean isSingleFactorAuthenticationAllowed() { | ||
return singleFactorAuthenticationAllowed; | ||
} | ||
|
||
/** | ||
* Set single factor authentication is allowed | ||
* | ||
* @param singleFactorAuthenticationAllowed true if single factor authentication is allowed | ||
*/ | ||
public void setSingleFactorAuthenticationAllowed(boolean singleFactorAuthenticationAllowed) { | ||
this.singleFactorAuthenticationAllowed = singleFactorAuthenticationAllowed; | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user is not anonymous if the token is a multi factor authentication. This implementation should not consult
isMultiFactorAuthentication
to determine if the user is authenticatedThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MultiFactorAuthenticationToken
represents a principal in the middle of multi factor (stage) authentication.In the case of two-step authentication using a password and a security key, it indicates that the password has already been provided and authentication using the security key has not been completed.
Since authentication has not yet finished fully, I think it is appropriate to treat it as anonymous.
Do you think the name
MultiFactorAuthenticationToken
is inappropriate? I want a suggestion for a good name.