Skip to content

Commit

Permalink
Fixing Repatability headers + Tests + Bugs for HMAC in custom headers (
Browse files Browse the repository at this point in the history
…Azure#31993)

* - Fixing RepeatabilityHeaders: Allow null to be passed (Do not send repeataiblity headers)
- Auto-create repeatabilityHeaders by default
- Updated CustomeHMACHeaders to allow rawId in HMAC authentication
- Updated all tests and re-recorded based on changes

* Updating API doc

* Fixing hangup + repeatability headers
Initializing repeatability headers in all options

* Fixing Tests + recorded tests

Co-authored-by: Min Woo Lee 🧊 <[email protected]>
  • Loading branch information
minwoolee-msft and minwoolee-msft authored Oct 26, 2022
1 parent da4dff9 commit 1289b4d
Show file tree
Hide file tree
Showing 43 changed files with 2,237 additions and 1,531 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ protected CallAutomationEventBase() { }
}
public static partial class CallAutomationEventParser
{
public const string EventPrefix = "Microsoft.Communication.";
public static Azure.Communication.CallAutomation.CallAutomationEventBase Parse(Azure.Messaging.CloudEvent cloudEvent) { throw null; }
public static Azure.Communication.CallAutomation.CallAutomationEventBase Parse(System.BinaryData json) { throw null; }
public static Azure.Communication.CallAutomation.CallAutomationEventBase Parse(string eventData, string eventType) { throw null; }
Expand Down Expand Up @@ -695,11 +694,10 @@ internal RemoveParticipantsResult() { }
}
public partial class RepeatabilityHeaders
{
public RepeatabilityHeaders() { }
public RepeatabilityHeaders(System.Guid repeatabilityRequestId, System.DateTimeOffset repeatabilityFirstSent) { }
public System.DateTimeOffset RepeatabilityFirstSent { get { throw null; } }
public System.Guid RepeatabilityRequestId { get { throw null; } }
public string GetRepeatabilityFirstSentString() { throw null; }
public bool IsInvalidRepeatabilityHeaders() { throw null; }
}
public partial class ResultInformation
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,9 @@ public virtual async Task<Response<AnswerCallResult>> AnswerCallAsync(AnswerCall
try
{
if (options == null) throw new ArgumentNullException(nameof(options));
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

AnswerCallRequestInternal request = CreateAnswerCallRequest(options);
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

var answerResponse = await ServerCallingRestClient.AnswerCallAsync(request,
options.RepeatabilityHeaders?.RepeatabilityRequestId,
Expand Down Expand Up @@ -184,10 +183,9 @@ public virtual Response<AnswerCallResult> AnswerCall(AnswerCallOptions options,
try
{
if (options == null) throw new ArgumentNullException(nameof(options));
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

AnswerCallRequestInternal request = CreateAnswerCallRequest(options);
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

var answerResponse = ServerCallingRestClient.AnswerCall(request,
options.RepeatabilityHeaders?.RepeatabilityRequestId,
Expand Down Expand Up @@ -240,10 +238,9 @@ public virtual async Task<Response> RedirectCallAsync(RedirectCallOptions option
{
if (options == null)
throw new ArgumentNullException(nameof(options));
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

RedirectCallRequestInternal request = new RedirectCallRequestInternal(options.IncomingCallContext, CommunicationIdentifierSerializer.Serialize(options.Target));
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

return await ServerCallingRestClient.RedirectCallAsync(
request,
Expand Down Expand Up @@ -287,10 +284,9 @@ public virtual Response RedirectCall(RedirectCallOptions options, CancellationTo
{
if (options == null)
throw new ArgumentNullException(nameof(options));
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

RedirectCallRequestInternal request = new RedirectCallRequestInternal(options.IncomingCallContext, CommunicationIdentifierSerializer.Serialize(options.Target));
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

return ServerCallingRestClient.RedirectCall(
request,
Expand Down Expand Up @@ -331,11 +327,10 @@ public virtual async Task<Response> RejectCallAsync(RejectCallOptions options, C
{
if (options == null)
throw new ArgumentNullException(nameof(options));
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

RejectCallRequestInternal request = new RejectCallRequestInternal(options.IncomingCallContext);
request.CallRejectReason = options.CallRejectReason.ToString();
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

return await ServerCallingRestClient.RejectCallAsync(
request,
Expand Down Expand Up @@ -377,11 +372,10 @@ public virtual Response RejectCall(RejectCallOptions options, CancellationToken
{
if (options == null)
throw new ArgumentNullException(nameof(options));
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

RejectCallRequestInternal request = new RejectCallRequestInternal(options.IncomingCallContext);
request.CallRejectReason = options.CallRejectReason.ToString();
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

return ServerCallingRestClient.RejectCall(
request,
Expand Down Expand Up @@ -414,10 +408,8 @@ public virtual async Task<Response<CreateCallResult>> CreateCallAsync(CreateCall
if (options == null)
throw new ArgumentNullException(nameof(options));

if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

CreateCallRequestInternal request = CreateCallRequest(options);
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

var createCallResponse = await ServerCallingRestClient.CreateCallAsync(
request,
Expand Down Expand Up @@ -453,10 +445,8 @@ public virtual Response<CreateCallResult> CreateCall(CreateCallOptions options,
{
if (options == null) throw new ArgumentNullException(nameof(options));

if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

CreateCallRequestInternal request = CreateCallRequest(options);
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

var createCallResponse = ServerCallingRestClient.CreateCall(
request,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,7 @@ public virtual async Task<Response> HangUpAsync(HangUpOptions options, Cancellat

if (options.ForEveryone)
{
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();
return await RestClient.TerminateCallAsync(
CallConnectionId,
options.RepeatabilityHeaders?.RepeatabilityRequestId,
Expand Down Expand Up @@ -165,9 +163,7 @@ public virtual Response HangUp(HangUpOptions options,CancellationToken cancellat

if (options.ForEveryone)
{
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();
return RestClient.TerminateCall(
CallConnectionId,
options.RepeatabilityHeaders?.RepeatabilityRequestId,
Expand Down Expand Up @@ -204,10 +200,9 @@ public virtual async Task<Response<TransferCallToParticipantResult>> TransferCal
{
if (options == null)
throw new ArgumentNullException(nameof(options));
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

TransferToParticipantRequestInternal request = CreateTransferToParticipantRequest(options);;
TransferToParticipantRequestInternal request = CreateTransferToParticipantRequest(options);
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

return await RestClient.TransferToParticipantAsync(
CallConnectionId,
Expand Down Expand Up @@ -238,10 +233,9 @@ public virtual Response<TransferCallToParticipantResult> TransferCallToParticipa
{
if (options == null)
throw new ArgumentNullException(nameof(options));
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

TransferToParticipantRequestInternal request = CreateTransferToParticipantRequest(options);
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

return RestClient.TransferToParticipant(
CallConnectionId,
Expand Down Expand Up @@ -283,10 +277,9 @@ public virtual async Task<Response<AddParticipantsResult>> AddParticipantsAsync(
{
if (options == null)
throw new ArgumentNullException(nameof(options));
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

AddParticipantsRequestInternal request = CreateAddParticipantRequest(options);
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

var response = await RestClient.AddParticipantAsync(
callConnectionId: CallConnectionId,
Expand Down Expand Up @@ -319,10 +312,9 @@ public virtual Response<AddParticipantsResult> AddParticipants(AddParticipantsOp
{
if (options == null)
throw new ArgumentNullException(nameof(options));
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

AddParticipantsRequestInternal request = CreateAddParticipantRequest(options);
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

var response = RestClient.AddParticipant(
callConnectionId: CallConnectionId,
Expand Down Expand Up @@ -485,10 +477,9 @@ public virtual async Task<Response<RemoveParticipantsResult>> RemoveParticipants
{
if (options == null)
throw new ArgumentNullException(nameof(options));
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

RemoveParticipantsRequestInternal request = new RemoveParticipantsRequestInternal(options.ParticipantsToRemove.Select(t => CommunicationIdentifierSerializer.Serialize(t)).ToList());
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

request.OperationContext = options.OperationContext;

Expand Down Expand Up @@ -536,10 +527,9 @@ public virtual Response<RemoveParticipantsResult> RemoveParticipants(RemoveParti
{
if (options == null)
throw new ArgumentNullException(nameof(options));
if (options.RepeatabilityHeaders != null && options.RepeatabilityHeaders.IsInvalidRepeatabilityHeaders())
throw new ArgumentException(CallAutomationErrorMessages.InvalidRepeatabilityHeadersMessage);

RemoveParticipantsRequestInternal request = new RemoveParticipantsRequestInternal(options.ParticipantsToRemove.Select(t => CommunicationIdentifierSerializer.Serialize(t)).ToList());
options.RepeatabilityHeaders?.GenerateIfRepeatabilityHeadersNotProvided();

request.OperationContext = options.OperationContext;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Azure.Communication.Pipeline
{
internal class CustomHMACAuthenticationPolicy : HttpPipelinePolicy
{
private readonly String DATE_HEADER_NAME = "x-ms-date";
private readonly string DATE_HEADER_NAME = "x-ms-date";
private readonly AzureKeyCredential _keyCredential;
private readonly string _acsEndpoint;

Expand Down Expand Up @@ -100,11 +100,9 @@ private string GetAuthorizationHeader(RequestMethod method, Uri uri, string cont

private string ComputeHMAC(string value)
{
using (var hmac = new HMACSHA256(Convert.FromBase64String(_keyCredential.Key)))
{
var hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(value));
return Convert.ToBase64String(hash);
}
using var hmac = new HMACSHA256(Convert.FromBase64String(_keyCredential.Key));
var hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(value));
return Convert.ToBase64String(hash);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class AddParticipantsOptions
public AddParticipantsOptions(IEnumerable<CommunicationIdentifier> participantsToAdd)
{
ParticipantsToAdd = participantsToAdd;
RepeatabilityHeaders = new RepeatabilityHeaders();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public AnswerCallOptions(string incomingCallContext, Uri callbackUri)
{
IncomingCallContext = incomingCallContext;
CallbackUri = callbackUri;
RepeatabilityHeaders = new RepeatabilityHeaders();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public CreateCallOptions(CallSource callSource, IEnumerable<CommunicationIdentif
Targets = (IReadOnlyList<CommunicationIdentifier>)targets;
CallSource = callSource;
CallbackUri = callbackUri;
RepeatabilityHeaders = new RepeatabilityHeaders();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static class CallAutomationEventParser
/// <summary>
/// Parsing a CallAutomation event from a CloudEvent.
/// </summary>
public const string EventPrefix = "Microsoft.Communication.";
private const string EventPrefix = "Microsoft.Communication.";

/// <summary>
/// Parsing a CallAutomation event from a CloudEvent.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class HangUpOptions
public HangUpOptions(bool forEveryone)
{
ForEveryone = forEveryone;
RepeatabilityHeaders = new RepeatabilityHeaders();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public RedirectCallOptions(string incomingCallContext, CommunicationIdentifier t
{
IncomingCallContext = incomingCallContext;
Target = target;
RepeatabilityHeaders = new RepeatabilityHeaders();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class RejectCallOptions
public RejectCallOptions(string incomingCallContext)
{
IncomingCallContext = incomingCallContext;
RepeatabilityHeaders = new RepeatabilityHeaders();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class RemoveParticipantsOptions
public RemoveParticipantsOptions(IEnumerable<CommunicationIdentifier> participantsToRemove)
{
ParticipantsToRemove = (IReadOnlyList<CommunicationIdentifier>)participantsToRemove;
RepeatabilityHeaders = new RepeatabilityHeaders();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,21 @@ public class RepeatabilityHeaders
/// <summary>
/// The value of the Repeatability-Request-Id is an opaque string representing a client-generated unique identifier for the request. It is a version 4 (random) UUID.
/// </summary>
public Guid RepeatabilityRequestId { get; }
public Guid RepeatabilityRequestId { get; private set; }

/// <summary>
/// The value should be the date and time at which the request was first created.
/// </summary>
public DateTimeOffset RepeatabilityFirstSent { get; }
public DateTimeOffset RepeatabilityFirstSent { get; private set; }

/// <summary>
/// Let SDK provide repeatability headers. This is also the default behaviour if repeatability header is not provided. If you would like to exlucde repeataiblity headers in the request, pass the NULL value for RepeatabilityHeaders class.
/// </summary>
public RepeatabilityHeaders()
{
RepeatabilityRequestId = default;
RepeatabilityFirstSent = default;
}

/// <summary>
/// If specified, the client directs that the request is repeatable; that is, that the client can make the request multiple times with the same RepeatabilityHeaders and get back an appropriate response without the server executing the request multiple times.
Expand All @@ -34,16 +43,18 @@ public RepeatabilityHeaders(Guid repeatabilityRequestId, DateTimeOffset repeatab
/// Function that returns RepeatabilityFirstSent in string format using the IMF-fixdate form of HTTP-date.
/// </summary>
/// <returns></returns>
public string GetRepeatabilityFirstSentString() {
internal string GetRepeatabilityFirstSentString()
{
return RepeatabilityFirstSent.ToString("R");
}

/// <summary>
/// Function that checks the validity of the repeatability headers.
/// RepeatabilityHeaders is only valid when RepeatabilityRequestId and RepeatabilityFirstSent are set to non-default value.
/// </summary>
public Boolean IsInvalidRepeatabilityHeaders() {
return RepeatabilityRequestId.Equals(Guid.Empty) || RepeatabilityFirstSent.Equals(DateTimeOffset.MinValue) || RepeatabilityFirstSent.Equals(DateTimeOffset.MaxValue);
internal void GenerateIfRepeatabilityHeadersNotProvided()
{
if (RepeatabilityRequestId == default && RepeatabilityFirstSent == default)
{
RepeatabilityRequestId = Guid.NewGuid();
RepeatabilityFirstSent = DateTimeOffset.Now;
}
}
}
}
Loading

0 comments on commit 1289b4d

Please sign in to comment.