Komplett säkerställning av identitet mot navet med Powershell

This post is going to be in Swedish since it’s an custom-made integration against Swedish tax authority.

För tillfället pågår ett projekt hos oss där man har behov av att styrka identitet mot skatteverkets e-tjänst “Navet”. Projektet hade förhoppningar på att leverantörer av personalsystem eller motsvarande skulle kunna ta ansvar för konvertering och transport av data mot navet, men det var tydligen inget de kunde göra. Tieto hade flaggat för att de skulle kunna göra jobbet mot en säck pengar, dock ville man under testfasen komma igång så snabbt som möjligt och frågade mig och en kollega om vi skulle kunna vara hjälpliga och kanske ratta det manuellt under testet för att få momentum i projektet. Manuellt arbete är trist så jag satte upp allt med hjälp av 4 stycken powershell-script som vi framtiden kommer kunna återanvända i produktion. Svårigheterna i utvecklingen låg i bland annat att skatteverket rekommenderar ett freewareprogram som heter curl för att hämta och lämna filer och här ville jag göra allt med ren powershell, samt att skatteverket inte använder xml eller csv utan istället vad jag tror är någon hemmasnickrat stordatorformat(Och ja det kanske är ISO-standard sen 1967? men det är inte lättjobbat för det). Flödesschema för lösningen:

Slagning Navet flöde

Först exporteras en lista med en kolumn med personnummer från Heroma. Vi tar den listan och konverterar till  Navetkompatibelt format genom att köra det första skriptet av fyra. Navetfilen ska se ut på följande sätt:

#INFO_START
#FILTYP INDATAFIL
#BESTÄLLNINGSID XXXXXXXXX-XXXX-XXXXX
#BESTÄLLNINGSTYP URVAL
#NAMN_INFIL datafil.txt
#GILTIG_TOM XXXXXX
#INFO_SLUT
#DATA_START
#PNR 1927XXXXXXXX
#PNR 1928XXXXXXXX
#PNR 1939XXXXXXXX
#DATA_SLUT
#AVST_START
#ANTAL_POSTER 00000003
#AVST_SLUT
#FIL_SLUT

Jag löste konverteringen genom att skapa skapa 3 stycken textfiler med data som är statisk, sen skapa 2 st filer varje körning med datat som är dynamisk, dvs personnummer och antal poster. skriptet blev så här och gjorde jobbet:

##################################################
#Name: Convert_infile.ps1
#Aurthor: Viktor Lindström 
#
#Comments: Converts Heromfile with personal identity number to Navet compatible Infil file.
##################################################


#Variables
$personer = Get-Content "C:\PKI\personnummer.txt" | Sort-Object
$file2sökväg = "C:\pki\file2.txt"
$file4sökväg = "C:\pki\file4.txt"
$alldatafile = "C:\pki\datafil.txt"
#Count persons and add up with zeros
$antal_personer = "{0:D8}" -f $personer.Count


#Delete file2.txt if it exists.
if (test-path $file2sökväg)
{Remove-Item -Path $file2sökväg
    
}

#Delete file4.txt if it exists.
if (test-path $file4sökväg)
{Remove-Item -Path $file4sökväg
    
}

#Delete alldata.txt if it exists.
if (test-path $alldatafile)
{Remove-Item -Path $alldatafile
    
}

#Create Navet-compatible personal number 
foreach ($person in $personer)
{$person.Replace($person, "#PNR $person") | add-Content $file2sökväg 
    }


#Create Navet-compatible ANTAL_POSTER
Add-Content -Path $file4sökväg -Value "#ANTAL_POSTER $antal_personer"

#Import textfiles.
$file1 = Get-Content C:\PKI\file1.txt
$file2 = Get-Content C:\PKI\file2.txt
$file3 = Get-Content C:\PKI\file3.txt
$file4 = Get-Content C:\PKI\file4.txt
$file5 = Get-Content C:\PKI\file5.txt

#Add all data in one variable
$alldata = $file1+$file2+$file3+$file4+$file5

#Create NAvet infile
Add-Content -Path $alldatafile -Value $alldata

Steg två var att lämna filen med hjälp av powershell istället för rekommenderade curl. Det här var enklare än jag trodde först en enkel import av ett certfikat och sen invoke-webrequest med method post och peka ut filen:

 

##################################################
#Name: Push_infil.ps1
#Aurthor: Viktor Lindström 
#
#Comments: Uploads Navet Infil file to skatteverket navet e-transport.
##################################################

#Variabels
$produktidentitet = "xxxxxxxxx-xxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxx-xxxxxxxx"
$infil = "C:\pki\datafil.txt"

#get certificate
$certificate = Get-ChildItem -Path cert:\CurrentUser\My | where dnsnamelist -Like "*skatte*"

#Upload to Skatteverket
Invoke-WebRequest -Uri "https://shs.skatteverket.se/et/et_web/auto/$produktidentitet" -CertificateThumbprint $certificate.Thumbprint -Method Post -InFile $infil 

Efter att skatteverket fått våran fil så säkerhetsställer de identiteten mot sin databas och fyller på med för, efterenamn, etc etc… och skapar en fil som vi får hämta på ungefär samma sätt som vi lämnade men med skillnaden att vi gör en fråga mot en URL och i content:en så svarar skatteverket med slutet på URL där vi kan hämta filen:

 

##################################################
#Name: get-utfil.ps1
#Aurthor: Viktor Lindström 
#
#
#
#Comments: Downloads Navet Utfil file from skatteverket navet e-transport.
##################################################


#Variabels
$produktidentitet = 'xxxxxxxxx-xxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxx-xxxxxxxx'

#URL to check filename
$checkpatpath = "https://shs.skatteverket.se/et/et_web/auto/" + $produktidentitet + "?getfilenames=true"

#get certificate
$certificate = Get-ChildItem -Path cert:\CurrentUser\My | where dnsnamelist -Like "*skatte*"

#Upload to Skatteverket
$Filecheck = Invoke-WebRequest -Uri "$fullpath"  -CertificateThumbprint $certificate.Thumbprint  

#
$getpath = "https://shs.skatteverket.se/et/et_web/auto/" + $produktidentitet + "/" + $Filecheck.Content

$date = get-date -Format d

Invoke-WebRequest -Uri $getpath -CertificateThumbprint $certificate.Thumbprint -OutFile c:\pki\$date.txt

Det sista och för mig svåraste steget var sen att konvertera Navets fil till en Heromakompatibel csv-fil. Navets fil såg ut på följande sätt där varje kod motsvarar tex förnamn efternam etc etc…:

#INFO_START
#FILTYP UTDATAFIL
#BESTÄLLNINGSID XXXXXXXX-XXXXX-XXX
#BESTÄLLNINGSTYP URVAL
#EFFEKTUERAD 20150110
#INFIL_TILL_GRUND datafil.txt
#INFO_SLUT
#DATA_START
#POST_START
#UP 01001 1958XXXXXXXX
#UP 01012 Ulf Bengt
#UP 01014 Lundell
#POST_SLUT
#POST_START
#UP 01001 1975XXXXXXXX
#UP 01012 Jul
#UP 01014 Tomten
#POST_SLUT
#POST_START
#UP 01001 1978XXXXXXXX
#UP 01011 20
#UP 01012 Carl Christer
#UP 01014 Lopez
#POST_SLUT
#DATA_SLUT
#AVST_START
#ANTAL_POSTER 00000003
#AVST_SLUT
#FIL_SLUT

Jag hade lite olika idéer för hur jag skulle lösa konverteringen men landade till slut i lösning där jag kör select-string mot alla koder kan tänkas komma  och fyller sen en ny fil med de raderna, här plockar jag också bort citationstecken samt fyller på med kommatecken för att få till en csv där jag även lägger till två headers(code och value), nu har jag en csv med kod och värde. När vi rensat datat på allt ointressant så gäller det att börja sortera in det i en Heromakompatibel csv-fil. Jag börjar med att bygga en tom array variabel med alla headers som heroma vill ha och sedan kör jag en foreach på varje rad ur den tvättade datafilen med en switch där jag fyller på de olika fälten i den tom array:en . När en rad gått klart så kollar den om fälten personnummer förnamn och efternamn är fulla, om de är det så  exporteras array:en till en csv och därefter töms alla noteproperty i array:en. skriptet ser ut så här:

##################################################
#Name: Konvertering utfil.ps1
#Aurthor: Viktor Lindström 
#
#
#
#Comments: Converts Navet Utfil-file to Heroma compatible file
#Rev1.01(2015-01-15 Added Code 01003 because of secrecy
#Rev1.02(2015-01-15 replaced out-file to set-content to have ANSI encodeing. Line 79
##################################################

#File variables
$date = get-date -Format d

$sourcefile = "C:\pki\" + $date + ".txt"
$workfile = "C:\pki\workfile.txt"
$resultfile = "C:\pki\resultat.txt"
$heromafile = "C:\pki\heroma.txt"

#Filter working posts
$content = Get-Content $sourcefile -Encoding UTF7
$content | Select-String "#UP 01001","#UP 01002", "#UP 01012", "#UP 01014", "#UP 01011", "#UP 01013","#UP 01003"  | Set-Content $workfile -Encoding UTF8

#Wash away unwanted data and replace space between code and value with comma.
$content2 = Get-Content $workfile -Encoding UTF8
$content2 | foreach {$_ -replace "#UP 01001 ", "01001,"} | set-content $workfile -Encoding UTF8
$content2 = Get-Content $workfile -Encoding UTF8
$content2 | foreach {$_ -replace "#UP 01014 ", "01014,"} | set-content $workfile -Encoding UTF8
$content2 = Get-Content $workfile -Encoding UTF8
$content2 | foreach {$_ -replace "#UP 01012 ", "01012,"} | set-content $workfile -Encoding UTF8
$content2 = Get-Content $workfile -Encoding UTF8
$content2 | foreach {$_ -replace "#UP 01011 ", "01011,"} | set-content $workfile -Encoding UTF8
$content2 = Get-Content $workfile -Encoding UTF8
$content2 | foreach {$_ -replace "#UP 01013 ", "01013,"} | set-content $workfile -Encoding UTF8
$content2 = Get-Content $workfile -Encoding UTF
$content2 | foreach {$_ -replace "#UP 01003 ", "01003,"} | set-content $workfile -Encoding UTF8
$content2 = Get-Content $workfile -Encoding UTF8
$content2 | foreach {$_ -replace "#UP 01002 ", "01002,"} | set-content $workfile -Encoding UTF8


# Create CSV with headers.
$import = Import-Csv $workfile -Encoding UTF8 -Delimiter "," -Header Code, Value

#
$row = "" | select "Personnummer","Tilltalsnamnsmarkering", "Förnamn", "Mellannamn", "Efternamn","Fullständigt namn","C/O adress","Utdelningsadress 1","Utdelningsadress 2","Postnummer","Postort","Anonym"

#Delete resultfile if it exists.
if (test-path $resultfile)
{Remove-Item -Path $resultfile
    
}

foreach ($item in $import)
  { switch ($item.Code) {
    "01001" {$row.Personnummer = $item.value}
    "01002" {$row.Personnummer = $item.value}
    "01003" {$row.Anonym = $item.value}
    "01011" {$row.Tilltalsnamnsmarkering = $item.value}
    "01012" {$row.förnamn = $item.value}
    "01013" {$row.Mellannamn = $item.value}
    "01014" {$row.Efternamn = $item.value}tömms alla 

   }
    
                      
        if ($row.Personnummer -ne $null -And $row.Förnamn -ne $null -and $row.Efternamn -ne $null)
                { 
              
                $row | export-csv $resultfile  -Append -NoTypeInformation -Encoding UTF8 -Delimiter ";"
                $row.personnummer = $null
                $row.förnamn = $null
                $row.efternamn = $null
                $row.Tilltalsnamnsmarkering = $null
                $row.Mellannamn = $null
                $row.Anonym = $null
                
                    
                    
                               }

                               }
                               

#Remove qotations marks and delete headlines and convert to ANSI
                               Get-content $resultfile | % {$_ -replace '"', ""} | select -Skip 1| set-content $heromafile

Vid testkörning mot Navet så fungerade alla skript som de skulle och vi slapp skriva tusentals rader för hand. Om den här lösningen landar i produktion i en system center orchestrator eller som schemalagda skript eller om man väljer att köpa konvertering och transport återstår att se, dock kan man få till en fullständig säkerhetställning av identitet mot Navet genom att endast använda sig av Powershell.