Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev-proxy-abstractions/IProxyLogger.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Runtime.Serialization;
using Titanium.Web.Proxy.EventArguments;
using Microsoft.Extensions.Logging;

Expand Down Expand Up @@ -33,4 +32,5 @@ public interface IProxyLogger : ICloneable, ILogger
{
public LogLevel LogLevel { get; set; }
public void LogRequest(string[] message, MessageType messageType, LoggingContext? context = null);
public void LogRequest(string[] message, MessageType messageType, string method, string url);
}
22 changes: 22 additions & 0 deletions dev-proxy-abstractions/JsonExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Text.Json;

namespace Microsoft.DevProxy.Abstractions;

// from https://stackoverflow.com/questions/61553962/getting-nested-properties-with-system-text-json
public static partial class JsonExtensions
{
public static JsonElement? Get(this JsonElement element, string name) =>
element.ValueKind != JsonValueKind.Null && element.ValueKind != JsonValueKind.Undefined && element.TryGetProperty(name, out var value)
? value : (JsonElement?)null;

public static JsonElement? Get(this JsonElement element, int index)
{
if (element.ValueKind == JsonValueKind.Null || element.ValueKind == JsonValueKind.Undefined)
return null;
// Throw if index < 0
return index < element.GetArrayLength() ? element[index] : null;
}
}
36 changes: 36 additions & 0 deletions dev-proxy-abstractions/MockRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Text.Json.Serialization;

namespace Microsoft.DevProxy.Abstractions;

public class MockRequest
{
[JsonPropertyName("url")]
public string Url { get; set; } = string.Empty;
[JsonPropertyName("method")]
public string Method { get; set; } = "GET";
[JsonPropertyName("body")]
public dynamic? Body { get; set; }
[JsonPropertyName("headers")]
public List<MockRequestHeader>? Headers { get; set; }
}

public class MockRequestHeader
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("value")]
public string Value { get; set; } = string.Empty;

public MockRequestHeader()
{
}

public MockRequestHeader(string name, string value)
{
Name = name;
Value = value;
}
}
15 changes: 15 additions & 0 deletions dev-proxy-abstractions/PluginEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.CommandLine;
using System.CommandLine.Invocation;
using System.Security.Cryptography.X509Certificates;
using Titanium.Web.Proxy.EventArguments;
using Titanium.Web.Proxy.Http;

Expand All @@ -12,6 +13,7 @@ public interface IProxyContext
{
IProxyConfiguration Configuration { get; }
IProxyLogger Logger { get; }
X509Certificate2? Certificate { get; }
}

public class ThrottlerInfo
Expand Down Expand Up @@ -182,6 +184,10 @@ public interface IPluginEvents
/// Raised after recording request logs has stopped.
/// </summary>
event AsyncEventHandler<RecordingArgs>? AfterRecordingStop;
/// <summary>
/// Raised when user requested issuing mock requests.
/// </summary>
event AsyncEventHandler<EventArgs>? MockRequest;
}

public class PluginEvents : IPluginEvents
Expand All @@ -200,6 +206,7 @@ public class PluginEvents : IPluginEvents
public event EventHandler<RequestLogArgs>? AfterRequestLog;
/// <inheritdoc />
public event AsyncEventHandler<RecordingArgs>? AfterRecordingStop;
public event AsyncEventHandler<EventArgs>? MockRequest;

public void RaiseInit(InitArgs args)
{
Expand Down Expand Up @@ -247,4 +254,12 @@ public async Task RaiseRecordingStopped(RecordingArgs args)
await AfterRecordingStop.InvokeAsync(this, args, null);
}
}

public async Task RaiseMockRequest(EventArgs args)
{
if (MockRequest is not null)
{
await MockRequest.InvokeAsync(this, args, null);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

using Microsoft.Extensions.Logging;
using Microsoft.DevProxy.Abstractions;
using Microsoft.DevProxy.Plugins.MockResponses;
using Microsoft.DevProxy.Plugins.Mocks;
using System.Text.Json;

namespace Microsoft.DevProxy.Plugins.Behavior;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using Microsoft.Extensions.Logging;
using System.Text.Json;

namespace Microsoft.DevProxy.Plugins.MockResponses;
namespace Microsoft.DevProxy.Plugins.Mocks;

internal class CrudApiDefinitionLoader : IDisposable
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
using Microsoft.IdentityModel.Protocols;
using System.Security.Claims;

namespace Microsoft.DevProxy.Plugins.MockResponses;
namespace Microsoft.DevProxy.Plugins.Mocks;

public enum CrudApiActionType
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Web;
using Microsoft.DevProxy.Abstractions;

namespace Microsoft.DevProxy.Plugins.MockResponses;
namespace Microsoft.DevProxy.Plugins.Mocks;

class IdToken {
class IdToken
{
[JsonPropertyName("aud")]
public string? Aud { get; set; }
[JsonPropertyName("iss")]
Expand Down Expand Up @@ -56,13 +58,38 @@ protected override void ProcessMockResponse(ref byte[] body, IList<MockResponseH
StoreLastNonce(e);
UpdateMsalState(ref bodyString, e, ref changed);
UpdateIdToken(ref bodyString, e, ref changed);
UpdateDevProxyKeyId(ref bodyString, ref changed);
UpdateDevProxyCertificateChain(ref bodyString, ref changed);

if (changed)
{
body = Encoding.UTF8.GetBytes(bodyString);
}
}

private void UpdateDevProxyCertificateChain(ref string bodyString, ref bool changed)
{
if (!bodyString.Contains("@dynamic.devProxyCertificateChain"))
{
return;
}

var certificateChain = GetCertificateChain().First();
bodyString = bodyString.Replace("@dynamic.devProxyCertificateChain", certificateChain);
changed = true;
}

private void UpdateDevProxyKeyId(ref string bodyString, ref bool changed)
{
if (!bodyString.Contains("@dynamic.devProxyKeyId"))
{
return;
}

bodyString = bodyString.Replace("@dynamic.devProxyKeyId", GetKeyId());
changed = true;
}

private void StoreLastNonce(ProxyRequestArgs e)
{
if (e.Session.HttpClient.Request.RequestUri.Query.Contains("nonce="))
Expand Down Expand Up @@ -94,7 +121,7 @@ private void UpdateIdToken(ref string body, ProxyRequestArgs e, ref bool changed
{
return;
}

token.Nonce = lastNonce;

tokenChunks[1] = Convert.ToBase64String(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(token)));
Expand All @@ -121,4 +148,31 @@ private void UpdateMsalState(ref string body, ProxyRequestArgs e, ref bool chang
body = body.Replace("state=@dynamic", $"state={msalState}");
changed = true;
}

private string GetKeyId()
{
return _context?.Certificate?.Thumbprint ?? "";
}

private List<string> GetCertificateChain()
{
if (_context?.Certificate is null)
{
return new List<string>();
}

var collection = new X509Certificate2Collection
{
_context.Certificate
};

var certificateChain = new List<string>();
foreach (var certificate in collection)
{
var base64String = Convert.ToBase64String(certificate.RawData);
certificateChain.Add(base64String);
}

return certificateChain;
}
}
Loading