Skip to content

Commit 3eb7332

Browse files
authored
Merge pull request #5 from Staffbase/add-extensions-mechanism
Add extension mechanism
2 parents 0f68152 + b4346c1 commit 3eb7332

File tree

4 files changed

+65
-5
lines changed

4 files changed

+65
-5
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
*.test
2+
3+
/.idea

build_request.go

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ func (sp *SAMLServiceProvider) buildAuthnRequest(includeSig bool) (*etree.Docume
7878
}
7979
}
8080

81+
for _, processor := range sp.AuthNRequestProcessors {
82+
err := processor.Process(authnRequest)
83+
if err != nil {
84+
return nil, err
85+
}
86+
}
87+
8188
doc := etree.NewDocument()
8289

8390
// Only POST binding includes <Signature> in <AuthnRequest> (includeSig)
@@ -254,7 +261,7 @@ func (sp *SAMLServiceProvider) buildAuthBodyPostFromDocument(relayState string,
254261
return rv.Bytes(), nil
255262
}
256263

257-
//BuildAuthBodyPost builds the POST body to be sent to IDP.
264+
// BuildAuthBodyPost builds the POST body to be sent to IDP.
258265
func (sp *SAMLServiceProvider) BuildAuthBodyPost(relayState string) ([]byte, error) {
259266
var doc *etree.Document
260267
var err error
@@ -272,8 +279,8 @@ func (sp *SAMLServiceProvider) BuildAuthBodyPost(relayState string) ([]byte, err
272279
return sp.buildAuthBodyPostFromDocument(relayState, doc)
273280
}
274281

275-
//BuildAuthBodyPostFromDocument builds the POST body to be sent to IDP.
276-
//It takes the AuthnRequest xml as input.
282+
// BuildAuthBodyPostFromDocument builds the POST body to be sent to IDP.
283+
// It takes the AuthnRequest xml as input.
277284
func (sp *SAMLServiceProvider) BuildAuthBodyPostFromDocument(relayState string, doc *etree.Document) ([]byte, error) {
278285
return sp.buildAuthBodyPostFromDocument(relayState, doc)
279286
}
@@ -382,8 +389,8 @@ func (sp *SAMLServiceProvider) BuildLogoutRequestDocument(nameID string, session
382389
return sp.buildLogoutRequest(true, nameID, sessionIndex)
383390
}
384391

385-
//BuildLogoutBodyPostFromDocument builds the POST body to be sent to IDP.
386-
//It takes the LogoutRequest xml as input.
392+
// BuildLogoutBodyPostFromDocument builds the POST body to be sent to IDP.
393+
// It takes the LogoutRequest xml as input.
387394
func (sp *SAMLServiceProvider) BuildLogoutBodyPostFromDocument(relayState string, doc *etree.Document) ([]byte, error) {
388395
return sp.buildLogoutBodyPostFromDocument(relayState, doc)
389396
}
@@ -555,3 +562,16 @@ func signatureInputString(samlRequest, relayState, sigAlg string) string {
555562
}
556563
return buf.String()
557564
}
565+
566+
type AddIdpScoping struct {
567+
ProviderId string
568+
Name string
569+
}
570+
571+
func (a *AddIdpScoping) Process(doc *etree.Element) error {
572+
idpList := doc.CreateElement("samlp:Scoping").CreateElement("samlp:IDPList")
573+
idpEntry := idpList.CreateElement("samlp:IDPEntry")
574+
idpEntry.CreateAttr("ProviderID", a.ProviderId)
575+
idpEntry.CreateAttr("Name", a.Name)
576+
return nil
577+
}

build_request_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,34 @@ func TestIsPassiveIncluded(t *testing.T) {
213213
require.NotNil(t, attr)
214214
require.Equal(t, "true", attr.Value)
215215
}
216+
217+
func TestAddIdpScopingExtension(t *testing.T) {
218+
spURL := "https://sp.test"
219+
extension := AddIdpScoping{
220+
ProviderId: "foo",
221+
Name: "bar",
222+
}
223+
224+
sp := SAMLServiceProvider{
225+
AssertionConsumerServiceURL: spURL,
226+
AudienceURI: spURL,
227+
IdentityProviderIssuer: spURL,
228+
IdentityProviderSSOURL: "https://idp.test/saml/sso",
229+
230+
// Add IdP scoping extension
231+
AuthNRequestProcessors: []AuthNRequestProcessor{&extension},
232+
}
233+
234+
request, err := sp.BuildAuthRequest()
235+
require.NoError(t, err)
236+
237+
doc := etree.NewDocument()
238+
err = doc.ReadFromString(request)
239+
require.NoError(t, err)
240+
241+
el := doc.FindElement("./AuthnRequest/Scoping/IDPList/IDPEntry")
242+
243+
require.NotNil(t, el)
244+
require.Equal(t, el.SelectAttrValue("ProviderID", ""), "foo")
245+
require.Equal(t, el.SelectAttrValue("Name", ""), "bar")
246+
}

saml.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package saml2
1717
import (
1818
"crypto"
1919
"encoding/base64"
20+
"github.com/beevik/etree"
2021
"sync"
2122
"time"
2223

@@ -37,6 +38,10 @@ func (serr ErrSaml) Error() string {
3738
return "SAML error"
3839
}
3940

41+
type AuthNRequestProcessor interface {
42+
Process(request *etree.Element) error
43+
}
44+
4045
type SAMLServiceProvider struct {
4146
IdentityProviderSSOURL string
4247
IdentityProviderSSOBinding string
@@ -74,6 +79,8 @@ type SAMLServiceProvider struct {
7479
AllowMissingAttributes bool
7580
Clock *dsig.Clock
7681

82+
AuthNRequestProcessors []AuthNRequestProcessor
83+
7784
// Required encryption key and default signing key.
7885
// Deprecated: Use SetSPKeyStore instead of setting or reading this field.
7986
SPKeyStore dsig.X509KeyStore

0 commit comments

Comments
 (0)