I have used GmailQuickstart to modify email signatures. It updates my own gmail account, but I want o do that for all the users of the company.
How do I make my Google API project used be entire organization.
private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
// Load client secrets.
InputStream in = GmailQuickstart.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
.setAccessType("offline")
.build();
LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
}
public static void main(String... args) throws IOException, GeneralSecurityException {
// Build a new authorized API client service.
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
Gmail service = new Gmail.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
.setApplicationName(APPLICATION_NAME)
.build();
// Print the labels in the user's account.
String user = "me";
final java.util.logging.Logger buggyLogger = java.util.logging.Logger.getLogger(FileDataStoreFactory.class.getName());
buggyLogger.setLevel(java.util.logging.Level.SEVERE);
SendAs primaryAlias = null;
ListSendAsResponse aliases = service.users().settings().sendAs().list("me").execute();
for (SendAs alias : aliases.getSendAs()) {
if (alias.getIsPrimary()) {
primaryAlias = alias;
break;
}
}
//service.users().getProfile().getUserId();
SendAs aliasSettings = new SendAs()
.setSignature("Email : " + primaryAlias.getSendAsEmail() + "Company name, Address, zip");
SendAs result = service.users().settings().sendAs().patch(
"me",
primaryAlias.getSendAsEmail(),
aliasSettings)
.execute();
System.out.println("Updated signature for " + result.getDisplayName());
}
The above code works, I can change my email signatire. I would like to change email signature acress the comapony for all the users. Please Let me know if there is any solution that you guys have implemented?
Related
Below is the output from an error which is being generated whilst trying to authenticate credentials with Azure for allowing public access to a Power BI Embedded report:
It has initially displayed a pop to confirm that I want to give but after I have given permission the above error is displayed.
I have checked the credentials I have entered in the appsettings.json file and have confirmed that they are correct.
In the Startup.cs file I have added this section:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"), "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi(Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' '))
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
services.AddScoped(typeof(PowerBiServiceApi));
services.AddRazorPages()
.AddMicrosoftIdentityUI();
The error itself is being generated whilst acquiring the access token in the PowerBiServiceApi the code for which is provided below:
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Identity.Web;
using Microsoft.PowerBI.Api;
using Microsoft.PowerBI.Api.Models;
using Microsoft.Rest;
namespace NDTSM2.Services.Implementations.PowerBI
{
// A view model class to pass the data needed to embed a single report.
public class EmbeddedReportViewModel
{
public string Id;
public string Name;
public string EmbedUrl;
public string Token;
}
public class PowerBiServiceApi
{
private ITokenAcquisition tokenAcquisition { get; }
private string urlPowerBiServiceApiRoot { get; }
public PowerBiServiceApi(IConfiguration configuration, ITokenAcquisition tokenAcquisition)
{
this.urlPowerBiServiceApiRoot = configuration["PowerBi:ServiceRootUrl"];
this.tokenAcquisition = tokenAcquisition;
}
public const string powerbiApiDefaultScope = "https://analysis.windows.net/powerbi/api/.default";
// A method to get the Azure AD token (also known as 'access token')
public string GetAccessToken()
{
return this.tokenAcquisition.GetAccessTokenForAppAsync(powerbiApiDefaultScope).Result;
}
public PowerBIClient GetPowerBiClient()
{
var tokenCredentials = new TokenCredentials(GetAccessToken(), "Bearer");
return new PowerBIClient(new Uri(urlPowerBiServiceApiRoot), tokenCredentials);
}
public async Task<EmbeddedReportViewModel> GetReport(Guid WorkspaceId, Guid ReportId)
{
PowerBIClient pbiClient = GetPowerBiClient();
// Call the Power BI service API to get the embedding data
var report = await pbiClient.Reports.GetReportInGroupAsync(WorkspaceId, ReportId);
// Generate a read-only embed token for the report
var datasetId = report.DatasetId;
var tokenRequest = new GenerateTokenRequest(TokenAccessLevel.View, datasetId);
var embedTokenResponse = await pbiClient.Reports.GenerateTokenAsync(WorkspaceId, ReportId, tokenRequest);
var embedToken = embedTokenResponse.Token;
// Return the report embedded data to caller
return new EmbeddedReportViewModel
{
Id = report.Id.ToString(),
EmbedUrl = report.EmbedUrl,
Name = report.Name,
Token = embedToken
};
}
}
}
Does anyone have any ideas why the error is being generated (have looked for guidance but so far none of the advice has rectified the issue)?
Any help would be very much appreciated.
Further to original question:
Error Details:
Operation returned an invalid status code 'Unauthorized'
at Microsoft.PowerBI.Api.ReportsOperations.GetReportInGroupWithHttpMessagesAsync(Guid groupId, Guid reportId, Dictionary`2 customHeaders, CancellationToken cancellationToken)
at Microsoft.PowerBI.Api.ReportsOperationsExtensions.GetReportInGroupAsync(IReportsOperations operations, Guid groupId, Guid reportId, CancellationToken cancellationToken)
at Microsoft.PowerBI.Api.ReportsOperationsExtensions.GetReportInGroup(IReportsOperations operations, Guid groupId, Guid reportId)
at NDTSM2.Services.Implementations.PowerBI.PbiEmbedService.GetEmbedParams(Guid workspaceId, Guid reportId, Guid additionalDatasetId) in C:\Users\cryof\Desktop\NDTMS4\Service\NDTSM2.SERVICES\Implementations\PowerBI\PbiEmbedService.cs:line 41
at NDTMS2.Web.Controllers.EmbedInfoController.GetEmbedInfo() in C:\Users\cryof\Desktop\NDTMS4\NDTMS2.WEB\Controllers\EmbedInfoController.cs:line 40
The line that is generating the error in the PbiEmbedService is this:
var pbiReport = pbiClient.Reports.GetReportInGroup(workspaceId, reportId);
Follow the sample here
// For app only authentication, we need the specific tenant id in the authority url
var tenantSpecificUrl = azureAd.Value.AuthorityUrl.Replace("organizations", azureAd.Value.TenantId);
// Create a confidential client to authorize the app with the AAD app
IConfidentialClientApplication clientApp = ConfidentialClientApplicationBuilder
.Create(azureAd.Value.ClientId)
.WithClientSecret(azureAd.Value.ClientSecret)
.WithAuthority(tenantSpecificUrl)
.Build();
// Make a client call if Access token is not available in cache
authenticationResult = clientApp.AcquireTokenForClient(azureAd.Value.ScopeBase).ExecuteAsync().Result;
Similar issue here. I have checked the answer and try to implement all the possible forms of link in my startup.cs class with the following code:
var idClient = ConfidentialClientApplicationBuilder.Create(appId)
.WithRedirectUri(redirectUri)
.WithTenantId(tenantId)
.WithClientSecret(appSecret)
.WithAuthority(Authority) // Authority contains the link as mentioned in the page(link attached above)
.Build();
I still get the similar error:
"OpenIdConnectMessage.Error was not null, indicating an error. Error: 'invalid_request'. Error_Description (may be empty): 'AADSTS50194: Application 'xxx-xxx-xxx-xxx-xxxx'(ASPNET-Quickstart) is not configured as a multi-tenant application. Usage of the /common endpoint is not supported for such applications created after '10/15/2018'. Use a tenant-specific endpoint or configure the application to be multi-tenant.
Trace ID: xxx-xxx-xxx-xxx-xxxx
Correlation ID: xxx-xxx-xxx-xxx-xxxx
Timestamp: 2022-06-11 05:33:24Z'. Error_Uri (may be empty): 'error_uri is null'."
The combination of links I have used in variable Authority are the following: "https://login.microsoftonline.com/MY_TENANT_NAME" and "https://login.microsoftonline.com/MY_TENANT_ID"
I am being redirect to login page but after entering credentials OnAuthenticationFailedAsync method is being executed. This is the code of my startup class:
[assembly: OwinStartup(typeof(Web.Startup))]
namespace Web
{
public partial class Startup
{
// Load configuration settings from PrivateSettings.config
private static string appId = ConfigurationManager.AppSettings["ida:AppId"];
private static string appSecret = ConfigurationManager.AppSettings["ida:AppSecret"];
private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
private static string graphScopes = ConfigurationManager.AppSettings["ida:AppScopes"];
private static string tenantId = ConfigurationManager.AppSettings["ida:tenantId"];
private static string aadInstance = EnsureTrailingSlash(ConfigurationManager.AppSettings["ida:AADInstance"]);
public static string Authority = "https://graph.microsoft.com/"+ tenantId;
string graphResourceId = "https://graph.microsoft.com/";
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = appId,
Authority = "https://login.microsoftonline.com/common/v2.0",
Scope = $"openid email profile offline_access {graphScopes}",
RedirectUri = redirectUri,
PostLogoutRedirectUri = redirectUri,
TokenValidationParameters = new TokenValidationParameters
{
// For demo purposes only, see below
ValidateIssuer = true
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailedAsync,
AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync
}
}
);
}
private static Task OnAuthenticationFailedAsync(AuthenticationFailedNotification<OpenIdConnectMessage,
OpenIdConnectAuthenticationOptions> notification)
{
notification.HandleResponse();
string redirect = $"/Home/Error?message={notification.Exception.Message}";
if (notification.ProtocolMessage != null && !string.IsNullOrEmpty(notification.ProtocolMessage.ErrorDescription))
{
redirect += $"&debug={notification.ProtocolMessage.ErrorDescription}";
}
notification.Response.Redirect(redirect);
return Task.FromResult(0);
}
private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification)
{
var idClient = ConfidentialClientApplicationBuilder.Create(appId)
.WithRedirectUri(redirectUri)
.WithTenantId(tenantId)
.WithClientSecret(appSecret)
.WithAuthority(Authority)
.Build();
string email = string.Empty;
try
{
string[] scopes = graphScopes.Split(' ');
var result = await idClient.AcquireTokenByAuthorizationCode(
scopes, notification.Code).ExecuteAsync();
email = await GraphHelper.GetUserDetailsAsync(result.AccessToken);
}
catch (MsalException ex)
{
System.Diagnostics.Trace.TraceError(ex.Message);
}
notification.HandleResponse();
notification.Response.Redirect($"/Account/SignInAzure?email={email}");
}
private static string EnsureTrailingSlash(string value)
{
if (value == null)
{
value = string.Empty;
}
if (!value.EndsWith("/", StringComparison.Ordinal))
{
return value + "/";
}
return value;
}
}
}
My application is for single tenant so please don't suggest me to change the setting and make it for multi-tenant.
Please check below points:
After trying to change it to specific tenant i.e.;
After changing to Ex: - https://login.microsoftonline.com/contoso.onmicrosoft.com (or tenant id),
please save changes ,refresh portal / everything and try again.
If still it shows the error , check if the Application is registered to the Azure AD Tenant as Multi Tenant Application.
Then if it still remains check if the account is actually on Azure
AD ,as this error can occur when the user credentials you are trying
to use does not belong to the same tenant where the application is
actually registered in.
If it is different tenant and you are trying to access from different
account, then you may need to change its supported account types to
any organizational directory or you need to check for correct
credentials. If not check everything or create a new app registration
.
Also please check this "Use a tenant-specific endpoint or configure the application to be multi-tenant" when signing into my Azure website for possible
ways to solve the issue.
Else you can raise a support request
References:
msal - MsalException: Applicationis not configured as a multi-tenant
application. Android - Stack Overflow
Use single-tenant Azure AD apps with Microsoft Graph Toolkit -
Waldek Mastykarz
I have following in my startup:
public partial class Startup
{
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private static string aadInstance = ConfigurationManager.AppSettings["ida:AadInstance"];
private static string tenant = ConfigurationManager.AppSettings["ida:Tenant"];
private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
// B2C policy identifiers
// public static string SignUpPolicyId = ConfigurationManager.AppSettings["ida:SignUpPolicyId"];
public static string SignInUpPolicyId = ConfigurationManager.AppSettings["ida:SignInUpPolicyId"];
public static string DefaultPolicy = SignInUpPolicyId;
public static string ResetPasswordPolicyId = ConfigurationManager.AppSettings["ida:ResetPasswordPolicyId"];
public static string ProfilePolicyId = ConfigurationManager.AppSettings["ida:UserProfilePolicyId"];
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
// Configure OpenID Connect middleware for each policy
app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(SignInUpPolicyId));
//app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(ResetPasswordPolicyId));
// app.UseOpenIdConnectAuthentication(CreateOptionsFromPolicy(SignInPolicyId));
}
private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
notification.HandleResponse();
// Handle the error code that Azure AD B2C throws when trying to reset a password from the login page
// because password reset is not supported by a "sign-up or sign-in policy"
if (notification.ProtocolMessage.ErrorDescription != null && notification.ProtocolMessage.ErrorDescription.Contains("AADB2C90118"))
{
// If the user clicked the reset password link, redirect to the reset password route
notification.Response.Redirect("/Account/ResetPassword");
}
else if (notification.Exception.Message == "access_denied")
{
notification.Response.Redirect("/");
}
else
{
notification.Response.Redirect("/Home/Error?message=" + notification.Exception.Message);
}
return Task.FromResult(0);
}
private Task OnRedirectToIdentityProvider(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
var policy = notification.OwinContext.Get<string>("Policy");
if (!string.IsNullOrEmpty(policy) && !policy.Equals(DefaultPolicy))
{
//notification.ProtocolMessage.Scope = OpenIdConnectScopes.OpenId;
//notification.ProtocolMessage.ResponseType = OpenIdConnectResponseTypes.IdToken;
notification.ProtocolMessage.IssuerAddress = notification.ProtocolMessage.IssuerAddress.Replace(DefaultPolicy, policy);
}
return Task.FromResult(0);
}
private OpenIdConnectAuthenticationOptions CreateOptionsFromPolicy(string policy)
{
return new OpenIdConnectAuthenticationOptions
{
// For each policy, give OWIN the policy-specific metadata address, and
// set the authentication type to the id of the policy
MetadataAddress = String.Format(aadInstance, tenant, policy),
AuthenticationType = policy,
// These are standard OpenID Connect parameters, with values pulled from web.config
ClientId = clientId,
RedirectUri = redirectUri,
PostLogoutRedirectUri = redirectUri,
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailed
},
Scope = "openid",
ResponseType = "id_token",
// This piece is optional - it is used for displaying the user's name in the navigation bar.
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
SaveSigninToken = true //important to save the token in boostrapcontext
}
};
}
}
In my Controller I have following:
public void ResetPassword()
{
// Let the middleware know you are trying to use the reset password
policy (see OnRedirectToIdentityProvider in Startup.Auth.cs)
HttpContext.GetOwinContext().Set("Policy", Startup.ResetPasswordPolicyId);
// Set the page to redirect to after changing passwords
var authenticationProperties = new AuthenticationProperties { RedirectUri = "/" };
HttpContext.GetOwinContext().Authentication.Challenge(authenticationProperties);
}
Right now the reset password just redirect to "/". I am not sure how this works, and havent been able to find any samples. I tried following this sample but it uses some cores libraries and havent succeeded using the documentation.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-devquickstarts-web-dotnet-susi
After following Chris suggestion it worked. See image below when clicking reset password.
Follow this Startup.Auth.cs file as closely as possible to get yourself started.
The ConfigureAuth method of the Startup class registers the OWIN OpenID Connect middleware that enables an ASP.NET MVC controller to set the Azure AD B2C policy, to be redirected to, using the OWIN context.
Example:
HttpContext.GetOwinContext().Set("Policy", Startup.ResetPasswordPolicyId);
I want to list and change the tags and their values for the Azure Virtual Machines using .NET SDK.
Please let me know the way for this.
Thank You.
Since I don't have a Virtual Machine handy, I am posting code for updating tags for a Resource Group.
First, please ensure that Azure AD application is properly set up. You may find this link useful for that purpose: https://msdn.microsoft.com/en-us/library/azure/ee460782.aspx.
Next, I created a simple console application. What you would need to do is get Microsoft.Azure.ResourceManager 1.0.0-preview and Active Directory Authentication Library 2.22.302111727 Nuget packages in your application.
After that, things are pretty simple. Please see the code below:
using System;
using System.Linq;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Threading;
using Microsoft.Azure.Management.Resources;
using Microsoft.Rest;
namespace AzureARMDemo
{
class Program
{
private static string ClientId = "<your-application-client-id>";//This is the PowerShell Client Id
private static string TenantId = "<tenant-id>";
private static string LoginEndpoint = "https://login.microsoftonline.com/";
private static string ServiceManagementApiEndpoint = "https://management.core.windows.net/";
private static string RedirectUri = "urn:ietf:wg:oauth:2.0:oob";
private static string SubscriptionId = "<your-azure-subscription-id>";
private static string AzureResourceManagerEndpoint = "https://management.windows.net";
private static string ResourceGroupNameToUpdate = "<resource-group-name-to-update>";
static void Main(string[] args)
{
var token = GetAuthorizationHeader();
var credentials = new TokenCredentials(token);
var resourceManagerClient = new ResourceManagementClient(new Uri(AzureResourceManagerEndpoint), credentials)
{
SubscriptionId = SubscriptionId,
};
Console.WriteLine("Listing resource groups. Please wait....");
Console.WriteLine("----------------------------------------");
var resourceGroup = resourceManagerClient.ResourceGroups.List().FirstOrDefault(r => r.Name == ResourceGroupNameToUpdate);
if (resourceGroup != null)
{
var tags = resourceGroup.Tags;
if (!tags.ContainsKey("Key1"))
{
tags.Add("Key1", "Value1");
}
else
{
tags["Key1"] = tags["Key1"] + " Updated";
}
Console.WriteLine("Updating resource group. Please wait....");
Console.WriteLine("----------------------------------------");
resourceManagerClient.ResourceGroups.Patch(ResourceGroupNameToUpdate, resourceGroup);
Console.WriteLine("Resource group updated.");
Console.WriteLine("-----------------------");
}
//var resourceGroups = resourceManagerClient.ResourceGroups.List();
//foreach (resourceGroup in resourceGroups)
//{
// Console.WriteLine("Resource Group Name: " + resourceGroup.Name);
// Console.WriteLine("Resource Group Id: " + resourceGroup.Id);
// Console.WriteLine("Resource Group Location: " + resourceGroup.Location);
// Console.WriteLine("----------------------------------------");
//}
Console.WriteLine("Press any key to terminate the application");
Console.ReadLine();
}
private static string GetAuthorizationHeader()
{
AuthenticationResult result = null;
var context = new AuthenticationContext(LoginEndpoint + TenantId);
var thread = new Thread(() =>
{
result = context.AcquireToken(
ServiceManagementApiEndpoint,
ClientId,
new Uri(RedirectUri));
});
thread.SetApartmentState(ApartmentState.STA);
thread.Name = "AquireTokenThread";
thread.Start();
thread.Join();
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
string token = result.AccessToken;
return token;
}
}
}
I want read all messages with gmail account using Java and IMAP.
Can i do this, or now i need to use OAuth and Gmail API?
That is my Java simple code:
import java.util.*;
import javax.mail.*;
public class ReadingEmail {
public static void main(String[] args) {
Properties props = new Properties();
props.setProperty("mail.store.protocol", "imaps");
try {
Session session = Session.getInstance(props, null);
session.setDebug(true);
Store store = session.getStore("imaps");
store.connect("imap.gmail.com", "email", "pass");
Folder inbox = store.getFolder("INBOX");
inbox.open(Folder.READ_ONLY);
Message msg = inbox.getMessage(inbox.getMessageCount());
Address[] in = msg.getFrom();
for (Address address : in) {
System.out.println("FROM:" + address.toString());
}
Multipart mp = (Multipart) msg.getContent();
BodyPart bp = mp.getBodyPart(0);
System.out.println("SENT DATE:" + msg.getSentDate());
System.out.println("SUBJECT:" + msg.getSubject());
System.out.println("CONTENT:" + bp.getContent());
} catch (Exception mex) {
mex.printStackTrace();
}
}
}
But i have a error:
My client isn't accepting my username and password
IMAP is enabled in Gmail account settings. What to do?
Thank you!
Of course you can, that's the whole point of IMAP. You need to authenticate, though, either with OAuth2, or app-specific password (your account password will not work).