javaMail not working with OAuth gmail send email - oauth-2.0
javaMail: send mail using google oauth caused javax.mail.AuthenticationFailedException.
Properties props = new Properties();
props.put("mail.smtp.ssl.enable", "true"); // required for Gmail
props.put("mail.smtp.auth.mechanisms", "XOAUTH2");
Session session = Session.getInstance(props);
Transport transport = session.getTransport("smtps");
transport.connect("smtp.gmail.com", 465, xyz#gmail.com, oauth_access_token);
The oauth access token is valid, just refreshed, about 20 seconds before running the code.
Error:
javax.mail.AuthenticationFailedException: 535-5.7.8 Username and Password not accepted. Learn more at
535 5.7.8 https://support.google.com/mail/?p=BadCredentials s136sm158338qka.106 - gsmtp
at com.sun.mail.smtp.SMTPTransport$Authenticator.authenticate(SMTPTransport.java:965)
at com.sun.mail.smtp.SMTPTransport.authenticate(SMTPTransport.java:876)
at com.sun.mail.smtp.SMTPTransport.protocolConnect(SMTPTransport.java:780)
at javax.mail.Service.connect(Service.java:366)
From the logging, it seems that auth is using username/password, not OAUTH. guide: https://javaee.github.io/javamail/OAuth2
Logging:
DEBUG: JavaMail version 1.6.2
DEBUG: successfully loaded resource: /META-INF/javamail.default.address.map
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtps,com.sun.mail.smtp.SMTPSSLTransport,Oracle]
DEBUG SMTP: useEhlo true, useAuth false
DEBUG SMTP: trying to connect to host "smtp.gmail.com", port 465, isSSL true
220 smtp.gmail.com ESMTP s136sm158338qka.106 - gsmtp
DEBUG SMTP: connected to host "smtp.gmail.com", port: 465
250-8BITMIME
250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-CHUNKING
250 SMTPUTF8
DEBUG SMTP: Found extension "SIZE", arg "35882577"
DEBUG SMTP: Found extension "8BITMIME", arg ""
DEBUG SMTP: Found extension "AUTH", arg "LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH"
DEBUG SMTP: Found extension "ENHANCEDSTATUSCODES", arg ""
DEBUG SMTP: Found extension "PIPELINING", arg ""
DEBUG SMTP: Found extension "CHUNKING", arg ""
DEBUG SMTP: Found extension "SMTPUTF8", arg ""
DEBUG SMTP: protocolConnect login, host=smtp.gmail.com, user=xyz#gmail.com, password=<non-null>
DEBUG SMTP: Attempt to authenticate using mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM XOAUTH2
DEBUG SMTP: Using mechanism LOGIN
DEBUG SMTP: AUTH LOGIN command trace suppressed
DEBUG SMTP: AUTH LOGIN failed
In case someone comes across this page: JavaMail does work with Gmail OAuth2 authentication. The following is how it works on my Kotlin code base:
The props needed for Session is shown below (it's in yaml format, but you get the idea):
javamail:
config:
"mail.smtp.host": smtp.gmail.com
"mail.smtp.port": 587
"mail.smtp.starttls.enable": true
"mail.smtp.starttls.required": true
"mail.smtp.auth.mechanisms": XOAUTH2
When constructing an email (multi-part or not), the enclosing mime message must be bound to a Session that has all the above props. This can be easily missed when using a class from a library to construct an email (like SimpleEmail):
val session = Session.getInstance(javamail.config().toProperties())
val email = SimpleEmail().apply {
setMailSession(session) // do not forget this line
setCharset("utf-8")
setFrom(credInfo.email())
addTo("someone#somewhere.com")
setSubject("Test email")
setMsg("This is the test.")
buildMimeMessage()
}
Call a static method Transport.send(msg, username, password), where username is your email, and password is your fresh access-token. There's no need to create an instance of Transport, nor a need to call transport.connect():
Transport.send(email.mimeMessage, gmail, accessToken)
I think you need to disable the plain authentication to force Jakarta Mail to use XOAUTH2.
props.put("mail.smtp.auth.plain.disable", "true");
Trying the following code:
Properties props = new Properties()
props.setProperty("mail.smtp.host", "smtp.gmail.com")
props.setProperty("mail.smtp.port", "587")
props.put("mail.smtp.auth","true")
props.put("mail.smtp.starttls.enable", "true")
props.put("mail.smtp.starttls.required", "true")
props.put("mail.smtp.auth.mechanisms", "XOAUTH2")
props.put("mail.smtp.auth.login.disable", "true")
props.put("mail.smtp.auth.plain.disable", "true")
props.put("mail.smtp.auth.ntlm.disable", "true")
props.put("mail.debug", "true")
props.put("mail.debug.auth", "true")
Session session = Session.getInstance(props)
String emptyPassword = ""
final URLName unusedUrlName = null
SMTPTransport transport = new SMTPTransport(session, unusedUrlName)
transport.connect("smtp.gmail.com", googleEmail, googleAccessToken)\
Multipart multipart = new MimeMultipart()
BodyPart messageBodyPart = new MimeBodyPart()
def from = googleEmail
def to = "test#test.com"
def subj = "TestOath2Gmail"
def body = "TTT"
message.setFrom(new InternetAddress(googleEmail))
message.addRecipient(javax.mail.Message.RecipientType.TO, new InternetAddress(to))
Date sentDate = new Date()
message.setSentDate(sentDate)
message.setSubject(subj)
messageBodyPart.setContent(body, "text/html")
multipart.addBodyPart(messageBodyPart)
message.setContent(multipart)
transport.send(message)
Getting error:
DEBUG SMTP: Using mechanism XOAUTH2
AUTH XOAUTH2
235 2.7.0 Accepted
DEBUG: getProvider() returning javax.mail.Provider[TRANSPORT,smtp,com.sun.mail.smtp.SMTPTransport,Oracle]
DEBUG SMTP: need username and password for authentication
DEBUG SMTP: protocolConnect returning false, host=smtp.gmail.com, user=username, password=
Related
Unable to connect to Google SMTP server from Jenkins
I have configuared email extionsion with my credentials but still it tries to authenticate using jenkins as user and password = null DEBUG SMTP: protocolConnect returning false, host=smtp.gamil.com, user=jenkins, password=<null> DEBUG SMTP: useEhlo true, useAuth true DEBUG SMTP: trying to connect to host "smtp.gamil.com", port 465, isSSL false MessagingException message: Could not connect to SMTP host: smtp.gamil.com, port: 465 It should use credentials I provide but why it using user=jenkins, password=<null
Sending message to azure IoT hub with x509 certificate authentication
I am trying to send telemetry messages to Azure IoT Hub using the npm mqtt library, instead of using Azure Nodejs SDK/Library. I am using X509 certificate authentication. The device connection is working fine when I use azure Nodejs SDK/Library and I am able to send telemetry messages. When trying to use the MQTT library, it is saying unauthorized. const mqtt = require("mqtt"); const fs = require('fs'); let options = { cert: fs.readFileSync("device-cert.pem", "utf-8").toString(), key: fs.readFileSync("device-cert.key", "utf-8").toString(), passphrase: '1234', clientId: "device-003", username: "ih-iot-sample-001.azure-devices.net/device-003/?api-version=2021-04-12", } let client = mqtt.connect( "mqtts://ih-iot-sample-001.azure-devices.net:8883", options ); client.on("connect", function () { console.log("connected"); }); client.on("error", (err) => { console.log(err); process.exit(0) }); Error : Connection refused: Not authorized
The clientid and the deviceId in the username were wrong. That's why I got this error
how to access azure key vault for asp.net core dockerize app using managed identity
I am creating an asp.net core web app and within Visual studio I don't have any issue on below code while I am trying to fetch azure key vault using managed identity. public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, config) => { config.AddAzureKeyVault(new AzureKeyVaultConfigurationOptions { Vault = "https://testvaultXYZ.vault.azure.net/", Client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(new AzureServiceTokenProvider().KeyVaultTokenCallback)), }); }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }); Now I make this application to run in docker/container now when I am running this application in local container I am getting below error for above code, Microsoft.Azure.Services.AppAuthentication.AzureServiceTokenProviderException: 'Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/xxxxxxxxxxx. Exception Message: Tried the following 3 methods to get an access token, but none of them worked. Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/xxxxxxxxx. Exception Message: Tried to get token using Managed Service Identity. Unable to connect to the Managed Service Identity (MSI) endpoint. Please check that you are running on an Azure resource that has MSI setup. Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/xxxxxxxxxx. Exception Message: Tried to get token using Visual Studio. Access token could not be acquired. Environment variable LOCALAPPDATA not set. Parameters: Connection String: [No connection string specified], Resource: https://vault.azure.net, Authority: https://login.windows.net/xxxxxxxxxxxx. Exception Message: Tried to get token using Azure CLI. Access token could not be acquired. /bin/bash: az: No such file or directory I understand that user is different while running in docker container. What's the solution here? I saw some solution to get access token using below command, $Env:ACCESS_TOKEN=(az account get-access-token --resource=https://testvaultXYZ.vault.azure.net | ConvertFrom-Json).accessToken but here also getting error like, Get Token request returned http error: 400 and server response: {"error":"invalid_resource","error_description":"AADSTS500011: The resource principal named https://testvaultXYZ.vault.azure.net was not found in the tenant named XXXXXXX. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant.
It should be: az account get-access-token --resource=https://vault.azure.net. Then you get the access token you can use :) This is working for me.
To use the workaround with get-access-token: be sure that you're signed in to azure cli, just run the command az account get-access-token ... in terminal and check whether you're able to get the token; do you use correct tenant and subscription? save the result to environment variable in terminal session pass this variable to docker run --env KVTOKEN=$Env ... command as an environment variable don't forget to read this variable in application and pass it to KeyVaultClient constructor: var token = Environment.GetEnvironmentVariable("KVTOKEN"); KeyVaultClient kvclient = string.IsNullOrEmpty(token) ? new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(new AzureServiceTokenProvider().KeyVaultTokenCallback)) : new KeyVaultClient((authority, resource, scope) => token);
401 unauthorized streaming spring xd
I'm trying to follow this tutorial https://github.com/spring-projects/spring-xd-samples/tree/master/analytics-dashboard I did the configuration on modules.yml twitter: consumerKey: {your-consumer-key} consumerSecret: {your-consumer-secret} accessToken: {your-access-token} accessTokenSecret: {your-access-token-secret} with my own keys and then when i run stream create tweets --definition "twitterstream | log" --deploy this error appear 2016-05-24T12:48:07-0500 1.3.1.RELEASE ERROR twitterSource-1-1 twitter.TwitterStreamChannelAdapter - Twitter authentication failed: 401 Authorization Required
401 error means "Authentication credentials were missing or incorrect". Make sure the credentials is correct. see https://dev.twitter.com/overview/api/response-codes
ActionMailer SMTP "certificate verify failed"
I want to send emails from my Rails web application, and I do not want to disable TLS certificate verification. However for some reason, it always fails with "SSLv3 read server certificate B: certificate verify failed", even though the server certificate is valid. I doubled checked with openssl s_client (using /etc/ssl/certs/ca-certificates.crt), and running the following in the rails console also works, delivering successfully. smtp = Net::SMTP.new(host, port) smtp.enable_tls smtp.start("localhost", username, password, :login) do |smtp| smtp.send_message msgstr, from, to end The server has Rails 4.2.6 and Ruby 2.3.0 config.action_mailer.smtp_setting = { address: port: 465, user_name: password: authentication: :login, openssl_verify_mode: OpenSSL::SSL::VERIFY_PEER, enable_starttls_auto: false, ssl: true }
From the described behavior I am quite sure that peer verification has not been done in the console and that you need to explicitly set the certificate store for verifying peer certificates in your Rails configuration. Why it "works" in the console and how to actually verify peers there: The observation that it works from the console but does not from Rails code is caused by the fact that smtp.enable_tls in your console code does not force peer verification whereas your Rails configuration apparently does. Indeed, when you write the command to the console, you get the SSLContext printed out: smtp.enable_tls # => #<OpenSSL::SSL::SSLContext:0x000000064043d0 #cert=nil, #key=nil, #client_ca=nil, #ca_file=nil, #ca_path=nil, #timeout=nil, #verify_mode=nil, #verify_depth=nil, #renegotiation_cb=nil, #verify_callback=nil, #cert_store=nil, #extra_chain_cert=nil, #client_cert_cb=nil, #session_id_context=nil, #tmp_dh_callback=nil, #session_get_cb=nil, #session_new_cb=nil, #session_remove_cb=nil, #tmp_ecdh_callback=nil, #servername_cb=nil, #npn_protocols=nil, #alpn_protocols=nil, #alpn_select_cb=nil, #npn_select_cb=nil> Note that #verify_mode is nil so there is no peer verification enabled by default on the SSLContext. To force peer verification in console, so that you can play with the SSL settings manually, you need to use a custom SSLContext and pass it to enable_tls: ssl_context = Net::SMTP.default_ssl_context ssl_context.set_params smtp.enable_tls(ssl_context) # => #<OpenSSL::SSL::SSLContext:0x000000063c27c8 #cert=nil, #key=nil, #client_ca=nil, #ca_file=nil, #ca_path=nil, #timeout=nil, #verify_mode=1, #verify_depth=nil, #renegotiation_cb=nil, #verify_callback=nil, #cert_store=#<OpenSSL::X509::Store:0x00000002894408 #verify_callback=nil, #error=nil, #error_string=nil, #chain=nil, #time=nil>, #extra_chain_cert=nil, #client_cert_cb=nil, #session_id_context=nil, #tmp_dh_callback=nil, #session_get_cb=nil, #session_new_cb=nil, #session_remove_cb=nil, #tmp_ecdh_callback=nil, #servername_cb=nil, #npn_protocols=nil, #alpn_protocols=nil, #alpn_select_cb=nil, #npn_select_cb=nil> Watch closely the differences: the SSLContext now has verify_mode set to 1 and has a certificate store for the verifications defined. This is (among other things) what the set_params method in SSLContext does. How to configure the certificate store in Rails Now, Rails does not call the set_params methods when constructing the SSLContext for SMTP connection. Instead, it sets the individual attributes on it according to the options (see here and here in the source code). You have properly configured Rails that you want to verify peer certificates but you have not configured a certificate store to verify peers against. This can be done using the ca_file or ca_path options, so the following Rails configuration should work for you: config.action_mailer.smtp_setting = { ... ssl: true enable_starttls_auto: false, openssl_verify_mode: OpenSSL::SSL::VERIFY_PEER, ca_file: "/etc/ssl/certs/ca-certificates.crt", ... } I have no idea why this is not properly documented in the Rails Guides...
This Rails configuration works for me (using Ruby 2.2.2 and Rails 5): ActionMailer::Base.smtp_setting = { ... enable_starttls_auto: true, openssl_verify_mode: OpenSSL::SSL::VERIFY_PEER, openssl_verify_depth: 3, # if your CA is a sub signer ca_file: "/etc/ssl/certs/ca-certificates.crt", ... }