Service Now REST API script for listening from DevOps web hooks - azure-devops

I am wondering how connect between DevOps Boards Incidents and Tasks (web hooks used) to ServiceNow. The requirement is Service Now will need to listen every time there is an update to Azure DevOps boards incidents or Tasks.
I have created a Scripted REST API at Service Now with the following Example script:
`(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
var body = request.body.data;
var eventType = request.headers['auth_token'];
var workItem = body.resource;
var title = workItem.fields['System.Title'];
var description = workItem.fields['System.Description'];
var state = workItem.fields['System.State'];
var priority = workItem.fields['System.priority'];
if(eventType == 'workitem.created') {
title = workItem.fields['System.Title'];
description = workItem.fields['System.Description'];
state = workItem.fields['System.State'];
} else if(eventType == 'workitem.updated') {
title = workItem.fields['System.Title'];
description = workItem.fields['System.Description'];
state = workItem.fields['System.State'];
}
response.setStatus(200);
})(request, response);`
Now, Just wondering how to invoke this API end point when there is an update.

If you are on the Scripted REST Resource form in ServiceNow, then you should see a "Explore REST API" link at the bottom of the page. If you click that link it will take you page that you can use to test your API. Right below the "Send" button there should be links to generate code samples to call your API.

Related

Add new Files and Folders to Azure Git Repository with Azure DevOps REST API

How to Add new Files and Folders to Azure Git Repository with Azure DevOps REST API?
I want to add some static files to my repository using Azure DevOps REST APIs.
https://learn.microsoft.com/en-us/rest/api/azure/devops/git/repositories?view=azure-devops-rest-5.1
Is there any option available via REST API?.
or anyother automated way available, either CICD or through c#?
I found the answer, we can use the Git Push REST API uri
https://learn.microsoft.com/en-us/rest/api/azure/devops/git/pushes/create?view=azure-devops-rest-5.1
Follow below steps in your C# code
call GetRef REST https://dev.azure.com/{0}/{1}/_apis/git/repositories/{2}/refs{3}
this should return the object of your repository branch which you can use to push your changes
Next, call Push REST API to create folder or file into your repository
https://dev.azure.com/{0}/{1}/_apis/git/repositories/{2}/pushes{3}
var changes = new List<ChangeToAdd>();
//Add Files
//pnp_structure.yml
var jsonContent = File.ReadAllText(#"./static-files/somejsonfile.json");
ChangeToAdd changeJson = new ChangeToAdd()
{
changeType = "add",
item = new ItemBase() { path = string.Concat(path, "/[your-folder-name]/somejsonfile.json") },
newContent = new Newcontent()
{
contentType = "rawtext",
content = jsonContent
}
};
changes.Add(changeJson);
CommitToAdd commit = new CommitToAdd();
commit.comment = "commit from code";
commit.changes = changes.ToArray();
var content = new List<CommitToAdd>() { commit };
var request = new
{
refUpdates = refs,
commits = content
};
var personalaccesstoken = _configuration["azure-devOps-configuration-token"];
var authorization = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", personalaccesstoken)));
_logger.LogInformation($"[HTTP REQUEST] make a http call with uri: {uri} ");
//here I making http client call
// https://dev.azure.com/{orgnizationName}/{projectName}/_apis/git/repositories/{repositoryId}/pushes{?api-version}
var result = _httpClient.SendHttpWebRequest(uri, method, data, authorization);

How do I create an AlertsClient from an Azure Active Directory secret? [duplicate]

My company is looking into reporting on Azure. We only want our customers to give us read only credentials for us to use. I did some research and it looks like Azure Active Directory does just that. So I'm looking to authenticate using a read only Azure Directory Application.
To get me started I was following this blog on using the Management API via Azure Active Directory.
https://msdn.microsoft.com/en-us/library/azure/dn722415.aspx
Aside from the approach show being very unfriendly, it doesn't work =(
I get this error after logging in as a global administrator:
"AADSTS90014: The request body must contain the following parameter: 'client_secret or client_assertion'."
Did some research and found this style of authentication was for native app and NOT web apps (despite what the blog post saying other wise..). So I made a tweak. My GetAuthorizationHeader now looks like this:
private static string GetAuthorizationHeader()
{
AuthenticationResult result = null;
var context = new AuthenticationContext("https://login.windows.net/" + ConfigurationManager.AppSettings["tenantId"]);
string clientId = ConfigurationManager.AppSettings["clientId"];
string clientSecret = ConfigurationManager.AppSettings["clientSecret"];
ClientCredential clientCred = new ClientCredential(clientId, clientSecret);
var thread = new Thread(() =>
{
result = context.AcquireToken(
"https://management.core.windows.net/",
clientCred);
});
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 am able to get the Access Token (yay). But now when I try to use this with the Azure Management library client I get this error:
"ForbiddenError: The server failed to authenticate the request. Verify that the certificate is valid and is associated with this subscription."
I double checked my permissions in my application. It looked good. I tried giving full access to everything to see if that would have made a difference.
I double checked my tenantId, clientId, and subscriptionId, all looked good.
I made sure the subscription I'm using is pointed to the AD my application is in.
I tried making a new secret key.
My guess is this is the issue:
However in this UI I am unable to select any values for that property. I'm unsure if this is the result of a bug or an unfinished feature.
Am I missing something here?
Thanks
Here's my full code for reference:
class Program
{
static void Main(string[] args)
{
var token = GetAuthorizationHeader();
var credential = new TokenCloudCredentials(ConfigurationManager.AppSettings["subscriptionId"], token);
using (var computeClient = new ComputeManagementClient(credential))
{
var images = computeClient.VirtualMachineOSImages.List();
}
}
private static string GetAuthorizationHeader()
{
AuthenticationResult result = null;
var context = new AuthenticationContext("https://login.windows.net/" + ConfigurationManager.AppSettings["tenantId"]);
string clientId = ConfigurationManager.AppSettings["clientId"];
string clientSecret = ConfigurationManager.AppSettings["clientSecret"];
ClientCredential clientCred = new ClientCredential(clientId, clientSecret);
var thread = new Thread(() =>
{
result = context.AcquireToken(
"https://management.core.windows.net/",
clientCred);
});
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;
}
}
EDIT:
Progress has been made. As I discussed with Gaurav, I needed to ditch the Azure Management Library because as of right now it does not seem to support Azure Resource Manager (ARM) API! So instead I did raw web requests. And it works as intended. If I remove role access off my AD Application I get access denied. When I have it I get back data.
One thing I'm not sure about is making it so my application is auto-adding to new resources.
Also, Is there a way to list Resource Groups that are accessible for my AD Application?
New code:
class Program
{
static void Main(string[] args)
{
var token = GetAuthorizationHeader();
string subscriptionId = ConfigurationManager.AppSettings["subscriptionId"];
string resourceGroupName = ConfigurationManager.AppSettings["resourceGroupName"];
var uriListMachines = string.Format("https://management.azure.com/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Compute/virtualmachines?api-version=2015-05-01-preview", subscriptionId, resourceGroupName);
var t = WebRequest.Create(uriListMachines);
t.ContentType = "application/json";
t.Headers.Add("Authorization", "Bearer " + token);
var response = (HttpWebResponse)t.GetResponse();
string result = "";
using (var reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}
//Original Attempt:
//var credential = new TokenCloudCredentials(ConfigurationManager.AppSettings["subscriptionId"], token);
//using (var client = CloudContext.Clients.CreateComputeManagementClient(credential))
//{
// var images = client.VirtualMachineVMImages.List();
//}
}
private static string GetAuthorizationHeader()
{
AuthenticationResult result = null;
var context = new AuthenticationContext("https://login.windows.net/" + ConfigurationManager.AppSettings["tenantId"]);
string clientId = ConfigurationManager.AppSettings["clientId"];
string clientSecret = ConfigurationManager.AppSettings["clientSecret"];
ClientCredential clientCred = new ClientCredential(clientId, clientSecret);
var thread = new Thread(() =>
{
result = context.AcquireToken(
"https://management.core.windows.net/",
clientCred);
});
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;
}
}
EDIT EDIT:
I figured out my hung up. Resources created in the OLD portal will get it's own distinct resource group.
From what I can tell you can not add a resource made in the old portal existing resource group (boooo). Resources created in the new portal will be able to assign the resource to an existing group (aka one that gives a role access to my AD Application).
This is such a mess! But at least I know what is going on now.
I believe you're on the right track as to why you're running into this problem.
Here's what's happening:
Essentially permission to execute Service Management API is a delegated permission and not an application permission. In other words, the API is executed in context of the user for which the token is acquired. Now you are getting this token for your application (specified by client id/secret). However your application doesn't have access to your Azure Subscription because the user record created for this application in your Azure AD is of type Service Principal. Since this Service Principal doesn't have access to your Azure Subscription, you're getting this Forbidden Error (I must say that the error is misleading because you're not using certificate at all).
There are a few things you could do:
Switch to Azure Resource Manager (ARM) API - ARM API is the next generation of Service Management API (SM API) and Azure is moving towards this direction only. It exclusively works off of Azure AD token. If possible, make use of that to manage your Azure resources (though you need to keep in mind that as of today not all Azure resources can be managed through ARM API). They way you do it is take your Service Principal and assign it to a particular role using new Azure Portal. Please see this link for more details on this: https://azure.microsoft.com/en-in/documentation/articles/resource-group-create-service-principal-portal/.
Use X509 Certificate - You can always use X509 Certificate based authorization to authorize your SM API requests. Please see this link for more details on that: https://msdn.microsoft.com/en-us/library/azure/ee460782.aspx#bk_cert. The downside of this approach is that the application (or whosoever has access to this certificate) will get full access to your Azure Subscription and can do everything there (including deleting resources).
Acquire token for a user instead of an application - This is another approach you can take. Essentially ask your users to login into Azure AD through your console application and acquire token for that user. Again, please keep in mind that this user must be a Co-Admin in your Azure Subscription and will have full access to your Azure Subscription as with SM API there's no concept of Role-based access control.

Azure mobile service doesn't register push notifications tags on Android

I'm trying to use the following code to send push notifications to specific users with tags (VS Cordova Project using Azure mobile service).
var tags = [userid, platform];
// Get the handle returned during registration.
var handle = data.registrationId;
// Set the device-specific message template.
if (platform == "android" || platform == "Android") {
// Template registration.
var template = '{ "data" : {"message":"$(message)"}}';
// Register for notifications.
mobileServiceClient.push.gcm.registerTemplate(handle,
"myTemplate", template, null, tags)
.done(registrationSuccess, registrationFailure);
} else if (platform == "iOS") {
// Template registration.
var template = '{"aps": {"alert": "$(message)"}}';
// Register for notifications.
mobileServiceClient.push.apns.registerTemplate(handle,
"myTemplate", template, null, tags)
.done(registrationSuccess, registrationFailure);
}
It registered successfully with the tags for Apple APNS , however on android it only registered the device, but the tags doesn't get registered.
I'm using push plugin 1.4.4 and Azure mobile service 1.2.9
Does anyone knows how to fix this? Any suggestion is appreciated, thanks!
After tracing the source code of azure mobile service plugin, I found that
gcm.prototype.registerTemplate = function (deviceId, name, bodyTemplate, tags)
is missing the "expiryTemplate" parameter. Changing it to
gcm.prototype.registerTemplate = function (deviceId, name, bodyTemplate, expiryTemplate, tags)
fix the problem.
My blog here details on how to receive notifications based on tags in a Cordova client. Basically you'll need a bit of server side code to update your installation / registration to handle specific tags. That's this bit of code:
NotificationHubClient _hub = NotificationHubClient.CreateClientFromConnectionString(notificationHubConnection, notificationHubName);
public async Task CreateOrUpdateInstallationAsync(string installationId, string registrationId, IEnumerable<string> tags)
{
Installation installation = new Installation();
installation.InstallationId = installationId;
installation.PushChannel = registrationId;
installation.Tags = tags.ToArray();
installation.Platform = NotificationPlatform.Gcm;
await _hub.CreateOrUpdateInstallationAsync(installation);
}

How do I get actions posted via the graph to show up in hte users feed and not the activity log?

Currently when my app posts on a users behalf the custom action shows up in the activity log and not on the user's wall. I am expecting the action to show up in /me/feed in the open graph. I am using the c# library. Below is the code I am using:
public async Task JoinSmaxNation(int nationId)
{
dynamic parameters = new ExpandoObject();
parameters.smax_nation = String.Format(_smaxNationUrlFormat, nationId, UserId);
parameters.no_feed_story = false;
parameters.expires_in = 86400;
dynamic result = await _fb.PostTaskAsync("me/smaxsport:join", parameters);
}
It looks like the fb:explicitly_shared=true option was required.

Progressing Alfresco workflows through web script

I have an Alfresco document reference; what I'm looking for is a way to access workflow attached to that document and finish it (or progress it to the next transition) through Javascript.
Almost every example on the web shows how to start workflow, and from the dashlet I could call task command processor (/alfresco/command/task/end/[/transition]) if I knew the task ID, but how do I do the same thing from server-side web script starting only from the document reference?
There must be a way to access workflows from document and manage them programatically.
From a document nodeRef you can signal the current task like this:
var docNodeRef = "workspace://SpacesStore/<GUID HERE>";
var transitionId = "some action";
var theDocument = search.findNode(docNodeRef);
foreach (currWorkflow in theDocument.activeWorkflows)
{
var path = currWorkflow.paths[currWorkflow.paths.length-1];
var task = path.tasks[0];
for (var transitionKey in task.transitions)
{
if (task.transitions[transitionKey] == transitionId)
{
path.signal(transitionId);
break;
}
}
}
If you want to signal the default transition you can skip the inner loop and just do this:
var docNodeRef = "workspace://SpacesStore/<GUID HERE>";
var transitionId = "some action";
var theDocument = search.findNode(docNodeRef);
foreach (currWorkflow in theDocument.activeWorkflows)
{
var path = currWorkflow.paths[currWorkflow.paths.length-1];
var task = path.tasks[0];
// Signal default transition
path.signal(null);
}
Well, I still don't know how to transition, but there are a couple of things I found out.
First, I can access workflows document participates in and cancel it:
for each (workflow in document.activeWorkflows) {
workflow.cancel();
}
However, I'm still not quite sure how to progress tasks. I can get to the task and do something with it:
var task = workflow.getTask(taskId);
task.endTask(transitionId);
...but I still have no idea how to get to taskId or transitionId, either programmatically or through Alfresco.
EDIT: figured it out, transitionId is actually transition name as defined in workflow processdefinition XML:
<transition name="SomeTransitionId" to="end">
Also, to get list of tasks from the workflow you can iterate through paths (workflow.getPaths()) and then through tasks with path.getTasks().