I have a REST API on the internet that is secured with Azure AD and a required header (custom apikey).
You can call this API in example with postman using the client credentials flow. This all works fine.
I'm now developing a custom Azure DevOps extension that is showing the information returned from that API in the workitem form of ADO. I can call the API (if I remove the security from the API) from the extension through a generic Service Connection. Now I want to get the security working.
So I want to create a custom service connection that will get an accesstoken from the azure AD using ClientID and ClientSecret (client credentials flow).
When I have that working, I can call my API on a secure way.
Also how do I add the mandatory header to the call to the api? I need to add the header as field to the service connection as well right?
So I think I end up with a custom service connection instance that asks for TenantId, ClientId, Client Secret, Audience/Scope, List of headers (name/value).
For a more reference blog post I used this one: https://thingswithcode.blogspot.com/2019/07/using-azure-devops-service-connections.html
{
"id": "api-service-connection",
"description": "Service connection for api",
"type": "ms.vss-endpoint.service-endpoint-type",
"targets": [
"ms.vss-endpoint.endpoint-types"
],
"properties": {
"name": "Call API",
"displayName": "Call API",
"icon": "img/world.png",
"url": {
"displayName": "API Url",
"value": "https://path-to-api",
"helpText": "Url of the API to connect to."
},
"inputDescriptors": [
{
"id": "api-key",
"name": "API Key",
"description": "The value for the header 'ApiKey'",
"inputMode": "textbox",
"isConfidential": false,
"validation": {
"isRequired": true,
"dataType": "string"
}
}
],
"authenticationSchemes": [
{
"type": "ms.vss-endpoint.endpoint-auth-scheme-oauth2" // this is wrong...
}
],
"headers": [
{
"name": "ApiKey",
"value": "{{endpoint.api-key}}"
}
],
"helpMarkDown": "<b>Learn more</b>"
}
}
Thanks
Related
I followed this example https://learn.microsoft.com/en-us/microsoftteams/platform/sbs-calling-and-meeting
These are the steps I have done.
Registered an App in Azure using demo tenant
Created a policy for a demo tenant user for creating the online meeting on behalf of that user.
Added following Graph API Applications permissions to my Azure App
CallRecords.Read.All
Calls.Initiate.All
Calls.AccessMedia.All
Calls.InitiateGroupCall.All
Calls.JoinGroupCall.All
OnlineMeetings.ReadWrite.All
OnlineMeetings.Read.All
Calls.JoinGroupCallAsGuest.All
Granted Admin consent for the above permissions
For Bot
Created a Bot Channel Registeration in Azure account which have
subscription enabled.
While registering the bot, used https://<my_ngrok_url>/api/messages as the messaging endpoint.
Enabled the Teams Channel. Provided App-Name, Resource Group and
other required information I did Select the Calling tab on the Teams
channel page.
Select Enable calling, and then updated the Webhook
(for calling) with (https://yourNgrok/callback.
I am receiving the notifications.So this part works.
For bot my manifest is
{
"$schema": "https://github.com/OfficeDev/microsoft-teams-app-schema/blob/preview/DevPreview/MicrosoftTeams.schema.json",
"manifestVersion": "devPreview",
"version": "1.0.0",
"id": "<<app-id>>",
"packageName": "com.acs.sample",
"developer": {
"name": "Contoso",
"websiteUrl": "https://example.azurewebsites.net",
"privacyUrl": "https://teams.microsoft.com",
"termsOfUseUrl": "https://teams.microsoft.com"
},
"icons": {
"color": "color.png",
"outline": "outline.png"
},
"name": {
"short": "Calling bot",
"full": "Calling bot"
},
"description": {
"short": "Calling bot",
"full": "Calling bot"
},
"accentColor": "#FFFFFF",
"bots": [
{
"botId": "<<app-id>>",
"scopes": [ "personal", "team", "groupchat" ],
"supportsFiles": false,
"isNotificationOnly": false,
"supportsCalling": true,
"supportsVideo": true
}
],
"permissions": [ "identity", "messageTeamMembers" ],
"validDomains": [ "*.ngrok.io" ]
}
Installed Calling Bot in Teams
Installed without any error. I can make calls from the bot and see the notifications on my calling endpoints. One strange behavior I noticed, Its message text-box becomes disabled after a while but I can still make call from the bot.
Now I want to make call to a user from an endpoint.
From my python code. I used this code to get access token.
def getToken():
url = "https://login.microsoftonline.com/tenant_id/oauth2/v2.0/token"
type = 'post'
data={
"client_id": 'client_id',
"client_secret": 'client_secret',
"scope": 'https://graph.microsoft.com/.default',
"grant_type": 'client_credentials',
}
resp = requests.request(
method = type,
url = url,
data = data
)
resp_data = resp.json()
return resp_data['access_token'];
This access token is correct because I used the token to get users list etc using graph api to see if I can use the api or not.
Then using this token I call calls endpoint
def call_user():
accessToken = getToken();
url = "https://graph.microsoft.com/beta/communications/calls"
type = 'post'
data={
"#odata.type": "#microsoft.graph.call",
"callbackUri": "https://my_ngrok_url/call",
"targets": [
{
"#odata.type": "#microsoft.graph.invitationParticipantInfo",
"identity": {
"#odata.type": "#microsoft.graph.identitySet",
"user": {
"#odata.type": "#microsoft.graph.identity",
"displayName": "John",
"id": "user_id_to_whom_i_want_to_call"
}
}
}
],
"requestedModalities": [
"audio"
],
"mediaConfig": {
"#odata.type": "#microsoft.graph.serviceHostedMediaConfig"
}
}
resp = requests.request(
method = type,
url = url,
data = data,
headers={"Authorization": "Bearer " + accessToken},
)
resp_data = resp.json()
return resp_data
It gives internal server error as response. Please help what i am doing wrong.
I have a with yeoman teams scaffolded tab in which I ask for adminconsent for application permission.
On a Go backend I then use the code to retrieve the access token. I am also getting all Users of the team.
Although I am using only application permissions, I can not send notifications to the admin account. When trying to send notifications to other accounts, the Graph API returns a 204 Status Code but the activity feed of the recipient stays empty.
The application has following application permissions (with granted admin consent):
ChannelMember.ReadAll
GroupMember.ReadAll
Team.ReadBasic.All
TeamMember.Read.All
TeamsActivity.Send
This is the Manifest file with version 1.11:
{
"manifestVersion": "1.11",
"id": "{{APPLICATION_ID}}",
"version": "{{VERSION}}",
"permissions": [
"identity",
"messageTeamMembers"
],
"webApplicationInfo": {
"id": "{{APPLICATION_ID}}",
"resource": "api://{{DOMAIN}}.{{APPLICATION_ID}}"
},
"devicePermissions": [
"notifications"
],
"activities": {
"activityTypes": [
{
"type": "newActivity",
"description": "A new Activity Description"
}
]
}
}
The HTTP POST request to: https://graph.microsoft.com/v1.0/teams/{teamID}/sendNotification
The JSON Body:
{
"topic": {
"source": "entityUrl",
"value": "https://graph.microsoft.com/v1.0/teams/%s"
},
"activityType": "newActivity",
"previewText": {
"content": "A new Activity Description"
},
"recipient": {
"odata.type": "microsoft.graph.aadUserNotificationRecipient",
"userId": "{{USER_ID}}"
}
}
The recipient is also Member of the channel the activity is referring to. I also made sure that the recipient can receive notifications.
If you look at the properties key,secret value is SecretUsedToCreateHMACHexDigestThatYouWillFindIn
where do i get this value from ?
{
"displayName": "TranscriptionCompletionWebHook",
"properties": {
"secret": "SecretUsedToCreateHMACHexDigestThatYouWillFindIn\"X-MicrosoftSpeechServices-Signature\"HeaderWhenBeingCalledBack"
},
"webUrl": "https://contoso.com/call/me/back",
"events": {
"transcriptionCompletion": true
},
"description": "I registered this URL to get a POST request for each completed transcription."
}
When adding/updating AAD user with ARM template/resources.explorer, why does a Basic user also get created?
This is the payload:
{
"apiVersion": "2017-03-01",
"type": "users",
"name": "user1",
"properties": {
"firstName": "FirstName",
"lastName": "LastName",
"email": "[parameters('user1Email')]",
"state": "active",
"identities": [
{
"provider": "Aad",
"id": "[parameters('user1UserId')]"
}
]
}
}
As you can see i do not include the
{
"provider": "Basic",
"id": "basic.userg#basic.com"
}
I don't want to create Basic Auth, I only want Azure AD.
When creating AD user from the developer portal we don't get this behaviour, but with ARM it also creates Basic.
The only way I see at the moment is to do a second PATCH (!) request with same payload but no Basic identity.
We are setting up Microsoft Azure Active Directory as an SSO solution for our mobile app but want to manage the account creation for users via the server side Microsoft Graph API.
For internal users of the domain, this works perfectly as we are using the Graph API as an admin user to create the accounts.
But, when trying to create an external account, (say joe.bloggs#gmail.com), this fails.
We are using the API call:
POST https://graph.microsoft.com/v1.0/users
BODY:
{
"accountEnabled": true,
"mailNickname": "joe.bloggs",
"displayName": "Joe Bloggs",
"givenName": "Joe",
"surname": "Bloggs",
"userPrincipalName": "joe.bloggs#gmail.com",
"passwordProfile" : {
"forceChangePasswordNextSignIn": false,
"password": "somepassword"
}
}
RESPONSE:
{
"error": {
"code": "Request_BadRequest",
"message": "Property userPrincipalName is invalid.",
"innerError": {
"request-id": "619450ec-e703-4a12-86e3-8f53c20d55fc",
"date": "2018-01-17T16:30:37"
},
"details": [
{
"target": "userPrincipalName",
"code": "InvalidValue"
}
]
}
}
It is saying the "userPrincipalName" is invalid, but after reviewing the documentation I'm not sure if the API supports external accounts or not?
NOTE: I realise you can use the "/beta/invitations" call but this does not create accounts.
I assume that you'r using Azure AD B2B and want to add new guest users to your Directory.
One thing I want to make clear is that you can invite guest users to your Directory , but you cannot create guest users directly in your Directory.
So, you can invite guest users with this Microsoft Graph API:
Request
POST https://graph.microsoft.com/beta/invitations
Content-type: application/json
Content-length: 551
{
"invitedUserEmailAddress": "yyy#test.com",
"inviteRedirectUrl": "https://myapp.com"
}
Response
HTTP/1.1 201 OK
Content-type: application/json
Content-length: 551
{
"id": "7b92124c-9fa9-406f-8b8e-225df8376ba9",
"inviteRedeemUrl": "https://invitations.microsoft.com/redeem/?tenant=04dcc6ab-388a-4559-b527-fbec656300ea&user=7b92124c-9fa9-406f-8b8e-225df8376ba9&ticket=VV9dmiExBsfRIVNFjb9ITj9VXAd07Ypv4gTg%2f8PiuJs%3d&lc=1033&ver=2.0",
"invitedUserDisplayName": "yyy",
"invitedUserEmailAddress": "yyy#test.com",
"sendInvitationMessage": false,
"invitedUserMessageInfo": {
"messageLanguage": null,
"ccRecipients": [
{
"emailAddress": {
"name": null,
"address": null
}
}
],
"customizedMessageBody": null
},
"inviteRedirectUrl": "https://myapp.com/",
"status": "Completed",
"invitedUser": [ { "id": "243b1de4-ad9f-421c-a933-d55305fb165d" } ]
}
Additional, if you want to invite guest users without an invitation, please refer to this document.
Hope this helps!