I am working on a app using gmail api.
I want to perform archive functionality.
I had gone through the api https://developers.google.com/gmail/api but unable to find any desired solutions.
Can anyone suggest me any solution for the same.
Thanks in Advance.
A archived message is just a message that lies in the All Mail (which isn't an actual label). You can achieve this by removing the INBOX-label on the message (or any other label you have added to it), which can be achieved with modify.
C# Code for Gmail APIs Archive email by using OAuth 2.0 service.
class ReadAllMails
{
static string[] Scopes = { GmailService.Scope.MailGoogleCom };
static string ApplicationName = "Gmail API .NET Quickstart";
static void Main(string[] args)
{
UserCredential credential;
using (var stream =
new FileStream("credentials_dev.json", FileMode.Open, FileAccess.Read))
{
string credPath = "token_MailGoogleCom.json";
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
}
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
List<string> lableIds = new List<string>();
lableIds.Add("INBOX");
ModifyMessageRequest mods = new ModifyMessageRequest();
mods.RemoveLabelIds= lableIds;
service.Users.Messages.Modify(mods, "me", emailId).Execute();
//emailId that you want to archive
}
}
Related
I have a problem with accessing the (payload of) JWT in a dotnet core controller. I don't know where I am wrong. I think I covered all the important points in the following description. If I have missed something, that could help, please let me know.
Thank you for your time.
Adding authentication service to the servicecollection
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = false,
ValidIssuer = null,
ValidAudience = null,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("testify"))
};
});
The token I used for the request:
The postman call:
The code of the controller action:
[HttpPost]
[ProducesResponseType(typeof(void), 201)]
[ProducesResponseType(typeof(void), 400)]
[ProducesResponseType(typeof(void), 401)]
[ProducesResponseType(typeof(void), 403)]
[ApiExplorerSettings(GroupName = "AuditLog")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public IActionResult Insert([Required] Dto.Log auditLog) => RunSafely(() =>
{
var log = _mapper.Map<Dto.Log, Log>(auditLog);
log.CorrelationId = _headerReader.GetCorrelationId(Request?.Headers);
_logRepository.AddLog(log);
return this.StatusCode((int)HttpStatusCode.Created);
});
The state of the controller:
Your question is a little unclear to me, too, and I am not sure about the creation process of your token. However, I have the exact scenario in one of my projects, which works fine. Here is the code for different puzzles:
Creating the Token:
if (user != null)
{
var result = await _signInManager.CheckPasswordSignInAsync(user, model.Password, false);
if (result.Succeeded)
{
// Create the Token
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName)
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Tokens:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
_config["Tokens:Issuer"],
_config["Tokens:Audience"],
claims,
expires: DateTime.UtcNow.AddMinutes(120),
signingCredentials: creds);
var results = new
{
token = new JwtSecurityTokenHandler().WriteToken(token),
expiration = token.ValidTo
};
return Created("", results);
}
}
For IServiceCollection :
services.AddAuthentication()
.AddCookie()
.AddJwtBearer(cfg =>
{
cfg.TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = _config["Tokens:Issuer"],
ValidAudience = _config["Tokens:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Tokens:Key"]))
};
});
And config.json file: (Note that I changed real-world info due to security reasons)
"Tokens": {
"Key": "foo-foo-foo-foo-foo-foo-foo-foo",
"Issuer": "localhost",
"Audience": "localhost"
}
These settings are exact that I'm using in one of my small projects, and It's working fine. Check if something is missing in your project or not.
You can access payload of jwt by using User object inside of System.Security.Claims.ClaimsPrincipal namespace. For example:
var claims = User.Claims;
This claims contains payload of jwt. Also, you can access other informations like:
if (User.Identity.IsAuthenticated)
{ ....
Within a controller, you can take a dependency on IHttpContextAccessor and then, on the HttpContext, call the extension method GetTokenAsync(string), which will return the encoded string.
string encodedToken = _httpContextAccessor.HttpContext.GetTokenAsync("access_token");
JwtSecurityToken decodedToken = new JwtSecurityToken(encodedToken);
string email = decodedToken.Payload["email"].ToString();
JwtSecurityToken is in the System.IdentityModel.Tokens.Jwt namespace, and GetTokenAsync extension method of HttpContext is in the Microsoft.AspNetCore.Authentication namespace.
RAW PAYLOAD
You can access the raw JWT access token to get its JWTPayload using the following type of code in a .NET API controller:
using System.IdentityModel.Tokens.Jwt;
[Route("api/contacts")]
public class ContactsController : Controller
{
[HttpGet("")]
public async Task<IEnumerable<Contact>> GetContactsAsync()
{
var authHeader = this.HttpContext.Request.Headers.Authorization.ToString();
var parts = authHeader.Split(' ');
var accessToken = parts[1];
var handler = new JwtSecurityTokenHandler();
var token = handler.ReadJwtToken(accessToken);
var payload = token.Payload;
System.Console.WriteLine($"Access token expiry time is {payload.Exp}");
// Business code goes here
}
}
CLAIMS
Microsoft provide a higher level programming model, where by default you never get access to the JWT details. This is a good model to follow - business logic should only ever use a ClaimsPrincipal:
var expiry = this.User.Claims.First(c => c.Type == "exp");
System.Console.WriteLine($"Access token expiry time is {expiry.Value}");
CUSTOM JWT PROCESSING
If you want to implement custom behaviour related to JWTs then it is standard to use the extensibility features of the framework. The plumbing then goes into a middleware class, so that controller classes stay business focused. A couple of example classes of mine show how to extend the .NET framework:
CustomAuthenticationHandler
CustomJWTSecurityTokenHandler
For more info, see these resources of mine, which are focused on promoting understanding of the important standards based OAuth concepts in APIs:
.NET 6 API Code Sample
Blog Post
Easiest way to access payload is by using IHttpContextAccessor injected into your class like below.
public class MyClass: IEwocUser
{
private readonly IHeaderDictionary _headers;
public MyClass(IHttpContextAccessor httpContextAccessor)
{
_headers = httpContextAccessor.HttpContext?.Request.Headers;
}
}
From the headers you can filter for Auth token.
As per this documentation you should be able to create an appRoleAssignment via Microsoft Graph, however this doesn't work. In a GitHub issue I was instructed to create the issue here. We have migrated most of our code from Azure Graph API to Microsoft Graph and this is the last piece that is missing.
This finally worked for me!
There might be more optimized ways to post the JSON but I had to go to basics to make sure nothing is causing this to fail behind the scenes.
const string ROLE_ASSIGNMENT_FORMATTER = "https://graph.microsoft.com/beta/servicePrincipals/{0}/appRoleAssignments";
public static async Task AddApplicationUsers(string enterpriseAppId, string userId, string roleId)
{
HttpClient client = new HttpClient();
string url = string.Format(ROLE_ASSIGNMENT_FORMATTER, enterpriseAppId);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", await GetAccessToken());
var roleAssignment = new
{
appRoleId = roleId,
principalId = userId,
resourceId = enterpriseAppId
};
var content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(roleAssignment), Encoding.UTF8, "application/json");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await client.PostAsync(url, content);
if (response.IsSuccessStatusCode)
{
return ;
}
else
{
throw new HttpRequestException(response.ReasonPhrase);
}
}
i tried to retrieve data from google analytic api, and here is my class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Google.Apis.Analytics.v3;
using Google.Apis.Auth.OAuth2;
using System.Threading;
using Google.Apis.Util.Store;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Services;
namespace zirfoon.model
{
public class googleanalyze
{
public static void main(){
string[] scopes = new string[] { AnalyticsService.Scope.Analytics,AnalyticsService.Scope.AnalyticsManageUsers }; // view and manage your Google Analytics data
var keyFilePath = HttpContext.Current.Server.MapPath("/loominexMvc-f104810a4caa.p12"); // Downloaded from https://console.developers.google.com
var serviceAccountEmail = "loominexmvc#appspot.gserviceaccount.com"; // found https://console.developers.google.com
//loading the Key file
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes =scopes
}.FromCertificate(certificate));
}
}
}
when i get to line below
var credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes =scopes
}.FromCertificate(certificate));
visual studio debugger opens a windows to select ServiceCredential.cs but it does not exist,i changed scope but still nothing...
i have created my api account correctly and all of the information such as serviceAccountEmail and keyFilePath is correct but i still get error
Your code is a little different then what I normally use.
Authentication
string[] scopes = new string[] {AnalyticsService.Scope.Analytics}; // view and manage your Google Analytics data
var keyFilePath = #"c:\file.p12" ; // Downloaded from https://console.developers.google.com
var serviceAccountEmail = "xx#developer.gserviceaccount.com"; // found https://console.developers.google.com
//loading the Key file
var certificate = new X509Certificate2(keyFilePath, "notasecret", X509KeyStorageFlags.Exportable);
var credential = new ServiceAccountCredential( new ServiceAccountCredential.Initializer(serviceAccountEmail) {
Scopes = scopes}.FromCertificate(certificate));
Create the service
var service = new AnalyticsService(new BaseClientService.Initializer() { HttpClientInitializer = credential,
ApplicationName = "Analytics API Sample",});
I would double check that your mapping to keyFilePath is correct.
Code ripped from my tutorial Google Analytics API authentcation
I found out that problem was only for debugging mode
When I ran project without debugger there was not any issue...
I currently have a pair of OWIN-based services that each use OAuth authentication against the same set of users. I intend to isolate the authorisation server (i.e. The token endpoint) and somehow configure both of my services to accept this token. I assume this would involve some configuration of all my services to allow this token to be decrypted across all relevant services. Is this possible?
After talking with Brock Allen in the comments to the original post, I can't really guarantee this is a good/safe solution, but this is the code I ended up using. (Note: a version of this code is available as a nuget package.)
I created a IDataProtector implementation that uses AES:
internal class AesDataProtectorProvider : IDataProtector
{
// Fields
private byte[] key;
// Constructors
public AesDataProtectorProvider(string key)
{
using (var sha1 = new SHA256Managed())
{
this.key = sha1.ComputeHash(Encoding.UTF8.GetBytes(key));
}
}
// IDataProtector Methods
public byte[] Protect(byte[] data)
{
byte[] dataHash;
using (var sha = new SHA256Managed())
{
dataHash = sha.ComputeHash(data);
}
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = this.key;
aesAlg.GenerateIV();
using (var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV))
using (var msEncrypt = new MemoryStream())
{
msEncrypt.Write(aesAlg.IV, 0, 16);
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (var bwEncrypt = new BinaryWriter(csEncrypt))
{
bwEncrypt.Write(dataHash);
bwEncrypt.Write(data.Length);
bwEncrypt.Write(data);
}
var protectedData = msEncrypt.ToArray();
return protectedData;
}
}
}
public byte[] Unprotect(byte[] protectedData)
{
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = this.key;
using (var msDecrypt = new MemoryStream(protectedData))
{
byte[] iv = new byte[16];
msDecrypt.Read(iv, 0, 16);
aesAlg.IV = iv;
using (var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV))
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
using (var brDecrypt = new BinaryReader(csDecrypt))
{
var signature = brDecrypt.ReadBytes(32);
var len = brDecrypt.ReadInt32();
var data = brDecrypt.ReadBytes(len);
byte[] dataHash;
using (var sha = new SHA256Managed())
{
dataHash = sha.ComputeHash(data);
}
if (!dataHash.SequenceEqual(signature))
throw new SecurityException("Signature does not match the computed hash");
return data;
}
}
}
}
}
And then used this in an ISecureDataFormat implementation like so:
public class SecureTokenFormatter : ISecureDataFormat<AuthenticationTicket>
{
// Fields
private TicketSerializer serializer;
private IDataProtector protector;
private ITextEncoder encoder;
// Constructors
public SecureTokenFormatter(string key)
{
this.serializer = new TicketSerializer();
this.protector = new AesDataProtectorProvider(key);
this.encoder = TextEncodings.Base64Url;
}
// ISecureDataFormat<AuthenticationTicket> Members
public string Protect(AuthenticationTicket ticket)
{
var ticketData = this.serializer.Serialize(ticket);
var protectedData = this.protector.Protect(ticketData);
var protectedString = this.encoder.Encode(protectedData);
return protectedString;
}
public AuthenticationTicket Unprotect(string text)
{
var protectedData = this.encoder.Decode(text);
var ticketData = this.protector.Unprotect(protectedData);
var ticket = this.serializer.Deserialize(ticketData);
return ticket;
}
}
The 'key' parameter on the constructor can then set to the same value on a number of services and they will all be able to decrypt ('unprotect') and use the ticket.
The Katana OAuth2 Authorization Server middleware wasn't really designed for this scenario (mainly because its reliance upon the machinekey for token verification).
If you're looking to centralize the token generation then you should look into an OAuth2 authorization server that's designed for this. Thinktecture AuthorizationServer is an open source server that does this: http://thinktecture.github.io/Thinktecture.AuthorizationServer/
I know this is an old question, but I had a similar use case. According to the docs, OWIN OAuth uses the machine key to protect the data. Since you control all instances, I presume that simply setting the machinekey in the web config would work.
Ref: http://msdn.microsoft.com/en-us/library/microsoft.owin.security.oauth.oauthauthorizationserveroptions(v=vs.113).aspx
You can use this nuget package https://www.nuget.org/packages/Owin.Security.AesDataProtectorProvider/
It contains extension method for IAppBuilder that allows you setup own key
appBuilder.UseAesDataProtectorProvider(key);
I'm trying to get in memory hosting working for integration testing our web api project, but have hit an issue with authentication when using it. I have recreated this on a basic Web Api project using the default Web Api template and the values controller it creates.
We are using Autofac so have included this in the test too. We are also using windows authentication for the web api, but for the purposes of the test this is not important.
The issue is that the "server" in the test always returns "Authorization has been denied for this request."
So what is the best way to authorize with the in memory server? I've commented out some code from another stackoverflow question but that also didn't seem to work.
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web.Http;
using Autofac;
using Autofac.Integration.WebApi;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WebApiTesting.Controllers;
namespace WebApiTesting.Tests.Controllers
{
[TestClass]
public class ValuesControllerTest
{
private const string URL = "http://test.testing.com/";
private const string Username = "user";
private const string Password = "supersecret";
[TestMethod]
public void InMemoryHosting()
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new {id = RouteParameter.Optional});
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
var server = new HttpServer(config);
var builder = new ContainerBuilder();
// Register API controllers using assembly scanning.
builder.RegisterApiControllers(typeof(ValuesController).Assembly);
var container = builder.Build();
server.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
var client = new HttpClient(server);
using (var request = CreateRequest("api/values", "application/json", HttpMethod.Get))
{
//Act
using (HttpResponseMessage response = client.SendAsync(request).Result)
{
// Assert
Assert.IsNotNull(response.Content);
Assert.AreEqual("application/json", response.Content.Headers.ContentType.MediaType);
var content = response.Content.ReadAsStringAsync().Result;
Assert.AreNotEqual("{\"Message\":\"Authorization has been denied for this request.\"}", content);
}
}
}
private HttpRequestMessage CreateRequest(string url, string mthv, HttpMethod method)
{
var request = new HttpRequestMessage { RequestUri = new Uri(URL + url) };
/*byte[] toEncodeAsBytes = Encoding.UTF8.GetBytes(string.Format("{0}:{1}", Username, Password));
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(toEncodeAsBytes));*/
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(mthv));
request.Method = method;
return request;
}
}
}
Just to document what worked in the end, I added the following line to my CreateRequest Method
Thread.CurrentPrincipal = new ClientRolePrincipal(new HttpListenerBasicIdentity(Username, Password));
I'm not really sure if this is the best way to handle it, but it does work at least.