• This repository has been archived on 06/Jun/2023
  • Stars
    star
    131
  • Rank 266,866 (Top 6 %)
  • Language
    Go
  • License
    MIT License
  • Created almost 9 years ago
  • Updated 8 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A just good enough SAML client library written in Go.

Unsupported

Unfortunately, the decision has been made to sunset support for this project. We thank everyone for supporting and utilizing the project.

Couple of alternatives could be https://github.com/russellhaering/gosaml2 or maybe https://github.com/crewjam/saml. These are solely suggestions to start the look for an alternative and are not an endorsement by RNP. We've not done a code review of these repos. We recommend doing a vetting pass on the repository prior to integrating any third party dependencies.

go-saml

Build Status

A just good enough SAML client library written in Go. This library is by no means complete and has been developed to solve several specific integration efforts. However, it's a start, and it would be great to see it evolve into a more fleshed out implemention.

Inspired by the early work of Matt Baird.

The library supports:

  • generating signed/unsigned AuthnRequests
  • validating signed AuthnRequests
  • generating service provider metadata
  • generating signed Responses
  • validating signed Responses

Installation

$ go get github.com/RobotsAndPencils/go-saml

Here's a convenient way to generate a certificate:

curl -sSL https://raw.githubusercontent.com/frntn/x509-san/master/gencert.sh | CRT_CN="mycert"  bash

Usage

Below are samples to show how you might use the library.

Generating Signed AuthnRequests

sp := saml.ServiceProviderSettings{
  PublicCertPath:              "../default.crt",
  PrivateKeyPath:              "../default.key",
  IDPSSOURL:                   "http://idp/saml2",
  IDPSSODescriptorURL:         "http://idp/issuer",
  IDPPublicCertPath:           "idpcert.crt",
  SPSignRequest:               "true",
  AssertionConsumerServiceURL: "http://localhost:8000/saml_consume",
}
sp.Init()

// generate the AuthnRequest and then get a base64 encoded string of the XML
authnRequest := sp.GetAuthnRequest()
b64XML, err := authnRequest.EncodedSignedString(sp.PrivateKeyPath)
if err != nil {
  panic(err)
}

// for convenience, get a URL formed with the SAMLRequest parameter
url, err := saml.GetAuthnRequestURL(sp.IDPSSOURL, b64XML)
if err != nil {
  panic(err)
}

// below is bonus for how you might respond to a request with a form that POSTs to the IdP
data := struct {
  Base64AuthRequest string
  URL               string
}{
  Base64AuthRequest: b64XML,
  URL:               url,
}

t := template.New("saml")
t, err = t.Parse("<html><body style=\"display: none\" onload=\"document.frm.submit()\"><form method=\"post\" name=\"frm\" action=\"{{.URL}}\"><input type=\"hidden\" name=\"SAMLRequest\" value=\"{{.Base64AuthRequest}}\" /><input type=\"submit\" value=\"Submit\" /></form></body></html>")

// how you might respond to a request with the templated form that will auto post
t.Execute(w, data)

Validating a received SAML Response

response = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  encodedXML := r.FormValue("SAMLResponse")

  if encodedXML == "" {
    httpcommon.SendBadRequest(w, "SAMLResponse form value missing")
    return
  }

  response, err := saml.ParseEncodedResponse(encodedXML)
  if err != nil {
    httpcommon.SendBadRequest(w, "SAMLResponse parse: "+err.Error())
    return
  }

  err = response.Validate(&sp)
  if err != nil {
    httpcommon.SendBadRequest(w, "SAMLResponse validation: "+err.Error())
    return
  }

  samlID := response.GetAttribute("uid")
  if samlID == "" {
    httpcommon.SendBadRequest(w, "SAML attribute identifier uid missing")
    return
  }

  //...
}

Service provider metadata

func samlMetadataHandler(sp *saml.ServiceProviderSettings) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		md, err := sp.GetEntityDescriptor()
		if err != nil {
      w.WriteHeader(500)
      w.Write([]byte("Error: " + err.Error()))
			return
		}

		w.Header().Set("Content-Type", "application/xml")
		w.Write([]byte(md))
	})
}

Receiving a authnRequest

b64Request := r.URL.Query().Get("SAMLRequest")
if b64Request == "" {
  w.WriteHeader(400)
  w.Write([]byte("SAMLRequest parameter missing"))
  return
}

defated, err := base64.StdEncoding.DecodeString(b64Request)
if err != nil {
  w.WriteHeader(500)
  w.Write([]byte("Error: " + err.Error()))
  return
}

// enflate and unmarshal
var buffer bytes.Buffer
rdr := flate.NewReader(bytes.NewReader(defated))
io.Copy(&buffer, rdr)
var authnRequest saml.AuthnRequest

err = xml.Unmarshal(buffer.Bytes(), &authnRequest)
if err != nil {
  w.WriteHeader(500)
  w.Write([]byte("Error: " + err.Error()))
  return
}

if authnRequest.Issuer.Url != issuerURL {
  w.WriteHeader(500)
  w.Write([]byte("unauthorized issuer "+authnRequest.Issuer.Url))
  return
}

Creating a SAML Response (if acting as an IdP)

issuer := "http://localhost:8000/saml"
authnResponse := saml.NewSignedResponse()
authnResponse.Issuer.Url = issuer
authnResponse.Assertion.Issuer.Url = issuer
authnResponse.Signature.KeyInfo.X509Data.X509Certificate.Cert = stringValueOfCert
authnResponse.Assertion.Subject.NameID.Value = userIdThatYouAuthenticated
authnResponse.AddAttribute("uid", userIdThatYouAuthenticated)
authnResponse.AddAttribute("email", "someone@domain")
authnResponse.Assertion.Subject.SubjectConfirmation.SubjectConfirmationData.InResponseTo = authnRequestIdRespondingTo
authnResponse.InResponseTo = authnRequestIdRespondingTo
authnResponse.Assertion.Subject.SubjectConfirmation.SubjectConfirmationData.Recipient = issuer

// signed XML string
signed, err := authnResponse.SignedString("/path/to/private.key")

// or signed base64 encoded XML string
b64XML, err := authnResponse.EncodedSignedString("/path/to/private.key")

Contributing

Would love any contributions you having including better documentation, tests, or more robust functionality.

git clone [email protected]:RobotsAndPencils/go-saml.git
make init
make test

Contact

Robots & Pencils Logo

Made with ❤ī¸ by Robots & Pencils (@robotsNpencils)

Maintainers

More Repositories

1

XcodesApp

The easiest way to install and switch between multiple versions of Xcode - with a mouse click.
Swift
4,603
star
2

xcodes

The best command-line tool to install and switch between multiple versions of Xcode.
Swift
2,382
star
3

RPSlidingMenu

A collection view menu in the style of UltraVisual.
Objective-C
864
star
4

buford

A push notification delivery engine for the new HTTP/2 APNS service.
Go
475
star
5

objective-c-style-guide

Our Objective-C coding style guide. Fall in line!
101
star
6

RPBorderlessSegmentedControl

A replica of Xcode 5's toolbar segmented controls.
Objective-C
93
star
7

terraform-ecs-autoscaling

A terraform module for creating an AWS autoscaling group for ECS
HCL
70
star
8

RPClarity

A Swift 1.2 playground that shows a technique for blurring an image behind the characters (glyphs) of one or more UILabels
Swift
42
star
9

RPInstantAlpha

Easily allow users to remove the background from an image, just like in iWork
Objective-C
30
star
10

1password-action

Import logins, passwords and documents from your 1Password vaults to use in your GitHub Action workflows.
TypeScript
30
star
11

stencil-xclangspec

Xcode syntax highlighting for Stencil
Shell
26
star
12

marvin

Slack bot written in Go
Go
24
star
13

go-swaggerLite

Framework agnostic Swagger API description generator
Go
20
star
14

terrible

Transform Terraform state into Ansible inventories
Python
18
star
15

Astro

Astro is a library, built in Swift, used to hold common utility methods.
Swift
17
star
16

Scribble

A Photoshop script that automatically annotates your PSDs with font information
JavaScript
11
star
17

Jeff

Record your screen as a GIF and share it anywhere with Dropbox
Objective-C
11
star
18

ErrorHandling

An easy way to thoroughly handle errors in SwiftUI, with support for retry/recovery and sign out.
Swift
7
star
19

AsyncHTTPNetworkService

A Network layer for Swift using Concurrency
Swift
7
star
20

pencilcase

Objective-C
6
star
21

json-github-editor

Modify JSON files in a GitHub repo with this structured, client-side editor that you host
JavaScript
5
star
22

homebrew-made

Ruby
4
star
23

react-gantry

R&P's React Starter Kit
SCSS
4
star
24

ex-puppeteer-img

Elixir Package to use the puppeteer-img command line tool to make website screenshots.
Elixir
4
star
25

RPJSContext

JSContext++
JavaScript
3
star
26

pegboard

Pegboard sets up your tools.
Shell
3
star
27

RoboSchema

Easily convert SQL Schemas to Salesforce
JavaScript
3
star
28

react-robits

Reusable React Components
JavaScript
2
star
29

ElectricBarn

Basic template for stubbing network requests with the MITMProxy libraries
Python
2
star
30

VRadventure

A Virtual Reality Adventure
Swift
2
star
31

EmitterGenerator

EmitterGenerator
Objective-C
2
star
32

heroku-buildpack-freetds

Shell
1
star
33

go-httpsign

Go middleware for signing and verifying http requests
Go
1
star
34

CharlesTrustCertificateLibrary

Android library to trust user installed CA certificates (e.g. the Charles Root Certificate)
1
star
35

SourceryTemplates

Our latest Sourcery templates for Swift code generation
1
star
36

FastBit-iOS

C++
1
star
37

feedbackassistant.apple.com

Repository containing sample projects for feedbackassistant.apple.com (nÊe radar.apple.com)
Swift
1
star
38

Scythe

Scythe cuts your Harvest ⛏
Swift
1
star
39

MainThreadChecker

Simple example of iOS 11's new, Main Thread Checker
Swift
1
star
40

puppeteer-img

Command link tool to make webpage screenshot images using puppeteer
JavaScript
1
star
41

cache-money-client

Go Client for the Azure GitHub Actions caching service.
Go
1
star
42

ExtendedBrowser

Extended Browser for Android
Java
1
star