github.com/crewjam/saml@v0.4.14/example/service.go (about)

     1  // This is an example that implements a bitly-esque short link service.
     2  package main
     3  
     4  import (
     5  	"bytes"
     6  	"context"
     7  	"crypto/rsa"
     8  	"crypto/tls"
     9  	"crypto/x509"
    10  	"encoding/xml"
    11  	"flag"
    12  	"fmt"
    13  	"net/http"
    14  	"net/url"
    15  	"strings"
    16  
    17  	"github.com/dchest/uniuri"
    18  	"github.com/kr/pretty"
    19  	"github.com/zenazn/goji"
    20  	"github.com/zenazn/goji/web"
    21  
    22  	"github.com/crewjam/saml/samlsp"
    23  )
    24  
    25  var links = map[string]Link{}
    26  
    27  // Link represents a short link
    28  type Link struct {
    29  	ShortLink string
    30  	Target    string
    31  	Owner     string
    32  }
    33  
    34  // CreateLink handles requests to create links
    35  func CreateLink(_ web.C, w http.ResponseWriter, r *http.Request) {
    36  	account := r.Header.Get("X-Remote-User")
    37  	l := Link{
    38  		ShortLink: uniuri.New(),
    39  		Target:    r.FormValue("t"),
    40  		Owner:     account,
    41  	}
    42  	links[l.ShortLink] = l
    43  
    44  	fmt.Fprintf(w, "%s\n", l.ShortLink)
    45  }
    46  
    47  // ServeLink handles requests to redirect to a link
    48  func ServeLink(_ web.C, w http.ResponseWriter, r *http.Request) {
    49  	l, ok := links[strings.TrimPrefix(r.URL.Path, "/")]
    50  	if !ok {
    51  		http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
    52  		return
    53  	}
    54  	http.Redirect(w, r, l.Target, http.StatusFound)
    55  }
    56  
    57  // ListLinks returns a list of the current user's links
    58  func ListLinks(_ web.C, w http.ResponseWriter, r *http.Request) {
    59  	account := r.Header.Get("X-Remote-User")
    60  	for _, l := range links {
    61  		if l.Owner == account {
    62  			fmt.Fprintf(w, "%s\n", l.ShortLink)
    63  		}
    64  	}
    65  }
    66  
    67  var (
    68  	key = []byte(`-----BEGIN RSA PRIVATE KEY-----
    69  MIICXgIBAAKBgQDU8wdiaFmPfTyRYuFlVPi866WrH/2JubkHzp89bBQopDaLXYxi
    70  3PTu3O6Q/KaKxMOFBqrInwqpv/omOGZ4ycQ51O9I+Yc7ybVlW94lTo2gpGf+Y/8E
    71  PsVbnZaFutRctJ4dVIp9aQ2TpLiGT0xX1OzBO/JEgq9GzDRf+B+eqSuglwIDAQAB
    72  AoGBAMuy1eN6cgFiCOgBsB3gVDdTKpww87Qk5ivjqEt28SmXO13A1KNVPS6oQ8SJ
    73  CT5Azc6X/BIAoJCURVL+LHdqebogKljhH/3yIel1kH19vr4E2kTM/tYH+qj8afUS
    74  JEmArUzsmmK8ccuNqBcllqdwCZjxL4CHDUmyRudFcHVX9oyhAkEA/OV1OkjM3CLU
    75  N3sqELdMmHq5QZCUihBmk3/N5OvGdqAFGBlEeewlepEVxkh7JnaNXAXrKHRVu/f/
    76  fbCQxH+qrwJBANeQERF97b9Sibp9xgolb749UWNlAdqmEpmlvmS202TdcaaT1msU
    77  4rRLiQN3X9O9mq4LZMSVethrQAdX1whawpkCQQDk1yGf7xZpMJ8F4U5sN+F4rLyM
    78  Rq8Sy8p2OBTwzCUXXK+fYeXjybsUUMr6VMYTRP2fQr/LKJIX+E5ZxvcIyFmDAkEA
    79  yfjNVUNVaIbQTzEbRlRvT6MqR+PTCefC072NF9aJWR93JimspGZMR7viY6IM4lrr
    80  vBkm0F5yXKaYtoiiDMzlOQJADqmEwXl0D72ZG/2KDg8b4QZEmC9i5gidpQwJXUc6
    81  hU+IVQoLxRq0fBib/36K9tcrrO5Ba4iEvDcNY+D8yGbUtA==
    82  -----END RSA PRIVATE KEY-----
    83  `)
    84  	cert = []byte(`-----BEGIN CERTIFICATE-----
    85  MIIB7zCCAVgCCQDFzbKIp7b3MTANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGEwJV
    86  UzELMAkGA1UECAwCR0ExDDAKBgNVBAoMA2ZvbzESMBAGA1UEAwwJbG9jYWxob3N0
    87  MB4XDTEzMTAwMjAwMDg1MVoXDTE0MTAwMjAwMDg1MVowPDELMAkGA1UEBhMCVVMx
    88  CzAJBgNVBAgMAkdBMQwwCgYDVQQKDANmb28xEjAQBgNVBAMMCWxvY2FsaG9zdDCB
    89  nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1PMHYmhZj308kWLhZVT4vOulqx/9
    90  ibm5B86fPWwUKKQ2i12MYtz07tzukPymisTDhQaqyJ8Kqb/6JjhmeMnEOdTvSPmH
    91  O8m1ZVveJU6NoKRn/mP/BD7FW52WhbrUXLSeHVSKfWkNk6S4hk9MV9TswTvyRIKv
    92  Rsw0X/gfnqkroJcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQCMMlIO+GNcGekevKgk
    93  akpMdAqJfs24maGb90DvTLbRZRD7Xvn1MnVBBS9hzlXiFLYOInXACMW5gcoRFfeT
    94  QLSouMM8o57h0uKjfTmuoWHLQLi6hnF+cvCsEFiJZ4AbF+DgmO6TarJ8O05t8zvn
    95  OwJlNCASPZRH/JmF8tX0hoHuAQ==
    96  -----END CERTIFICATE-----
    97  `)
    98  )
    99  
   100  func main() {
   101  	rootURLstr := flag.String("url", "https://962766ce.ngrok.io", "The base URL of this service")
   102  	idpMetadataURLstr := flag.String("idp", "https://516becc2.ngrok.io/metadata", "The metadata URL for the IDP")
   103  	flag.Parse()
   104  
   105  	keyPair, err := tls.X509KeyPair(cert, key)
   106  	if err != nil {
   107  		panic(err) // TODO handle error
   108  	}
   109  	keyPair.Leaf, err = x509.ParseCertificate(keyPair.Certificate[0])
   110  	if err != nil {
   111  		panic(err) // TODO handle error
   112  	}
   113  
   114  	idpMetadataURL, err := url.Parse(*idpMetadataURLstr)
   115  	if err != nil {
   116  		panic(err) // TODO handle error
   117  	}
   118  
   119  	idpMetadata, err := samlsp.FetchMetadata(context.Background(), http.DefaultClient,
   120  		*idpMetadataURL)
   121  	if err != nil {
   122  		panic(err) // TODO handle error
   123  	}
   124  
   125  	rootURL, err := url.Parse(*rootURLstr)
   126  	if err != nil {
   127  		panic(err) // TODO handle error
   128  	}
   129  
   130  	samlSP, err := samlsp.New(samlsp.Options{
   131  		URL:               *rootURL,
   132  		Key:               keyPair.PrivateKey.(*rsa.PrivateKey),
   133  		Certificate:       keyPair.Leaf,
   134  		AllowIDPInitiated: true,
   135  		IDPMetadata:       idpMetadata,
   136  	})
   137  	if err != nil {
   138  		panic(err) // TODO handle error
   139  	}
   140  
   141  	// register with the service provider
   142  	spMetadataBuf, _ := xml.MarshalIndent(samlSP.ServiceProvider.Metadata(), "", "  ")
   143  
   144  	spURL := *idpMetadataURL
   145  	spURL.Path = "/services/sp"
   146  	resp, err := http.Post(spURL.String(), "text/xml", bytes.NewReader(spMetadataBuf))
   147  
   148  	if err != nil {
   149  		panic(err)
   150  	}
   151  
   152  	if err := resp.Body.Close(); err != nil {
   153  		panic(err)
   154  	}
   155  
   156  	goji.Handle("/saml/*", samlSP)
   157  
   158  	authMux := web.New()
   159  	authMux.Use(samlSP.RequireAccount)
   160  	authMux.Get("/whoami", func(w http.ResponseWriter, r *http.Request) {
   161  		if _, err := pretty.Fprintf(w, "%# v", r); err != nil {
   162  			panic(err)
   163  		}
   164  	})
   165  	authMux.Post("/", CreateLink)
   166  	authMux.Get("/", ListLinks)
   167  
   168  	goji.Handle("/*", authMux)
   169  	goji.Get("/:link", ServeLink)
   170  
   171  	goji.Serve()
   172  }