Wednesday, 19 March 2025

crewja saml manual sp and idp

 

go get github.com/crewjam/saml/samlsp


package main


import (

    "crypto/rsa"

    "crypto/tls"

    "crypto/x509"

    "encoding/pem"

    "log"

    "net/http"

    "net/url"


    "github.com/crewjam/saml"

    "github.com/crewjam/saml/samlsp"

)


// Load X.509 Certificate and Private Key

func loadCertificate(certPath, keyPath string) (*x509.Certificate, *rsa.PrivateKey, error) {

    certPEM, err := tls.LoadX509KeyPair(certPath, keyPath)

    if err != nil {

        return nil, nil, err

    }


    certBlock, _ := pem.Decode(certPEM.Certificate[0])

    if certBlock == nil {

        return nil, nil, err

    }


    cert, err := x509.ParseCertificate(certBlock.Bytes)

    if err != nil {

        return nil, nil, err

    }


    key, ok := certPEM.PrivateKey.(*rsa.PrivateKey)

    if !ok {

        return nil, nil, err

    }


    return cert, key, nil

}


// Define IdP Metadata Manually

func getIDPMetadata() *saml.EntityDescriptor {

    idpCertPEM := `-----BEGIN CERTIFICATE-----

MIIC+TCCAeGgAwIBAgIJAPoVnx9vAgxwMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNV

...

-----END CERTIFICATE-----`


    return &saml.EntityDescriptor{

        EntityID: "https://idp.example.com",

        IDPSSODescriptor: &saml.IDPSSODescriptor{

            SingleSignOnServices: []saml.Endpoint{

                {

                    Binding:  saml.HTTPRedirectBinding,

                    Location: "https://idp.example.com/sso/redirect",

                },

                {

                    Binding:  saml.HTTPPostBinding,

                    Location: "https://idp.example.com/sso/post",

                },

            },

            SingleLogoutServices: []saml.Endpoint{

                {

                    Binding:  saml.HTTPRedirectBinding,

                    Location: "https://idp.example.com/slo/redirect",

                },

                {

                    Binding:  saml.HTTPPostBinding,

                    Location: "https://idp.example.com/slo/post",

                },

            },

            KeyDescriptors: []saml.KeyDescriptor{

                {

                    Use: "signing",

                    KeyInfo: saml.KeyInfo{

                        XMLName:  saml.XMLName{Local: "ds:KeyInfo"},

                        X509Data: &saml.X509Data{X509Certificates: []string{idpCertPEM}},

                    },

                },

            },

        },

    }

}


func main() {

    // Load SP certificate & key

    cert, key, err := loadCertificate("sp-cert.pem", "sp-key.pem")

    if err != nil {

        log.Fatalf("Failed to load certificate: %v", err)

    }


    // Define SP Metadata

    spEntityID := "https://myservice.example.com/metadata"

    spACSURL := "https://myservice.example.com/saml/acs"

    spSLOURL := "https://myservice.example.com/saml/logout"


    sp := saml.ServiceProvider{

        EntityID: spEntityID,

        Key:      key,

        Certificate: cert,

        AssertionConsumerServices: []saml.Endpoint{

            {

                Binding:  saml.HTTPPostBinding,

                Location: spACSURL,

            },

            {

                Binding:  saml.HTTPRedirectBinding,

                Location: spACSURL,

            },

        },

        SingleLogoutServices: []saml.Endpoint{

            {

                Binding:  saml.HTTPPostBinding,

                Location: spSLOURL,

            },

            {

                Binding:  saml.HTTPRedirectBinding,

                Location: spSLOURL,

            },

        },

        NameIDFormat: saml.EmailAddressNameIDFormat,

        IDPMetadata:  getIDPMetadata(),

    }


    // Configure SAML Middleware

    samlMiddleware := samlsp.Middleware{

        ServiceProvider: sp,

    }


    // Secure route

    app := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

        user, _ := samlsp.SessionFromContext(r.Context())

        w.Write([]byte("Hello, " + user.(samlsp.Session).GetNameID() + "!"))

    })


    http.Handle("/hello", samlMiddleware.RequireAccount(app))

    http.Handle("/saml/", samlMiddleware)


    log.Println("Server started at :8000")

    log.Fatal(http.ListenAndServe(":8000", nil))

}

No comments:

Post a Comment