diff --git a/docker/Dockerfile b/docker/Dockerfile index 52c6430b..d9f30415 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -26,30 +26,38 @@ COPY providers/keycloak-phone-provider.resources.jar /opt/keycloak/providers/ #dummy provider COPY providers/keycloak-sms-provider-dummy.jar /opt/keycloak/providers/ -#yuntongxin provider +#yuntongxin sms provider COPY providers/keycloak-sms-provider-cloopen.jar /opt/keycloak/providers/ -#totalvoice provider +#totalvoice sms provider COPY providers/keycloak-sms-provider-totalvoice.jar /opt/keycloak/providers/ -#twilio provider +#twilio sms provider COPY providers/keycloak-sms-provider-twilio.jar /opt/keycloak/providers/ -#yunxin provider +#yunxin sms provider COPY providers/keycloak-sms-provider-yunxin.jar /opt/keycloak/providers/ -#tencent provider +#tencent sms provider COPY providers/keycloak-sms-provider-tencent.jar /opt/keycloak/providers/ -#aliyun provider +#aliyun sms provider COPY providers/keycloak-sms-provider-aliyun.jar /opt/keycloak/providers/ -#aws provider +#aws sms provider COPY providers/keycloak-sms-provider-aws-sns.jar /opt/keycloak/providers/ +#bulksms sms provider +COPY providers/keycloak-sms-provider-bulksms.jar /opt/keycloak/providers/ + +#Two-factor sms provider +COPY providers/keycloak-sms-provider-twofactor.jar /opt/keycloak/providers/ + #wx app provider COPY providers/keycloak-wx-provider-app.jar /opt/keycloak/providers/ + + RUN mkdir /opt/keycloak/certs RUN /opt/keycloak/bin/kc.sh build diff --git a/examples/docker-compose.yml b/examples/docker-compose.yml index 64a8edeb..bd05df47 100644 --- a/examples/docker-compose.yml +++ b/examples/docker-compose.yml @@ -27,6 +27,7 @@ services: - 8080:8080 command: - start-dev + - --spi-phone-default-service=dummy environment: KEYCLOAK_ADMIN: admin KEYCLOAK_ADMIN_PASSWORD: admin diff --git a/examples/start.sh b/examples/start.sh new file mode 100755 index 00000000..06a57023 --- /dev/null +++ b/examples/start.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin coopersoft/keycloak:25.0.2_phone-2.4.1-snapshot start-dev --spi-phone-default-service=dummy \ No newline at end of file diff --git a/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/Utils.java b/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/Utils.java index 5c075a78..f40c1941 100644 --- a/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/Utils.java +++ b/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/Utils.java @@ -12,6 +12,8 @@ import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; import jakarta.validation.constraints.NotNull; +import org.keycloak.utils.StringUtil; + import java.util.*; import java.util.function.Predicate; import java.util.regex.Pattern; @@ -77,7 +79,10 @@ private static Optional localeToCountry(String locale) { private static String defaultRegion(KeycloakSession session) { var defaultRegion = session.getProvider(PhoneProvider.class).defaultPhoneRegion(); return defaultRegion - .orElseGet(() -> localeToCountry(session.getContext().getRealm().getDefaultLocale()).orElse(null)); + .orElseGet(() -> OptionalUtils.ofBlank(session.getContext().getRealm().getDefaultLocale()) + .flatMap(Utils::localeToCountry) + .orElseGet(() -> Locale.getDefault().getCountry()) + ); } /** @@ -92,7 +97,10 @@ public static String canonicalizePhoneNumber(KeycloakSession session, @NotNull S var phoneNumberUtil = PhoneNumberUtil.getInstance(); var resultPhoneNumber = phoneNumber.trim(); var defaultRegion = defaultRegion(session); + logger.info(String.format("default region '%s' will be used", defaultRegion)); + + try { var parsedNumber = phoneNumberUtil.parse(resultPhoneNumber, defaultRegion); if (provider.validPhoneNumber() && !phoneNumberUtil.isValidNumber(parsedNumber)) { diff --git a/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/providers/spi/FullSmsSenderAbstractService.java b/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/providers/spi/FullSmsSenderAbstractService.java index d9fc514e..fe5d5453 100644 --- a/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/providers/spi/FullSmsSenderAbstractService.java +++ b/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/providers/spi/FullSmsSenderAbstractService.java @@ -1,5 +1,6 @@ package cc.coopersoft.keycloak.phone.providers.spi; +import cc.coopersoft.common.OptionalUtils; import cc.coopersoft.keycloak.phone.Utils; import cc.coopersoft.keycloak.phone.providers.constants.TokenCodeType; import cc.coopersoft.keycloak.phone.providers.exception.MessageSendException; @@ -65,9 +66,13 @@ private Optional localizeMessage(TokenCodeType type, String phoneNumber, final Optional userLocale = user.map(u -> u.getFirstAttribute(UserModel.LOCALE)); // Use locale from user or default to realm locale - final String localeName = userLocale.isPresent() ? userLocale.get() - : session.getContext().getRealm().getDefaultLocale(); - final Locale locale = Locale.forLanguageTag(localeName); + final String localeName = userLocale.orElseGet(() -> session.getContext().getRealm().getDefaultLocale()); + + + final Locale locale = OptionalUtils.ofBlank(localeName).map(Locale::forLanguageTag).orElseGet(() -> { + logger.warn("user's locale and realm's default locale is not config,sms message language Locale.getDefault will be used!"); + return Locale.getDefault(); + }) ; // Get message template from login theme bundle final Properties messages = loginTheme.getMessages(locale); diff --git a/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/providers/spi/impl/DefaultPhoneProvider.java b/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/providers/spi/impl/DefaultPhoneProvider.java index 857caa55..1dd45929 100644 --- a/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/providers/spi/impl/DefaultPhoneProvider.java +++ b/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/providers/spi/impl/DefaultPhoneProvider.java @@ -47,6 +47,8 @@ public class DefaultPhoneProvider implements PhoneProvider { this.service + "' will be used. You can use keycloak start param '--spi-phone-default-service' to specify a different one. "); + logger.info("SMS sender provider '" + this.service + "' will be used!"); + this.tokenExpiresIn = config.getInt("tokenExpiresIn", 60); this.targetHourMaximum = config.getInt("targetHourMaximum", 3); this.sourceHourMaximum = config.getInt("sourceHourMaximum", 10); diff --git a/keycloak-sms-provider-twofactorapi/README.md b/keycloak-sms-provider-twofactor/README.md similarity index 50% rename from keycloak-sms-provider-twofactorapi/README.md rename to keycloak-sms-provider-twofactor/README.md index 8110ea1d..9514f519 100644 --- a/keycloak-sms-provider-twofactorapi/README.md +++ b/keycloak-sms-provider-twofactor/README.md @@ -1,17 +1,15 @@ # Twilio SMS Sender Provider -**Not verify in Quarkus 19.0.1** +**Not verify ** ```sh cp target/providers/keycloak-phone-provider.jar ${KEYCLOAK_HOME}/providers/ cp target/providers/keycloak-phone-provider.resources.jar ${KEYCLOAK_HOME}/providers/ -cp target/providers/keycloak-sms-provider-twilio.jar ${KEYCLOAK_HOME}/providers/ +cp target/providers/keycloak-sms-provider-twofactor.jar ${KEYCLOAK_HOME}/providers/ ${KEYCLOAK_HOME}/bin/kc.sh build -${KEYCLOAK_HOME}/bin/kc.sh start --spi-phone-default-service=twilio \ - --spi-message-sender-service-twilio-account=${account} \ - --spi-message-sender-service-twilio-token=${token} \ - --spi-message-sender-service-twilio-number=${servicePhoneNumber} +${KEYCLOAK_HOME}/bin/kc.sh start --spi-phone-default-service=twofactor \ + --spi-message-sender-service-twofactor-key=${key} ``` diff --git a/keycloak-sms-provider-twofactorapi/pom.xml b/keycloak-sms-provider-twofactor/pom.xml similarity index 86% rename from keycloak-sms-provider-twofactorapi/pom.xml rename to keycloak-sms-provider-twofactor/pom.xml index 66b23dea..ee64c6d0 100644 --- a/keycloak-sms-provider-twofactorapi/pom.xml +++ b/keycloak-sms-provider-twofactor/pom.xml @@ -10,7 +10,7 @@ 2.4.1-snapshot - keycloak-sms-provider-twofactorapi + keycloak-sms-provider-twofactor @@ -19,22 +19,14 @@ 2.4.1-snapshot provided - - com.twilio.sdk - twilio - 9.2.4 - + com.squareup.okhttp3 okhttp 4.10.0 - - jakarta.annotation - jakarta.annotation-api - 3.0.0 - + diff --git a/keycloak-sms-provider-twofactorapi/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorMessageSenderServiceProviderFactory.java b/keycloak-sms-provider-twofactor/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorMessageSenderServiceProviderFactory.java similarity index 96% rename from keycloak-sms-provider-twofactorapi/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorMessageSenderServiceProviderFactory.java rename to keycloak-sms-provider-twofactor/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorMessageSenderServiceProviderFactory.java index 6dc13142..8db12a55 100644 --- a/keycloak-sms-provider-twofactorapi/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorMessageSenderServiceProviderFactory.java +++ b/keycloak-sms-provider-twofactor/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorMessageSenderServiceProviderFactory.java @@ -30,6 +30,6 @@ public void close() { @Override public String getId() { - return "two-factor"; + return "twofactor"; } } diff --git a/keycloak-sms-provider-twofactorapi/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorSmsSenderServiceProvider.java b/keycloak-sms-provider-twofactor/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorSmsSenderServiceProvider.java similarity index 75% rename from keycloak-sms-provider-twofactorapi/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorSmsSenderServiceProvider.java rename to keycloak-sms-provider-twofactor/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorSmsSenderServiceProvider.java index c04b171a..98f6a13d 100644 --- a/keycloak-sms-provider-twofactorapi/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorSmsSenderServiceProvider.java +++ b/keycloak-sms-provider-twofactor/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorSmsSenderServiceProvider.java @@ -9,24 +9,18 @@ import org.keycloak.Config.Scope; import org.keycloak.models.KeycloakSession; -import jakarta.annotation.PostConstruct; - public class TwoFactorSmsSenderServiceProvider extends FullSmsSenderAbstractService { private static final Logger logger = Logger.getLogger(TwoFactorSmsSenderServiceProvider.class); - private String twoFactorApiKey; + private final String apiKey; private static final String twoFactorUrl = "https://2factor.in/API/V1/"; - private OkHttpClient client; - - @PostConstruct - public void doSetUp() { - client = new OkHttpClient().newBuilder() - .build(); - } + private final OkHttpClient client; TwoFactorSmsSenderServiceProvider(KeycloakSession session, Scope config) { super(session); - this.twoFactorApiKey = config.get("twoFactorApiKey"); + apiKey = config.get("key"); + client = new OkHttpClient().newBuilder() + .build(); } @@ -34,15 +28,15 @@ public void doSetUp() { public void sendMessage(String phoneNumber, String message) throws MessageSendException { Request request = new Request.Builder() - .url(twoFactorUrl + twoFactorApiKey + "/SMS/" + phoneNumber + "/AUTOGEN/OTP1") + .url(twoFactorUrl + apiKey + "/SMS/" + phoneNumber + "/AUTOGEN/OTP1") .get() .build(); try (Response response = client.newCall(request).execute()) { - String responseString = response.body().string(); - if (response.isSuccessful()) { + + if (response.isSuccessful() && response.body() != null) { + String responseString = response.body().string(); logger.info(responseString + ": sms sent successfully"); } else { - logger.error(responseString + ": sms sending failed"); throw new MessageSendException(response.code(), String.valueOf(response.code()), response.message()); diff --git a/keycloak-sms-provider-twofactor/src/main/resources/META-INF/services/cc.coopersoft.keycloak.phone.providers.spi.MessageSenderServiceProviderFactory b/keycloak-sms-provider-twofactor/src/main/resources/META-INF/services/cc.coopersoft.keycloak.phone.providers.spi.MessageSenderServiceProviderFactory new file mode 100644 index 00000000..6cadb638 --- /dev/null +++ b/keycloak-sms-provider-twofactor/src/main/resources/META-INF/services/cc.coopersoft.keycloak.phone.providers.spi.MessageSenderServiceProviderFactory @@ -0,0 +1 @@ +cc.coopersoft.keycloak.phone.providers.sender.TwoFactorMessageSenderServiceProviderFactory \ No newline at end of file diff --git a/keycloak-sms-provider-twofactorapi/src/main/resources/META-INF/services/cc.coopersoft.keycloak.phone.providers.spi.MessageSenderServiceProviderFactory b/keycloak-sms-provider-twofactorapi/src/main/resources/META-INF/services/cc.coopersoft.keycloak.phone.providers.spi.MessageSenderServiceProviderFactory deleted file mode 100644 index a0d83f36..00000000 --- a/keycloak-sms-provider-twofactorapi/src/main/resources/META-INF/services/cc.coopersoft.keycloak.phone.providers.spi.MessageSenderServiceProviderFactory +++ /dev/null @@ -1 +0,0 @@ -cc.coopersoft.keycloak.phone.providers.sender.TwilioMessageSenderServiceProviderFactory \ No newline at end of file diff --git a/pom.xml b/pom.xml index f4dace82..219d1ecf 100644 --- a/pom.xml +++ b/pom.xml @@ -70,7 +70,7 @@ keycloak-sms-provider-yunxin keycloak-sms-provider-aliyun keycloak-sms-provider-tencent - keycloak-sms-provider-twofactorapi + keycloak-sms-provider-twofactor keycloak-wx-provider-app