Skip to content

Commit 7222246

Browse files
.Net: Provide access to the security scheme and requirement for an Open API function (#9430)
### Motivation and Context Exploring a fix for #9429 ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [ ] The code builds clean without any errors or warnings - [ ] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [ ] All unit tests pass, and I have added new tests where possible - [ ] I didn't break anyone 😄
1 parent 874ee95 commit 7222246

16 files changed

+634
-15
lines changed

dotnet/src/Functions/Functions.OpenApi.Extensions/Extensions/ApiManifestKernelExtensions.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,15 +146,17 @@ public static async Task<KernelPlugin> CreatePluginFromApiManifestAsync(
146146
var server = filteredOpenApiDocument.Servers.FirstOrDefault();
147147
if (server?.Url is not null)
148148
{
149+
var info = OpenApiDocumentParser.ExtractRestApiInfo(filteredOpenApiDocument);
150+
var security = OpenApiDocumentParser.CreateRestApiOperationSecurityRequirements(filteredOpenApiDocument.SecurityRequirements);
149151
foreach (var path in filteredOpenApiDocument.Paths)
150152
{
151-
var operations = OpenApiDocumentParser.CreateRestApiOperations([server], path.Key, path.Value, null, logger);
153+
var operations = OpenApiDocumentParser.CreateRestApiOperations(filteredOpenApiDocument, path.Key, path.Value, null, logger);
152154
foreach (RestApiOperation operation in operations)
153155
{
154156
try
155157
{
156158
logger.LogTrace("Registering Rest function {0}.{1}", pluginName, operation.Id);
157-
functions.Add(OpenApiKernelPluginFactory.CreateRestApiFunction(pluginName, runner, operation, openApiFunctionExecutionParameters, new Uri(server.Url), loggerFactory));
159+
functions.Add(OpenApiKernelPluginFactory.CreateRestApiFunction(pluginName, runner, info, security, operation, openApiFunctionExecutionParameters, new Uri(server.Url), loggerFactory));
158160
}
159161
catch (Exception ex) when (!ex.IsCriticalException())
160162
{
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Diagnostics.CodeAnalysis;
6+
7+
namespace Microsoft.SemanticKernel.Plugins.OpenApi;
8+
9+
/// <summary>
10+
/// REST API OAuth Flow.
11+
/// </summary>
12+
[Experimental("SKEXP0040")]
13+
public sealed class RestApiOAuthFlow
14+
{
15+
/// <summary>
16+
/// REQUIRED. The authorization URL to be used for this flow.
17+
/// Applies to implicit and authorizationCode OAuthFlow.
18+
/// </summary>
19+
public Uri AuthorizationUrl { get; init; }
20+
21+
/// <summary>
22+
/// REQUIRED. The token URL to be used for this flow.
23+
/// Applies to password, clientCredentials, and authorizationCode OAuthFlow.
24+
/// </summary>
25+
public Uri TokenUrl { get; init; }
26+
27+
/// <summary>
28+
/// The URL to be used for obtaining refresh tokens.
29+
/// </summary>
30+
public Uri? RefreshUrl { get; init; }
31+
32+
/// <summary>
33+
/// REQUIRED. A map between the scope name and a short description for it.
34+
/// </summary>
35+
public IReadOnlyDictionary<string, string> Scopes { get; init; }
36+
37+
/// <summary>
38+
/// Creates an instance of a <see cref="RestApiOAuthFlow"/> class.
39+
/// </summary>
40+
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
41+
internal RestApiOAuthFlow()
42+
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
43+
{
44+
}
45+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System.Diagnostics.CodeAnalysis;
4+
5+
namespace Microsoft.SemanticKernel.Plugins.OpenApi;
6+
7+
/// <summary>
8+
/// REST API OAuth Flows.
9+
/// </summary>
10+
[Experimental("SKEXP0040")]
11+
public sealed class RestApiOAuthFlows
12+
{
13+
/// <summary>
14+
/// Configuration for the OAuth Implicit flow
15+
/// </summary>
16+
public RestApiOAuthFlow? Implicit { get; init; }
17+
18+
/// <summary>
19+
/// Configuration for the OAuth Resource Owner Password flow.
20+
/// </summary>
21+
public RestApiOAuthFlow? Password { get; init; }
22+
23+
/// <summary>
24+
/// Configuration for the OAuth Client Credentials flow.
25+
/// </summary>
26+
public RestApiOAuthFlow? ClientCredentials { get; init; }
27+
28+
/// <summary>
29+
/// Configuration for the OAuth Authorization Code flow.
30+
/// </summary>
31+
public RestApiOAuthFlow? AuthorizationCode { get; init; }
32+
33+
/// <summary>
34+
/// Creates an instance of a <see cref="RestApiOAuthFlows"/> class.
35+
/// </summary>
36+
internal RestApiOAuthFlows()
37+
{
38+
}
39+
}

dotnet/src/Functions/Functions.OpenApi/Model/RestApiOperation.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ public sealed class RestApiOperation
5656
/// </summary>
5757
public IReadOnlyList<RestApiOperationServer> Servers { get; }
5858

59+
/// <summary>
60+
/// The security requirements.
61+
/// </summary>
62+
public IReadOnlyList<RestApiSecurityRequirement>? SecurityRequirements { get; }
63+
5964
/// <summary>
6065
/// The operation parameters.
6166
/// </summary>
@@ -87,6 +92,7 @@ public sealed class RestApiOperation
8792
/// <param name="parameters">The operation parameters.</param>
8893
/// <param name="payload">The operation payload.</param>
8994
/// <param name="responses">The operation responses.</param>
95+
/// <param name="securityRequirements">The operation security requirements.</param>
9096
internal RestApiOperation(
9197
string id,
9298
IReadOnlyList<RestApiOperationServer> servers,
@@ -95,7 +101,8 @@ internal RestApiOperation(
95101
string description,
96102
IReadOnlyList<RestApiOperationParameter> parameters,
97103
RestApiOperationPayload? payload = null,
98-
IReadOnlyDictionary<string, RestApiOperationExpectedResponse>? responses = null)
104+
IReadOnlyDictionary<string, RestApiOperationExpectedResponse>? responses = null,
105+
IReadOnlyList<RestApiSecurityRequirement>? securityRequirements = null)
99106
{
100107
this.Id = id;
101108
this.Servers = servers;
@@ -105,6 +112,7 @@ internal RestApiOperation(
105112
this.Parameters = parameters;
106113
this.Payload = payload;
107114
this.Responses = responses ?? new Dictionary<string, RestApiOperationExpectedResponse>();
115+
this.SecurityRequirements = securityRequirements;
108116
}
109117

110118
/// <summary>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System.Collections.Generic;
4+
using System.Collections.ObjectModel;
5+
using System.Diagnostics.CodeAnalysis;
6+
7+
namespace Microsoft.SemanticKernel.Plugins.OpenApi;
8+
9+
/// <summary>
10+
/// The REST API security requirement object.
11+
/// </summary>
12+
[Experimental("SKEXP0040")]
13+
public sealed class RestApiSecurityRequirement : ReadOnlyDictionary<RestApiSecurityScheme, IList<string>>
14+
{
15+
/// <summary>
16+
/// Creates an instance of a <see cref="RestApiSecurityRequirement"/> class.
17+
/// </summary>
18+
/// <param name="dictionary">Dictionary containing the security schemes.</param>
19+
internal RestApiSecurityRequirement(IDictionary<RestApiSecurityScheme, IList<string>> dictionary) : base(dictionary)
20+
{
21+
}
22+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System;
4+
using System.Diagnostics.CodeAnalysis;
5+
6+
namespace Microsoft.SemanticKernel.Plugins.OpenApi;
7+
8+
/// <summary>
9+
/// REST API Security Scheme.
10+
/// </summary>
11+
[Experimental("SKEXP0040")]
12+
public sealed class RestApiSecurityScheme
13+
{
14+
/// <summary>
15+
/// REQUIRED. The type of the security scheme. Valid values are "apiKey", "http", "oauth2", "openIdConnect".
16+
/// </summary>
17+
public string SecuritySchemeType { get; init; }
18+
19+
/// <summary>
20+
/// A short description for security scheme. CommonMark syntax MAY be used for rich text representation.
21+
/// </summary>
22+
public string? Description { get; init; }
23+
24+
/// <summary>
25+
/// REQUIRED. The name of the header, query or cookie parameter to be used.
26+
/// </summary>
27+
public string Name { get; init; }
28+
29+
/// <summary>
30+
/// REQUIRED. The location of the API key. Valid values are "query", "header" or "cookie".
31+
/// </summary>
32+
public RestApiOperationParameterLocation In { get; init; }
33+
34+
/// <summary>
35+
/// REQUIRED. The name of the HTTP Authorization scheme to be used
36+
/// in the Authorization header as defined in RFC7235.
37+
/// </summary>
38+
public string Scheme { get; init; }
39+
40+
/// <summary>
41+
/// A hint to the client to identify how the bearer token is formatted.
42+
/// Bearer tokens are usually generated by an authorization server,
43+
/// so this information is primarily for documentation purposes.
44+
/// </summary>
45+
public string? BearerFormat { get; init; }
46+
47+
/// <summary>
48+
/// REQUIRED. An object containing configuration information for the flow types supported.
49+
/// </summary>
50+
public RestApiOAuthFlows? Flows { get; init; }
51+
52+
/// <summary>
53+
/// REQUIRED. OpenId Connect URL to discover OAuth2 configuration values.
54+
/// </summary>
55+
public Uri OpenIdConnectUrl { get; init; }
56+
57+
/// <summary>
58+
/// Creates an instance of a <see cref="RestApiSecurityScheme"/> class.
59+
/// </summary>
60+
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
61+
internal RestApiSecurityScheme()
62+
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
63+
{
64+
}
65+
}

dotnet/src/Functions/Functions.OpenApi/Model/RestApiSpecification.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ internal sealed class RestApiSpecification
1414
/// </summary>
1515
public RestApiInfo Info { get; private set; }
1616

17+
/// <summary>
18+
/// The REST API security requirements.
19+
/// </summary>
20+
public List<RestApiSecurityRequirement>? SecurityRequirements { get; private set; }
21+
1722
/// <summary>
1823
/// The REST API operations.
1924
/// </summary>
@@ -23,10 +28,12 @@ internal sealed class RestApiSpecification
2328
/// Construct an instance of <see cref="RestApiSpecification"/>
2429
/// </summary>
2530
/// <param name="info">REST API information.</param>
31+
/// <param name="securityRequirements">REST API security requirements.</param>
2632
/// <param name="operations">REST API operations.</param>
27-
public RestApiSpecification(RestApiInfo info, IList<RestApiOperation> operations)
33+
public RestApiSpecification(RestApiInfo info, List<RestApiSecurityRequirement>? securityRequirements, IList<RestApiOperation> operations)
2834
{
2935
this.Info = info;
36+
this.SecurityRequirements = securityRequirements;
3037
this.Operations = operations;
3138
}
3239
}

0 commit comments

Comments
 (0)