<commit_before>package saml2

import (
	"bytes"
	"encoding/base64"
	"errors"
	"fmt"
	"net/url"
	"strconv"
	"time"

	"github.com/beevik/etree"
	"github.com/russellhaering/goxmldsig"
	"github.com/satori/go.uuid"
)

const issueInstantFormat = "2006-01-02T15:04:05"

type SAMLServiceProvider struct {
	IdentityProviderSSOURL      string
	IdentityProviderIssuer      string
	AssertionConsumerServiceURL string
	SignAuthnRequests           bool
	AudienceURI                 string
	IDPCertificateStore         dsig.X509CertificateStore
	SPKeyStore                  dsig.X509KeyStore
}

func (sp *SAMLServiceProvider) SigningContext() *dsig.SigningContext {
	return dsig.NewDefaultSigningContext(sp.SPKeyStore)
}

func (sp *SAMLServiceProvider) validationContext() *dsig.ValidationContext {
	return dsig.NewDefaultValidationContext(sp.IDPCertificateStore)
}

func (sp *SAMLServiceProvider) BuildAuthRequest() (string, error) {
	authnRequest := &etree.Element{
		Space: "samlp",
		Tag:   "AuthnRequest",
	}

	authnRequest.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol")
	authnRequest.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion")

	authnRequest.CreateAttr("ID", "_"+uuid.NewV4().String())
	authnRequest.CreateAttr("Version", "2.0")
	authnRequest.CreateAttr("ProtocolBinding", "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST")
	authnRequest.CreateAttr("AssertionConsumerServiceURL", sp.AssertionConsumerServiceURL)
	authnRequest.CreateAttr("AssertionConsumerServiceIndex", "0")
	authnRequest.CreateAttr("AttributeConsumingServiceIndex", "0")
	authnRequest.CreateAttr("IssueInstant", time.Now().UTC().Format(issueInstantFormat))

	authnRequest.CreateElement("saml:Issuer").SetText(sp.IdentityProviderIssuer)

	nameIdPolicy := authnRequest.CreateElement("samlp:NameIDPolicy")
	nameIdPolicy.CreateAttr("AllowCreate", "true")
	nameIdPolicy.CreateAttr("Format", "urn:oasis:names:tc:SAML:2.0:nameid-format:transient")

	requestedAuthnContext := authnRequest.CreateElement("samlp:RequestedAuthnContext")
	requestedAuthnContext.CreateAttr("Comparison", "exact")

	authnContextClassRef := requestedAuthnContext.CreateElement("saml:AuthnContextClassRef")
	authnContextClassRef.SetText("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")

	doc := etree.NewDocument()

	if sp.SignAuthnRequests {
		signed, err := sp.SigningContext().SignEnveloped(authnRequest)
		if err != nil {
			return "", err
		}

		doc.SetRoot(signed)
	} else {
		doc.SetRoot(authnRequest)
	}

	buf := &bytes.Buffer{}

	_, err := doc.WriteTo(buf)
	if err != nil {
		return "", err
	}

	return doc.WriteToString()
}

func (sp *SAMLServiceProvider) BuildAuthURL(relayState string) (string, error) {
	parsedUrl, err := url.Parse(sp.IdentityProviderSSOURL)
	if err != nil {
		return "", err
	}

	authnRequest, err := sp.BuildAuthRequest()
	if err != nil {
		return "", err
	}

	qs := parsedUrl.Query()

	qs.Add("SAMLRequest", base64.StdEncoding.EncodeToString([]byte(authnRequest)))

	if relayState != "" {
		qs.Add("RelayState", relayState)
	}

	parsedUrl.RawQuery = qs.Encode()
	return parsedUrl.String(), nil
}

func (sp *SAMLServiceProvider) Validate(el *etree.Element) error {
	el = el.Copy()

	destinationAttr := el.SelectAttr(DestinationAttr)
	if destinationAttr == nil {
		return errors.New("Missing Destination attribute")
	}
	if destinationAttr.Value != sp.AssertionConsumerServiceURL {
		return errors.New(fmt.Sprintf("Did not recognize Destination value, Expected: %s, Actual: %s", sp.AssertionConsumerServiceURL, destinationAttr.Value))
	}

	idAttr := el.SelectAttr(IdAttr)
	if idAttr == nil || idAttr.Value == "" {
		return errors.New("Missing ID attribute")<commit_msg>Compress param per spec, since SAMLEncoding param is ommitted<commit_after>package saml2

import (
	"bytes"
	"compress/flate"
	"encoding/base64"
	"errors"
	"fmt"
	"net/url"
	"strconv"
	"time"

	"github.com/beevik/etree"
	"github.com/russellhaering/goxmldsig"
	"github.com/satori/go.uuid"
)

const issueInstantFormat = "2006-01-02T15:04:05"

type SAMLServiceProvider struct {
	IdentityProviderSSOURL      string
	IdentityProviderIssuer      string
	AssertionConsumerServiceURL string
	SignAuthnRequests           bool
	AudienceURI                 string
	IDPCertificateStore         dsig.X509CertificateStore
	SPKeyStore                  dsig.X509KeyStore
}

func (sp *SAMLServiceProvider) SigningContext() *dsig.SigningContext {
	return dsig.NewDefaultSigningContext(sp.SPKeyStore)
}

func (sp *SAMLServiceProvider) validationContext() *dsig.ValidationContext {
	return dsig.NewDefaultValidationContext(sp.IDPCertificateStore)
}

func (sp *SAMLServiceProvider) BuildAuthRequest() (string, error) {
	authnRequest := &etree.Element{
		Space: "samlp",
		Tag:   "AuthnRequest",
	}

	authnRequest.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:2.0:protocol")
	authnRequest.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:2.0:assertion")

	authnRequest.CreateAttr("ID", "_"+uuid.NewV4().String())
	authnRequest.CreateAttr("Version", "2.0")
	authnRequest.CreateAttr("ProtocolBinding", "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST")
	authnRequest.CreateAttr("AssertionConsumerServiceURL", sp.AssertionConsumerServiceURL)
	authnRequest.CreateAttr("AssertionConsumerServiceIndex", "0")
	authnRequest.CreateAttr("AttributeConsumingServiceIndex", "0")
	authnRequest.CreateAttr("IssueInstant", time.Now().UTC().Format(issueInstantFormat))

	authnRequest.CreateElement("saml:Issuer").SetText(sp.IdentityProviderIssuer)

	nameIdPolicy := authnRequest.CreateElement("samlp:NameIDPolicy")
	nameIdPolicy.CreateAttr("AllowCreate", "true")
	nameIdPolicy.CreateAttr("Format", "urn:oasis:names:tc:SAML:2.0:nameid-format:transient")

	requestedAuthnContext := authnRequest.CreateElement("samlp:RequestedAuthnContext")
	requestedAuthnContext.CreateAttr("Comparison", "exact")

	authnContextClassRef := requestedAuthnContext.CreateElement("saml:AuthnContextClassRef")
	authnContextClassRef.SetText("urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport")

	doc := etree.NewDocument()

	if sp.SignAuthnRequests {
		signed, err := sp.SigningContext().SignEnveloped(authnRequest)
		if err != nil {
			return "", err
		}

		doc.SetRoot(signed)
	} else {
		doc.SetRoot(authnRequest)
	}

	buf := &bytes.Buffer{}

	_, err := doc.WriteTo(buf)
	if err != nil {
		return "", err
	}

	return doc.WriteToString()
}

func (sp *SAMLServiceProvider) BuildAuthURL(relayState string) (string, error) {
	parsedUrl, err := url.Parse(sp.IdentityProviderSSOURL)
	if err != nil {
		return "", err
	}

	authnRequest, err := sp.BuildAuthRequest()
	if err != nil {
		return "", err
	}

	buf := &bytes.Buffer{}

	fw, err := flate.NewWriter(buf, flate.DefaultCompression)
	if err != nil {
		return "", fmt.Errorf("flate NewWriter error: %v", err)
	}

	_, err = fw.Write([]byte(authnRequest))
	if err != nil {
		return "", fmt.Errorf("flate.Writer Write error: %v", err)
	}

	err = fw.Close()
	if err != nil {
		return "", fmt.Errorf("flate.Writer Close error: %v", err)
	}

	qs := parsedUrl.Query()

	qs.Add("SAMLRequest", base64.StdEncoding.EncodeToString(buf.Bytes()))

	if relayState != "" {
		qs.Add("RelayState", relayState)
	}

	parsedUrl.RawQuery = qs.Encode()
	return parsedUrl.String(), nil
}

func (sp *SAMLServiceProvider) Validate(el *etree.Element) error {
	el = el.Copy()

	destinationAttr := el.SelectAttr(DestinationAttr)
	if destinationAttr == nil {
		return errors.New("Missing Destination attribute")
	}
	if destinationAttr.Value != sp.AssertionConsumerServiceURL {
		return errors.New(fmt.Sprintf("Did not recognize Destination value, Expected: %s, Actual: %s", sp.AssertionConsumerServiceURL, destinationAttr.Value))
	}

	idAttr := el.SelectAttr(IdAttr)
	if idAttr == nil || idAttr.Value == "" {
		return errors.New("Missing ID attribute")
{'fraction_non_alphanumeric': 0.13550863723608444, 'fraction_numerical': 0.010236724248240563, 'mean_word_length': 5.663256606990623, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1801473', 'n_tokens_mistral': 2778, 'n_tokens_neox': 2661, 'n_words': 435}