diff --git a/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/providers/spi/impl/DefaultPhoneVerificationCodeProvider.java b/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/providers/spi/impl/DefaultPhoneVerificationCodeProvider.java index 6d83a5d3..f1b7de83 100644 --- a/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/providers/spi/impl/DefaultPhoneVerificationCodeProvider.java +++ b/keycloak-phone-provider/src/main/java/cc/coopersoft/keycloak/phone/providers/spi/impl/DefaultPhoneVerificationCodeProvider.java @@ -29,6 +29,7 @@ import java.time.Instant; import java.util.Date; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; public class DefaultPhoneVerificationCodeProvider implements PhoneVerificationCodeProvider { @@ -199,7 +200,7 @@ public void tokenValidated(UserModel user, String phoneNumber, String tokenCodeI } }) .map(CredentialModel::getId) - .toList() + .collect(Collectors.toList()) .forEach(id -> u.credentialManager().removeStoredCredentialById(id)); }); } diff --git a/keycloak-sms-provider-twofactorapi/README.md b/keycloak-sms-provider-twofactorapi/README.md new file mode 100644 index 00000000..8110ea1d --- /dev/null +++ b/keycloak-sms-provider-twofactorapi/README.md @@ -0,0 +1,17 @@ +# Twilio SMS Sender Provider + +**Not verify in Quarkus 19.0.1** + +```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/ + + +${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} +``` diff --git a/keycloak-sms-provider-twofactorapi/pom.xml b/keycloak-sms-provider-twofactorapi/pom.xml new file mode 100644 index 00000000..d9892278 --- /dev/null +++ b/keycloak-sms-provider-twofactorapi/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + + cc.coopersoft + keycloak-phone-provider-parent + 2.3.4-snapshot + + + keycloak-sms-provider-twofactorapi + + + + cc.coopersoft + keycloak-phone-provider + 2.3.4-snapshot + provided + + + com.twilio.sdk + twilio + 9.2.4 + + + + com.squareup.okhttp3 + okhttp + 4.10.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 + + + + + + + diff --git a/keycloak-sms-provider-twofactorapi/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorMessageSenderServiceProviderFactory.java b/keycloak-sms-provider-twofactorapi/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorMessageSenderServiceProviderFactory.java new file mode 100644 index 00000000..52b085dd --- /dev/null +++ b/keycloak-sms-provider-twofactorapi/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorMessageSenderServiceProviderFactory.java @@ -0,0 +1,35 @@ +package cc.coopersoft.keycloak.phone.providers.sender; + +import cc.coopersoft.keycloak.phone.providers.spi.MessageSenderService; +import cc.coopersoft.keycloak.phone.providers.spi.MessageSenderServiceProviderFactory; +import org.keycloak.Config.Scope; +import org.keycloak.models.KeycloakSession; +import org.keycloak.models.KeycloakSessionFactory; + +public class TwoFactorMessageSenderServiceProviderFactory implements MessageSenderServiceProviderFactory { + + private Scope config; + + @Override + public MessageSenderService create(KeycloakSession session) { + return new TwoFactorSmsSenderServiceProvider(config,session.getContext().getRealm().getDisplayName()); + } + + @Override + public void init(Scope config) { + this.config = config; + } + + @Override + public void postInit(KeycloakSessionFactory keycloakSessionFactory) { + } + + @Override + public void close() { + } + + @Override + public String getId() { + return "two-factor"; + } +} diff --git a/keycloak-sms-provider-twofactorapi/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorSmsSenderServiceProvider.java b/keycloak-sms-provider-twofactorapi/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorSmsSenderServiceProvider.java new file mode 100644 index 00000000..713686cc --- /dev/null +++ b/keycloak-sms-provider-twofactorapi/src/main/java/cc/coopersoft/keycloak/phone/providers/sender/TwoFactorSmsSenderServiceProvider.java @@ -0,0 +1,60 @@ +package cc.coopersoft.keycloak.phone.providers.sender; + +import cc.coopersoft.keycloak.phone.providers.exception.MessageSendException; +import cc.coopersoft.keycloak.phone.providers.spi.FullSmsSenderAbstractService; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.jboss.logging.Logger; +import org.keycloak.Config.Scope; + +import javax.annotation.PostConstruct; + +public class TwoFactorSmsSenderServiceProvider extends FullSmsSenderAbstractService { + + private static final Logger logger = Logger.getLogger(TwoFactorSmsSenderServiceProvider.class); + private String twoFactorApiKey; + private static final String twoFactorUrl = "https://2factor.in/API/V1/"; + private OkHttpClient client; + + @PostConstruct + public void doSetUp() { + client = new OkHttpClient().newBuilder() + .build(); + } + + TwoFactorSmsSenderServiceProvider(Scope config, String realmDisplay) { + super(realmDisplay); + this.twoFactorApiKey = config.get("twoFactorApiKey"); + + } + + @Override + public void sendMessage(String phoneNumber, String message) throws MessageSendException { + + Request request = new Request.Builder() + .url(twoFactorUrl + twoFactorApiKey + "/SMS/" + phoneNumber + "/AUTOGEN/OTP1") + .get() + .build(); + try (Response response = client.newCall(request).execute()) { + String responseString = response.body().string(); + if (response.isSuccessful()) { + logger.info(responseString + ": sms sent successfully"); + } else { + logger.error(responseString + ": sms sending failed"); + throw new MessageSendException(response.code(), + String.valueOf(response.code()), + response.message()); + } + } catch (Exception e) { + logger.error(e.getMessage()); + throw new MessageSendException(400, + String.valueOf(400), + e.getMessage()); + } + } + + @Override + public void close() { + } +} 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 new file mode 100644 index 00000000..a0d83f36 --- /dev/null +++ b/keycloak-sms-provider-twofactorapi/src/main/resources/META-INF/services/cc.coopersoft.keycloak.phone.providers.spi.MessageSenderServiceProviderFactory @@ -0,0 +1 @@ +cc.coopersoft.keycloak.phone.providers.sender.TwilioMessageSenderServiceProviderFactory \ No newline at end of file diff --git a/pom.xml b/pom.xml index 68178acc..64be29f9 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