Coder Social home page Coder Social logo

dreezey / argon2-password-hash-provider Goto Github PK

View Code? Open in Web Editor NEW
25.0 3.0 16.0 47 KB

Argon2 Password Hash Provider for Keycloak

License: Apache License 2.0

Java 100.00%
keycloak-provider argon2 password-hashing keycloak ear argon2-password-hashing bouncycastle

argon2-password-hash-provider's Introduction

Introduction

This project introduces Argon2 Password Hashing for Keycloak, there are 2 versions:

  • V1.x, which uses de.mkammerer.argon2 as the library, more can be found on the GitHub Project. (Compatible with Keycloak V8.x and above)
  • V2.x, which inherits Keycloak's BouncyCastle V1.62 with native support for Argon2 (Compatible with Keycloak V10.x and above only)

V1.x is packaged as an EAR due to external dependencies. I will no longer maintain this version. Choose this one if you don't Keycloak V10.x or above.

V2.x is packaged as a JAR since it uses Keycloak's provided libraries. This will be the actively maintained version for now.

Both are deployed using Keycloak Deployer.

Build

Build the project using:

mvn clean package;

This will build the provider JAR:

[INFO] ----------< be.cronos.keycloak:argon2-password-hash-provider >----------
[INFO] Building Argon2 Password Hash Provider 2.x.x
[INFO] --------------------------------[ jar ]---------------------------------

Installation

Simply hot-deploy the module:

cp target/argon2-password-hash-provider-*.jar /opt/keycloak/standalone/deployments/argon2-password-hash-provider.jar;

Keycloak configuration

Finally, in the Keycloak realm of your choosing, activate the Argon2 password hashing via: Authentication > Password Policy and then selecting the policy Hashing Algorithm and name it: argon2.

Further tuning can be done by the other Policy Providers:

  • Argon2 Version --> you can choose which Argon2 version to use, either: 10 or 13 (default: 13)
  • Argon2 Variant --> you can choose which Argon2 variant to use, either: ARGON2i, ARGON2d or ARGON2id (default: ARGON2id)
  • Argon2 Iterations --> tune the number of iterations the provider will perform (default: 1)
  • Argon2 Memory Usage --> tune the memory limitation (in KB) of the provider (default: 65536)
  • Argon2 Parallelism --> tune the number of threads and memory lanes (default: 1)
  • Argon2 Salt Length --> tune the length of the salt (default: 16)
  • Argon2 Hash Length --> tune the length of the hash (default: 32)

I have deprecated use of the Argon2 Max Time provider, as I believe it offers no real value. If you still have a use-case for this, let me know.

For parameter optimization, check the Argon2 whitepaper recommendations.

argon2-password-hash-provider's People

Contributors

dependabot[bot] avatar dreezey avatar robertheim avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

argon2-password-hash-provider's Issues

Index 1 out of bounds for length 1

Hi and thanks for the integration!

For existing users, re-hasing their existing passwords on login with another hash algo fails.

I can consistently reproduce it:

There exists a testuser with a hashed password using {"hashIterations":27500,"algorithm":"pbkdf2-sha256"}. This is the default and there was no policy set. Then, I changed the password policy to argon2. Creating a new user is fine. However, when I try to login with the existing testuser I get this error:

keycloak_1  | 15:51:39,472 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-10) Uncaught server error: be.cronos.keycloak.exceptions.Argon2RuntimeException: Index 1 out of bounds for length 1
keycloak_1  | 	at deployment.argon2-password-hash-provider.jar//be.cronos.keycloak.utils.Argon2EncodingUtils.extractArgon2ParametersFromEncodedPassword(Argon2EncodingUtils.java:46)
keycloak_1  | 	at deployment.argon2-password-hash-provider.jar//be.cronos.keycloak.credential.hash.Argon2PasswordHashProvider.policyCheck(Argon2PasswordHashProvider.java:31)
keycloak_1  | 	at [email protected]//org.keycloak.credential.PasswordCredentialProvider.isValid(PasswordCredentialProvider.java:265)
keycloak_1  | 	at [email protected]//org.keycloak.credential.UserCredentialStoreManager.validate(UserCredentialStoreManager.java:187)
keycloak_1  | 	at [email protected]//org.keycloak.credential.UserCredentialStoreManager.isValid(UserCredentialStoreManager.java:177)
keycloak_1  | 	at [email protected]//org.keycloak.credential.UserCredentialStoreManager.isValid(UserCredentialStoreManager.java:112)
keycloak_1  | 	at [email protected]//org.keycloak.authentication.authenticators.directgrant.ValidatePassword.authenticate(ValidatePassword.java:47)
keycloak_1  | 	at [email protected]//org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:443)
keycloak_1  | 	at [email protected]//org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:252)
keycloak_1  | 	at [email protected]//org.keycloak.authentication.AuthenticationProcessor.authenticateOnly(AuthenticationProcessor.java:978)
keycloak_1  | 	at [email protected]//org.keycloak.protocol.oidc.endpoints.TokenEndpoint.resourceOwnerPasswordCredentialsGrant(TokenEndpoint.java:635)
keycloak_1  | 	at [email protected]//org.keycloak.protocol.oidc.endpoints.TokenEndpoint.processGrantRequest(TokenEndpoint.java:220)
keycloak_1  | 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
keycloak_1  | 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
keycloak_1  | 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
keycloak_1  | 	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:138)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:543)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:432)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$0(ResourceMethodInvoker.java:393)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:358)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:395)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:364)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:150)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:110)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:141)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:104)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:440)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:229)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:135)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.interception.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:358)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:138)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:215)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:245)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:61)
keycloak_1  | 	at [email protected]//org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
keycloak_1  | 	at [email protected]//javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
keycloak_1  | 	at [email protected]//org.keycloak.provider.wildfly.WildFlyRequestFilter.lambda$doFilter$0(WildFlyRequestFilter.java:41)
keycloak_1  | 	at [email protected]//org.keycloak.services.filters.AbstractRequestFilter.filter(AbstractRequestFilter.java:43)
keycloak_1  | 	at [email protected]//org.keycloak.provider.wildfly.WildFlyRequestFilter.doFilter(WildFlyRequestFilter.java:39)
keycloak_1  | 	at [email protected]//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
keycloak_1  | 	at [email protected]//org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
keycloak_1  | 	at [email protected]//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
keycloak_1  | 	at [email protected]//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
keycloak_1  | 	at [email protected]//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
keycloak_1  | 	at [email protected]//io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
keycloak_1  | 	at [email protected]//io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
keycloak_1  | 	at [email protected]//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
keycloak_1  | 	at [email protected]//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
keycloak_1  | 	at [email protected]//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
keycloak_1  | 	at [email protected]//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
keycloak_1  | 	at [email protected]//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:68)
keycloak_1  | 	at [email protected]//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
keycloak_1  | 	at [email protected]//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
keycloak_1  | 	at [email protected]//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
keycloak_1  | 	at [email protected]//org.wildfly.extension.undertow.security.SecurityContextThreadSetupAction.lambda$create$0(SecurityContextThreadSetupAction.java:105)
keycloak_1  | 	at [email protected]//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
keycloak_1  | 	at [email protected]//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
keycloak_1  | 	at [email protected]//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
keycloak_1  | 	at [email protected]//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1530)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
keycloak_1  | 	at [email protected]//io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
keycloak_1  | 	at [email protected]//io.undertow.server.Connectors.executeRootHandler(Connectors.java:370)
keycloak_1  | 	at [email protected]//io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
keycloak_1  | 	at [email protected]//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
keycloak_1  | 	at [email protected]//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1982)
keycloak_1  | 	at [email protected]//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
keycloak_1  | 	at [email protected]//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
keycloak_1  | 	at java.base/java.lang.Thread.run(Thread.java:834)

Any idea?

KC 9.0.0 compatibility?

Hi,
I made an attempt to use argon2 in Keycloak v9 -- I think I am missing something here, because Keycloak complains the Password Hashing Provider "argon2" is not found.

Here is my Dockerfile - I'd appreciate your help.

running on docker?

Is there any way to use this module on current docker version of keycloak?

Salt from CredentialModel is wrongly decoded

Hi,
I have found a failing test. This way, salt is wrongly base64 decoded to only 15 bytes instead of 16 and verification fails. Probably more Keycloak bug, but maybe can interest you.

@Test
public void testArgon2iVerifyPredefinedHashFromCredentialModel() {
    String rawPassword = "tekvica";
    CredentialModel credentialModel = new CredentialModel();
    credentialModel.setSecretData("{\"value\":\"$argon2i$v=19$m=16,t=2,p=1$a3I5aE5QR3N0U3VGU05peg$fHjVdRNXcS+bS2D4Vu+IHw\",\"salt\":\"a3I5aE5QR3N0U3VGU05peg\"}");
    credentialModel.setCredentialData("{\"hashIterations\":1,\"algorithm\":\"argon2\"}");
    PasswordCredentialModel passwordCredentialModel = PasswordCredentialModel.createFromCredentialModel(credentialModel);
    boolean verified = Argon2Helper.verifyPassword(rawPassword, passwordCredentialModel);
    Assert.assertTrue(verified);
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.