Skip to content

Commit 01cff67

Browse files
committed
feat: add Invoke-ExecCippLogsSas function to generate read-only SAS token for CippLogs table
1 parent a96f0e1 commit 01cff67

2 files changed

Lines changed: 67 additions & 4 deletions

File tree

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
function Invoke-ExecCippLogsSas {
2+
<#
3+
.SYNOPSIS
4+
Generate a read-only SAS token for the CippLogs table
5+
.DESCRIPTION
6+
Creates a long-lived, read-only SAS URL for the CippLogs Azure Storage table.
7+
.FUNCTIONALITY
8+
Entrypoint
9+
.ROLE
10+
CIPP.AppSettings.ReadWrite
11+
#>
12+
[CmdletBinding()]
13+
param($Request, $TriggerMetadata)
14+
15+
$APIName = $Request.Params.CIPPEndpoint
16+
Write-LogMessage -headers $Request.Headers -API $APIName -message 'Generating CippLogs readonly SAS token' -Sev Info
17+
18+
try {
19+
$conn = @{}
20+
foreach ($part in ($env:AzureWebJobsStorage -split ';')) {
21+
$p = $part.Trim()
22+
if ($p -match '^(.+?)=(.+)$') { $conn[$matches[1]] = $matches[2] }
23+
}
24+
25+
$Days = [int]($Request.Query.Days ?? $Request.Body.Days ?? 365)
26+
if ($Days -lt 1 -or $Days -gt 3650) {
27+
throw 'Days must be between 1 and 3650'
28+
}
29+
30+
$Sas = New-CIPPAzServiceSAS `
31+
-AccountName $conn['AccountName'] `
32+
-AccountKey $conn['AccountKey'] `
33+
-Service 'table' `
34+
-ResourcePath 'CippLogs' `
35+
-Permissions 'r' `
36+
-ExpiryTime ([DateTime]::UtcNow.AddDays($Days))
37+
38+
$SASTable = Get-CIPPTable -TableName 'CippSASTokens'
39+
$Entity = @{
40+
PartitionKey = 'SAS'
41+
RowKey = 'CippLogs'
42+
Permissions = 'r'
43+
ExpiryTime = $Sas.ExpiryTime
44+
}
45+
Add-CIPPAzDataTableEntity @SASTable -Entity $Entity
46+
47+
$Body = @{
48+
SASUrl = $Sas.ResourceUri + $Sas.Token
49+
ExpiresOn = $Sas.Query['se']
50+
}
51+
$StatusCode = [HttpStatusCode]::OK
52+
} catch {
53+
$ErrorMessage = Get-CippException -Exception $_
54+
Write-LogMessage -headers $Request.Headers -API $APIName -message "Failed to generate CippLogs readonly SAS token: $($ErrorMessage.NormalizedError)" -Sev Error -LogData $ErrorMessage
55+
$Body = @{ Results = "Failed to generate readonly SAS token: $($ErrorMessage.NormalizedError)" }
56+
$StatusCode = [HttpStatusCode]::InternalServerError
57+
}
58+
59+
return ([HttpResponseContext]@{
60+
StatusCode = $StatusCode
61+
Body = $Body
62+
})
63+
}

Modules/CIPPCore/Public/GraphHelper/New-CIPPAzServiceSAS.ps1

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ function New-CIPPAzServiceSAS {
3838
'blob' { return "/blob/$AccountName/$decodedPath" }
3939
'queue' { return "/queue/$AccountName/$decodedPath" }
4040
'file' { return "/file/$AccountName/$decodedPath" }
41-
'table' { return "/table/$AccountName/$decodedPath" }
41+
'table' { return "/table/$AccountName/$($decodedPath.ToLowerInvariant())" }
4242
}
4343
}
4444

@@ -171,9 +171,9 @@ function New-CIPPAzServiceSAS {
171171
$q['sr'] = $SignedResource
172172
if ($SnapshotTime) { $q['sst'] = $SnapshotTime }
173173
} elseif ($Service -eq 'table') {
174+
# Table SAS requires tn (table name) in the query string
175+
$q['tn'] = $ResourcePath.TrimStart('/')
174176
# Table SAS may include ranges (spk/srk/epk/erk), omitted here unless future parameters are added
175-
# Table also uses tn (table name) in query, but canonicalizedResource already includes table name
176-
# We rely on canonicalizedResource and omit tn unless specified by callers via ResourcePath
177177
} elseif ($Service -eq 'queue') {
178178
# No sr for queue
179179
}
@@ -262,7 +262,7 @@ function New-CIPPAzServiceSAS {
262262
$q['sig'] = $SignatureBase64
263263

264264
# Compose ordered query for readability (common fields first)
265-
$orderedKeys = @('sp', 'st', 'se', 'sip', 'spr', 'sv', 'sr', 'si', 'snapshot', 'ses', 'sdd', 'rscc', 'rscd', 'rsce', 'rscl', 'rsct', 'sig')
265+
$orderedKeys = @('sp', 'st', 'se', 'sip', 'spr', 'sv', 'sr', 'tn', 'si', 'snapshot', 'ses', 'sdd', 'rscc', 'rscd', 'rsce', 'rscl', 'rsct', 'sig')
266266
$parts = [System.Collections.Generic.List[string]]::new()
267267
foreach ($k in $orderedKeys) {
268268
if ($q.ContainsKey($k) -and -not [string]::IsNullOrEmpty($q[$k])) {

0 commit comments

Comments
 (0)