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