-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathServiceNowTicketValidatorService.cs
More file actions
166 lines (148 loc) · 7.2 KB
/
ServiceNowTicketValidatorService.cs
File metadata and controls
166 lines (148 loc) · 7.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
// Copyright (c) One Identity LLC. All rights reserved.
namespace ServiceNowTicketValidator
{
using System;
using System.Configuration;
using System.Security;
using System.Text.Json;
using global::ServiceNowTicketValidator.DTOs;
using OneIdentity.SafeguardDotNet;
using OneIdentity.SafeguardDotNet.Event;
using Serilog;
internal class ServiceNowTicketValidatorService
{
private readonly string _safeguardAddress;
private readonly string _safeguardClientCertificateThumbprint;
private readonly int _safeguardApiVersion;
private readonly bool _safeguardIgnoreSsl;
private readonly string _serviceNowDnsName;
private readonly SecureString _serviceNowClientSecret;
private readonly string _serviceNowUserName;
private readonly SecureString _safeguardA2AApiKeyForServiceNowPassword;
private SecureString _serviceNowPassword;
private ISafeguardEventListener _eventListener;
private ISafeguardConnection _connection;
private ServiceNowTicketValidator _validator;
public ServiceNowTicketValidatorService()
{
_safeguardAddress =
ConfigUtils.ReadRequiredSettingFromAppConfig("SafeguardAddress", "Safeguard appliance network address");
_safeguardClientCertificateThumbprint =
ConfigUtils.ReadRequiredSettingFromAppConfig("SafeguardClientCertificateThumbprint",
"Safeguard client certificate thumbprint").ToUpper();
_safeguardApiVersion =
int.Parse(ConfigUtils.ReadRequiredSettingFromAppConfig("SafeguardApiVersion", "Safeguard API version"));
_safeguardIgnoreSsl = bool.Parse(ConfigurationManager.AppSettings["SafeguardIgnoreSsl"]);
_serviceNowDnsName =
ConfigUtils.ReadRequiredSettingFromAppConfig("ServiceNowDnsName", "ServiceNow server DNS name");
_serviceNowClientSecret = ConfigUtils.ReadSettingFromAppConfigIfPresent("ServiceNowClientSecret")
?.ToSecureString();
_serviceNowUserName =
ConfigUtils.ReadRequiredSettingFromAppConfig("ServiceNowUserName", "ServiceNow user name");
_safeguardA2AApiKeyForServiceNowPassword = ConfigUtils
.ReadRequiredSettingFromAppConfig("SafeguardA2AApiKeyForServiceNowPassword",
"Safeguard A2A API key for retrieving ServiceNow password").ToSecureString();
}
private void HandlePendingApprovalNotification(string eventName, string eventBody)
{
if (eventName != "AccessRequestPendingApproval")
{
Log.Information("Received {EventName} event, ignoring it", eventName);
return;
}
try
{
var approvalEvent = JsonSerializer.Deserialize<AccessRequestApprovalPendingEvent>(eventBody);
var accessRequestId = approvalEvent.RequestId;
if (string.IsNullOrEmpty(accessRequestId))
{
Log.Warning("Unable to parse access requestId for event {EventBody}", eventBody);
return;
}
var accessRequestJson =
_connection.InvokeMethod(Service.Core, Method.Get, $"AccessRequests/{accessRequestId}");
var accessRequest = JsonSerializer.Deserialize<AccessRequest>(accessRequestJson);
// Only ServiceNow and Remedy are supported in Safeguard. We will be adding a generic ticket system
// that will allow for arbitrary ticket numbers. Until then, you could overload the comment with
// the ticket number. TODO: remove this comment when it becomes obselete
var ticketNumber = accessRequest.TicketNumber;
if (string.IsNullOrEmpty(ticketNumber))
{
Log.Information("Ignoring access request {AccessRequestId} without ticket number", accessRequestId);
return;
}
if (_connection.GetAccessTokenLifetimeRemaining() == 0)
{
_connection.RefreshAccessToken();
}
switch (_validator.CheckTicket(ticketNumber, accessRequest))
{
case ValidationResult.Approve:
Log.Information(
"Approving access request {AccessRequestId} with ticket number {TicketNumber}",
accessRequestId,
ticketNumber);
_connection.InvokeMethod(Service.Core, Method.Post, $"AccessRequests/{accessRequestId}/Approve");
break;
case ValidationResult.Deny:
Log.Information(
"Denying access request {AccessRequestId} with ticket number {TicketNumber}",
accessRequestId,
ticketNumber);
_connection.InvokeMethod(Service.Core, Method.Post, $"AccessRequests/{accessRequestId}/Deny");
break;
default:
Log.Information(
"Ignoring access request {AccessRequestId} with ticket number {TicketNumber}",
accessRequestId,
ticketNumber);
break;
}
}
catch (Exception ex)
{
Log.Error(ex, "Exception occured while handling event {EventName}, data={EventBody}", eventName, eventBody);
}
}
public void Start()
{
_eventListener = Safeguard.Event.GetPersistentEventListener(
_safeguardAddress,
_safeguardClientCertificateThumbprint,
_safeguardApiVersion,
_safeguardIgnoreSsl);
_connection = Safeguard.Connect(
_safeguardAddress,
_safeguardClientCertificateThumbprint,
_safeguardApiVersion,
_safeguardIgnoreSsl);
using (var a2AContext = Safeguard.A2A.GetContext(
_safeguardAddress,
_safeguardClientCertificateThumbprint,
_safeguardApiVersion,
_safeguardIgnoreSsl))
{
_serviceNowPassword = a2AContext.RetrievePassword(_safeguardA2AApiKeyForServiceNowPassword);
}
_validator = new ServiceNowTicketValidator(
_serviceNowDnsName,
_serviceNowClientSecret,
_serviceNowUserName,
_serviceNowPassword);
_eventListener.RegisterEventHandler("AccessRequestPendingApproval", HandlePendingApprovalNotification);
_eventListener.Start();
}
public void Stop()
{
_eventListener.Stop();
_eventListener?.Dispose();
_connection?.Dispose();
_serviceNowPassword?.Dispose();
_validator?.Dispose();
_eventListener = null;
_connection = null;
_serviceNowPassword = null;
_validator = null;
}
}
}