-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathQuoteConnectorWS.cs
More file actions
167 lines (147 loc) · 7.62 KB
/
QuoteConnectorWS.cs
File metadata and controls
167 lines (147 loc) · 7.62 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
167
using ConnectorService.Models;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using SuperOffice.Connectors;
using SuperOffice.Online.IntegrationService;
using SuperOffice.Online.IntegrationService.Contract.V1;
using SuperOffice.Online.Tokens;
using SuperOffice.SuperID.Contracts;
using SuperOffice.SuperID.Contracts.V1;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
namespace ConnectorService.Services
{
public class QuoteConnectorWS : OnlineQuoteConnector<QuoteConnector>, IIntegrationServiceConnectorAuth
{
public const string Endpoint = "QuoteConnectorWS.svc";
private readonly SuperIdOptions _superIdOptions;
private readonly ConnectorServiceOptions _connectorServiceOptions;
private readonly ISuperOfficeTokenValidator _superOfficeTokenValidator;
private readonly PartnerTokenIssuer _partnerTokenIssuer;
public QuoteConnectorWS(
IOptions<SuperIdOptions> superIdOptions,
IOptions<ConnectorServiceOptions> connectorServiceOptions,
ISuperOfficeTokenValidator superOfficeTokenValidator = null,
IPartnerTokenIssuer partnerTokenIssuer = null
) : base
(
connectorServiceOptions.Value.ClientId,
//GetPrivateKey(connectorServiceOptions.Value.PrivateKeyFile)
connectorServiceOptions.Value.PrivateKeyFile
)
{
_superIdOptions = superIdOptions.Value;
_connectorServiceOptions = connectorServiceOptions.Value;
_superOfficeTokenValidator = superOfficeTokenValidator
?? new SuperOfficeTokenValidator(new LocalStoreSuperIdCertificateResolver(thumbbprint: _superIdOptions.Certificate)); // This certificate should be loaded from online's discovery document.
_partnerTokenIssuer = new PartnerTokenIssuer(new PartnerCertificateResolver(() => PrivateKey));
}
/// <summary>
/// Authenticates an integration service request by validating the provided signed token and ensuring it matches the expected audience.
/// Returns an authentication response indicating success or failure.
/// </summary>
/// <param name="request">The authentication request containing the signed token.</param>
/// <returns>An AuthenticationResponse indicating the result of the authentication process.</returns>
AuthenticationResponse IIntegrationServiceConnectorAuth.Authenticate(AuthenticationRequest request)
{
var applicationIdentifier = _connectorServiceOptions.ClientId;
try
{
var token = ValidateSuperOfficeSignedToken(request.SignedToken);
var audience = token.FindFirst("aud")?.Value;
if (!string.Equals("spn:" + applicationIdentifier, audience, StringComparison.InvariantCultureIgnoreCase))
{
return new AuthenticationResponse
{
Succeeded = false,
Reason = "Wrong audience, missmatch on application identifier"
};
}
// Get nonce and sign the partner token
var nonce = token.GetNonce();
if (string.IsNullOrEmpty(nonce))
{
return new AuthenticationResponse
{
Succeeded = false,
Reason = "Failed to retrieve nonce from the token"
};
}
return new AuthenticationResponse
{
Succeeded = true,
SignedApplicationToken = _partnerTokenIssuer.SignPartnerToken(token: nonce)
};
}
catch
{
return new AuthenticationResponse
{
Succeeded = false,
Reason = "Failed to validate authentication request"
};
}
}
/// <summary>
/// Retrieves the inner typed quote connector based on the provided request.
/// If the request originates from Online, it updates the connection configuration fields.
/// </summary>
/// <typeparam name="TRequest">The type of the request.</typeparam>
/// <param name="request">The request containing connection configuration fields.</param>
/// <returns>The inner typed quote connector.</returns>
protected override QuoteConnector GetInnerTypedQuoteConnector<TRequest>(TRequest request)
{
// Check if the request comes from Online by inspecting the first property of ConnectionConfigFields
if (request.ConnectionConfigFields.Keys.FirstOrDefault() == "ApplicationId")
{
// Update the original ConnectionConfigFields with the new values
request.ConnectionConfigFields = RefactorConnectionConfigFields(request.ConnectionConfigFields);
}
var inner = base.GetInnerTypedQuoteConnector(request);
return inner;
}
/// <summary>
/// Refactors the connection configuration fields by updating or adding specific fields required by the ExcelQuoteConnector.
/// </summary>
/// <param name="requestConfigFields">The original connection configuration fields.</param>
/// <returns>A new ConnectionConfigFields object with the updated values.</returns>
private ConnectionConfigFields RefactorConnectionConfigFields(ConnectionConfigFields requestConfigFields)
{
// Create a new ConnectionConfigFields object to hold the updated values
var updatedConnectionConfigFields = new ConnectionConfigFields();
// Try to retrieve the file name from the connection config fields
if (requestConfigFields.TryGetValue("#1", out var fileName))
{
updatedConnectionConfigFields.Add("#1", Path.Combine(Path.Combine(AppContext.BaseDirectory, "Resources"), fileName));
}
else
{
updatedConnectionConfigFields.Add("DefaultFileName", Path.Combine(Path.Combine(AppContext.BaseDirectory, "Resources"), "ExcelConnectorWithCapabilities.xlsx"));
}
// Add the rest of the connection config fields
foreach (var entry in requestConfigFields)
{
updatedConnectionConfigFields.TryAdd(entry.Key, entry.Value);
}
return updatedConnectionConfigFields;
}
protected override ClaimsIdentity ValidateSuperOfficeSignedToken(string token)
{
string ValidIssuer = "SuperOffice AS";
var certificatePath = "App_Data/SuperOfficeFederatedLogin.crt";
if (string.IsNullOrEmpty(certificatePath) || !File.Exists(certificatePath))
{
throw new FileNotFoundException($"Certificate file not found at {certificatePath}");
}
var tokenHandler = new JwtSecurityTokenHandler();
var tokenValidationParameters = new TokenValidationParameters();
tokenValidationParameters.ValidateAudience = false;
tokenValidationParameters.ValidIssuer = ValidIssuer;
tokenValidationParameters.IssuerSigningKey = new X509SecurityKey(new X509Certificate2(certificatePath));
var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out var securityToken);
return principal.Identities.OfType<ClaimsIdentity>().FirstOrDefault();
}
}
}