Keycloak Send Email after successfull password reset - keycloak

Keycloak provides "Forgot Password" functionality out of the box. This is working perfectly fine. On clicking this, I enter email and a link is sent to my email. On clicking the link I can reset my password.
My question is, Is it possible to make Keycloak send an email after successfull password reset?

Thanks to some of the hints from Fabrice. I wrote a event listener do achieve this.
In the listener I filtered for event type UPDATE_PASSWORD and sent email myself. Something like this
public class ResetPasswordEventListenerProvider implements EventListenerProvider {
public ResetPasswordEventListenerProvider() {
}
#Override
public void onEvent(Event event) {
if(event.getType() == EventType.UPDATE_PASSWORD){
//Send email.
}
}
These are some of the articles I referred
https://dev.to/adwaitthattey/building-an-event-listener-spi-plugin-for-keycloak-2044
If you do not use any external dependency in your code, then packaging your code as jar and deploying is enough as indicated in the above article. But if you have any external dependency in your code, then it is very difficult to include those in the resulting jar.
For example in my case once I catch the event, I send the details to a Jms Queue(which will be picked by other service to send email). So I needed Jms related dependencies in the pom. This was not straightforward.
Hence I packaged the code as ear and deployed. The deployment process is similar to jar. But packaging is a bit different. It is shown clearly in this project
https://github.com/thomasdarimont/keycloak-user-storage-provider-demo

Yes, this is possible if you provide a customized copy of the "Reset credentials" authentication flow.
See documentation on how to cutomize a flow https://www.keycloak.org/docs/latest/server_development/index.html#_auth_spi
I guess you'll have to add a custom authenticator (e.g. "Send Reset Confirmation Email") after the "Reset Password" authenticator.
For the implementation of this custom authenticator, you'll only need to send the confirmation email in the authenticate() method.
You can look at keycloak built-in authenticators such as https://github.com/keycloak/keycloak/blob/master/services/src/main/java/org/keycloak/authentication/authenticators/resetcred/ResetCredentialEmail.java.
Regards,

Related

How to enable 2FA using email using keycloak-admin-client in spring boot

My requirement is enable 2FA using email in Keycloak.
When enabled, if user tries to login through email & password ,after user is successfully authenticated ,time based token will be sent to email .
User will do this action from custom UI i.e in our product we have UI to enable/disable 2FA for user.
We are using Keycloak & we want to achieve this using Keycloak API.
I am using keycloak-admin-client to interact with Keycloak API but I did not find sufficient resources to achieve this using keycloak-admin-client.
I am looking a way using keycloak-admin-client how to enable 2FA for user.
Any help will be highly appreciated.
Thank You
You should add custom REST endpoints to Keycloak to be able to enable 2FA from your custom UI. We have done this before. It's not that much complicated, but it requires you to have a look at Keycloak source to see what it's doing when OTP gets activated. Some important classes to check/use are TotpBean, OTPCredentialModel and OTPPolicy.
In order to enable the 2FA, we needed to show the QR code image in our custom UI. So we added an endpoint to Keycloak that instantiates an instance of TotpBean. It's the one that gives you access to the QR code image and the secret value that are required to generate the equivalent string representation of the image so that it could be scanned/entered in the 2FA app (e.g. Google Authenticator). Here is an example of how such an endpoint would look like:
#GET
#Produces({MediaType.APPLICATION_JSON})
#Path("/o2p-enable-config/{email}")
#NoCache
public Response fetchOtpEnableConfig(#Email #PathParam("email") String email) {
UserModel user = session.users().getUserByEmail(email, realm);
TotpBean totp = new TotpBean(session, realm, user, session.getContext().getUri().getRequestUriBuilder());
return Response
.ok(new YouOTPResponseClass("data:image/png;base64, " + totp.getTotpSecretQrCode(), totp.getTotpSecret(), totp.getTotpSecretEncoded()))
.build();
}
Then on your own backend, you call this endpoint and send the user's email to it and receive the image and the secret value. You can just display the image as is in your UI and keep the secret value on your backend (e.g. in user's session). When user scans the image using the app and enters the totp value provided by the app in your custom UI, you send the totp value and the secret to another endpoint that you should add to the Keycloak. This second endpoint is the one that does that verification of the value and enables 2FA.
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Path("/enable-2fa/{email}")
#NoCache
public Response enable2Fa(#Email #PathParam("email") String email, OtpDetails optDetails) {
OTPPolicy policy = realm.getOTPPolicy();
String totp = optDetails.getTotp();
UserModel user = session.users().getUserByEmail(email, realm);
OTPCredentialModel credential = OTPCredentialModel.createFromPolicy(realm, optDetails.getSecret(), optDetails.getUserLabel());
if (CredentialValidation.validOTP(totp, credential, policy.getLookAheadWindow())) {
CredentialHelper.createOTPCredential(session, realm, user, totp, credential);
return Response.noContent().status(204).build();
} else {
return Response.status(BAD_REQUEST).build();
}
}
Keycloak supports multiple 2FA for each user. That's why it also has a property named label that allows user to name them so that it would be displayed in the 2FA login scenario with given name. You can also allow user to enter the label value in your custom UI and pass it to the second endpoint (or just pass an empty value to Keycloak if you're not going to allow your users to setup multiple 2FA).
I know it seems complicated, but it's actually not that much. The Keycloak domain model is well designed and when you get familiar with it, you can easily find what you need to do and wrap it in custom APIs. But always ensure that exposing a functionality would not compromise the overall security model of the system.
Take a look at keycloak two factor email authenticator provider
https://github.com/mesutpiskin/keycloak-2fa-email-authenticator
I agree that is necessary to write a custom provider for this use case.
Take a look at https://www.n-k.de/2020/12/keycloak-2fa-sms-authentication.html and https://www.youtube.com/watch?v=GQi19817fFk for a look at how to implement that.
That is an example via SMS, but via e-mail would be very similar, changing just the way of sending the code to the user.

Mail stay in queue when i use Sendgrid in symfony6

I have set my Sendgrid single sender and validate it ( status = verified).
I use SMTP, create my key that i paste in my code (.env file of my app):
MAILER_DSN=sendgrid+smtp://#default
Then i try to test integration in Sendgrid by clicking on button and refresh my localhost/ page (of course the controller's route is "/" and it contains the code using mailer to send a mail as explain in mailer documentation).
On my vue i don't have error code but mail stay in queue status...
Here the screenshot taken of the profiler:
Can someone tell me why my mail stay queued?
Of course the From email address is mine ( the verified one) and the To is anotherone of mine.
Maybe i have to configure something in my outlook mail (the From one) ?
Sendgrid never match the verification, it stay in checking status until message :
Hmm, we haven't seen your email yet.
Please check your code, run it again, then click "Retry".
Thanks for reply,
Regards,
In your question you said that your MAILER_DSN environment variable is set to:
MAILER_DSN=sendgrid+smtp://#default
That is missing your API Key though. You need to create an API key in the SendGrid dashboard and then add the API key to the MAILER_DSN variable, between the // and the #default like this:
MAILER_DSN=sendgrid+smtp://API_KEY#default
One other thing, ensure that you have installed the SendGrid transport with this command:
composer require symfony/sendgrid-mailer
Yes, thanks you a lot for reply.
Of course all was set as you notify me.
I now have fix my issue, in fact the problem for me with the mail that remains in queued is that the messenger was installed so in asynchronous by default.
I had to add the option message_bus: false in my config/packages/mailer.yaml file not to have the asynchronous option used.
Hopefully this is useful for some people.
add the option message_bus: false in my config/packages/mailer.yaml:
framework:
mailer:
dsn: '%env(MAILER_DSN)%'
message_bus: false

Keycloak Custom message on user temporary lock

I am using Kyecloak:4.8.0, and have enabled Brute force attack for my realm.
Now whenever user provides wrong credentials for 3 times user will be locked temporarily.
But still user will see "Invalid username/password".
According to this thread Keycloak have done this intentionally:
https://issues.jboss.org/browse/KEYCLOAK-5284
But still i want to show user that his account has been locked.
Is there any way to customize this message?
I tried doing this by adding message in custom keycloak theme as below:
location: themes\adminlte\login\messages\messages_en.properties
accountTemporarilyDisabledMessage=Account is temporarily disabled, contact admin or try again later.
This change is not working.
After going through Keycloak base code what i found is: Keycloak uses Messages.INVALID_USER (invalidUserMessage) from properties which is written in AbstractFormAuthenticator class.
This class is at the end extended by UsernamePasswordForm now to change this to custom message i Wrote Custom Authenticator (Keycloak SPI) like below
public class CustomUsernameFormAuthenticator extends UsernamePasswordForm {
#Override
protected String tempDisabledError() {
return Messages.ACCOUNT_TEMPORARILY_DISABLED;
}
}
After this deploy spi Jar in keycloak and enable it in your realm.
And we are done :)

Apache Commons Email work with "normal gmail", but not "Gmail for work"?

Hi I'm using the following code to send email:
public static void sendEmail(String from, String to, String password) {
Email email = new SimpleEmail();
email.setHostName("smtp.googlemail.com");
email.setSmtpPort(465);
email.setAuthenticator(new DefaultAuthenticator(from, password));
email.setSSLOnConnect(true);
email.setSubject("Plain mail");
email.setMsg("test");
email.addTo(to);
email.send();
}
Now, it works when I'm calling this function with my "normal" gmail address:
sendMail("me#gmail.com","friend#gmail.com", "my-password");
So the above works. But when I'm trying to migrate to Gmail for Business, and create an email address "me#mycompany.com" (which is hooked to Gmail), I get an authentication error:
sendMail("me#mycompany.com","friend#gmail.com", "my-new-password");
Gives me this error:
javax.mail.AuthenticationFailedException:
<https://accounts.google.com/ContinueSignIn?sarp=1&scc=1&plt=AKgnsb...ZlTLN2wQG4>
Please log in via your web browser and then try again.
I suspect I need to set something in my Google Apps console, but I'm not even sure where to start looking for the info.
Can anybody help?
Thanks.
This answer is coming from a similar SO question here.
The issue is due to allowing less secure apps to access your account. Click the following link https://www.google.com/settings/security/lesssecureapps and disable security setting. For more information you can read this here.
Good luck!

Liferay: how do I add verication URL to new account e-mail

(Using Liferay 6.1.0-CE-GA1.) I have written my own user registration portlet. When I UserLocalServiceUtil.addUser(...), the sendEmail parameter is true and, indeed, it sends the Account Verification Notification.
I've modified that notification by adding this line to it:
Please verify your email address for [$PORTAL_URL$] by clicking this link: [$EMAIL_VERIFICATION_URL$].
Unfortunately the e-mail it sends contains this line, literally:
Please verify your email address for xxx by clicking this link: [$EMAIL_VERIFICATION_URL$].
Is there any way to make this work? I want to send one e-mail with the verification code. My program flow requires it.
Thank you.
You should use this after you added the account in the action
ServiceContext serv = ServiceContextFactory.getInstance(request);
UserLocalServiceUtil.sendEmailAddressVerification(user1, user1.getEmailAddress(), serv);