IllegalArgumentException when i am using google calendar API in java with service account credentials - google-calendar-api

Below is my code , I am getting illegalArgumentException in GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws ServiceException {
InputStream fileInputStream = new FileInputStream(CREDENTIALS_FILE_PATH);
if (fileInputStream == null) {
logger.debug("File for credentials not found");
throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
}
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(fileInputStream));
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
.setAccessType("online")
.build();
System.out.println(flow);
LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
logger.debug("Credentials for Google API returned successfully");
return credential;
}

Related

How to consume my authorized web api to my mvc web app

I have a web api controller which retrieves data from my database and a mvc web app controller which consumes this web api.
In my web api I used Microsoft.Owin for security and generating a token. Later, I am using this token taken from my web api via postman, and placing it statically on my web app. What I want to do is dynamically store every token I generate from every request and not copy-pasting it every time.
I used this video for creating my web api and generatin jwt token, and this video to consume my web api. Please help me, I'm stuck here for days now.
EDIT:
My web api controller:
[Authorize]
[HttpGet]
public IHttpActionResult GetOperators()
{
IList<OperatorClass> OperatorObject = myEntity.Operator.Include("Operator").Select(x => new OperatorClass()
{ id = x.id,
name = x.name,
lastname = x.lastname,
mobile = x.mobile,
username = x.username,
password = x.password
}).ToList<OperatorClass>();
return Ok(OperatorObject);
}
Startup.cs
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
var myProvider = new MyAuthorizationServerProvider();
OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(5),
Provider = myProvider
};
MyAuthorizationServerProvider.cs
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
if(context.UserName=="test" && context.Password == "test")
{
context.Validated(identity);
}
else
{
context.SetError("Invalid grant", "Provided username or password are incorrect");
return;
}
}
My web application controller
if (opc.username == "test" && opc.password == "test")
{
string token = "07Jv8mQ-pg6MlGdAAVJqxzsJ";
IEnumerable<OperatorClass> OperatorObject = null;
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://localhost:44304/api/");
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
var resultDisplay = await client.GetAsync("data");
if (resultDisplay.IsSuccessStatusCode)
{
var readTable = resultDisplay.Content.ReadAsAsync<IList<OperatorClass>>();
readTable.Wait();
OperatorObject = readTable.Result;
return View(OperatorObject);
}
else
{
OperatorObject = Enumerable.Empty<OperatorClass>();
ModelState.AddModelError(String.Empty, "No records found");
ViewBag.Error = "Token error. It may be incorrect or it has already expired. Check your token provider!";
return View("Error");
}
}
else
{
ViewBag.Error = "Incorrect username or password!";
return View("Login");
}
1- Why don't you store that token in database tables or Session for later use in request.
2- Everytime you ask question try to share relevant code as well next time.

Microsoft.Graph.ServiceException Code: MailboxNotEnabledForRESTAPI

Can successfully get user's emails by using Graph Explorer or DeviceCodeProvider.
DeviceCodeProvider
IPublicClientApplication publicClientApplication = PublicClientApplicationBuilder
.Create(clientId)
.Build();
Func<DeviceCodeResult, Task> deviceCodeReadyCallback = async dcr => await Console.Out.WriteLineAsync(dcr.Message);
DeviceCodeProvider authProvider = new DeviceCodeProvider(publicClientApplication, scopes, deviceCodeReadyCallback);
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var messages = await graphClient.Me.Messages
.Request()
.Select("sender,subject")
.GetAsync();
Failed to get the same user's emails when used PublicClientApplicationBuilder with UsernamePasswordProvider or ConfidentialClientApplicationBuilder. Graph API return
Exception has occurred: CLR/Microsoft.Graph.ServiceException
An exception of type 'Microsoft.Graph.ServiceException' occurred in System.Private.CoreLib.dll but was not handled in user code: 'Code: MailboxNotEnabledForRESTAPI
Message: REST API is not yet supported for this mailbox.
UsernamePasswordProvider
IPublicClientApplication clientApp = PublicClientApplicationBuilder.Create(clientId)
.WithAuthority(AzureCloudInstance.AzurePublic, tenantId)
.Build();
UsernamePasswordProvider authProvider = new UsernamePasswordProvider(clientApp, scopes);
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
String password = userPassword;
System.Security.SecureString sec_pass = new System.Security.SecureString();
Array.ForEach(password.ToArray(), sec_pass.AppendChar);
sec_pass.MakeReadOnly();
var me = await graphClient.Me.Messages.Request()
.WithUsernamePassword(userPrincipalName, sec_pass)
.Select("sender,subject")
.GetAsync();
ConfidentialClientApplicationBuilder
var scopes = new[] { "https://graph.microsoft.com/.default" };
var authority = $"https://login.microsoftonline.com/{tenantId}";
var app = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri(authority))
.Build();
var authenticationProvider = new ClientCredentialProvider(app);
var graphClient = new GraphServiceClient(authenticationProvider);
var user = await graphClient.Users[userPrincipalName].Request().GetAsync();
var mailFolders = await graphClient.Users[user.Id].Messages.Request().GetAsync();
The service built is running in back-end. Because of this, the popup login must be avoided. What did I do wrong? please help. Thanks in advance

Fetching user based access token using grant type as password

I am trying to retrieve access token by using user credential.
I am using AcquireTokenAsync method for retrieving the token where I am using constructor with resource, client id and user credential as parameter.
public async Task<IHttpActionResult> GetToken()
{
AuthenticationResult authenticationResult = null;
try
{
string authority = "https://login.microsoftonline.com/tenant";
string resource ="2424-234-234234-234-23-32423";
string username = "yxyzzz";
string password = "password";
string clientId="2424-234-234234-234-23-32423";
var useridpassword = new UserPasswordCredential(username, password);
AuthenticationContext context = new AuthenticationContext(authority);
context.TokenCache.Clear();
authenticationResult = await context.AcquireTokenAsync(resource, clientId, useridpassword);
return authenticationResult.AccessToken;
}
catch (Exception ex)
{
throw ex;
}
}
I am expecting access token to be returned but I am getting an exception while acquiring token. Below is the error message I am getting.
AdalException: {"error":"invalid_client","error_description":"AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.\r\nTrace ID: 674f29fe-73c6-49a3-9c3f-24df4ea16000\r\nCorrelation ID: b14cb535-9df5-48fa-b911-7e8b927fceb7\r\nTimestamp: 2019-11-08 06:21:57Z","error_codes":[7000218],"timestamp":"2019-11-08 06:21:57Z","trace_id":"674f29fe-73c6-49a3-9c3f-24df4ea16000","correlation_id":"b14cb535-9df5-48fa-b911-7e8b927fceb7","error_uri":"https://login.microsoftonline.com/error?code=7000218"}: Unknown error
To use resource owner password credential, you need to treat application as a public client.
Go to azure portal->App registrations->find your application->check the advanced settings
This is the code i am using to fetch token. This is what i wanted to retrieve the access token.
string authority = "https://login.microsoftonline.com/tenant";
string resource ="2424-234-234234-234-23-32423";
string username = "yxyzzz";
string password = "password";
string clientId="2424-234-234234-234-23-32423";
string tokenEndpointUri = authority + "/oauth2/token";
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", username),
new KeyValuePair<string, string>("password", password),
new KeyValuePair<string, string>("client_id", authmodel.ClientId),
new KeyValuePair<string, string>("client_secret", authmodel.ClientSecret),
new KeyValuePair<string, string>("resource", resource)
}
);
using (var client = new HttpClient())
{
HttpResponseMessage res = null;
client.PostAsync(tokenEndpointUri, content).
ContinueWith(t =>
{
try
{
res = t.Result;
}
catch (Exception ex)
{
throw ex;
}
})
.Wait();
string json = await res.Content.ReadAsStringAsync();
}
I am getting access token in json variable with other details. If you want to fetch the token value, then you can deserialize it to .net Object and get the value.

C#: Google.Apis.Auth.OAuth2.Responses.TokenResponseException: Error:"invalid_client", Description:"The OAuth client was not found.", Uri:""

I am trying to integrate Google calendar in my web application. I have successfully integrate Google calendar and able to read events from my Visual Studio IIS Express server. But when I publish and upload my application on web server I have start receiving error
Google.Apis.Auth.OAuth2.Responses.TokenResponseException: Error:"invalid_client", Description:"The OAuth client was not found.", Uri:""
My Code
var certificate = new X509Certificate2(System.Web.HttpContext.Current.Server.MapPath("~/App_Data/key.p12"), "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(/*My Service Account */)
{
Scopes = new string[] { CalendarService.Scope.Calendar }
}.FromCertificate(certificate));
// Create Google Calendar API service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Test",
});
EventsResource.ListRequest request = service.Events.List("primary");
request.TimeMin = DateTime.Now;
request.ShowDeleted = false;
request.SingleEvents = true;
request.MaxResults = 10;
request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime;
// List events.
Events events = request.Execute();
I have solve my problem by using .JSON key instead of .P12 key.
I have download new .JSON key from google API console. and change little bit of code as bellow.
GoogleCredential credential;
using (var stream = new FileStream(System.Web.HttpContext.Current.Server.MapPath("~/App_Data/key.json"), FileMode.Open, FileAccess.Read))
{
credential = GoogleCredential.FromStream(stream)
.CreateScoped(new string[] { CalendarService.Scope.Calendar });
}
// Create Google Calendar API service.
var service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Test",
});
EventsResource.ListRequest request = service.Events.List("primary");
request.TimeMin = DateTime.Now;
request.ShowDeleted = false;
request.SingleEvents = true;
request.MaxResults = 10;
request.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime;
// List events.
Events events = request.Execute();
For more detail please visit link from comment section. Thank you DaImTo.

Send push notifications from server with FCM

Recently I asked a question on sending push notifications using GCM: Send push notifications to Android. Now that there is FCM, I am wondering how different it would be from the server side development. Coding wise, are they the same? Where can I find example FCM codes showing sending push notifications from server to Android device?
Do I need to download any JAR library for sending notifications to FCM using Java codes? The example codes in Send push notifications to Android shows sending push notifications using GCM and a server side GCM JAR file is required.
However, another example in https://www.quora.com/How-do-I-make-a-post-request-to-a-GCM-server-in-Java-to-push-a-notification-to-the-client-app shows sending push notifications using GCM and no server side GCM JAR file is required since it is just sending via an HTTP connection. Can the same codes be used for FCM? The URL used is "https://android.googleapis.com/gcm/send". What would be the equivalent URL for FCM?
How different is server-side coding?
Since there is not much difference, you can just check out most of the example server-side codes for GCM as well. Main difference with regards to GCM and FCM is that when using FCM, you can use the new features with it (as mentioned in this answer). FCM also has a Console where you can send the Message/Notification from, without having your own app server.
NOTE: Creating your own app server is up to you. Just stating that you can send a message/notification via the console.
The URL used is "https://android.googleapis.com/gcm/send". What would be the equivalent URL for FCM?
The equivalent URL for FCM is https://fcm.googleapis.com/fcm/send. You can check out the this doc for more details.
Cheers! :D
Use below code to send push notification from FCM server :
public class PushNotifictionHelper {
public final static String AUTH_KEY_FCM = "Your api key";
public final static String API_URL_FCM = "https://fcm.googleapis.com/fcm/send";
public static String sendPushNotification(String deviceToken)
throws IOException {
String result = "";
URL url = new URL(API_URL_FCM);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "key=" + AUTH_KEY_FCM);
conn.setRequestProperty("Content-Type", "application/json");
JSONObject json = new JSONObject();
json.put("to", deviceToken.trim());
JSONObject info = new JSONObject();
info.put("title", "notification title"); // Notification title
info.put("body", "message body"); // Notification
// body
json.put("notification", info);
try {
OutputStreamWriter wr = new OutputStreamWriter(
conn.getOutputStream());
wr.write(json.toString());
wr.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
String output;
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println(output);
}
result = CommonConstants.SUCCESS;
} catch (Exception e) {
e.printStackTrace();
result = CommonConstants.FAILURE;
}
System.out.println("GCM Notification is sent successfully");
return result;
}
This is coming straight from Google
You won’t need to make any server-side protocol changes for the upgrade. The service protocol has not changed. However, note that all new server enhancements will be documented in FCM server documentation.
And from receiving messages it seams there is only some places where its only slightly different. Mainly deleting somethings.
And the FCM server documentation can be found here
https://firebase.google.com/docs/cloud-messaging/server
FULL SOLUTION FOR TOPIC, SINGLE DEVICE AND MULTIPLE DEVICES
Create a class FireMessage. This is an example for data messages. You can change data to notification.
public class FireMessage {
private final String SERVER_KEY = "YOUR SERVER KEY";
private final String API_URL_FCM = "https://fcm.googleapis.com/fcm/send";
private JSONObject root;
public FireMessage(String title, String message) throws JSONException {
root = new JSONObject();
JSONObject data = new JSONObject();
data.put("title", title);
data.put("message", message);
root.put("data", data);
}
public String sendToTopic(String topic) throws Exception { //SEND TO TOPIC
System.out.println("Send to Topic");
root.put("condition", "'"+topic+"' in topics");
return sendPushNotification(true);
}
public String sendToGroup(JSONArray mobileTokens) throws Exception { // SEND TO GROUP OF PHONES - ARRAY OF TOKENS
root.put("registration_ids", mobileTokens);
return sendPushNotification(false);
}
public String sendToToken(String token) throws Exception {//SEND MESSAGE TO SINGLE MOBILE - TO TOKEN
root.put("to", token);
return sendPushNotification(false);
}
private String sendPushNotification(boolean toTopic) throws Exception {
URL url = new URL(API_URL_FCM);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Authorization", "key=" + SERVER_KEY);
System.out.println(root.toString());
try {
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(root.toString());
wr.flush();
BufferedReader br = new BufferedReader(new InputStreamReader( (conn.getInputStream())));
String output;
StringBuilder builder = new StringBuilder();
while ((output = br.readLine()) != null) {
builder.append(output);
}
System.out.println(builder);
String result = builder.toString();
JSONObject obj = new JSONObject(result);
if(toTopic){
if(obj.has("message_id")){
return "SUCCESS";
}
} else {
int success = Integer.parseInt(obj.getString("success"));
if (success > 0) {
return "SUCCESS";
}
}
return builder.toString();
} catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
}
}
And call anywhere like this. Both server and android we can use this.
FireMessage f = new FireMessage("MY TITLE", "TEST MESSAGE");
//TO SINGLE DEVICE
/* String fireBaseToken="c2N_8u1leLY:APA91bFBNFYDARLWC74QmCwziX-YQ68dKLNRyVjE6_sg3zs-dPQRdl1QU9X6p8SkYNN4Zl7y-yxBX5uU0KEKJlam7t7MiKkPErH39iyiHcgBvazffnm6BsKjRCsKf70DE5tS9rIp_HCk";
f.sendToToken(fireBaseToken); */
// TO MULTIPLE DEVICE
/* JSONArray tokens = new JSONArray();
tokens.put("c2N_8u1leLY:APA91bFBNFYDARLWC74QmCwziX-YQ68dKLNRyVjE6_sg3zs-dPQRdl1QU9X6p8SkYNN4Zl7y-yxBX5uU0KEKJlam7t7MiKkPErH39iyiHcgBvazffnm6BsKjRCsKf70DE5tS9rIp_HCk");
tokens.put("c2R_8u1leLY:APA91bFBNFYDARLWC74QmCwziX-YQ68dKLNRyVjE6_sg3zs-dPQRdl1QU9X6p8SkYNN4Zl7y-yxBX5uU0KEKJlam7t7MiKkPErH39iyiHcgBvazffnm6BsKjRCsKf70DE5tS9rIp_HCk");
f.sendToGroup(tokens); */
//TO TOPIC
String topic="yourTopicName";
f.sendToTopic(topic);
I have created a lib for FCM notification Server. Just use it like GCM lib.
For FCM Server use this code :
GCM Server URL-"android.googleapis.com/gcm/send"
FCM Server URL - "fcm.googleapis.com/fcm/send"
Append https with URL
Sender objSender = new Sender(gAPIKey);
or
Sender objSender = new Sender(gAPIKey,"SERVER_URL");
by DEFAULT FCM SERVER URL IS ASSIGNED
Message objMessage = new Message.Builder().collapseKey("From FCMServer").timeToLive(3).delayWhileIdle(false)
.notification(notification)
.addData("ShortMessage", "Sh").addData("LongMessage", "Long ")
.build();
objMulticastResult = objSender.send(objMessage,clientId, 4);
Dependency need for this lib is same like GCM lib required (jsonsimple.jar).
Download lib from FCM_Server.jar
public class SendPushNotification extends AsyncTask<Void, Void, Void> {
private final String FIREBASE_URL = "https://fcm.googleapis.com/fcm/send";
private final String SERVER_KEY = "REPLACE_YOUR_SERVER_KEY";
private Context context;
private String token;
public SendPushNotification(Context context, String token) {
this.context = context;
this.token = token;
}
#Override
protected Void doInBackground(Void... voids) {
/*{
"to": "DEVICE_TOKEN",
"data": {
"type": "type",
"title": "Android",
"message": "Push Notification",
"data": {
"key": "Extra data"
}
}
}*/
try {
URL url = new URL(FIREBASE_URL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Authorization", "key=" + SERVER_KEY);
JSONObject root = new JSONObject();
root.put("to", token);
JSONObject data = new JSONObject();
data.put("type", "type");
data.put("title", "Android");
data.put("message", "Push Notification");
JSONObject innerData = new JSONObject();
innerData.put("key", "Extra data");
data.put("data", innerData);
root.put("data", data);
Log.e("PushNotification", "Data Format: " + root.toString());
try {
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write(root.toString());
writer.flush();
writer.close();
int responseCode = connection.getResponseCode();
Log.e("PushNotification", "Request Code: " + responseCode);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader((connection.getInputStream())));
String output;
StringBuilder builder = new StringBuilder();
while ((output = bufferedReader.readLine()) != null) {
builder.append(output);
}
bufferedReader.close();
String result = builder.toString();
Log.e("PushNotification", "Result JSON: " + result);
} catch (Exception e) {
e.printStackTrace();
Log.e("PushNotification", "Error: " + e.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
Log.e("PushNotification", "Error: " + e.getMessage());
}
return null;
}
}
Use
SendPushNotification sendPushNotification = new SendPushNotification(context, "token");
sendPushNotification.execute();

Resources