NoSuchProvider JavaX Mail - jakarta-mail

I always get the Error:
javax.mail.NoSuchProviderException: Invalid protocol: null
at javax.mail.Session.getProvider(Session.java:525)
at javax.mail.Session.getStore(Session.java:620)
at javax.mail.Session.getStore(Session.java:600)
at javax.mail.Session.getStore(Session.java:586)
at de.jankrb.mailcrawler.methods.CheckAll.check(CheckAll.java:23)
at de.jankrb.mailcrawler.Launcher.main(Launcher.java:10)
I didn't try anything, because I didn't find anything on the internet.
This is making trouble:
Properties properties = new Properties();
properties.put("mail.transport.protocol", "smtp");
properties.put("mail.smtp.host", HOST);
properties.put("mail.user", USER);
properties.put("mail.password", PASS);
Session session = Session.getDefaultInstance(properties);
Store store = session.getStore();
store.connect(HOST, USER, PASS);
Launcher.java:10 just uses the method, where the snippet above is inside.

Properties properties = new Properties();
properties.put("mail.store.protocol", "pop3");
properties.put("mail.pop3.host", HOST);
properties.put("mail.pop3.port", "995");
properties.put("mail.pop3.ssl.trust", "true");
//properties.put("mail.pop3.starttls.enable", "true");
Session session = Session.getDefaultInstance(properties);
Store store = session.getStore("pop3s");
store.connect(HOST, USER, PASS);
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_ONLY);
This is the code i'm using and its working. Thanks anyways

Related

Is there a way to avoid using the redirected form in Spring OAuth2 Authorization server when trying to get Authorization code? [duplicate]

I'm trying to create a local Java-based client that interacts with the SurveyMonkey API.
SurveyMonkey requires a long-lived access token using OAuth 2.0, which I'm not very familiar with.
I've been googling this for hours, and I think the answer is no, but I just want to be sure:
Is it possible for me to write a simple Java client that interacts with the SurveyMonkey, without setting up my own redirect server in some cloud?
I feel like having my own online service is mandatory to be able to receive the bearer tokens generated by OAuth 2.0. Is it possible that I can't have SurveyMonkey send bearer tokens directly to my client?
And if I were to set up my own custom Servlet somewhere, and use it as a redirect_uri, then the correct flow would be as follows:
Java-client request bearer token from SurveyMonkey, with
redirect_uri being my own custom servlet URL.
SurveyMonkey sends token to my custom servlet URL.
Java-client polls custom servlet URL until a token is available?
Is this correct?
Yes, it is possible to use OAuth2 without a callback URL.
The RFC6749 introduces several flows. The Implicit and Authorization Code grant types require a redirect URI. However the Resource Owner Password Credentials grant type does not.
Since RFC6749, other specifications have been issued that do not require any redirect URI:
RFC7522: Security Assertion Markup Language (SAML) 2.0 Profile for OAuth 2.0 Client Authentication and Authorization Grants
RFC7523: JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants
RFC8628: OAuth 2.0 Device Authorization Grant
In any case, if the grant types above do not fit on your needs, nothing prevent you from creating a custom grant type.
Not exactly, the whole point of the OAuth flow is that the user (the client you're accessing the data on behalf of) needs to give you permission to access their data.
See the authentication instructions. You need to send the user to the OAuth authorize page:
https://api.surveymonkey.net/oauth/authorize?api_key<your_key>&client_id=<your_client_id>&response_type=code&redirect_uri=<your_redirect_uri>
This will show a page to the user telling them which parts of their account you are requesting access to (ex. see their surveys, see their responses, etc). Once the user approves that by clicking "Authorize" on that page, SurveyMonkey will automatically go to whatever you set as your redirect URI (make sure the one from the url above matches with what you set in the settings for your app) with the code.
So if your redirect URL was https://example.com/surveymonkey/oauth, SurveyMonkey will redirect the user to that URL with a code:
https://example.com/surveymonkey/oauth?code=<auth_code>
You need to take that code and then exchange it for an access token by doing a POST request to https://api.surveymonkey.net/oauth/token?api_key=<your_api_key> with the following post params:
client_secret=<your_secret>
code=<auth_code_you_just_got>
redirect_uri=<same_redirect_uri_as_before>
grant_type=authorization_code
This will return an access token, you can then use that access token to access data on the user's account. You don't give the access token to the user it's for you to use to access the user's account. No need for polling or anything.
If you're just accessing your own account, you can use the access token provided in the settings page of your app. Otherwise there's no way to get an access token for a user without setting up your own redirect server (unless all the users are in the same group as you, i.e. multiple users under the same account; but I won't get into that). SurveyMonkey needs a place to send you the code once the user authorizes, you can't just request one.
You do need to implement something that will act as the redirect_uri, which does not necessarily need to be hosted somewhere else than your client (as you say, in some cloud).
I am not very familiar with Java and Servelets, but if I assume correctly, it would be something that could handle http://localhost:some_port. In that case, the flow that you describe is correct.
I implemented the same flow successfully in C#. Here is the class that implements that flow. I hope it helps.
class OAuth2Negotiator
{
private HttpListener _listener = null;
private string _accessToken = null;
private string _errorResult = null;
private string _apiKey = null;
private string _clientSecret = null;
private string _redirectUri = null;
public OAuth2Negotiator(string apiKey, string address, string clientSecret)
{
_apiKey = apiKey;
_redirectUri = address.TrimEnd('/');
_clientSecret = clientSecret;
_listener = new HttpListener();
_listener.Prefixes.Add(address + "/");
_listener.AuthenticationSchemes = AuthenticationSchemes.Anonymous;
}
public string GetToken()
{
var url = string.Format(#"https://api.surveymonkey.net/oauth/authorize?redirect_uri={0}&client_id=sm_sunsoftdemo&response_type=code&api_key=svtx8maxmjmqavpavdd5sg5p",
HttpUtility.UrlEncode(#"http://localhost:60403"));
System.Diagnostics.Process.Start(url);
_listener.Start();
AsyncContext.Run(() => ListenLoop(_listener));
_listener.Stop();
if (!string.IsNullOrEmpty(_errorResult))
throw new Exception(_errorResult);
return _accessToken;
}
private async void ListenLoop(HttpListener listener)
{
while (true)
{
var context = await listener.GetContextAsync();
var query = context.Request.QueryString;
if (context.Request.Url.ToString().EndsWith("favicon.ico"))
{
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
context.Response.Close();
}
else if (query != null && query.Count > 0)
{
if (!string.IsNullOrEmpty(query["code"]))
{
_accessToken = await SendCodeAsync(query["code"]);
break;
}
else if (!string.IsNullOrEmpty(query["error"]))
{
_errorResult = string.Format("{0}: {1}", query["error"], query["error_description"]);
break;
}
}
}
}
private async Task<string> SendCodeAsync(string code)
{
var GrantType = "authorization_code";
//client_secret, code, redirect_uri and grant_type. The grant type must be set to “authorization_code”
var client = new HttpClient();
client.BaseAddress = new Uri("https://api.surveymonkey.net");
var request = new HttpRequestMessage(HttpMethod.Post, string.Format("/oauth/token?api_key={0}", _apiKey));
var formData = new List<KeyValuePair<string, string>>();
formData.Add(new KeyValuePair<string, string>("client_secret", _clientSecret));
formData.Add(new KeyValuePair<string, string>("code", code));
formData.Add(new KeyValuePair<string, string>("redirect_uri", _redirectUri));
formData.Add(new KeyValuePair<string, string>("grant_type", GrantType));
formData.Add(new KeyValuePair<string, string>("client_id", "sm_sunsoftdemo"));
request.Content = new FormUrlEncodedContent(formData);
var response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
_errorResult = string.Format("Status {0}: {1}", response.StatusCode.ToString(), response.ReasonPhrase.ToString());
return null;
}
var data = await response.Content.ReadAsStringAsync();
if (data == null)
return null;
Dictionary<string, string> tokenInfo = JsonConvert.DeserializeObject<Dictionary<string, string>>(data);
return(tokenInfo["access_token"]);
}
}

Is there a way to validate azure app credentials?

Given I have the following info from Azure app registration:
Application (client) ID,
Client secret,
Directory (tenant) ID,
Object ID
Is there a way to check it's a valid credential programmatically (like using curl etc but not powershell)?
If you meant to check client secret validity or even the properties of that app ,then please check if the below c# code can be worked around .We can try to query the application and see expiry date of secret. Please grant the app with Directory.Read.All ,Application.Read.All permission to this API for using client credentials flow.
var graphResourceId = "https://graph.microsoft.com";
var applicationId= "";
var ObjectId = "";
var clientsecret = "";
var clientCredential = new ClientCredential(applicationId,secret);
var tenantId = "xxx.onmicrosoft.com";
AuthenticationContext authContext = new AuthenticationContext($"https://login.microsoftonline.com/{tenantId}");
//get accesstoken
var accessToken = authContext.AcquireTokenAsync(graphResourceId, clientCredential).Result.AccessToken;
Uri servicePointUri = new Uri(graphResourceId);
Uri serviceRoot = new Uri(servicePointUri, tenantId);
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot, async () => await Task.FromResult(accessToken));
var app = activeDirectoryClient.Applications.GetByObjectId(appObjectId).ExecuteAsync().Result;
foreach (var passwordCredential in app.PasswordCredentials)
{
Console.WriteLine($"KeyID:{passwordCredential.KeyId}\r\nEndDate:{passwordCredential.EndDate}\r\n");
}
If you want , you can even request token using curl this way and validate using post man or by checking token in https://jwt.io .
Reference: check client secret expiry using C#

Accessing Dynamics CRM via username/password throwing AdalServiceException: AADSTS65001

I followed the quickstart here: https://learn.microsoft.com/en-us/powerapps/developer/common-data-service/webapi/enhanced-quick-start
Which worked great, so then I need to register my app, so I followed this:
https://learn.microsoft.com/en-us/powerapps/developer/common-data-service/walkthrough-register-app-azure-active-directory
But now my unit tests give me the error:
Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException:
AADSTS65001: The user or administrator has not consented to use the
application with ID '[GUID]' named '[AppName]'. Send an interactive
authorization request for this user and resource.
I feel like I understand the error, that the administrator needs to consent. My program is doing some magic in the bakcgorund and the user is not signing in, it is using a set username and password and the user should not be consenting to anyone. Is there any way to set this consent permanently, or force it every time through the Helper class in the first tutorial? All my Google-fu came up empty... Thank you.
You can use something like this:
CrmserviceClient is from Microsoft.Xrm.Tooling.Connector nuget
private CrmServiceClient GenerateService()
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.Expect100Continue = true;
ServicePointManager.CheckCertificateRevocationList = true;
ServicePointManager.DefaultConnectionLimit = 10;
var service = new CrmServiceClient(new Uri(organizationUrl), clientId, secret, false, string.Empty);
if (service.IsReady == false)
{
throw new Exception("CrmOrgService isn't ready. " + service.LastCrmError);
}
return service;
}
Or if you want to use connection string you can use this:
Connection string : https://learn.microsoft.com/en-us/dynamics365/customerengagement/on-premises/developer/xrm-tooling/use-connection-strings-xrm-tooling-connect
var connectionString =
ConfigurationManager.ConnectionStrings["XY"].ConnectionString;
var conn = new CrmServiceClient(connectionString);
IOrganizationService orgService = conn.OrganizationServiceProxy;

Are emails sent using Google OAuth 2.0 SMTP always encoded to base64?

I am using Google OAuth 2.0 to send emails on behalf of my users using Gmail. It uses the SMTP protocol. Here is my code:
Properties props = new Properties();
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.starttls.required", "true");
props.put("mail.smtp.sasl.enable", "false");
Session session = Session.getInstance(props);
session.setDebug(false);
final URLName unusedUrlName = null;
SMTPTransport transport = new SMTPTransport(session, unusedUrlName);
transport.connect("smtp.gmail.com", 587, fromAddress, null);
byte[] response = String.format("user=%s\1auth=Bearer %s\1\1", lFrom, oauthToken).getBytes();
response = BASE64EncoderStream.encode(response);
transport.issueCommand("AUTH XOAUTH2 " + new String(response),
235);
MimeMessage msg = new MimeMessage( session );
msg.setFrom( new InternetAddress( fromAddress , fromName ) );
msg.setRecipients( Message.RecipientType.TO , InternetAddress.parse( toAddress , false ) );
msg.setSubject( emailSubject );
MimeBodyPart htmlPart = new MimeBodyPart();
Multipart multiPart = new MimeMultipart();
htmlPart.setContent( "<html>email content</html>" , "text/html; charset=UTF-8" );
multiPart.addBodyPart( htmlPart );
msg.setContent( multiPart );
msg.saveChanges();
transport.sendMessage(msg, msg.getAllRecipients());
Our software is hosted on the Google App Engine platform. The emails sent using the above method always have Content-Transfer-Encoding header with value "base64".
Normal emails sent using gmail.com aren't encoded like this. Is there a way around? Or is this what is always expected? Do all email service providers (including private servers) support it? I know very little about this. Thanks.
First of all, you can simplify your use of OAuth2 by using the built-in OAuth2 support in JavaMail 1.5.2.
The authentication method isn't going to have any effect on the Content-Transfer-Encoding that JavaMail chooses; it's based entirely on the actual content of the message. If your content includes a lot of non-ASCII characters, it will use base64.

logging into d2l lms using valence

I want to authenticate and get a specific course org unit id using valence and java. I have a application id and user key for the application I got from the d2l keytool. I am also using d2l's java client library for authenticating. i.e. com.d2lvalence.idkeyauth.*;
I am getting a http 403 error on the last line of code.
Can someone see what I doing wrong?
URL url = null;
URLConnection connection = null;
String host = "ucbdev.desire2learn.com";
int port = 443;
String appID = "from d2l";
String appKey = "from d2l";
String userId = "";
String userKey = "";
AuthenticationSecurityFactory factory = new AuthenticationSecurityFactory();
// appID and appKey are from d2l
ID2LAppContext appContext = factory.createSecurityContext(appID, appKey);
URI resultUri=new URI("?x_a=fromd2l&x_b=fromd2l");
ID2LUserContext userContext=appContext.createUserContext(resultUri, host, port, true);
if (userContext == null){
System.out.println("USERCONTEXT is NULL");
}
System.out.println("USERCONTEXT HOST NAME IS :"+userContext.getHostName());
userId = userContext.getUserId();
userKey = userContext.getUserKey();
System.out.println("userID is "+userId);
System.out.println("userKey is "+userKey);
URI newUri = userContext.createAuthenticatedUri("/d2l/api/lp/1.0/orgstructure/", "GET");
String res = newUri.toString();
System.out.println("authenticated uri usercontext s "+res);
connection = newUri.toURL().openConnection();
//cast the connection to a HttpURLConnection so we can examin the status code
HttpURLConnection httpConnection = (HttpURLConnection) connection;
httpConnection.setRequestMethod("GET");
StringBuilder sb=new StringBuilder();
BufferedReader in = null;
//if the status code is success then the body is read from the input stream
if(httpConnection.getResponseCode()==200) {
in = new BufferedReader(new InputStreamReader(httpConnection.getInputStream()));
//otherwise the body is read from the output stream
} else {
System.out.println("Error: " + httpConnection.getResponseCode() + ""); //error 403 here
// in = new BufferedReader(new InputStreamReader(httpConnection.getErrorStream()));
}
You do not seem to be clear on how the authentication works for the Valence Learning Framework API.
The AppId/AppKey pair you get back from D2L's KeyTool is the keypair that you'll use to prove that your API call comes from your app (i.e. you pass the AppId in the x_a parameter on a normal call, and you use the AppKey to generate a signature that you then pass in the x_c parameter on the call). But each normal API call also requires user tokens to prove the is being made on behalf of a known user:
All our SDKs work in the same general way:
First you create an application context object that's built using your AppID/Key keypair.
Then, you create an "URL for authentication": this URL will be a call to the special "get user tokens" API call (here the x_a parameter is your AppId, and the x_b parameter is the signature).
You direct the user's browser to go to this URL for authentication, and it's x_target query parameter specifies the callback URL where the LMS should send the user ID/Key pair after it successfully determines who the user is.
Once you have this User ID/Key pair, in subsequent normal API calls, you will pass the User ID in the x_b parameter (as you're passing the App Id in the x_a) and you will use the User Key to make a signature that you will pass in the x_d parameter.
Please follow along the authentication conceptual topic in the docs carefully, as it will show you all the steps involved in the process of your app getting back a UserID/Key pair so you can then use it to make API calls.

Resources