I'm trying to create a custom "from" send-as alias (sendAsEmail) with Gmail API and Google Admin: https://developers.google.com/gmail/api/reference/rest/v1/users.settings.sendAs/create
I'm getting a 400 error with sendAsEmail is not a valid user or group.
In Google Admin I have a 3 verified domains, all with MX properly registered with gmail services :
#domain-a.com is primary domain
#domain-b.com (not a domain alias)
#domain-c.com (not a domain alias)
user#domain-a.com is a user, with no send-as alias defined.
When I create the sendAsEmail user#domain-b.com, no issue. I can see it appears in gmail.
When I create the sendAsEmail user#domain-c.com, it fails. I can not find out why. If I search for user#domain-c.com in Google Admin to be sure if it is not a group, no result. Any help would be very welcomed.
I'm doing my api calls with PHP, but I dont thing that the issue is related with the language.
Finally found a solution. There was actually multiples causes :
Google Admin :
First on Google Admin side, I had to create an alias : https://developers.google.com/admin-sdk/directory/v1/guides/manage-user-aliases. If you dont do this, the Gmail sendAsEmail creation will fail. Note that the Client HTTP used to do this call needs to use an admin user :
<?php
putenv('GOOGLE_APPLICATION_CREDENTIALS=./client_secrets.json');
$this->client = new Google_Client();
$this->client->useApplicationDefaultCredentials(); // loads whats in that json service account file.
$this->client->setScopes([
Google_Service_Directory::ADMIN_DIRECTORY_USER,
Google_Service_Directory::ADMIN_DIRECTORY_USER_SECURITY,
Google_Service_Directory::ADMIN_DIRECTORY_USER_ALIAS
]);
$this->client->setSubject('admin#domain.com');
Gmail :
Create a sendAsEmail like explained here : https://developers.google.com/gmail/api/reference/rest/v1/users.settings.sendAs/create
Note that the Client Http used to do this call needs to impersonate the user :
<?php
putenv('GOOGLE_APPLICATION_CREDENTIALS=./client_secrets.json');
$this->client = new Google_Client();
$this->client->useApplicationDefaultCredentials(); // loads whats in that json service account file.
$this->client->setScopes([
Google_Service_Gmail::GMAIL_SETTINGS_BASIC,
Google_Service_Gmail::GMAIL_SETTINGS_SHARING
]);
$this->client->setSubject('user#domain.com');
Related
I want to create Microsoft BotBuilder following this tutorial. But it seems SO complicated compared to v3.(BTW: starting a tutorial with 3 authentications that cover 75% of the article is not a good sign)
So I follow the EchoBot sample (I chose MultiTenant because my server is outside AND it seems the most covered):
const credentialsFactory = new BotBuilder.ConfigurationServiceClientCredentialFactory({
MicrosoftAppId: '***',
MicrosoftAppPassword: '***',
MicrosoftAppType: 'MultiTenant',
});
const botFrameworkAuthentication = BotBuilder.createBotFrameworkAuthenticationFromConfiguration(null, credentialsFactory);
const onTurnErrorHandler = async (context, error) => { /* for errors */ }
const adapter = new BotBuilder.CloudAdapter(botFrameworkAuthentication);
adapter.onTurnError = onTurnErrorHandler;
Questions:
How do I test everything is working ? isValidAppId() and isAuthenticationDisabled() are the only available method and seems OK.
How do I get MicrosoftAppPassword ? According to the documentation I have to click manage, then create a value/secret pair. Should I use value ? or secret ? Why none is named password ? Anyway none works ...
To test if it works, I follow the sample:
setup an HTTP POST Endpoint (with Node-RED)
declare the endpoint in Azure Portal Bot Configuration
go to webchat to test
I correctly receive the Messages then try to do some authentication/parisng (I assume) :
await adapter.process(msg.req, msg.res, (context) => {
/* do some stuff */
});
But it fails with a very explicit error :
Error: 1 validation issue(s)
Issue #0: custom_error at [[root]]
Response
I think, the errors is related to an authentication issue, since I don't understand what/how to set the password. I guess I have to go through this CloudAdapter in order to get a parsed context and be able to send messages.
EDIT 07/05/2022:
I use the AppId from here :
I click "Manage" but where is the AppPassword ?
EDIT 12/05/2022:
Using cURL I manage to validate the appID and appPassword (the value (hidden by stars) of the secret).
BotBuilder is mixing the Communication Stack (HTTP / WebSocket) and the Logic stack (Turn Conversation). I think it's a bad habbit but I manage a workaround:
I use a BotFrameworkAdapter instead of CloudAdpater
I call adapter.processActivity() instead of adapter.process()
The adapter still want to end() the request and set deprecated values but it works in Node-RED. The context handle all the requirement to call sendActivity() anywhere multiple times.
To answer second question in your case, kindly go through the link :https://learn.microsoft.com/en-us/azure/bot-service/bot-service-quickstart-registration?view=azure-bot-service-4.0&tabs=multitenant
To answer the first question in your case, kindly check disabling and enabling the authentication to test the app: https://learn.microsoft.com/en-us/azure/bot-service/bot-service-troubleshoot-authentication-problems?view=azure-bot-service-4.0&tabs=csharp
As far as getting the password goes, when you create a new Multi Tenant Azure Bot resource, the app password goes into the Azure Key Vault created alongside it. The AppId and AppPassword are randomly generated by Azure. You can get them from the key vault in the Azure portal in the correct resource group.
If you want to create a resource manually using the CLI and define your own password, you can use this docs page for deploying a bot. Make sure you select the correct tabs. I have pre-selected C# and Multi Tenant in a new resource group for the above link.
Single Tenant is for limiting your bot's connections to Azure resources within the same tenant, and a User Assigned Managed Identity is if you want to make use of an Azure Managed Identity across the bot's resources instead of having a password for each resource.
You should be able to simply add the AppId and AppPassword to the echo bot sample and deploy it.
We are developing a PowerAutomate Flow to automate the process of inviting external users to a SharePoint Site.
Below are the steps being followed so far
Created an MS Form for an external user to register
Passing the response**(Email)** from the form to the flow
Adding the user to a SharePoint Group using email parameter and sending an email invite to the External User(Requirement)
I have been able to get to point no 2 , However I have been experiencing challenges achieving point no 3
Came across different articles online for adding a guest users , However most of them talk about adding the guest to Azure AD as shown below
https://medium.com/southworks/adding-a-guest-to-an-office-365-sharepoint-site-with-javascript-fa7604ad8678
https://laurakokkarinen.com/how-to-build-a-guest-user-self-service-registration-for-office-365-with-azure/
https://www.timlinenterprises.com/how-to-invite-external-users-using-microsoft-flow-and-microsoft-graph-api/
Also checked a few articles for running PowerShell commands from Flow , However this approach doesn't look straightforward either
The below article works only for internal users
https://www.c-sharpcorner.com/article/add-the-users-to-the-sharepoint-groups-using-microsoft-flow/
The end goal here is to invite external user to a SharePoint Site once the user registers himself through a registration form (MS Form)
Would appreciate if anyone could help me out in achieving this.
Thanks in advance
Before inviting the user to SharePoint you must add him to Azure AD. So you will need to configure an HTTP action to invite the user first.
If you are using SharePoint Modern Sites (those who have Microsoft 365 groups associated), you need to create a HTTP action to add the guest to the group:
HTTP Action Configuration Here
NOTE: HTTP will not accept "#" sign directly, so you need to put it into a "Compose" or "Variable" and add it as per my screenshot.
In the URI you have the Group ID from Azure AD.
In the Body it's the guest user ID
You will need to register and Azure AD App to use for the HTTP action and give it the following permissions:
Graph -> Application -> GroupMember.ReadWrite.All, Group.ReadWrite.All and Directory.ReadWrite.All
https://learn.microsoft.com/en-us/graph/api/group-post-members?view=graph-rest-1.0&tabs=http#permissions
Use the App ID and Secret to connect the HTTP action.
This is my solution to add Guest Users to Private Channels in MS Teams with PowerAutomate.
Step0 - Register the domain of the Guest Users in your AD account as a valida Guest Domain
Step1 - User a registration form (MS Forms)
Step2 - Create a Trigger Process in MS PowerAutomate to receive the Form Data. I like to create small/short flows to only capture and validate form data, and then call a separate Flow / RestService. This makes your solution a little bit more decoupled and reusable. (Imagine replacing the Form with a web app form or mobile app form in the future).
Create a second HTTP request trigger flow receiving the Form data (optional way to setup multi-flow solution)
Step3 - Create a Private Channel in teams via GrapAPI
GraphAPI - POST https://graph.microsoft.com/v1.0/teams/<teams_id>/channels
POST BODY:
{
"membershipType": "private",
"displayName": "<e.g. channel name from form data>",
"description": "<e.g. description from form data>",
"members": [
{
"#odata.type": "#microsoft.graph.aadUserConversationMember",
"user#odata.bind": "https://graph.microsoft.com/v1.0/users('owner.user#mydomain.com')",
"roles": [
"owner"
]
}
],
"#odata.type": "#Microsoft.Graph.channel"
}
Step4 - Call GraphAPI to retrieve the Guest User Details
GraphAPI: GET https://graph.microsoft.com/v1.0/users?$filter=mail eq 'guest.user#email.com'
I have added this in a loop - since I had many members who had to be added - and I also included a condition check to check if the domain is indeed valid
Now you can assign the output (or portions of the output) to some variables
Step5 - Retrieve the ID value from the step above (Step4). This is the value that must be used to add the new guest member.
Retrieve the ID from the Step4 output
Also set a variable to the account type - which should (MUST BE) be "guest"
Now - Add guest users to the private teams channel
Step6 - Call GraphAPI to add guest members
GraphAPI: POST https://graph.microsoft.com/v1.0/teams/<team_id>/channels/<channel_id>/members
Post Body:
The role must be "guest" for guest account
But valid options for other types of access can be
owner
member
guest
Microsoft documentation (HERE) states roles must be owner or empty
This did not work so well for me.
Use guest
{
"#odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": [
"#{variables('membership_type')}"
],
"user#odata.bind": "https://graph.microsoft.com/v1.0/users('#{variables('principal_user')}')"
}
Bonus Step
Now you can catch all responses from the previous steps and respond back with an HTTP Request/Response connector.
A 200 response on successful executions
A non-200 response on failed executions (or how ever you desire)
To configure exception handling or failure handling responses do this below
I am trying to create an application to browse my contacts directory on Exchange.
I have set up everything and I am able request the authorization from my app.
I can present the modal view, enter the login information, retrieve the token, but when I try to authorize the app with the same account I have created it I get this message:
The client <my app id> and resource <my app URI> identify the same application.
If I try to authorize another account, I receive this message instead:
User account <an email> from external identity provider <a url> is not
supported for application <my app id>
If I try to login on the Graph Explorer Console or on the Office 365 OAuth Sandbox, they work fine with the second address, but not with the first one.
I am really confuse. I feel like I have mess up some configuration option, but I don't really understand which one.
Regarding #1, please do not pass App ID of your application for resource querystring parameter when authenticating against your tenant URL. I ran into the exact same problem.
Then I ran WebApp-MultiTenant-OpenIdConnect-DotNet from Github and noted down the sign-in URL it created and I used the following:
var signInUrl = String.Format(
"https://login.windows.net/{0}/oauth2/authorize?response_mode=form_post&response_type=code+id_token&scope=openid+profile&client_id={1}&resource={2}&redirect_uri={3}&state={4}&nonce={5}",
Uri.EscapeDataString(tenantId),
Uri.EscapeDataString(clientId),
Uri.EscapeDataString("https://graph.windows.net"),
Uri.EscapeDataString(redirectUri),
Uri.EscapeDataString(state),
string.Format("{0}{1}", DateTime.UtcNow.Ticks, Guid.NewGuid().Stringify())
);
Basically I used https://graph.windows.net instead of App ID and magically things started to work :).
Another thing you could try (and I have not tried it) is authenticating against common endpoint https://login.windows.net/common/oauth2/authorize and provide your App ID for the resource querystring.
I am integrating the login of a NodeJS app to the company's Active Directory using the Exchange Web Services endpoint. This way I can validate if the provided credentials (username and password) match with the Active Directory user's credentials.
So far I was able to successfully validate if a username/password pair is valid. What I couldn't find a solution for is getting the email address given a username.
I cannot query the Active Directory directly using LDAP since the NodeJS app will be hosted outside the company's network. An available option is to use the Exchange Web Services (2010) endpoint.
I am currently doing a ResolveNames operation http://msdn.microsoft.com/en-us/library/exchange/aa563518(v=exchg.150).aspx
The problem is that doing a Resolvenames with the username as the UnresolvedEntry value will return several Resolutions, for example if a username is john and there are also other johns in the directory, the Resolvenames query will return those as well.
I am looking for a way to get unambiguously the email address using EWS for a username (which corresponds to the valid credentials being used to query the EWS SOAP service).
Have never came across a direct method that gives email-address of logged in user, but you can do simple hack by creating a PostItem and then getting email-address by its PostItem.getFrom() method, something like :
PostItem postItem = new PostItem( service );
postItem.setBody( MessageBody.getMessageBodyFromText("Test for email-address " ) );
postItem.save();
postItem = PostItem.bind( service , postItem.getId() );
System.out.println( postItem.getFrom() );
postItem.delete( DeleteMode.HardDelete );
I have implemented FBA (Claim based Authentication) on Sharepoint 2010. Following are implemented.
Custom Login page
Custom Sign-in Page
Password recovery page (ForgetPassword.aspx)
In ForgetPassword page user is asked to enter their email address, they used while sign-in and in code behind I am using this email to get the UserName using the Membership.GetUserNameByEmail function and then passing this username to Membership.GetUser function to get the user credential to be send through mail.
But now the code throws as exception saying "The function is not implemented". I am wondering; I am not using any custom database for which I had to create a Custom Membership Provider. Then why I am getting this error. Let me know if anyone has any clue or faced similar problem. Thanks.
Regards,
Paddy
When FBA is configured for SharePoint 2010, two membership providers are defined in the web.config file - Microsoft.SharePoint.Administration.Claims.SPClaimsAuthMembershipProvider (usually named i) and System.Web.Security.SqlMembershipProvider (named FBAMembership in this case). Default membership provider must be set to the former (i.e. SharePoint claims one) in order for FBA authentication to work properly.
When the line containing Membership.GetUserNameByEmail(...) is executed, the default membership provider is used and as a result SPClaimsAuthMembershipProvider.GetUserNameByEmail is called. MSDN says that this method is reserved for internal use and is not intended to be used directly from your code and according to the comment in the Community Content section it throws NotImplementedException.
You need to retrieve an instance of the SqlMembershipProvider provider from the Membership.Providers collection and then call the GetUserNameByEmail method using this instance.
I use prefixes when configuring providers in the web.config file and the retrieve them like this:
string applicationNamePrefix = "fbaProvider_";
MembershipProvider fbaProvider;
foreach (MembershipProvider provider in Membership.Providers)
{
if (provider.ApplicationName.StartsWith(applicationNamePrefix, StringComparison.InvariantCultureIgnoreCase))
{
fbaProvider = provider;
}
}
throw new InvalidOperationException("Appropriate provider was not found.");