From 11b44b1868cbef8549dc818c38592c4046288e8e Mon Sep 17 00:00:00 2001 From: Davide Perego Date: Thu, 29 Jul 2021 21:49:28 +0100 Subject: [PATCH 01/37] renewed expired Example SP certificate --- example/sp.pem | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/example/sp.pem b/example/sp.pem index e5c0847..1bc67eb 100644 --- a/example/sp.pem +++ b/example/sp.pem @@ -1,16 +1,17 @@ -----BEGIN CERTIFICATE----- -MIICljCCAX4CCQDP2/0y0d0/dzANBgkqhkiG9w0BAQsFADANMQswCQYDVQQGEwJJ -VDAeFw0xODA2MjgwOTM2MDRaFw0xOTA2MjgwOTM2MDRaMA0xCzAJBgNVBAYTAklU -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo4i2HsG/+Qm3qe0gqwEO -h4wlBYK181WCn3RTuyFNQh6mdn6pLdv/dYXY22zER2ufY227FFto3vqtSdT306lp -IoVuXKBAVoWwcrzO0dadM4dyHX7KRmWSDT51GBqkP6Hj1UoUywbXp5q9GXP5uVL8 -U93caT11VZaalHhEjKxtSYJHDP7ZP/2k9p54JgVIonMF0DJVhx0smPZ3QdHX+my/ -JNevsnuXTZIyyu0KjcXlflKSldngVDjv9D6cGE4wGOa5Vz5M+z4tjKnJtfj/xacI -Wcj/4Ukuu6CDyQ8+YNCaE9YjitRmdi5ZqTDOoGKonmlbhCcfqPeRvGwfWXJcVR+q -UwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBVO9pGMnJ3X5D6ny/32TM4fvFesdRB -tSTnivkdssvn4o8u6570XZIpz2AFQ9eltREbobAqYuWrXIr+1x5aACsReFSjusSM -Nb9dUCwZbpcId53WQdGikXVkLwgRw9LfYSr73EfeUIIc9R5HCbR5p2piDzw9cNpR -9wGhhL64g1zhy7O7bdWCXZ4cg9in9N2fCMTjdNpUvG4ZiToRdUqvuMDF4gsQJOwV -wmN6BxQFloyODpdf1XoTk9dEqPqFO5B8h+DY/26JV8QYUPKzGUJkr24GxjFj5dly -d8++oQDBEz0WVC0uRl5nGj+MDAO0DmHNeaS05gWQpp/KpykPzKyQw7cg ------END CERTIFICATE----- \ No newline at end of file +MIICoTCCAYkCFF5EIcofizvlSV+cMzaM458OR9HgMA0GCSqGSIb3DQEBCwUAMA0x +CzAJBgNVBAYTAklUMB4XDTIxMDQxNTEzNTM0OFoXDTMxMDQxMzEzNTM0OFowDTEL +MAkGA1UEBhMCSVQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCjiLYe +wb/5Cbep7SCrAQ6HjCUFgrXzVYKfdFO7IU1CHqZ2fqkt2/91hdjbbMRHa59jbbsU +W2je+q1J1PfTqWkihW5coEBWhbByvM7R1p0zh3IdfspGZZINPnUYGqQ/oePVShTL +Btenmr0Zc/m5UvxT3dxpPXVVlpqUeESMrG1JgkcM/tk//aT2nngmBUiicwXQMlWH +HSyY9ndB0df6bL8k16+ye5dNkjLK7QqNxeV+UpKV2eBUOO/0PpwYTjAY5rlXPkz7 +Pi2Mqcm1+P/FpwhZyP/hSS67oIPJDz5g0JoT1iOK1GZ2LlmpMM6gYqieaVuEJx+o +95G8bB9ZclxVH6pTAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAH2fN9TBKtzcfmaT +GQ/hAmTur2BAU9vbMRJizgpQR9hSO7ty1FSVfS/rzTGOKr/oRfVI3SaTjo+ZYUjc +rVMw3gn/3JfJGTnZmZ6f1yqu0Cm7a7wbvyqWQxbCZzXEqHG13xYq64aYP/aKV8eS +zs1VTw7ShhfhrSYNlQWlr5OUMTgy6WN7ENAr8aCLCKyj+CR4et3hGyo66WPmKGuJ +eD97BYxP/No0S47Z6hUO+W8AgF1Qp52oAMQQ6N6EBVtViT34XMhpK1/7RnmTYusc +gj13zX2qZGt+HpOEOLqA2N/5PtLfEenxPO6vs6ZEPwngelpOQST8St2DmpSBwRjN +PObavq0= +-----END CERTIFICATE----- From f3ec6da3ecec759a60e7b6a68a66f19e9177413a Mon Sep 17 00:00:00 2001 From: Davide Perego Date: Mon, 27 Sep 2021 21:57:39 +0100 Subject: [PATCH 02/37] Added Organization struct to SP metadata --- example/service.go | 5 +++ spidsaml/spid.go | 78 +++++++++++++++++++++++++++------------------- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/example/service.go b/example/service.go index ded89f2..dd5f80c 100644 --- a/example/service.go +++ b/example/service.go @@ -43,6 +43,11 @@ func main() { Attributes: []string{"fiscalNumber", "name", "familyName", "dateOfBirth"}, }, }, + Organization: spidsaml.SPOrganization{ + OrganizationName: "Example Srl", + OrganizationDisplayName: "Example S.r.l.", + OrganizationURL: "https://www.example-sp.it", + }, } // Load Identity Providers from their XML metadata diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 9a7fb37..d2df25b 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -26,6 +26,13 @@ const ( HTTPPost SAMLBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" ) +// Organization adds infos about SP +type SPOrganization struct { + OrganizationName string + OrganizationDisplayName string + OrganizationURL string +} + // SP represents our Service Provider type SP struct { EntityID string @@ -37,6 +44,7 @@ type SP struct { IDP map[string]*IDP _cert *x509.Certificate _key *rsa.PrivateKey + Organization SPOrganization } // Session represents an active SPID session. @@ -109,52 +117,58 @@ func (sp *SP) GetIDP(entityID string) (*IDP, error) { // Metadata generates XML metadata of this Service Provider. func (sp *SP) Metadata() string { - const tmpl = ` - - - - - - - - {{ .Cert }} - - + const tmpl = ` + + + + + + + + {{ .Cert }} + + - + {{ range $url, $binding := .SingleLogoutServices }} - + Location="{{ $url }}" /> {{ end }} - - urn:oasis:names:tc:SAML:2.0:nameid-format:transient + + urn:oasis:names:tc:SAML:2.0:nameid-format:transient {{ range $index, $url := .AssertionConsumerServices }} - + {{ end }} - + {{ range $index, $attcs := .AttributeConsumingServices }} - + {{ $attcs.ServiceName }} {{ range $attr := $attcs.Attributes }} - + {{ end }} {{ end }} - + + + + {{ .Organization.OrganizationName }} + {{ .Organization.OrganizationDisplayName }} + {{ .Organization.OrganizationURL }} + ` From 68b381815891835769daa419ed98392b67d3632c Mon Sep 17 00:00:00 2001 From: nicolasvac <45635090+nicolasvac@users.noreply.github.com> Date: Thu, 28 Oct 2021 15:45:06 +0200 Subject: [PATCH 03/37] Update module --- spidsaml/go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spidsaml/go.mod b/spidsaml/go.mod index 8c301b7..7e4713f 100644 --- a/spidsaml/go.mod +++ b/spidsaml/go.mod @@ -1,4 +1,4 @@ -module github.com/italia/spid-go/spidsaml +module github.com/nicolasvac/spid-go/spidsaml require ( github.com/beevik/etree v1.0.1 From 6c7c00186b8207903a7e3b0be3dd515a0a714900 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 28 Oct 2021 16:46:21 +0200 Subject: [PATCH 04/37] Add dynamic contact person in SP structure --- spidsaml/spid.go | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index d2df25b..cc9dfca 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -26,13 +26,26 @@ const ( HTTPPost SAMLBinding = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" ) -// Organization adds infos about SP +// SPOrganization Organization adds infos about SP type SPOrganization struct { OrganizationName string OrganizationDisplayName string OrganizationURL string } +// SPContactPerson ContactPerson metadata about sp full +type SPContactPerson struct { + ContactType string + EntityType string + IpaCode string + VatNumber string + FiscalCode string + Company string + EmailAddress string + TelephoneNumber string + IsFullAggregator bool +} + // SP represents our Service Provider type SP struct { EntityID string @@ -45,6 +58,7 @@ type SP struct { _cert *x509.Certificate _key *rsa.PrivateKey Organization SPOrganization + ContactPersons []SPContactPerson } // Session represents an active SPID session. @@ -170,6 +184,22 @@ func (sp *SP) Metadata() string { {{ .Organization.OrganizationURL }} + {{ range $index, $contact := .ContactPersons }} + + + {{ $contact.IpaCode }} + {{ $contact.VatNumber }} + {{ $contact.FiscalCode }} + {{ if $contact.IsFullAggregator }} + + {{ end }} + + {{ $contact.Company }} + {{ $contact.Email }} + {{ $contact.TelephoneNumber }} + + {{ end }} + ` aux := struct { From 212e14eb61d00f028ded17bbcce8c243b7bc5236 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 28 Oct 2021 16:54:41 +0200 Subject: [PATCH 05/37] Only add extensions if populated --- spidsaml/spid.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index cc9dfca..df6bd13 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -186,10 +186,16 @@ func (sp *SP) Metadata() string { {{ range $index, $contact := .ContactPersons }} - - {{ $contact.IpaCode }} - {{ $contact.VatNumber }} + + {{ if $contact.IpaCode != nil && $contact.IpaCode != "" }} + {{ $contact.IpaCode }} + {{ end }} + {{ if $contact.VatNumber != nil && $contact.VatNumber != "" }} + {{ $contact.VatNumber }} + {{ end }} + {{ if $contact.FiscalCode != nil && $contact.FiscalCode != "" }} {{ $contact.FiscalCode }} + {{ end }} {{ if $contact.IsFullAggregator }} {{ end }} From 90221d0a112eeb827f17fd41ae6f1f60eba6e143 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 28 Oct 2021 17:02:56 +0200 Subject: [PATCH 06/37] Use if not instead of if != --- spidsaml/spid.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index df6bd13..36efca1 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -187,13 +187,13 @@ func (sp *SP) Metadata() string { {{ range $index, $contact := .ContactPersons }} - {{ if $contact.IpaCode != nil && $contact.IpaCode != "" }} + {{ if not $contact.IpaCode == nil && not $contact.IpaCode == "" }} {{ $contact.IpaCode }} {{ end }} - {{ if $contact.VatNumber != nil && $contact.VatNumber != "" }} + {{ if not $contact.VatNumber == nil && not $contact.VatNumber == "" }} {{ $contact.VatNumber }} {{ end }} - {{ if $contact.FiscalCode != nil && $contact.FiscalCode != "" }} + {{ if not $contact.FiscalCode == nil && not $contact.FiscalCode == "" }} {{ $contact.FiscalCode }} {{ end }} {{ if $contact.IsFullAggregator }} From 1948a5381278de4914e4d6fa79e20bebc27cd27d Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 28 Oct 2021 17:06:39 +0200 Subject: [PATCH 07/37] Use eq instead of == --- spidsaml/spid.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 36efca1..ea4f92e 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -187,13 +187,13 @@ func (sp *SP) Metadata() string { {{ range $index, $contact := .ContactPersons }} - {{ if not $contact.IpaCode == nil && not $contact.IpaCode == "" }} + {{ if not eq $contact.IpaCode nil && not eq $contact.IpaCode "" }} {{ $contact.IpaCode }} {{ end }} - {{ if not $contact.VatNumber == nil && not $contact.VatNumber == "" }} + {{ if not eq $contact.VatNumber nil && not eq $contact.VatNumber "" }} {{ $contact.VatNumber }} {{ end }} - {{ if not $contact.FiscalCode == nil && not $contact.FiscalCode == "" }} + {{ if not eq $contact.FiscalCode nil && not eq $contact.FiscalCode "" }} {{ $contact.FiscalCode }} {{ end }} {{ if $contact.IsFullAggregator }} From 6d28fa6ae3f9db7b009630a248c2ecd0ff931883 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 28 Oct 2021 17:10:56 +0200 Subject: [PATCH 08/37] Bugfix --- spidsaml/spid.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index ea4f92e..677c274 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -187,13 +187,13 @@ func (sp *SP) Metadata() string { {{ range $index, $contact := .ContactPersons }} - {{ if not eq $contact.IpaCode nil && not eq $contact.IpaCode "" }} + {{ if ne $contact.IpaCode nil and ne $contact.IpaCode "" }} {{ $contact.IpaCode }} {{ end }} - {{ if not eq $contact.VatNumber nil && not eq $contact.VatNumber "" }} + {{ if ne $contact.VatNumber nil and ne $contact.VatNumber "" }} {{ $contact.VatNumber }} {{ end }} - {{ if not eq $contact.FiscalCode nil && not eq $contact.FiscalCode "" }} + {{ if ne $contact.FiscalCode nil and ne $contact.FiscalCode "" }} {{ $contact.FiscalCode }} {{ end }} {{ if $contact.IsFullAggregator }} From 85ee99a61cff56e339671f7b0208f98d82dd3732 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 28 Oct 2021 17:17:40 +0200 Subject: [PATCH 09/37] Bugfix --- spidsaml/spid.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 677c274..3d60260 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -187,13 +187,13 @@ func (sp *SP) Metadata() string { {{ range $index, $contact := .ContactPersons }} - {{ if ne $contact.IpaCode nil and ne $contact.IpaCode "" }} + {{ if ne $contact.IpaCode nil }} {{ $contact.IpaCode }} {{ end }} - {{ if ne $contact.VatNumber nil and ne $contact.VatNumber "" }} + {{ if ne $contact.VatNumber nil }} {{ $contact.VatNumber }} {{ end }} - {{ if ne $contact.FiscalCode nil and ne $contact.FiscalCode "" }} + {{ if ne $contact.FiscalCode nil }} {{ $contact.FiscalCode }} {{ end }} {{ if $contact.IsFullAggregator }} From 4a9118e52d61608ea4da56ea7eafacfb27740c87 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 28 Oct 2021 17:20:14 +0200 Subject: [PATCH 10/37] Bugfix --- spidsaml/spid.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 3d60260..687e2ec 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -187,13 +187,13 @@ func (sp *SP) Metadata() string { {{ range $index, $contact := .ContactPersons }} - {{ if ne $contact.IpaCode nil }} + {{ if ne $contact.IpaCode "" }} {{ $contact.IpaCode }} {{ end }} - {{ if ne $contact.VatNumber nil }} + {{ if ne $contact.VatNumber "" }} {{ $contact.VatNumber }} {{ end }} - {{ if ne $contact.FiscalCode nil }} + {{ if ne $contact.FiscalCode "" }} {{ $contact.FiscalCode }} {{ end }} {{ if $contact.IsFullAggregator }} From 61d5c9399469669b6e17513ccd626fe07cc2b647 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 28 Oct 2021 17:26:35 +0200 Subject: [PATCH 11/37] Bugfix --- spidsaml/spid.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 687e2ec..4604bd8 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -201,7 +201,7 @@ func (sp *SP) Metadata() string { {{ end }} {{ $contact.Company }} - {{ $contact.Email }} + {{ $contact.EmailAddress }} {{ $contact.TelephoneNumber }} {{ end }} From d74e9671625a1a06530ed0cb28c955bad0230472 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Fri, 29 Oct 2021 12:04:26 +0200 Subject: [PATCH 12/37] Add xmlns:spid --- spidsaml/spid.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 4604bd8..aba66c9 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -131,10 +131,11 @@ func (sp *SP) GetIDP(entityID string) (*IDP, error) { // Metadata generates XML metadata of this Service Provider. func (sp *SP) Metadata() string { - const tmpl = ` + const tmpl = ` From d1dbad675a36492681b63ab14886f117628a7615 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Fri, 29 Oct 2021 12:07:42 +0200 Subject: [PATCH 13/37] Add xmlns:fpa --- spidsaml/spid.go | 1 + 1 file changed, 1 insertion(+) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index aba66c9..a67d0f8 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -136,6 +136,7 @@ func (sp *SP) Metadata() string { xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:spid="https://spid.gov.it/saml-extensions" + xmlns:fpa="https://spid.gov.it/invoicing-extensions" entityID="{{.EntityID}}" ID="_681a637-6cd4-434f-92c3-4fed720b2ad8"> From c84a117ba59d44a1d501c79c2582baf3dfd924b3 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Fri, 29 Oct 2021 12:17:06 +0200 Subject: [PATCH 14/37] Add IsPrivateFullAggregator, IsPublicFullAggregator --- spidsaml/spid.go | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index a67d0f8..49f9ac9 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -35,15 +35,16 @@ type SPOrganization struct { // SPContactPerson ContactPerson metadata about sp full type SPContactPerson struct { - ContactType string - EntityType string - IpaCode string - VatNumber string - FiscalCode string - Company string - EmailAddress string - TelephoneNumber string - IsFullAggregator bool + ContactType string + EntityType string + IpaCode string + VatNumber string + FiscalCode string + Company string + EmailAddress string + TelephoneNumber string + IsPrivateFullAggregator bool + IsPublicFullAggregator bool } // SP represents our Service Provider @@ -198,9 +199,12 @@ func (sp *SP) Metadata() string { {{ if ne $contact.FiscalCode "" }} {{ $contact.FiscalCode }} {{ end }} - {{ if $contact.IsFullAggregator }} + {{ if $contact.IsPublicFullAggregator }} {{ end }} + {{ if $contact.IsPrivateFullAggregator }} + + {{ end }} {{ $contact.Company }} {{ $contact.EmailAddress }} From f75cffea66edfb12118c24d72a08660f81a7fb6d Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Fri, 29 Oct 2021 13:51:02 +0200 Subject: [PATCH 15/37] Add randomly generated request ids --- spidsaml/spid.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 49f9ac9..386ef42 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -2,12 +2,14 @@ package spidsaml import ( "bytes" + "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/base64" "encoding/pem" "errors" "io/ioutil" + "math/big" "text/template" ) @@ -130,6 +132,20 @@ func (sp *SP) GetIDP(entityID string) (*IDP, error) { return nil, errors.New("IdP not found") } +func (sp *SP) GenerateRandomRequestID() string { + const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" + ret := make([]byte, 43) + for i := 0; i < 43; i++ { + num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))) + if err != nil { + return "" + } + ret[i] = letters[num.Int64()] + } + + return string(ret) +} + // Metadata generates XML metadata of this Service Provider. func (sp *SP) Metadata() string { const tmpl = ` @@ -138,8 +154,8 @@ func (sp *SP) Metadata() string { xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:spid="https://spid.gov.it/saml-extensions" xmlns:fpa="https://spid.gov.it/invoicing-extensions" - entityID="{{.EntityID}}" - ID="_681a637-6cd4-434f-92c3-4fed720b2ad8"> + entityID="{{ .EntityID }}" + ID="{{ .RandomRequestID }}"> Date: Wed, 3 Nov 2021 10:00:22 +0100 Subject: [PATCH 16/37] Add Signature tag --- spidsaml/go.mod | 8 +++++++- spidsaml/go.sum | 2 ++ spidsaml/spid.go | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/spidsaml/go.mod b/spidsaml/go.mod index 7e4713f..e1ccd95 100644 --- a/spidsaml/go.mod +++ b/spidsaml/go.mod @@ -1,7 +1,13 @@ module github.com/nicolasvac/spid-go/spidsaml +go 1.17 + require ( github.com/beevik/etree v1.0.1 - github.com/crewjam/errset v0.0.0-20160219153700-f78d65de925c // indirect github.com/crewjam/go-xmlsec v0.0.0-20170116132012-1aa2f9374afa ) + +require ( + github.com/crewjam/errset v0.0.0-20160219153700-f78d65de925c // indirect + github.com/ma314smith/signedxml v0.0.0-20210628192057-abc5b481ae1c // indirect +) diff --git a/spidsaml/go.sum b/spidsaml/go.sum index 5fc5f07..9157a17 100644 --- a/spidsaml/go.sum +++ b/spidsaml/go.sum @@ -4,3 +4,5 @@ github.com/crewjam/errset v0.0.0-20160219153700-f78d65de925c h1:dCJ9oZ0VgnzJHR5B github.com/crewjam/errset v0.0.0-20160219153700-f78d65de925c/go.mod h1:XhiWL7J86xoqJ8+x2OA+AM2l9skQP2DZ0UOXQYVg7uI= github.com/crewjam/go-xmlsec v0.0.0-20170116132012-1aa2f9374afa h1:P3H7u0mfn9zEniDEKN50Yos1m60AM2PNOcyrInUjRFM= github.com/crewjam/go-xmlsec v0.0.0-20170116132012-1aa2f9374afa/go.mod h1:M9eHnKpImgRwzOFdlFQnbgJRqFwW/eX1cKAVobv03uE= +github.com/ma314smith/signedxml v0.0.0-20210628192057-abc5b481ae1c h1:UPJygtyk491bJJ/DnRJFuzcq9Dl9NSeFrJ7VdiRzMxc= +github.com/ma314smith/signedxml v0.0.0-20210628192057-abc5b481ae1c/go.mod h1:KEgVcb43+f5KFUH/x6Vd3NROG0AIL2CuKMrIqYsmx6E= diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 386ef42..1a81981 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -11,6 +11,8 @@ import ( "io/ioutil" "math/big" "text/template" + + "github.com/ma314smith/signedxml" ) // AttributeConsumingService defines, well, an AttributeConsumingService. @@ -157,6 +159,27 @@ func (sp *SP) Metadata() string { entityID="{{ .EntityID }}" ID="{{ .RandomRequestID }}"> + + + + + + + + + + + + + + + + + {{ .Cert }} + + + + Date: Wed, 3 Nov 2021 10:06:29 +0100 Subject: [PATCH 17/37] Bugfix _key instead of Key() --- spidsaml/spid.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 1a81981..58b5b9a 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -280,7 +280,7 @@ func (sp *SP) Metadata() string { return "" } - completeXML, err := signer.Sign(sp._key) + completeXML, err := signer.Sign(sp.Key()) if err != nil { return "" From 2b6cd01e3c7291ba65be6f8cb7e51446f1123bd7 Mon Sep 17 00:00:00 2001 From: Vaccari Nicolas Date: Wed, 3 Nov 2021 11:23:18 +0100 Subject: [PATCH 18/37] Add cert subject --- spidsaml/spid.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 58b5b9a..6814b6f 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -188,6 +188,7 @@ func (sp *SP) Metadata() string { + {{ .CertSubject }} {{ .Cert }} @@ -257,23 +258,23 @@ func (sp *SP) Metadata() string { *SP Cert string RandomRequestID string + CertSubject string }{ sp, base64.StdEncoding.EncodeToString(sp.Cert().Raw), - sp.GenerateRandomRequestID(), // Generate a random ID for each request + sp.GenerateRandomRequestID(), // Generate a random ID for each request, + sp.Cert().Subject.String(), } t := template.Must(template.New("metadata").Parse(tmpl)) var metadata bytes.Buffer // Parse now the template - if t.Execute(&metadata, aux) != nil { return "" } // Sign the XML - signer, err := signedxml.NewSigner(metadata.String()) if err != nil { From 1c08609f427b7a2000812849d3e5cabe13d143ab Mon Sep 17 00:00:00 2001 From: Vaccari Nicolas Date: Wed, 3 Nov 2021 11:37:31 +0100 Subject: [PATCH 19/37] Bugfix missing _ in requestID and added # on URI= --- spidsaml/spid.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 6814b6f..a821736 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -145,7 +145,7 @@ func (sp *SP) GenerateRandomRequestID() string { ret[i] = letters[num.Int64()] } - return string(ret) + return "_" + string(ret) } // Metadata generates XML metadata of this Service Provider. @@ -163,7 +163,7 @@ func (sp *SP) Metadata() string { - + From 4a55a443334524252d0bb0cf8f6aaac07b734d6c Mon Sep 17 00:00:00 2001 From: Vaccari Nicolas Date: Wed, 3 Nov 2021 11:52:39 +0100 Subject: [PATCH 20/37] Add isPublic, isPrivate to ContactPerson --- spidsaml/spid.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index a821736..326ee3e 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -47,6 +47,8 @@ type SPContactPerson struct { Company string EmailAddress string TelephoneNumber string + IsPrivate bool + isPublic bool IsPrivateFullAggregator bool IsPublicFullAggregator bool } @@ -238,6 +240,12 @@ func (sp *SP) Metadata() string { {{ end }} {{ if ne $contact.FiscalCode "" }} {{ $contact.FiscalCode }} + {{ end }} + {{ if $contact.IsPrivate }} + + {{ end }} + {{ if $contact.isPublic }} + {{ end }} {{ if $contact.IsPublicFullAggregator }} From 7e55ca34bac1600c8170e4008255806f1b94e605 Mon Sep 17 00:00:00 2001 From: Vaccari Nicolas Date: Wed, 3 Nov 2021 11:56:55 +0100 Subject: [PATCH 21/37] Bugfix IsPublic --- spidsaml/spid.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 326ee3e..0306104 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -48,7 +48,7 @@ type SPContactPerson struct { EmailAddress string TelephoneNumber string IsPrivate bool - isPublic bool + IsPublic bool IsPrivateFullAggregator bool IsPublicFullAggregator bool } @@ -244,7 +244,7 @@ func (sp *SP) Metadata() string { {{ if $contact.IsPrivate }} {{ end }} - {{ if $contact.isPublic }} + {{ if $contact.IsPublic }} {{ end }} {{ if $contact.IsPublicFullAggregator }} From bd70c53970c622160af8a0798f803660fdaaa85f Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Wed, 3 Nov 2021 17:17:51 +0100 Subject: [PATCH 22/37] Try adding contact persons dinamically --- .gitignore | 5 ++ spidsaml/go.mod | 6 ++- spidsaml/go.sum | 22 +++++++++ spidsaml/spid.go | 119 +++++++++++++++++++++++++++++------------------ 4 files changed, 106 insertions(+), 46 deletions(-) diff --git a/.gitignore b/.gitignore index 0d8c5ba..077c171 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,8 @@ example/example .vscode +/.idea/.gitignore +/.idea/dbnavigator.xml +/.idea/modules.xml +/.idea/spid-go.iml +/.idea/vcs.xml diff --git a/spidsaml/go.mod b/spidsaml/go.mod index e1ccd95..30651a0 100644 --- a/spidsaml/go.mod +++ b/spidsaml/go.mod @@ -3,11 +3,13 @@ module github.com/nicolasvac/spid-go/spidsaml go 1.17 require ( - github.com/beevik/etree v1.0.1 + github.com/beevik/etree v1.1.0 github.com/crewjam/go-xmlsec v0.0.0-20170116132012-1aa2f9374afa + github.com/ma314smith/signedxml v0.0.0-20210628192057-abc5b481ae1c ) require ( github.com/crewjam/errset v0.0.0-20160219153700-f78d65de925c // indirect - github.com/ma314smith/signedxml v0.0.0-20210628192057-abc5b481ae1c // indirect + github.com/smartystreets/goconvey v1.7.2 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect ) diff --git a/spidsaml/go.sum b/spidsaml/go.sum index 9157a17..a12436c 100644 --- a/spidsaml/go.sum +++ b/spidsaml/go.sum @@ -1,8 +1,30 @@ github.com/beevik/etree v1.0.1 h1:lWzdj5v/Pj1X360EV7bUudox5SRipy4qZLjY0rhb0ck= github.com/beevik/etree v1.0.1/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= +github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= +github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/crewjam/errset v0.0.0-20160219153700-f78d65de925c h1:dCJ9oZ0VgnzJHR5BjkSrwkXA1USu483qlxBd0u29P8s= github.com/crewjam/errset v0.0.0-20160219153700-f78d65de925c/go.mod h1:XhiWL7J86xoqJ8+x2OA+AM2l9skQP2DZ0UOXQYVg7uI= github.com/crewjam/go-xmlsec v0.0.0-20170116132012-1aa2f9374afa h1:P3H7u0mfn9zEniDEKN50Yos1m60AM2PNOcyrInUjRFM= github.com/crewjam/go-xmlsec v0.0.0-20170116132012-1aa2f9374afa/go.mod h1:M9eHnKpImgRwzOFdlFQnbgJRqFwW/eX1cKAVobv03uE= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/ma314smith/signedxml v0.0.0-20210628192057-abc5b481ae1c h1:UPJygtyk491bJJ/DnRJFuzcq9Dl9NSeFrJ7VdiRzMxc= github.com/ma314smith/signedxml v0.0.0-20210628192057-abc5b481ae1c/go.mod h1:KEgVcb43+f5KFUH/x6Vd3NROG0AIL2CuKMrIqYsmx6E= +github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs= +github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg= +github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 0306104..9a0fc03 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -8,6 +8,7 @@ import ( "encoding/base64" "encoding/pem" "errors" + "github.com/beevik/etree" "io/ioutil" "math/big" "text/template" @@ -37,20 +38,20 @@ type SPOrganization struct { OrganizationURL string } -// SPContactPerson ContactPerson metadata about sp full +// SPContactPerson ContactPerson metadata type SPContactPerson struct { - ContactType string - EntityType string - IpaCode string - VatNumber string - FiscalCode string - Company string - EmailAddress string - TelephoneNumber string - IsPrivate bool - IsPublic bool - IsPrivateFullAggregator bool - IsPublicFullAggregator bool + ContactType string + Company string + EmailAddress string + TelephoneNumber string + Extensions []SPContactPersonExtension +} + +// SPContactPersonExtension extensions for contact person +type SPContactPersonExtension struct { + Tag string + Value string + Extensions []SPContactPersonExtension } // SP represents our Service Provider @@ -229,37 +230,6 @@ func (sp *SP) Metadata() string { {{ .Organization.OrganizationURL }} - {{ range $index, $contact := .ContactPersons }} - - - {{ if ne $contact.IpaCode "" }} - {{ $contact.IpaCode }} - {{ end }} - {{ if ne $contact.VatNumber "" }} - {{ $contact.VatNumber }} - {{ end }} - {{ if ne $contact.FiscalCode "" }} - {{ $contact.FiscalCode }} - {{ end }} - {{ if $contact.IsPrivate }} - - {{ end }} - {{ if $contact.IsPublic }} - - {{ end }} - {{ if $contact.IsPublicFullAggregator }} - - {{ end }} - {{ if $contact.IsPrivateFullAggregator }} - - {{ end }} - - {{ $contact.Company }} - {{ $contact.EmailAddress }} - {{ $contact.TelephoneNumber }} - - {{ end }} - ` aux := struct { @@ -295,5 +265,66 @@ func (sp *SP) Metadata() string { return "" } + completeXML, err = addContactPersons(completeXML, sp.ContactPersons) + + if err != nil { + return "" + } + return completeXML } + +func addContactPersons(signedXML string, persons []SPContactPerson) (string, error) { + xmlDoc := etree.NewDocument() + + if xmlDoc.ReadFromString(signedXML) != nil { + return "", nil + } + + // Get the basic entity descriptor element + entityDescriptor := xmlDoc.FindElement("EntityDescriptor") + + for _, contactPerson := range persons { + // Create basic contact person element + contactPersonXML := entityDescriptor.CreateElement("md:ContactPerson") + // Add the specified contact type + contactPersonXML.CreateAttr("contactType", contactPerson.ContactType) + + // Add company data + if contactPerson.Company != "" { + contactPersonXML.CreateElement("md:Company").CreateText(contactPerson.Company) + } + + // Add email address data + if contactPerson.EmailAddress != "" { + contactPersonXML.CreateElement("md:EmailAddress").CreateText(contactPerson.EmailAddress) + } + + // Add telephone number data + if contactPerson.TelephoneNumber != "" { + contactPersonXML.CreateElement("md:TelephoneNumber").CreateText(contactPerson.TelephoneNumber) + } + + // Add extensions data + contactPersonExtensionsXML := contactPersonXML.CreateElement("md:Extensions") + + addContactPersonExtensions(contactPersonExtensionsXML, contactPerson.Extensions) + } + + return xmlDoc.WriteToString() +} + +func addContactPersonExtensions(xml *etree.Element, extensions []SPContactPersonExtension) { + + for _, extension := range extensions { + xmlElement := xml.CreateElement(extension.Tag) + + if extension.Value != "" { + xmlElement.CreateText(extension.Value) + } + + if len(extension.Extensions) > 0 { + addContactPersonExtensions(xmlElement, extension.Extensions) + } + } +} From 73ef362d604aa2b8a910178bfd2ebd778bbc1caa Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Wed, 3 Nov 2021 17:49:51 +0100 Subject: [PATCH 23/37] Bugfix contact persons --- spidsaml/spid.go | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 9a0fc03..4028908 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -252,20 +252,21 @@ func (sp *SP) Metadata() string { return "" } - // Sign the XML - signer, err := signedxml.NewSigner(metadata.String()) + // Add the contact persons to the XML + completeXML, err := addContactPersons(metadata.String(), sp.ContactPersons) if err != nil { return "" } - completeXML, err := signer.Sign(sp.Key()) + // Sign the XML + signer, err := signedxml.NewSigner(completeXML) if err != nil { return "" } - completeXML, err = addContactPersons(completeXML, sp.ContactPersons) + completeXML, err = signer.Sign(sp.Key()) if err != nil { return "" @@ -290,6 +291,11 @@ func addContactPersons(signedXML string, persons []SPContactPerson) (string, err // Add the specified contact type contactPersonXML.CreateAttr("contactType", contactPerson.ContactType) + // Add extensions data + contactPersonExtensionsXML := contactPersonXML.CreateElement("md:Extensions") + + addContactPersonExtensions(contactPersonExtensionsXML, contactPerson.Extensions) + // Add company data if contactPerson.Company != "" { contactPersonXML.CreateElement("md:Company").CreateText(contactPerson.Company) @@ -304,11 +310,6 @@ func addContactPersons(signedXML string, persons []SPContactPerson) (string, err if contactPerson.TelephoneNumber != "" { contactPersonXML.CreateElement("md:TelephoneNumber").CreateText(contactPerson.TelephoneNumber) } - - // Add extensions data - contactPersonExtensionsXML := contactPersonXML.CreateElement("md:Extensions") - - addContactPersonExtensions(contactPersonExtensionsXML, contactPerson.Extensions) } return xmlDoc.WriteToString() From 293a3fdbc123829d606b01b3e984b929d815d0a8 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 4 Nov 2021 12:15:49 +0100 Subject: [PATCH 24/37] Add PKCS8 Key Support --- spidsaml/spid.go | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 4028908..d2cbf59 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -106,12 +106,28 @@ func (sp *SP) Key() *rsa.PrivateKey { byteValue, _ := ioutil.ReadFile(sp.KeyFile) block, _ := pem.Decode(byteValue) - if block == nil || block.Type != "RSA PRIVATE KEY" { - panic("failed to parse private key from PEM file") + if block == nil { + panic("failed to parse private key from PEM file " + sp.KeyFile) } var err error - sp._key, err = x509.ParsePKCS1PrivateKey(block.Bytes) + + switch block.Type { + case "RSA PRIVATE KEY": + sp._key, err = x509.ParsePKCS1PrivateKey(block.Bytes) + + case "PRIVATE KEY": + var keyOfSomeType interface{} + keyOfSomeType, err = x509.ParsePKCS8PrivateKey(block.Bytes) + var ok bool + sp._key, ok = keyOfSomeType.(*rsa.PrivateKey) + if !ok { + err = errors.New("file " + sp.KeyFile + " does not contain an RSA private key") + } + default: + err = errors.New("unknown key type " + block.Type) + } + if err != nil { panic(err) } From 11d6a3629f9a70f07a585a0b6342b1afe403eb26 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 4 Nov 2021 12:26:14 +0100 Subject: [PATCH 25/37] Remove redundant cast --- spidsaml/messages.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spidsaml/messages.go b/spidsaml/messages.go index 7e9df5a..8683373 100644 --- a/spidsaml/messages.go +++ b/spidsaml/messages.go @@ -70,7 +70,7 @@ func (msg *outMessage) RedirectURL(baseurl string, xml []byte, param string) str w := &bytes.Buffer{} w1 := base64.NewEncoder(base64.StdEncoding, w) w2, _ := flate.NewWriter(w1, 9) - w2.Write([]byte(xml)) + w2.Write(xml) w2.Close() w1.Close() From 6b203a38fbe560d83f46425f2ca6ec591a47b7ff Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 4 Nov 2021 12:38:10 +0100 Subject: [PATCH 26/37] Add verification of IDP XML Signature --- spidsaml/idp.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/spidsaml/idp.go b/spidsaml/idp.go index 503faaf..c5108d0 100644 --- a/spidsaml/idp.go +++ b/spidsaml/idp.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "encoding/pem" "fmt" + "github.com/ma314smith/signedxml" "io/ioutil" "log" "os" @@ -31,12 +32,21 @@ func NewIDPFromXML(xml []byte) *IDP { panic(err) } - // TODO: if metadata is signed, validate /md:EntityDescriptor/dsig:Signature - // against a known CA - idp := new(IDP) idp.EntityID = doc.FindElement("/EntityDescriptor").SelectAttr("entityID").Value + // Check if there is a signature present, and in case is present + // use the xml signature validator. + if doc.FindElement("/EntityDescriptor/Signature/SignedInfo") != nil { + validator, err := signedxml.NewValidator(string(xml)) + + _, err = validator.ValidateReferences() + + if err != nil { + panic(fmt.Sprintf("Unable to verify IDP (%s) Signature.", idp.EntityID)) + } + } + // SingleSignOnService idp.SSOURLs = make(map[SAMLBinding]string) for _, e := range doc.FindElements("/EntityDescriptor/IDPSSODescriptor/SingleSignOnService") { From ba8b09eebfd6a2e1d53021da29e3995b0bc9be28 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 4 Nov 2021 12:49:09 +0100 Subject: [PATCH 27/37] Add complete error to idp signature verification --- spidsaml/idp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spidsaml/idp.go b/spidsaml/idp.go index c5108d0..c187223 100644 --- a/spidsaml/idp.go +++ b/spidsaml/idp.go @@ -43,7 +43,7 @@ func NewIDPFromXML(xml []byte) *IDP { _, err = validator.ValidateReferences() if err != nil { - panic(fmt.Sprintf("Unable to verify IDP (%s) Signature.", idp.EntityID)) + panic(fmt.Sprintf("Unable to verify IDP (%s) Signature. Complete error: %s", idp.EntityID, err)) } } From 8f6410026ee895d1a9fd62e1df33dfac3f89007d Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 4 Nov 2021 13:01:36 +0100 Subject: [PATCH 28/37] Fix Reading XML from bytes --- spidsaml/idp.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/spidsaml/idp.go b/spidsaml/idp.go index c187223..ccbd760 100644 --- a/spidsaml/idp.go +++ b/spidsaml/idp.go @@ -38,8 +38,17 @@ func NewIDPFromXML(xml []byte) *IDP { // Check if there is a signature present, and in case is present // use the xml signature validator. if doc.FindElement("/EntityDescriptor/Signature/SignedInfo") != nil { - validator, err := signedxml.NewValidator(string(xml)) + // Convert XML to a readable string + xmlString, err := doc.WriteToString() + if err != nil { + panic("Unable to convert IDP XML to String.") + } + + // Initialize the validator + validator, err := signedxml.NewValidator(xmlString) + + // Check if signature is valid _, err = validator.ValidateReferences() if err != nil { From 59ec60d55340caf33e038f4b42eef3b244523b03 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Thu, 4 Nov 2021 13:25:27 +0100 Subject: [PATCH 29/37] Remove IDP metadata XML verification --- spidsaml/idp.go | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/spidsaml/idp.go b/spidsaml/idp.go index ccbd760..8c7a0a3 100644 --- a/spidsaml/idp.go +++ b/spidsaml/idp.go @@ -5,7 +5,6 @@ import ( "encoding/base64" "encoding/pem" "fmt" - "github.com/ma314smith/signedxml" "io/ioutil" "log" "os" @@ -35,27 +34,6 @@ func NewIDPFromXML(xml []byte) *IDP { idp := new(IDP) idp.EntityID = doc.FindElement("/EntityDescriptor").SelectAttr("entityID").Value - // Check if there is a signature present, and in case is present - // use the xml signature validator. - if doc.FindElement("/EntityDescriptor/Signature/SignedInfo") != nil { - // Convert XML to a readable string - xmlString, err := doc.WriteToString() - - if err != nil { - panic("Unable to convert IDP XML to String.") - } - - // Initialize the validator - validator, err := signedxml.NewValidator(xmlString) - - // Check if signature is valid - _, err = validator.ValidateReferences() - - if err != nil { - panic(fmt.Sprintf("Unable to verify IDP (%s) Signature. Complete error: %s", idp.EntityID, err)) - } - } - // SingleSignOnService idp.SSOURLs = make(map[SAMLBinding]string) for _, e := range doc.FindElements("/EntityDescriptor/IDPSSODescriptor/SingleSignOnService") { From 1335fdbf09ff27776a215943bf660c25d5b3000b Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Wed, 10 Nov 2021 15:31:54 +0100 Subject: [PATCH 30/37] Save XML document to IDP.XML --- spidsaml/idp.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spidsaml/idp.go b/spidsaml/idp.go index 8c7a0a3..6617251 100644 --- a/spidsaml/idp.go +++ b/spidsaml/idp.go @@ -75,6 +75,8 @@ func NewIDPFromXML(xml []byte) *IDP { panic("failed to parse certificate: " + err.Error()) } + idp.XML, _ = doc.WriteToString() + return idp } From c40e389cde65a1bbc86799fb6847d928f9e70dd8 Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Wed, 10 Nov 2021 16:44:58 +0100 Subject: [PATCH 31/37] Optional sign mechanism --- spidsaml/spid.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index d2cbf59..a3ce066 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -168,7 +168,7 @@ func (sp *SP) GenerateRandomRequestID() string { } // Metadata generates XML metadata of this Service Provider. -func (sp *SP) Metadata() string { +func (sp *SP) Metadata(enableSign bool) string { const tmpl = ` Date: Wed, 10 Nov 2021 16:59:16 +0100 Subject: [PATCH 32/37] Optional sign mechanism in xml template --- spidsaml/spid.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spidsaml/spid.go b/spidsaml/spid.go index a3ce066..9b3cae7 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -168,7 +168,7 @@ func (sp *SP) GenerateRandomRequestID() string { } // Metadata generates XML metadata of this Service Provider. -func (sp *SP) Metadata(enableSign bool) string { +func (sp *SP) Metadata(enableSigning bool) string { const tmpl = ` + {{ if .EnableSigning }} @@ -198,6 +199,7 @@ func (sp *SP) Metadata(enableSign bool) string { + {{ end }} Date: Wed, 10 Nov 2021 17:49:29 +0100 Subject: [PATCH 33/37] Sign authnrequest_out.go --- spidsaml/authnrequest_out.go | 26 +++++++++++++++++++++++--- spidsaml/messages.go | 12 +----------- spidsaml/spid.go | 18 +----------------- spidsaml/utils.go | 20 ++++++++++++++++++++ 4 files changed, 45 insertions(+), 31 deletions(-) create mode 100644 spidsaml/utils.go diff --git a/spidsaml/authnrequest_out.go b/spidsaml/authnrequest_out.go index baba20d..a251145 100644 --- a/spidsaml/authnrequest_out.go +++ b/spidsaml/authnrequest_out.go @@ -2,6 +2,7 @@ package spidsaml import ( "bytes" + "github.com/ma314smith/signedxml" "text/template" ) @@ -23,7 +24,7 @@ func (sp *SP) NewAuthnRequest(idp *IDP) *AuthnRequest { req := new(AuthnRequest) req.SP = sp req.IDP = idp - req.ID = generateMessageID() + req.ID = GenerateRandomID() req.AcsIndex = -1 req.AttrIndex = -1 req.Level = 1 @@ -90,8 +91,27 @@ func (authnreq *AuthnRequest) XML(binding SAMLBinding) []byte { t := template.Must(template.New("req").Parse(tmpl)) var metadata bytes.Buffer - t.Execute(&metadata, data) - return metadata.Bytes() + + if t.Execute(&metadata, data) != nil { + return nil + } + + completeXML := metadata.String() + + // Sign the Authnrequest + signer, err := signedxml.NewSigner(completeXML) + + if err != nil { + return nil + } + + completeXML, err = signer.Sign(authnreq.SP.Key()) + + if err != nil { + return nil + } + + return []byte(completeXML) } // RedirectURL returns the full URL of the Identity Provider where user should be diff --git a/spidsaml/messages.go b/spidsaml/messages.go index 8683373..951beb6 100644 --- a/spidsaml/messages.go +++ b/spidsaml/messages.go @@ -19,7 +19,7 @@ import ( "time" "github.com/beevik/etree" - xmlsec "github.com/crewjam/go-xmlsec" + "github.com/crewjam/go-xmlsec" ) // protocolMessage is the base class for all SAML messages @@ -43,16 +43,6 @@ type inMessage struct { RelayState string } -func generateMessageID() string { - id := make([]byte, 16) - if _, err := rand.Reader.Read(id); err != nil { - panic(err) - } - - // first character must not be a digit - return fmt.Sprintf("_%x", id) -} - func (msg *outMessage) IssueInstant() *time.Time { if msg.issueInstant == nil { t := time.Now().UTC() diff --git a/spidsaml/spid.go b/spidsaml/spid.go index 9b3cae7..3e60873 100644 --- a/spidsaml/spid.go +++ b/spidsaml/spid.go @@ -2,7 +2,6 @@ package spidsaml import ( "bytes" - "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/base64" @@ -10,7 +9,6 @@ import ( "errors" "github.com/beevik/etree" "io/ioutil" - "math/big" "text/template" "github.com/ma314smith/signedxml" @@ -153,20 +151,6 @@ func (sp *SP) GetIDP(entityID string) (*IDP, error) { return nil, errors.New("IdP not found") } -func (sp *SP) GenerateRandomRequestID() string { - const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" - ret := make([]byte, 43) - for i := 0; i < 43; i++ { - num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))) - if err != nil { - return "" - } - ret[i] = letters[num.Int64()] - } - - return "_" + string(ret) -} - // Metadata generates XML metadata of this Service Provider. func (sp *SP) Metadata(enableSigning bool) string { const tmpl = ` @@ -259,7 +243,7 @@ func (sp *SP) Metadata(enableSigning bool) string { }{ sp, base64.StdEncoding.EncodeToString(sp.Cert().Raw), - sp.GenerateRandomRequestID(), // Generate a random ID for each request, + GenerateRandomID(), // Generate a random ID for each request, sp.Cert().Subject.String(), enableSigning, } diff --git a/spidsaml/utils.go b/spidsaml/utils.go new file mode 100644 index 0000000..61e8b75 --- /dev/null +++ b/spidsaml/utils.go @@ -0,0 +1,20 @@ +package spidsaml + +import ( + "crypto/rand" + "math/big" +) + +func GenerateRandomID() string { + const letters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" + ret := make([]byte, 43) + for i := 0; i < 43; i++ { + num, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))) + if err != nil { + return "" + } + ret[i] = letters[num.Int64()] + } + + return "_" + string(ret) +} From f2c055bc1f804711f7b8303738dc3ba597d960da Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Wed, 10 Nov 2021 17:55:57 +0100 Subject: [PATCH 34/37] Remove button.go Sign all other requests/responses --- spidsaml/button.go | 28 ---------------------------- spidsaml/logoutrequest_in.go | 2 +- spidsaml/logoutrequest_out.go | 25 ++++++++++++++++++++++--- spidsaml/logoutresponse_in.go | 4 ++-- spidsaml/logoutresponse_out.go | 26 +++++++++++++++++++++++--- 5 files changed, 48 insertions(+), 37 deletions(-) delete mode 100644 spidsaml/button.go diff --git a/spidsaml/button.go b/spidsaml/button.go deleted file mode 100644 index 1fa47b6..0000000 --- a/spidsaml/button.go +++ /dev/null @@ -1,28 +0,0 @@ -package spidsaml - -import ( - "bytes" - "fmt" - "html/template" - "net/url" -) - -const tmplButton = ` -{{ range $entityID, $url := . }} -

Login with SPID ({{ $entityID }})

-{{ end }} -` - -// GetButton returns the rendered HTML of the SPID button. -func (sp *SP) GetButton(pattern string) string { - items := make(map[string]string) // entityID: URL - - for entityID := range sp.IDP { - items[entityID] = fmt.Sprintf(pattern, url.QueryEscape(entityID)) - } - - t := template.Must(template.New("button").Parse(tmplButton)) - var button bytes.Buffer - t.Execute(&button, items) - return button.String() -} diff --git a/spidsaml/logoutrequest_in.go b/spidsaml/logoutrequest_in.go index bee13c7..52ca6dc 100644 --- a/spidsaml/logoutrequest_in.go +++ b/spidsaml/logoutrequest_in.go @@ -53,7 +53,7 @@ func (logoutreq *LogoutRequestIn) validate(r *http.Request) error { } } if !knownDestination { - return fmt.Errorf("Invalid Destination: '%s'", destination) + return fmt.Errorf("invalid Destination: '%s'", destination) } return nil diff --git a/spidsaml/logoutrequest_out.go b/spidsaml/logoutrequest_out.go index e015588..1aa5661 100644 --- a/spidsaml/logoutrequest_out.go +++ b/spidsaml/logoutrequest_out.go @@ -2,6 +2,7 @@ package spidsaml import ( "bytes" + "github.com/ma314smith/signedxml" "text/template" ) @@ -25,7 +26,7 @@ func (sp *SP) NewLogoutRequest(session *Session) (*LogoutRequestOut, error) { if err != nil { return nil, err } - req.ID = generateMessageID() + req.ID = GenerateRandomID() req.Session = session return req, nil } @@ -78,8 +79,26 @@ func (logoutreq *LogoutRequestOut) XML(binding SAMLBinding) []byte { t := template.Must(template.New("req").Parse(tmpl)) var metadata bytes.Buffer - t.Execute(&metadata, data) - return metadata.Bytes() + if t.Execute(&metadata, data) != nil { + return nil + } + + completeXML := metadata.String() + + // Sign the request + signer, err := signedxml.NewSigner(completeXML) + + if err != nil { + return nil + } + + completeXML, err = signer.Sign(logoutreq.SP.Key()) + + if err != nil { + return nil + } + + return []byte(completeXML) } // RedirectURL returns the full URL of the Identity Provider where user should be diff --git a/spidsaml/logoutresponse_in.go b/spidsaml/logoutresponse_in.go index c37cb0e..6e00f78 100644 --- a/spidsaml/logoutresponse_in.go +++ b/spidsaml/logoutresponse_in.go @@ -43,7 +43,7 @@ func (logoutres *LogoutResponseIn) validate(r *http.Request, inResponseTo string } if inResponseTo != logoutres.InResponseTo() { - return fmt.Errorf("Invalid InResponseTo: '%s' (expected: '%s')", + return fmt.Errorf("invalid InResponseTo: '%s' (expected: '%s')", logoutres.InResponseTo(), inResponseTo) } @@ -58,7 +58,7 @@ func (logoutres *LogoutResponseIn) validate(r *http.Request, inResponseTo string } } if !knownDestination { - return fmt.Errorf("Invalid Destination: '%s'", destination) + return fmt.Errorf("invalid Destination: '%s'", destination) } return nil diff --git a/spidsaml/logoutresponse_out.go b/spidsaml/logoutresponse_out.go index 29a223b..0e207a7 100644 --- a/spidsaml/logoutresponse_out.go +++ b/spidsaml/logoutresponse_out.go @@ -2,6 +2,7 @@ package spidsaml import ( "bytes" + "github.com/ma314smith/signedxml" "text/template" ) @@ -34,7 +35,7 @@ func (sp *SP) NewLogoutResponse(logoutreq *LogoutRequestIn, status LogoutStatus) if err != nil { return nil, err } - res.ID = generateMessageID() + res.ID = GenerateRandomID() res.InResponseTo = logoutreq.ID() return res, nil } @@ -92,8 +93,27 @@ func (logoutres *LogoutResponseOut) XML(binding SAMLBinding) []byte { t := template.Must(template.New("req").Parse(tmpl)) var metadata bytes.Buffer - t.Execute(&metadata, data) - return metadata.Bytes() + + if t.Execute(&metadata, data) != nil { + return nil + } + + completeXML := metadata.String() + + // Sign the response + signer, err := signedxml.NewSigner(completeXML) + + if err != nil { + return nil + } + + completeXML, err = signer.Sign(logoutres.SP.Key()) + + if err != nil { + return nil + } + + return []byte(completeXML) } // RedirectURL returns the full URL of the Identity Provider where user should be From 47171941a7a4d73f498f1279730e043434c4e9af Mon Sep 17 00:00:00 2001 From: Nicolas Vaccari Date: Wed, 10 Nov 2021 18:11:15 +0100 Subject: [PATCH 35/37] test --- spidsaml/authnrequest_out.go | 18 +-------- spidsaml/logoutrequest_out.go | 18 +-------- spidsaml/logoutresponse_out.go | 18 +-------- spidsaml/messages.go | 71 +++++++++++++++++++--------------- 4 files changed, 43 insertions(+), 82 deletions(-) diff --git a/spidsaml/authnrequest_out.go b/spidsaml/authnrequest_out.go index a251145..208d0be 100644 --- a/spidsaml/authnrequest_out.go +++ b/spidsaml/authnrequest_out.go @@ -2,7 +2,6 @@ package spidsaml import ( "bytes" - "github.com/ma314smith/signedxml" "text/template" ) @@ -96,22 +95,7 @@ func (authnreq *AuthnRequest) XML(binding SAMLBinding) []byte { return nil } - completeXML := metadata.String() - - // Sign the Authnrequest - signer, err := signedxml.NewSigner(completeXML) - - if err != nil { - return nil - } - - completeXML, err = signer.Sign(authnreq.SP.Key()) - - if err != nil { - return nil - } - - return []byte(completeXML) + return metadata.Bytes() } // RedirectURL returns the full URL of the Identity Provider where user should be diff --git a/spidsaml/logoutrequest_out.go b/spidsaml/logoutrequest_out.go index 1aa5661..4d1fd3f 100644 --- a/spidsaml/logoutrequest_out.go +++ b/spidsaml/logoutrequest_out.go @@ -2,7 +2,6 @@ package spidsaml import ( "bytes" - "github.com/ma314smith/signedxml" "text/template" ) @@ -83,22 +82,7 @@ func (logoutreq *LogoutRequestOut) XML(binding SAMLBinding) []byte { return nil } - completeXML := metadata.String() - - // Sign the request - signer, err := signedxml.NewSigner(completeXML) - - if err != nil { - return nil - } - - completeXML, err = signer.Sign(logoutreq.SP.Key()) - - if err != nil { - return nil - } - - return []byte(completeXML) + return metadata.Bytes() } // RedirectURL returns the full URL of the Identity Provider where user should be diff --git a/spidsaml/logoutresponse_out.go b/spidsaml/logoutresponse_out.go index 0e207a7..f0fc285 100644 --- a/spidsaml/logoutresponse_out.go +++ b/spidsaml/logoutresponse_out.go @@ -2,7 +2,6 @@ package spidsaml import ( "bytes" - "github.com/ma314smith/signedxml" "text/template" ) @@ -98,22 +97,7 @@ func (logoutres *LogoutResponseOut) XML(binding SAMLBinding) []byte { return nil } - completeXML := metadata.String() - - // Sign the response - signer, err := signedxml.NewSigner(completeXML) - - if err != nil { - return nil - } - - completeXML, err = signer.Sign(logoutres.SP.Key()) - - if err != nil { - return nil - } - - return []byte(completeXML) + return metadata.Bytes() } // RedirectURL returns the full URL of the Identity Provider where user should be diff --git a/spidsaml/messages.go b/spidsaml/messages.go index 951beb6..4681541 100644 --- a/spidsaml/messages.go +++ b/spidsaml/messages.go @@ -11,6 +11,7 @@ import ( "encoding/base64" "errors" "fmt" + "github.com/ma314smith/signedxml" "io/ioutil" "net/http" "net/url" @@ -95,24 +96,29 @@ func (msg *outMessage) RedirectURL(baseurl string, xml []byte, param string) str func (msg *outMessage) PostForm(url string, xml []byte, param string) []byte { // We need to get the name of the root element doc := etree.NewDocument() - doc.ReadFromBytes(xml) - - signedDoc, err := xmlsec.Sign(msg.SP.KeyPEM(), xml, xmlsec.SignatureOptions{ - XMLID: []xmlsec.XMLIDOption{ - { - ElementName: doc.Root().Tag, - ElementNamespace: "", - AttributeName: "ID", - }, - }, - }) + err := doc.ReadFromBytes(xml) + + if err != nil { + panic(err) + } + + completeXML, _ := doc.WriteToString() + + // Sign the Authnrequest + signer, err := signedxml.NewSigner(completeXML) + + if err != nil { + panic(err) + } + + completeXML, err = signer.Sign(msg.SP.Key()) + if err != nil { panic(err) } - //os.Stdout.Write(signedDoc) // encode in base64 - encodedReqBuf := base64.StdEncoding.EncodeToString(signedDoc) + encodedReqBuf := base64.StdEncoding.EncodeToString([]byte(completeXML)) tmpl := template.Must(template.New("saml-post-form").Parse(` @@ -148,23 +154,23 @@ func (msg *outMessage) signatureTemplate() []byte { tmpl := template.Must(template.New("saml-post-form").Parse(` - - - - - - - - - - - - - - - {{ .Cert }} - - + + + + + + + + + + +
+ + + + {{ .Cert }} + + `)) data := struct { @@ -176,7 +182,10 @@ func (msg *outMessage) signatureTemplate() []byte { } var rv bytes.Buffer - tmpl.Execute(&rv, data) + err := tmpl.Execute(&rv, data) + if err != nil { + return nil + } return rv.Bytes() } From e07b5cbebd3b05664c4855eccb7780c5ada87740 Mon Sep 17 00:00:00 2001 From: Vaccari Nicolas Date: Fri, 12 Nov 2021 17:15:02 +0100 Subject: [PATCH 36/37] Bugfix spazi saml:Issuer --- spidsaml/authnrequest_out.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/spidsaml/authnrequest_out.go b/spidsaml/authnrequest_out.go index 208d0be..f763aef 100644 --- a/spidsaml/authnrequest_out.go +++ b/spidsaml/authnrequest_out.go @@ -32,6 +32,7 @@ func (sp *SP) NewAuthnRequest(idp *IDP) *AuthnRequest { } // XML generates the XML representation of this AuthnRequest +// Applicato il bugfix di saml:Issuer func (authnreq *AuthnRequest) XML(binding SAMLBinding) []byte { var signatureTemplate string if binding == HTTPPost { @@ -71,11 +72,7 @@ func (authnreq *AuthnRequest) XML(binding SAMLBinding) []byte { ForceAuthn="{{ if gt .Level 1 }}true{{ else }}false{{ end }}"> - - {{ .SP.EntityID }} - + {{ .SP.EntityID }} {{ .SignatureTemplate }} From 697beab7b8b381a892ec44d44e168e7dd2951a5a Mon Sep 17 00:00:00 2001 From: Vaccari Nicolas Date: Wed, 17 Nov 2021 12:53:57 +0100 Subject: [PATCH 37/37] Fix SpidL format --- spidsaml/authnrequest_out.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spidsaml/authnrequest_out.go b/spidsaml/authnrequest_out.go index f763aef..2603577 100644 --- a/spidsaml/authnrequest_out.go +++ b/spidsaml/authnrequest_out.go @@ -78,9 +78,7 @@ func (authnreq *AuthnRequest) XML(binding SAMLBinding) []byte { - - https://www.spid.gov.it/SpidL{{ .Level }} - + https://www.spid.gov.it/SpidL{{ .Level }} `