From 83afe06c7305134e250fc6be14df8221ab88b252 Mon Sep 17 00:00:00 2001 From: cooper Date: Fri, 9 Aug 2024 15:00:34 +0800 Subject: [PATCH] ConditionalPhoneProvided Negate output set default value --- README.md | 17 +- examples/docker-compose.yml | 2 +- keycloak-phone-provider.resources/pom.xml | 2 +- keycloak-phone-provider/pom.xml | 2 +- ...uthenticationCodeAuthenticatorFactory.java | 2 +- keycloak-sms-provider-aliyun/pom.xml | 4 +- keycloak-sms-provider-aws-sns/pom.xml | 4 +- keycloak-sms-provider-bulksms/pom.xml | 4 +- keycloak-sms-provider-cloopen/pom.xml | 4 +- keycloak-sms-provider-dummy/pom.xml | 4 +- keycloak-sms-provider-tencent/pom.xml | 4 +- keycloak-sms-provider-totalvoice/pom.xml | 4 +- keycloak-sms-provider-twilio/pom.xml | 4 +- keycloak-sms-provider-twofactorapi/pom.xml | 4 +- keycloak-sms-provider-yunxin/pom.xml | 4 +- keycloak-wx-provider-app/pom.xml | 75 +++++++ .../directgrant/WXAppAuthenticator.java | 211 ++++++++++++++++++ .../WXAppAuthenticatorFactory.java | 115 ++++++++++ ...ycloak.authentication.AuthenticatorFactory | 1 + pom.xml | 3 +- 20 files changed, 444 insertions(+), 26 deletions(-) create mode 100644 keycloak-wx-provider-app/pom.xml create mode 100644 keycloak-wx-provider-app/src/main/java/cc/coopersoft/keycloak/wx/app/providers/directgrant/WXAppAuthenticator.java create mode 100644 keycloak-wx-provider-app/src/main/java/cc/coopersoft/keycloak/wx/app/providers/directgrant/WXAppAuthenticatorFactory.java create mode 100755 keycloak-wx-provider-app/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory diff --git a/README.md b/README.md index 340b40ea..85ada52a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Keycloak (Quarkus 21.x.x) Phone Provider +# Keycloak (Quarkus 25.x.x) Phone Provider - Bate ![Build Status](https://github.com/cooperlyt/keycloak-phone-provider/actions/workflows/compile-and-liveness-check.yml/badge.svg) ![ci](https://github.com/cooperlyt/keycloak-phone-provider/actions/workflows/ci-keycloak20.yml/badge.svg) ![ci](https://github.com/cooperlyt/keycloak-phone-provider/actions/workflows/ci-keycloak21.yml/badge.svg) @@ -23,6 +23,7 @@ Currently, there are implementations for: + TotalVoice + Twilio, + YunTongXun SMS ++ WeiXin App grant More services can be added with ease due to the modularity of the code. In fact, nothing would stop you from implementing a sender of TTS calls or WhatsApp messages. @@ -276,6 +277,20 @@ Set Bind `Reset credentials with phone` to `Reset credentials flow` + `Update Phone Number` update user's phone number on next login. + `Configure OTP over SMS` update OTP Credential's phone number on next login. +## ** WeiXin APP Grant + +Under `Authentication` > `Flows`: ++ Copy the `Direct Grant` flow to `Direct grant weixin app ` flow ++ Click on `Actions` > `Add step` on the `WX APP auth` line and move to first ++ Delete or disable other + +Under `Clients` > `$YOUR_CLIENT` > `Advanced` > `Authentication Flow Overrides` +Set Direct Grant Flow to `Direct grant weixin app` + + ++ `POST /realms/{realmName}/protocol/openid-connect/token` + `Content-Type: application/x-www-form-urlencoded` + `grant_type=password&code=$CODE&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRECT` **Phone one key login** diff --git a/examples/docker-compose.yml b/examples/docker-compose.yml index f679c2af..574ad170 100644 --- a/examples/docker-compose.yml +++ b/examples/docker-compose.yml @@ -21,7 +21,7 @@ services: keycloak: - image: coopersoft/keycloak:21.0.1_phone-2.2.2 + image: coopersoft/keycloak:25.0.2_phone-2.4.1-snapshot # restart: always ports: - 8080:8080 diff --git a/keycloak-phone-provider.resources/pom.xml b/keycloak-phone-provider.resources/pom.xml index be438464..a0ba9bba 100644 --- a/keycloak-phone-provider.resources/pom.xml +++ b/keycloak-phone-provider.resources/pom.xml @@ -7,7 +7,7 @@ cc.coopersoft keycloak-phone-provider-parent - 2.3.4-snapshot + 2.4.1-snapshot keycloak-phone-provider.resources diff --git a/keycloak-phone-provider/pom.xml b/keycloak-phone-provider/pom.xml index 2c150073..b6f09b17 100644 --- a/keycloak-phone-provider/pom.xml +++ b/keycloak-phone-provider/pom.xml @@ -7,7 +7,7 @@ cc.coopersoft keycloak-phone-provider-parent - 2.3.4-snapshot + 2.4.1-snapshot keycloak-phone-provider diff --git a/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/authentication/authenticators/directgrant/AuthenticationCodeAuthenticatorFactory.java b/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/authentication/authenticators/directgrant/AuthenticationCodeAuthenticatorFactory.java index 4669c6da..08d78450 100644 --- a/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/authentication/authenticators/directgrant/AuthenticationCodeAuthenticatorFactory.java +++ b/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/authentication/authenticators/directgrant/AuthenticationCodeAuthenticatorFactory.java @@ -39,7 +39,7 @@ public Authenticator create(KeycloakSession session) { return new AuthenticationCodeAuthenticator(session); } - private static AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { + private static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { AuthenticationExecutionModel.Requirement.REQUIRED, // AuthenticationExecutionModel.Requirement.DISABLED }; diff --git a/keycloak-sms-provider-aliyun/pom.xml b/keycloak-sms-provider-aliyun/pom.xml index 8aa90ebe..3dd669e3 100644 --- a/keycloak-sms-provider-aliyun/pom.xml +++ b/keycloak-sms-provider-aliyun/pom.xml @@ -5,7 +5,7 @@ keycloak-phone-provider-parent cc.coopersoft - 2.3.4-snapshot + 2.4.1-snapshot 4.0.0 @@ -16,7 +16,7 @@ cc.coopersoft keycloak-phone-provider - 2.3.4-snapshot + 2.4.1-snapshot provided diff --git a/keycloak-sms-provider-aws-sns/pom.xml b/keycloak-sms-provider-aws-sns/pom.xml index e165230e..0fcdedca 100755 --- a/keycloak-sms-provider-aws-sns/pom.xml +++ b/keycloak-sms-provider-aws-sns/pom.xml @@ -7,7 +7,7 @@ cc.coopersoft keycloak-phone-provider-parent - 2.3.4-snapshot + 2.4.1-snapshot keycloak-sms-provider-aws-sns @@ -16,7 +16,7 @@ cc.coopersoft keycloak-phone-provider - 2.3.4-snapshot + 2.4.1-snapshot provided diff --git a/keycloak-sms-provider-bulksms/pom.xml b/keycloak-sms-provider-bulksms/pom.xml index 4ad6ce18..1059781c 100644 --- a/keycloak-sms-provider-bulksms/pom.xml +++ b/keycloak-sms-provider-bulksms/pom.xml @@ -7,7 +7,7 @@ cc.coopersoft keycloak-phone-provider-parent - 2.3.4-snapshot + 2.4.1-snapshot keycloak-sms-provider-bulksms @@ -16,7 +16,7 @@ cc.coopersoft keycloak-phone-provider - 2.3.4-snapshot + 2.4.1-snapshot provided diff --git a/keycloak-sms-provider-cloopen/pom.xml b/keycloak-sms-provider-cloopen/pom.xml index ebacb560..e2c12d3d 100644 --- a/keycloak-sms-provider-cloopen/pom.xml +++ b/keycloak-sms-provider-cloopen/pom.xml @@ -5,7 +5,7 @@ cc.coopersoft keycloak-phone-provider-parent - 2.3.4-snapshot + 2.4.1-snapshot 4.0.0 @@ -15,7 +15,7 @@ cc.coopersoft keycloak-phone-provider - 2.3.4-snapshot + 2.4.1-snapshot provided diff --git a/keycloak-sms-provider-dummy/pom.xml b/keycloak-sms-provider-dummy/pom.xml index 455bc3d7..c7dc4f8d 100644 --- a/keycloak-sms-provider-dummy/pom.xml +++ b/keycloak-sms-provider-dummy/pom.xml @@ -7,7 +7,7 @@ cc.coopersoft keycloak-phone-provider-parent - 2.3.4-snapshot + 2.4.1-snapshot keycloak-sms-provider-dummy @@ -16,7 +16,7 @@ cc.coopersoft keycloak-phone-provider - 2.3.4-snapshot + 2.4.1-snapshot provided diff --git a/keycloak-sms-provider-tencent/pom.xml b/keycloak-sms-provider-tencent/pom.xml index 45481aa7..aa23162b 100644 --- a/keycloak-sms-provider-tencent/pom.xml +++ b/keycloak-sms-provider-tencent/pom.xml @@ -5,7 +5,7 @@ keycloak-phone-provider-parent cc.coopersoft - 2.3.4-snapshot + 2.4.1-snapshot 4.0.0 @@ -16,7 +16,7 @@ cc.coopersoft keycloak-phone-provider - 2.3.4-snapshot + 2.4.1-snapshot provided diff --git a/keycloak-sms-provider-totalvoice/pom.xml b/keycloak-sms-provider-totalvoice/pom.xml index 84eff5c5..55dad008 100644 --- a/keycloak-sms-provider-totalvoice/pom.xml +++ b/keycloak-sms-provider-totalvoice/pom.xml @@ -7,7 +7,7 @@ cc.coopersoft keycloak-phone-provider-parent - 2.3.4-snapshot + 2.4.1-snapshot keycloak-sms-provider-totalvoice @@ -16,7 +16,7 @@ cc.coopersoft keycloak-phone-provider - 2.3.4-snapshot + 2.4.1-snapshot provided diff --git a/keycloak-sms-provider-twilio/pom.xml b/keycloak-sms-provider-twilio/pom.xml index e5575590..645787c1 100644 --- a/keycloak-sms-provider-twilio/pom.xml +++ b/keycloak-sms-provider-twilio/pom.xml @@ -7,7 +7,7 @@ cc.coopersoft keycloak-phone-provider-parent - 2.3.4-snapshot + 2.4.1-snapshot keycloak-sms-provider-twilio @@ -16,7 +16,7 @@ cc.coopersoft keycloak-phone-provider - 2.3.4-snapshot + 2.4.1-snapshot provided diff --git a/keycloak-sms-provider-twofactorapi/pom.xml b/keycloak-sms-provider-twofactorapi/pom.xml index 52e3d292..66b23dea 100644 --- a/keycloak-sms-provider-twofactorapi/pom.xml +++ b/keycloak-sms-provider-twofactorapi/pom.xml @@ -7,7 +7,7 @@ cc.coopersoft keycloak-phone-provider-parent - 2.3.4-snapshot + 2.4.1-snapshot keycloak-sms-provider-twofactorapi @@ -16,7 +16,7 @@ cc.coopersoft keycloak-phone-provider - 2.3.4-snapshot + 2.4.1-snapshot provided diff --git a/keycloak-sms-provider-yunxin/pom.xml b/keycloak-sms-provider-yunxin/pom.xml index a3a20d4d..176d995c 100644 --- a/keycloak-sms-provider-yunxin/pom.xml +++ b/keycloak-sms-provider-yunxin/pom.xml @@ -5,7 +5,7 @@ keycloak-phone-provider-parent cc.coopersoft - 2.3.4-snapshot + 2.4.1-snapshot 4.0.0 @@ -15,7 +15,7 @@ cc.coopersoft keycloak-phone-provider - 2.3.4-snapshot + 2.4.1-snapshot provided diff --git a/keycloak-wx-provider-app/pom.xml b/keycloak-wx-provider-app/pom.xml new file mode 100644 index 00000000..a2f64258 --- /dev/null +++ b/keycloak-wx-provider-app/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + cc.coopersoft + keycloak-phone-provider-parent + 2.4.1-snapshot + + + keycloak-wx-provider-app + + + 21 + 21 + UTF-8 + + + + + com.squareup.okhttp3 + okhttp + 4.12.0 + + + + + + + maven-assembly-plugin + + + package + + single + + + + + + jar-with-dependencies + + ${project.build.finalName} + false + + + + maven-dependency-plugin + + + package + + copy + + + + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + ../target/providers + true + true + + + + + + + + + \ No newline at end of file diff --git a/keycloak-wx-provider-app/src/main/java/cc/coopersoft/keycloak/wx/app/providers/directgrant/WXAppAuthenticator.java b/keycloak-wx-provider-app/src/main/java/cc/coopersoft/keycloak/wx/app/providers/directgrant/WXAppAuthenticator.java new file mode 100644 index 00000000..3284f07f --- /dev/null +++ b/keycloak-wx-provider-app/src/main/java/cc/coopersoft/keycloak/wx/app/providers/directgrant/WXAppAuthenticator.java @@ -0,0 +1,211 @@ +package cc.coopersoft.keycloak.wx.app.providers.directgrant; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import lombok.Data; +import lombok.NoArgsConstructor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import org.jboss.logging.Logger; +import org.keycloak.authentication.AuthenticationFlowContext; +import org.keycloak.authentication.AuthenticationFlowError; +import org.keycloak.authentication.Authenticator; +import org.keycloak.events.Errors; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.RealmModel; +import org.keycloak.models.UserModel; +import org.keycloak.representations.idm.OAuth2ErrorRepresentation; +import org.keycloak.utils.StringUtil; + +import java.io.IOException; +import java.util.Optional; + +public class WXAppAuthenticator implements Authenticator { + + private static final Logger logger = Logger.getLogger(WXAppAuthenticator.class); + + private static final String CODE_PARAM_NAME = "code"; + + private static final String WX_CODE_TO_SESSION_URI = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"; + + private static final String USER_UNION_ID_ATTRIBUTE = "wx_union_id"; + + private static final String USER_OPEN_ID_ATTRIBUTE = "wx_open_id"; + + @Override + public void authenticate(AuthenticationFlowContext context) { + context.clearUser(); + getCode(context).flatMap(code -> getWXUserSession(context,code)).ifPresent(session -> + validUser(context, session.unionid, session.openid)); + } + + @Override + public void action(AuthenticationFlowContext authenticationFlowContext) { + authenticate(authenticationFlowContext); + } + + @Override + public boolean requiresUser() { + return false; + } + + @Override + public boolean configuredFor(KeycloakSession keycloakSession, RealmModel realmModel, UserModel userModel) { + return true; + } + + @Override + public void setRequiredActions(KeycloakSession keycloakSession, RealmModel realmModel, UserModel userModel) { + } + + @Override + public void close() { + } + + private Response errorResponse(int status, String error, String errorDescription) { + OAuth2ErrorRepresentation errorRep = new OAuth2ErrorRepresentation(error, errorDescription); + return Response.status(status).entity(errorRep).type(MediaType.APPLICATION_JSON_TYPE).build(); + } + + private Optional getCode(AuthenticationFlowContext context) { + String code = context.getHttpRequest().getDecodedFormParameters().getFirst(CODE_PARAM_NAME); + if (StringUtil.isNotBlank(code)){ + return Optional.of(code); + } + context.getEvent().error(Errors.INVALID_REQUEST); + Response challenge = errorResponse(Response.Status.BAD_REQUEST.getStatusCode(), "invalid_request", + "Invalid WX APP grant request, code is must"); + context.failure(AuthenticationFlowError.INVALID_CREDENTIALS, challenge); + return Optional.empty(); + } + + private Optional getWXUserSession(AuthenticationFlowContext context, String code){ + logger.info("WX APP grant request by:" + code); + + return getWXAPICredentials(context).flatMap(cer -> { + OkHttpClient okHttpClient = new OkHttpClient(); + + Request request = new Request.Builder() + .addHeader("content-type", "application/json") + .url(String.format(WX_CODE_TO_SESSION_URI, cer.id, cer.secret, code)) + .get() + .build(); + + + try (okhttp3.Response response = okHttpClient.newCall(request).execute()){ + if (response.isSuccessful() && response.body() != null){ + ObjectMapper objectMapper = new ObjectMapper(); + WXUserSessionInfo result = objectMapper.readValue(response.body().string(), WXUserSessionInfo.class); + logger.debug("wx api result: " + result); + if (result.valid()){ + return Optional.of(result); + } + + logger.error("WX API response invalid " + result.errcode + ":" + result.errmsg); + context.getEvent().error(Errors.INVALID_REQUEST); + Response challenge = errorResponse(Response.Status.BAD_GATEWAY.getStatusCode(), "invalid_wx_api_exception", + "WX API call invalid" + result.errcode + ":" + result.errmsg); + context.failure(AuthenticationFlowError.ACCESS_DENIED, challenge); + return Optional.empty(); + } + + logger.error("WX API call exception, code:" + response.code()); + context.getEvent().error(Errors.INVALID_REQUEST); + Response challenge = errorResponse(Response.Status.BAD_GATEWAY.getStatusCode(), "invalid_wx_api_exception", + "WX API call exception, code:" + response.code()); + context.failure(AuthenticationFlowError.ACCESS_DENIED, challenge); + return Optional.empty(); + + } catch (IOException e) { + logger.error(e.getMessage(),e); + context.getEvent().error(Errors.INVALID_REQUEST); + Response challenge = errorResponse(Response.Status.BAD_GATEWAY.getStatusCode(), "invalid_wx_api_exception", + "WX API call exception"); + context.failure(AuthenticationFlowError.ACCESS_DENIED, challenge); + return Optional.empty(); + } + }); + } + + private boolean isAllowEvery(AuthenticationFlowContext context) { + return context.getAuthenticatorConfig() == null || + context.getAuthenticatorConfig().getConfig().getOrDefault(WXAppAuthenticatorFactory.CONFIG_EVERY, "true") + .equals("true"); + } + + private Optional getWXAPICredentials(AuthenticationFlowContext context){ + + String appid = context.getAuthenticatorConfig().getConfig().get(WXAppAuthenticatorFactory.WX_API_ID); + String secret = context.getAuthenticatorConfig().getConfig().get(WXAppAuthenticatorFactory.WX_API_SECRET); + + if (StringUtil.isNotBlank(appid) && StringUtil.isNotBlank(secret)){ + return Optional.of(new WXAPICredentials(appid,secret)); + } + + context.getEvent().error(Errors.INVALID_REQUEST); + Response challenge = errorResponse(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), "invalid_api_credentials", + "WX API credentials not config"); + context.failure(AuthenticationFlowError.ACCESS_DENIED, challenge); + return Optional.empty(); + + } + + private Optional findUser(AuthenticationFlowContext context, String unionId, String openId){ + + var userProvider = context.getSession().users(); + + return userProvider.searchForUserByUserAttributeStream(context.getRealm(), USER_UNION_ID_ATTRIBUTE, unionId).findFirst() + .or(() -> userProvider.searchForUserByUserAttributeStream(context.getRealm(), USER_OPEN_ID_ATTRIBUTE, openId).findFirst()) + .or(() -> createEveryUser(context,unionId,openId)); + + } + + private Optional createEveryUser(AuthenticationFlowContext context, String unionId, String openId){ + if (isAllowEvery(context)){ + UserModel newUser = context.getSession().users().addUser(context.getRealm(), unionId); + + newUser.setEnabled(true); + newUser.setSingleAttribute(USER_UNION_ID_ATTRIBUTE, unionId); + newUser.setSingleAttribute(USER_OPEN_ID_ATTRIBUTE, openId); + //context.getAuthenticationSession().setClientNote(OIDCLoginProtocol.LOGIN_HINT_PARAM, unionId); + logger.info("create user by wx :" + unionId); + return Optional.of(newUser); + + } + context.getEvent().error(Errors.USER_NOT_FOUND); + Response challenge = errorResponse(Response.Status.FORBIDDEN.getStatusCode(), "invalid_user", + "Invalid WX User:" + unionId); + context.failure(AuthenticationFlowError.INVALID_CREDENTIALS, challenge); + return Optional.empty(); + } + + private void validUser(AuthenticationFlowContext context, String unionId, String openId){ + findUser(context,unionId,openId).ifPresent( + user -> { + context.setUser(user); + context.success(); + } + ); + } + + + @Data + @NoArgsConstructor + private static class WXUserSessionInfo { + private String sessionKey; // 会话密钥 + private String unionid;// 用户在开放平台的唯一标识符,若当前小程序已绑定到微信开放平台账号下会返回,详见 UnionID 机制说明。 + private String errmsg; // 错误信息 + private String openid;// 用户唯一标识 + private int errcode;// int32 错误码 + + public boolean valid(){ + return StringUtil.isNotBlank(unionid) && StringUtil.isNotBlank(openid); + } + + } + + private record WXAPICredentials(String id, String secret) { + + } +} diff --git a/keycloak-wx-provider-app/src/main/java/cc/coopersoft/keycloak/wx/app/providers/directgrant/WXAppAuthenticatorFactory.java b/keycloak-wx-provider-app/src/main/java/cc/coopersoft/keycloak/wx/app/providers/directgrant/WXAppAuthenticatorFactory.java new file mode 100644 index 00000000..8b2387ec --- /dev/null +++ b/keycloak-wx-provider-app/src/main/java/cc/coopersoft/keycloak/wx/app/providers/directgrant/WXAppAuthenticatorFactory.java @@ -0,0 +1,115 @@ +package cc.coopersoft.keycloak.wx.app.providers.directgrant; + +import org.keycloak.Config; +import org.keycloak.authentication.Authenticator; +import org.keycloak.authentication.AuthenticatorFactory; +import org.keycloak.models.AuthenticationExecutionModel; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; +import org.keycloak.provider.ProviderConfigProperty; +import org.keycloak.provider.ProviderConfigurationBuilder; + +import java.util.Collections; +import java.util.List; + +import static org.keycloak.provider.ProviderConfigProperty.BOOLEAN_TYPE; + +public class WXAppAuthenticatorFactory implements AuthenticatorFactory { + + + + public static final String PROVIDER_ID = "wx-app-authenticator"; + + public static final String CONFIG_EVERY = "every"; + + public static final String WX_API_ID = "appid"; + + public static final String WX_API_SECRET = "app_secret"; + + private static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = { + AuthenticationExecutionModel.Requirement.REQUIRED, + }; + + private static final List CONFIG_PROPERTIES; + + static { + CONFIG_PROPERTIES = ProviderConfigurationBuilder.create() + .property().name(CONFIG_EVERY) + .type(ProviderConfigProperty.BOOLEAN_TYPE) + .label("Every body") + .helpText("Auto register user.") + .defaultValue(true) + .add() + .property().name(WX_API_ID) + .type(ProviderConfigProperty.STRING_TYPE) + .label("WX API ID") + .helpText("WX API ID") + .add() + .property().name(WX_API_SECRET) + .type(ProviderConfigProperty.STRING_TYPE) + .label("WX API secret") + .helpText("WX API secret") + .add() + .build(); + } + + @Override + public String getDisplayType() { + return "WX APP auth"; + } + + @Override + public String getReferenceCategory() { + return "WX APP Grant"; + } + + @Override + public boolean isConfigurable() { + return true; + } + + @Override + public AuthenticationExecutionModel.Requirement[] getRequirementChoices() { + return REQUIREMENT_CHOICES; + } + + @Override + public boolean isUserSetupAllowed() { + return true; + } + + @Override + public String getHelpText() { + return "WX APP auth"; + } + + @Override + public List getConfigProperties() { + return CONFIG_PROPERTIES; + } + + @Override + public Authenticator create(KeycloakSession session) { + return new WXAppAuthenticator(); + } + + @Override + public void init(Config.Scope config) { + + } + + @Override + public void postInit(KeycloakSessionFactory factory) { + + } + + @Override + public void close() { + + } + + @Override + public String getId() { + return PROVIDER_ID; + } +} diff --git a/keycloak-wx-provider-app/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory b/keycloak-wx-provider-app/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory new file mode 100755 index 00000000..ad85ad30 --- /dev/null +++ b/keycloak-wx-provider-app/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory @@ -0,0 +1 @@ +cc.coopersoft.keycloak.wx.app.providers.directgrant.WXAppAuthenticatorFactory \ No newline at end of file diff --git a/pom.xml b/pom.xml index 7bca9934..f4dace82 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ cc.coopersoft keycloak-phone-provider-parent pom - 2.3.4-snapshot + 2.4.1-snapshot keycloak-phone-provider keycloak phone support. @@ -71,6 +71,7 @@ keycloak-sms-provider-aliyun keycloak-sms-provider-tencent keycloak-sms-provider-twofactorapi + keycloak-wx-provider-app