Skip to content

Initial checking#1950

Open
anthonydummer wants to merge 6 commits into
masterfrom
cme-895
Open

Initial checking#1950
anthonydummer wants to merge 6 commits into
masterfrom
cme-895

Conversation

@anthonydummer

Copy link
Copy Markdown

Jira link

https://tools.hmcts.net/jira/browse/CME-895

Change description

Fixes to security tickets

Testing done

All tests have been updated.

Security Vulnerability Assessment

CVE Suppression: Are there any CVEs present in the codebase (either newly introduced or pre-existing) that are being intentionally suppressed or ignored by this commit?

  • Yes
  • No

Checklist

  • commit messages are meaningful and follow good commit message guidelines
  • README and other documentation has been updated / added (if needed)
  • tests have been updated / new tests has been added (if needed)
  • Does this PR introduce a breaking change - no

@hmcts-jenkins-a-to-c

hmcts-jenkins-a-to-c Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Plan Result (aat)

Plan: 0 to add, 3 to change, 0 to destroy.
  • Update
    • azurerm_api_management_subscription.fee_pay_team_telephony_subscription
    • azurerm_api_management_subscription.pcipal_supplier_subscription
    • module.cft_api_mgmt_policy.azurerm_api_management_api_policy.api_policy
Change Result (Click me)
  # azurerm_api_management_subscription.fee_pay_team_telephony_subscription will be updated in-place
  ~ resource "azurerm_api_management_subscription" "fee_pay_team_telephony_subscription" {
      ~ allow_tracing       = false -> true
        id                  = "/subscriptions/96c274ce-846d-4e48-89a7-d528432298a7/resourceGroups/cft-aat-network-rg/providers/Microsoft.ApiManagement/service/cft-api-mgmt-stg/subscriptions/5a89d26c-6d91-4997-8a4e-13e4e279ee0a"
        # (10 unchanged attributes hidden)
    }

  # azurerm_api_management_subscription.pcipal_supplier_subscription will be updated in-place
  ~ resource "azurerm_api_management_subscription" "pcipal_supplier_subscription" {
      ~ allow_tracing       = false -> true
        id                  = "/subscriptions/96c274ce-846d-4e48-89a7-d528432298a7/resourceGroups/cft-aat-network-rg/providers/Microsoft.ApiManagement/service/cft-api-mgmt-stg/subscriptions/ea576e34-00bd-4eff-80d5-85f6c6392bb2"
        # (10 unchanged attributes hidden)
    }

  # module.cft_api_mgmt_policy.azurerm_api_management_api_policy.api_policy will be updated in-place
  ~ resource "azurerm_api_management_api_policy" "api_policy" {
        id                  = "/subscriptions/96c274ce-846d-4e48-89a7-d528432298a7/resourceGroups/cft-aat-network-rg/providers/Microsoft.ApiManagement/service/cft-api-mgmt-stg/apis/telephony-api"
      ~ xml_content         = <<-EOT
          - <policies>
          - 	<backend>
          - 		<base />
          - 	</backend>
          - 	<inbound>
          - 		<base />
          - 		<choose>
          - 			<when condition="@(context.Request.Headers["X-ARR-ClientCertThumbprint"] == null)">
          - 				<return-response>
          - 					<set-status code="401" />
          - 					<set-body>Missing client certificate.</set-body>
          - 				</return-response>
          - 			</when>
          - 			<when condition="@(!(new string[] {&quot;B1BF8007527F85085D7C4A3DC406A9A6D124D721&quot;,&quot;68EDF481C5394D65962E9810913455D3EC635FA5&quot;,&quot;13D1848E8B050CE55E4D41A35A60FF4A17E686A6&quot;,&quot;B660C97A7CC2734ABD41FBF9F6ADAA61B0C399D4&quot;}.Contains(context.Request.Headers[&quot;X-ARR-ClientCertThumbprint&quot;].First().ToUpperInvariant())))">
          - 				<return-response>
          - 					<set-status code="401" />
          - 					<set-body>Invalid client certificate.</set-body>
          - 				</return-response>
          - 			</when>
          - 			<!--          <when condition="@(context.Request.Certificate == null || context.Request.Certificate.NotAfter < DateTime.Now || context.Request.Certificate.NotBefore > DateTime.Now || !(new string[] {"B1BF8007527F85085D7C4A3DC406A9A6D124D721","68EDF481C5394D65962E9810913455D3EC635FA5","13D1848E8B050CE55E4D41A35A60FF4A17E686A6","B660C97A7CC2734ABD41FBF9F6ADAA61B0C399D4"}.Any(c => c == context.Request.Certificate.Thumbprint)))" >-->
          - 			<!--              <return-response>-->
          - 			<!--                <set-status code="401" />-->
          - 			<!--                <set-body>Invalid client certificate. Please check expiry.</set-body>-->
          - 			<!--              </return-response>-->
          - 			<!--          </when>-->
          - 		</choose>
          - 		<!-- generate totp using mgmt named values -->
          - 		<set-variable name="client_id" value="{{ccpay-s2s-client-id}}" />
          - 		<set-variable name="client_secret" value="{{ccpay-s2s-client-secret}}" />
          - 		<set-variable name="one_time_password" value="@{
          + <policies>
          +     <backend>
          +         <base/>
          +     </backend>
          +     <inbound>
          +         <base/>
          +         <!-- Strip any incoming client certificate thumbprint header -->
          +         <set-header name="X-ARR-ClientCertThumbprint" exists-action="delete" />
          + 
          +         <!-- Validate client certificate using mTLS -->
          +         <choose>
          +             <when condition="@(context.Request.Certificate == null ||
          +     context.Request.Certificate.NotAfter &lt; DateTime.Now ||
          +     context.Request.Certificate.NotBefore &gt; DateTime.Now ||
          +     !(new string[] {&quot;B1BF8007527F85085D7C4A3DC406A9A6D124D721&quot;,&quot;68EDF481C5394D65962E9810913455D3EC635FA5&quot;,&quot;13D1848E8B050CE55E4D41A35A60FF4A17E686A6&quot;,&quot;B660C97A7CC2734ABD41FBF9F6ADAA61B0C399D4&quot;}.Any(c => c == context.Request.Certificate.Thumbprint)))">
          +                 <return-response>
          +                     <set-status code="401" />
          +                     <set-body>Invalid client certificate.</set-body>
          +                 </return-response>
          +             </when>
          +         </choose>
          +         <!-- generate totp using mgmt named values -->
          +         <set-variable name="client_id" value="{{ccpay-s2s-client-id}}" />
          +         <set-variable name="client_secret" value="{{ccpay-s2s-client-secret}}" />
          +         <set-variable name="one_time_password" value="@{
                            const string Base32AllowedCharacters = &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ234567&quot;;
                            var clientSecret = ((string)context.Variables[&quot;client_secret&quot;]).ToUpper();
                            var bits = clientSecret.ToCharArray().Select(c => Convert.ToString(Base32AllowedCharacters.IndexOf(c), 2).PadLeft(5, '0')).Aggregate((a, b) => a + b);
                            var secretKeyBytes = Enumerable.Range(0, bits.Length / 8).Select(i => Convert.ToByte(bits.Substring(i * 8, 8), 2)).ToArray();
            
                            var unixTimestamp = (long) (DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
                            var timeIndex = unixTimestamp / 30;
                            byte[] challenge = BitConverter.GetBytes(timeIndex);
                            if (BitConverter.IsLittleEndian) {
                                Array.Reverse(challenge);
                            }
            
          -                 HMACSHA1 hmac = new HMACSHA1(secretKeyBytes);
          +                 HMACSHA256 hmac = new HMACSHA256(secretKeyBytes);
                            byte[] hash = hmac.ComputeHash(challenge);
          -                 int offset = hash[19] &amp; 0xf;
          +                 int offset = hash[hash.Length - 1] &amp; 0xf;
                            int truncatedHash = hash[offset] &amp; 0x7f;
                            for (int i = 1; i &lt; 4; i++)
                            {
                                truncatedHash &lt;&lt;= 8;
                                truncatedHash |= hash[offset + i] &amp; 0xff;
                            }
                            truncatedHash %= 1000000;
                            return truncatedHash.ToString(&quot;D6&quot;);
          -             }" />
          - 		<send-request ignore-error="false" timeout="20" response-variable-name="s2sBearerToken" mode="new">
          - 			<set-url>http://rpe-service-auth-provider-aat.service.core-compute-aat.internal/lease</set-url>
          - 			<set-method>POST</set-method>
          - 			<set-header name="Content-Type" exists-action="override">
          - 				<value>application/json</value>
          - 			</set-header>
          - 			<set-body>@{
          -                 return new JObject(
          -                 new JProperty("microservice", (string)context.Variables["client_id"]),
          -                 new JProperty("oneTimePassword", (string)context.Variables["one_time_password"])
          -                 ).ToString();
          -                 }</set-body>
          - 		</send-request>
          - 		<set-header name="ServiceAuthorization" exists-action="override">
          - 			<value>@("Bearer " + ((IResponse)context.Variables["s2sBearerToken"]).Body.As&lt;string&gt;())</value>
          - 		</set-header>
          - 	</inbound>
          - 	<outbound>
          - 		<base />
          - 	</outbound>
          - 	<on-error>
          - 		<base />
          - 	</on-error>
          +             }"/>
          +         <send-request ignore-error="false" timeout="20" response-variable-name="s2sBearerToken" mode="new">
          +             <set-url>http://rpe-service-auth-provider-aat.service.core-compute-aat.internal/lease</set-url>
          +             <set-method>POST</set-method>
          +             <set-header name="Content-Type" exists-action="override">
          +                 <value>application/json</value>
          +             </set-header>
          +             <set-body>@{
          +                 return new JObject(
          +                 new JProperty("microservice", (string)context.Variables["client_id"]),
          +                 new JProperty("oneTimePassword", (string)context.Variables["one_time_password"])
          +                 ).ToString();
          +                 }</set-body>
          +         </send-request>
          + 
          +         <set-header name="ServiceAuthorization" exists-action="override">
          +             <value>@("Bearer " + ((IResponse)context.Variables["s2sBearerToken"]).Body.As&lt;string&gt;())</value>
          +         </set-header>
          +     </inbound>
          +     <outbound>
          +         <base/>
          +     </outbound>
          +     <on-error>
          +         <base/>
          +     </on-error>
            </policies>
        EOT
        # (4 unchanged attributes hidden)
    }

Plan: 0 to add, 3 to change, 0 to destroy.

@hmcts-jenkins-a-to-c

hmcts-jenkins-a-to-c Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Plan Result (prod)

Plan: 0 to add, 3 to change, 0 to destroy.
  • Update
    • azurerm_api_management_subscription.fee_pay_team_telephony_subscription
    • azurerm_api_management_subscription.pcipal_supplier_subscription
    • module.cft_api_mgmt_policy.azurerm_api_management_api_policy.api_policy
Change Result (Click me)
  # azurerm_api_management_subscription.fee_pay_team_telephony_subscription will be updated in-place
  ~ resource "azurerm_api_management_subscription" "fee_pay_team_telephony_subscription" {
      ~ allow_tracing       = false -> true
        id                  = "/subscriptions/8cbc6f36-7c56-4963-9d36-739db5d00b27/resourceGroups/cft-prod-network-rg/providers/Microsoft.ApiManagement/service/cft-api-mgmt-prod/subscriptions/7229a544-a882-4520-a81e-2cd4ed6f0031"
        # (10 unchanged attributes hidden)
    }

  # azurerm_api_management_subscription.pcipal_supplier_subscription will be updated in-place
  ~ resource "azurerm_api_management_subscription" "pcipal_supplier_subscription" {
      ~ allow_tracing       = false -> true
        id                  = "/subscriptions/8cbc6f36-7c56-4963-9d36-739db5d00b27/resourceGroups/cft-prod-network-rg/providers/Microsoft.ApiManagement/service/cft-api-mgmt-prod/subscriptions/abd7d0f5-77bc-462c-a658-c8d1e1b40837"
        # (10 unchanged attributes hidden)
    }

  # module.cft_api_mgmt_policy.azurerm_api_management_api_policy.api_policy will be updated in-place
  ~ resource "azurerm_api_management_api_policy" "api_policy" {
        id                  = "/subscriptions/8cbc6f36-7c56-4963-9d36-739db5d00b27/resourceGroups/cft-prod-network-rg/providers/Microsoft.ApiManagement/service/cft-api-mgmt-prod/apis/telephony-api"
      ~ xml_content         = <<-EOT
          - <policies>
          - 	<backend>
          - 		<base />
          - 	</backend>
          - 	<inbound>
          - 		<base />
          - 		<choose>
          - 			<when condition="@(context.Request.Headers["X-ARR-ClientCertThumbprint"] == null)">
          - 				<return-response>
          - 					<set-status code="401" />
          - 					<set-body>Missing client certificate.</set-body>
          - 				</return-response>
          - 			</when>
          - 			<when condition="@(!(new string[] {&quot;68EDF481C5394D65962E9810913455D3EC635FA5&quot;,&quot;C46826BF1E82DF37664F7A3678E6498D056DA4A9&quot;,&quot;7CEAEFB76C3ED0909919CFD16613EFE483B9D05F&quot;}.Contains(context.Request.Headers[&quot;X-ARR-ClientCertThumbprint&quot;].First().ToUpperInvariant())))">
          - 				<return-response>
          - 					<set-status code="401" />
          - 					<set-body>Invalid client certificate.</set-body>
          - 				</return-response>
          - 			</when>
          - 			<!--          <when condition="@(context.Request.Certificate == null || context.Request.Certificate.NotAfter < DateTime.Now || context.Request.Certificate.NotBefore > DateTime.Now || !(new string[] {"68EDF481C5394D65962E9810913455D3EC635FA5","C46826BF1E82DF37664F7A3678E6498D056DA4A9","7CEAEFB76C3ED0909919CFD16613EFE483B9D05F"}.Any(c => c == context.Request.Certificate.Thumbprint)))" >-->
          - 			<!--              <return-response>-->
          - 			<!--                <set-status code="401" />-->
          - 			<!--                <set-body>Invalid client certificate. Please check expiry.</set-body>-->
          - 			<!--              </return-response>-->
          - 			<!--          </when>-->
          - 		</choose>
          - 		<!-- generate totp using mgmt named values -->
          - 		<set-variable name="client_id" value="{{ccpay-s2s-client-id}}" />
          - 		<set-variable name="client_secret" value="{{ccpay-s2s-client-secret}}" />
          - 		<set-variable name="one_time_password" value="@{
          + <policies>
          +     <backend>
          +         <base/>
          +     </backend>
          +     <inbound>
          +         <base/>
          +         <!-- Strip any incoming client certificate thumbprint header -->
          +         <set-header name="X-ARR-ClientCertThumbprint" exists-action="delete" />
          + 
          +         <!-- Validate client certificate using mTLS -->
          +         <choose>
          +             <when condition="@(context.Request.Certificate == null ||
          +     context.Request.Certificate.NotAfter &lt; DateTime.Now ||
          +     context.Request.Certificate.NotBefore &gt; DateTime.Now ||
          +     !(new string[] {&quot;68EDF481C5394D65962E9810913455D3EC635FA5&quot;,&quot;C46826BF1E82DF37664F7A3678E6498D056DA4A9&quot;,&quot;7CEAEFB76C3ED0909919CFD16613EFE483B9D05F&quot;}.Any(c => c == context.Request.Certificate.Thumbprint)))">
          +                 <return-response>
          +                     <set-status code="401" />
          +                     <set-body>Invalid client certificate.</set-body>
          +                 </return-response>
          +             </when>
          +         </choose>
          +         <!-- generate totp using mgmt named values -->
          +         <set-variable name="client_id" value="{{ccpay-s2s-client-id}}" />
          +         <set-variable name="client_secret" value="{{ccpay-s2s-client-secret}}" />
          +         <set-variable name="one_time_password" value="@{
                            const string Base32AllowedCharacters = &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ234567&quot;;
                            var clientSecret = ((string)context.Variables[&quot;client_secret&quot;]).ToUpper();
                            var bits = clientSecret.ToCharArray().Select(c => Convert.ToString(Base32AllowedCharacters.IndexOf(c), 2).PadLeft(5, '0')).Aggregate((a, b) => a + b);
                            var secretKeyBytes = Enumerable.Range(0, bits.Length / 8).Select(i => Convert.ToByte(bits.Substring(i * 8, 8), 2)).ToArray();
            
                            var unixTimestamp = (long) (DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
                            var timeIndex = unixTimestamp / 30;
                            byte[] challenge = BitConverter.GetBytes(timeIndex);
                            if (BitConverter.IsLittleEndian) {
                                Array.Reverse(challenge);
                            }
            
          -                 HMACSHA1 hmac = new HMACSHA1(secretKeyBytes);
          +                 HMACSHA256 hmac = new HMACSHA256(secretKeyBytes);
                            byte[] hash = hmac.ComputeHash(challenge);
          -                 int offset = hash[19] &amp; 0xf;
          +                 int offset = hash[hash.Length - 1] &amp; 0xf;
                            int truncatedHash = hash[offset] &amp; 0x7f;
                            for (int i = 1; i &lt; 4; i++)
                            {
                                truncatedHash &lt;&lt;= 8;
                                truncatedHash |= hash[offset + i] &amp; 0xff;
                            }
                            truncatedHash %= 1000000;
                            return truncatedHash.ToString(&quot;D6&quot;);
          -             }" />
          - 		<send-request ignore-error="false" timeout="20" response-variable-name="s2sBearerToken" mode="new">
          - 			<set-url>http://rpe-service-auth-provider-prod.service.core-compute-prod.internal/lease</set-url>
          - 			<set-method>POST</set-method>
          - 			<set-header name="Content-Type" exists-action="override">
          - 				<value>application/json</value>
          - 			</set-header>
          - 			<set-body>@{
          -                 return new JObject(
          -                 new JProperty("microservice", (string)context.Variables["client_id"]),
          -                 new JProperty("oneTimePassword", (string)context.Variables["one_time_password"])
          -                 ).ToString();
          -                 }</set-body>
          - 		</send-request>
          - 		<set-header name="ServiceAuthorization" exists-action="override">
          - 			<value>@("Bearer " + ((IResponse)context.Variables["s2sBearerToken"]).Body.As&lt;string&gt;())</value>
          - 		</set-header>
          - 	</inbound>
          - 	<outbound>
          - 		<base />
          - 	</outbound>
          - 	<on-error>
          - 		<base />
          - 	</on-error>
          +             }"/>
          +         <send-request ignore-error="false" timeout="20" response-variable-name="s2sBearerToken" mode="new">
          +             <set-url>http://rpe-service-auth-provider-prod.service.core-compute-prod.internal/lease</set-url>
          +             <set-method>POST</set-method>
          +             <set-header name="Content-Type" exists-action="override">
          +                 <value>application/json</value>
          +             </set-header>
          +             <set-body>@{
          +                 return new JObject(
          +                 new JProperty("microservice", (string)context.Variables["client_id"]),
          +                 new JProperty("oneTimePassword", (string)context.Variables["one_time_password"])
          +                 ).ToString();
          +                 }</set-body>
          +         </send-request>
          + 
          +         <set-header name="ServiceAuthorization" exists-action="override">
          +             <value>@("Bearer " + ((IResponse)context.Variables["s2sBearerToken"]).Body.As&lt;string&gt;())</value>
          +         </set-header>
          +     </inbound>
          +     <outbound>
          +         <base/>
          +     </outbound>
          +     <on-error>
          +         <base/>
          +     </on-error>
            </policies>
        EOT
        # (4 unchanged attributes hidden)
    }

Plan: 0 to add, 3 to change, 0 to destroy.

Comment thread infrastructure/template/cft-api-policy.xml Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants