1
0
Fork 0
mirror of https://github.com/documize/community.git synced 2025-08-08 23:15:29 +02:00

Bump version to 5.11.0

This commit is contained in:
Harvey Kandola 2024-01-10 14:47:40 -05:00
parent a32510b8e6
commit 510e1bd0bd
370 changed files with 18825 additions and 5454 deletions

12
vendor/gopkg.in/cas.v2/README.md generated vendored
View file

@ -3,10 +3,18 @@
CAS provides a http package compatible client implementation for use with
securing http frontends in golang.
import "gopkg.in/cas.v2"
```
import "gopkg.in/cas.v2"
```
If you are using go modules, get the library by running:
```
go get gopkg.in/cas.v2@v2.2.1
```
## Examples and Documentation
Documentation is available at: http://godoc.org/gopkg.in/cas.v1
Documentation is available at: https://pkg.go.dev/gopkg.in/cas.v2
Examples are included in the documentation but are also available in the
`_examples` directory.

286
vendor/gopkg.in/cas.v2/client.go generated vendored
View file

@ -3,32 +3,34 @@ package cas
import (
"crypto/rand"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"path"
"sync"
"github.com/golang/glog"
)
// Client configuration options
// Options : Client configuration options
type Options struct {
URL *url.URL // URL to the CAS service
Store TicketStore // Custom TicketStore, if nil a MemoryStore will be used
Client *http.Client // Custom http client to allow options for http connections
SendService bool // Custom sendService to determine whether you need to send service param
URL *url.URL // URL to the CAS service
Store TicketStore // Custom TicketStore, if nil a MemoryStore will be used
Client *http.Client // Custom http client to allow options for http connections
SendService bool // Custom sendService to determine whether you need to send service param
URLScheme URLScheme // Custom url scheme, can be used to modify the request urls for the client
Cookie *http.Cookie // http.Cookie options, uses Path, Domain, MaxAge, HttpOnly, & Secure
SessionStore SessionStore
}
// Client implements the main protocol
type Client struct {
url *url.URL
tickets TicketStore
client *http.Client
tickets TicketStore
client *http.Client
urlScheme URLScheme
cookie *http.Cookie
mu sync.Mutex
sessions map[string]string
sessions SessionStore
sendService bool
stValidator *ServiceTicketValidator
}
// NewClient creates a Client with the provided Options.
@ -44,6 +46,20 @@ func NewClient(options *Options) *Client {
tickets = &MemoryStore{}
}
var sessions SessionStore
if options.SessionStore != nil {
sessions = options.SessionStore
} else {
sessions = NewMemorySessionStore()
}
var urlScheme URLScheme
if options.URLScheme != nil {
urlScheme = options.URLScheme
} else {
urlScheme = NewDefaultURLScheme(options.URL)
}
var client *http.Client
if options.Client != nil {
client = options.Client
@ -51,12 +67,25 @@ func NewClient(options *Options) *Client {
client = &http.Client{}
}
var cookie *http.Cookie
if options.Cookie != nil {
cookie = options.Cookie
} else {
cookie = &http.Cookie{
MaxAge: 86400,
HttpOnly: false,
Secure: false,
}
}
return &Client{
url: options.URL,
tickets: tickets,
client: client,
sessions: make(map[string]string),
urlScheme: urlScheme,
cookie: cookie,
sessions: sessions,
sendService: options.SendService,
stValidator: NewServiceTicketValidator(client, options.URL),
}
}
@ -81,8 +110,11 @@ func requestURL(r *http.Request) (*url.URL, error) {
}
u.Host = r.Host
u.Scheme = "http"
if host := r.Header.Get("X-Forwarded-Host"); host != "" {
u.Host = host
}
u.Scheme = "http"
if scheme := r.Header.Get("X-Forwarded-Proto"); scheme != "" {
u.Scheme = scheme
} else if r.TLS != nil {
@ -94,7 +126,7 @@ func requestURL(r *http.Request) (*url.URL, error) {
// LoginUrlForRequest determines the CAS login URL for the http.Request.
func (c *Client) LoginUrlForRequest(r *http.Request) (string, error) {
u, err := c.url.Parse(path.Join(c.url.Path, "login"))
u, err := c.urlScheme.Login()
if err != nil {
return "", err
}
@ -113,7 +145,7 @@ func (c *Client) LoginUrlForRequest(r *http.Request) (string, error) {
// LogoutUrlForRequest determines the CAS logout URL for the http.Request.
func (c *Client) LogoutUrlForRequest(r *http.Request) (string, error) {
u, err := c.url.Parse(path.Join(c.url.Path, "logout"))
u, err := c.urlScheme.Logout()
if err != nil {
return "", err
}
@ -134,42 +166,20 @@ func (c *Client) LogoutUrlForRequest(r *http.Request) (string, error) {
// ServiceValidateUrlForRequest determines the CAS serviceValidate URL for the ticket and http.Request.
func (c *Client) ServiceValidateUrlForRequest(ticket string, r *http.Request) (string, error) {
u, err := c.url.Parse(path.Join(c.url.Path, "serviceValidate"))
if err != nil {
return "", err
}
service, err := requestURL(r)
if err != nil {
return "", err
}
q := u.Query()
q.Add("service", sanitisedURLString(service))
q.Add("ticket", ticket)
u.RawQuery = q.Encode()
return u.String(), nil
return c.stValidator.ServiceValidateUrl(service, ticket)
}
// ValidateUrlForRequest determines the CAS validate URL for the ticket and http.Request.
func (c *Client) ValidateUrlForRequest(ticket string, r *http.Request) (string, error) {
u, err := c.url.Parse(path.Join(c.url.Path, "validate"))
if err != nil {
return "", err
}
service, err := requestURL(r)
if err != nil {
return "", err
}
q := u.Query()
q.Add("service", sanitisedURLString(service))
q.Add("ticket", ticket)
u.RawQuery = q.Encode()
return u.String(), nil
return c.stValidator.ValidateUrl(service, ticket)
}
// RedirectToLogout replies to the request with a redirect URL to log out of CAS.
@ -181,7 +191,7 @@ func (c *Client) RedirectToLogout(w http.ResponseWriter, r *http.Request) {
}
if glog.V(2) {
glog.Info("Logging out, redirecting client to %v with status %v",
glog.Infof("Logging out, redirecting client to %v with status %v",
u, http.StatusFound)
}
@ -189,7 +199,7 @@ func (c *Client) RedirectToLogout(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, u, http.StatusFound)
}
// RedirectToLogout replies to the request with a redirect URL to authenticate with CAS.
// RedirectToLogin replies to the request with a redirect URL to authenticate with CAS.
func (c *Client) RedirectToLogin(w http.ResponseWriter, r *http.Request) {
u, err := c.LoginUrlForRequest(r)
if err != nil {
@ -205,134 +215,17 @@ func (c *Client) RedirectToLogin(w http.ResponseWriter, r *http.Request) {
}
// validateTicket performs CAS ticket validation with the given ticket and service.
//
// If the request returns a 404 then validateTicketCas1 will be returned.
func (c *Client) validateTicket(ticket string, service *http.Request) error {
if glog.V(2) {
serviceUrl, _ := requestURL(service)
glog.Infof("Validating ticket %v for service %v", ticket, serviceUrl)
}
u, err := c.ServiceValidateUrlForRequest(ticket, service)
serviceURL, err := requestURL(service)
if err != nil {
return err
}
r, err := http.NewRequest("GET", u, nil)
success, err := c.stValidator.ValidateTicket(serviceURL, ticket)
if err != nil {
return err
}
r.Header.Add("User-Agent", "Golang CAS client gopkg.in/cas")
if glog.V(2) {
glog.Infof("Attempting ticket validation with %v", r.URL)
}
resp, err := c.client.Do(r)
if err != nil {
return err
}
if glog.V(2) {
glog.Infof("Request %v %v returned %v",
r.Method, r.URL,
resp.Status)
}
if resp.StatusCode == http.StatusNotFound {
return c.validateTicketCas1(ticket, service)
}
body, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("cas: validate ticket: %v", string(body))
}
if glog.V(2) {
glog.Infof("Received authentication response\n%v", string(body))
}
success, err := ParseServiceResponse(body)
if err != nil {
return err
}
if glog.V(2) {
glog.Infof("Parsed ServiceResponse: %#v", success)
}
if err := c.tickets.Write(ticket, success); err != nil {
return err
}
return nil
}
// validateTicketCas1 performs CAS protocol 1 ticket validation.
func (c *Client) validateTicketCas1(ticket string, service *http.Request) error {
u, err := c.ValidateUrlForRequest(ticket, service)
if err != nil {
return err
}
r, err := http.NewRequest("GET", u, nil)
if err != nil {
return err
}
r.Header.Add("User-Agent", "Golang CAS client gopkg.in/cas")
if glog.V(2) {
glog.Info("Attempting ticket validation with %v", r.URL)
}
resp, err := c.client.Do(r)
if err != nil {
return err
}
if glog.V(2) {
glog.Info("Request %v %v returned %v",
r.Method, r.URL,
resp.Status)
}
data, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return err
}
body := string(data)
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("cas: validate ticket: %v", body)
}
if glog.V(2) {
glog.Infof("Received authentication response\n%v", body)
}
if body == "no\n\n" {
return nil // not logged in
}
success := &AuthenticationResponse{
User: body[4 : len(body)-1],
}
if glog.V(2) {
glog.Infof("Parsed ServiceResponse: %#v", success)
}
if err := c.tickets.Write(ticket, success); err != nil {
return err
}
@ -345,9 +238,9 @@ func (c *Client) validateTicketCas1(ticket string, service *http.Request) error
// A cookie is set on the response if one is not provided with the request.
// Validates the ticket if the URL parameter is provided.
func (c *Client) getSession(w http.ResponseWriter, r *http.Request) {
cookie := getCookie(w, r)
cookie := c.getCookie(w, r)
if s, ok := c.sessions[cookie.Value]; ok {
if s, ok := c.sessions.Get(cookie.Value); ok {
if t, err := c.tickets.Read(s); err == nil {
if glog.V(1) {
glog.Infof("Re-used ticket %s for %s", s, t.User)
@ -400,31 +293,34 @@ func (c *Client) getSession(w http.ResponseWriter, r *http.Request) {
}
// getCookie finds or creates the session cookie on the response.
func getCookie(w http.ResponseWriter, r *http.Request) *http.Cookie {
c, err := r.Cookie(sessionCookieName)
func (c *Client) getCookie(w http.ResponseWriter, r *http.Request) *http.Cookie {
cookie, err := r.Cookie(sessionCookieName)
if err != nil {
// NOTE: Intentionally not enabling HttpOnly so the cookie can
// still be used by Ajax requests.
c = &http.Cookie{
cookie = &http.Cookie{
Name: sessionCookieName,
Value: newSessionId(),
MaxAge: 86400,
HttpOnly: false,
Value: newSessionID(),
Path: c.cookie.Path,
Domain: c.cookie.Domain,
MaxAge: c.cookie.MaxAge,
HttpOnly: c.cookie.HttpOnly,
Secure: c.cookie.Secure,
}
if glog.V(2) {
glog.Infof("Setting %v cookie with value: %v", c.Name, c.Value)
glog.Infof("Setting %v cookie with value: %v", cookie.Name, cookie.Value)
}
r.AddCookie(c) // so we can find it later if required
http.SetCookie(w, c)
r.AddCookie(cookie) // so we can find it later if required
http.SetCookie(w, cookie)
}
return c
return cookie
}
// newSessionId generates a new opaque session identifier for use in the cookie.
func newSessionId() string {
func newSessionID() string {
const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
// generate 64 character string
@ -450,24 +346,22 @@ func (c *Client) setSession(id string, ticket string) {
glog.Infof("Recording session, %v -> %v", id, ticket)
}
c.mu.Lock()
c.sessions[id] = ticket
c.mu.Unlock()
c.sessions.Set(id, ticket)
}
// clearSession removes the session from the client and clears the cookie.
func (c *Client) clearSession(w http.ResponseWriter, r *http.Request) {
cookie := getCookie(w, r)
cookie := c.getCookie(w, r)
if s, ok := c.sessions[cookie.Value]; ok {
if err := c.tickets.Delete(s); err != nil {
if serviceTicket, ok := c.sessions.Get(cookie.Value); ok {
if err := c.tickets.Delete(serviceTicket); err != nil {
fmt.Printf("Failed to remove %v from %T: %v\n", cookie.Value, c.tickets, err)
if glog.V(2) {
glog.Errorf("Failed to remove %v from %T: %v", cookie.Value, c.tickets, err)
}
}
c.deleteSession(s)
c.deleteSession(cookie.Value)
}
clearCookie(w, cookie)
@ -475,29 +369,5 @@ func (c *Client) clearSession(w http.ResponseWriter, r *http.Request) {
// deleteSession removes the session from the client
func (c *Client) deleteSession(id string) {
c.mu.Lock()
delete(c.sessions, id)
c.mu.Unlock()
}
// findAndDeleteSessionWithTicket removes the session from the client via Single Log Out
//
// When a Single Log Out request is received we receive the service ticket identidier. This
// function loops through the sessions to find the matching session id. Once retrieved the
// session is removed from the client. When the session is next requested the getSession
// function will notice the session is invalid and revalidate the user.
func (c *Client) findAndDeleteSessionWithTicket(ticket string) {
var id string
for s, t := range c.sessions {
if t == ticket {
id = s
break
}
}
if id == "" {
return
}
c.deleteSession(id)
c.sessions.Delete(id)
}

View file

@ -24,9 +24,9 @@ func setClient(r *http.Request, c *Client) {
func getClient(r *http.Request) *Client {
if c := r.Context().Value(clientKey); c != nil {
return c.(*Client)
} else {
return nil // explicitly pass along the nil to caller -- conforms to previous impl
}
return nil // explicitly pass along the nil to caller -- conforms to previous impl
}
// RedirectToLogin allows CAS protected handlers to redirect a request
@ -68,9 +68,9 @@ func setAuthenticationResponse(r *http.Request, a *AuthenticationResponse) {
func getAuthenticationResponse(r *http.Request) *AuthenticationResponse {
if a := r.Context().Value(authenticationResponseKey); a != nil {
return a.(*AuthenticationResponse)
} else {
return nil // explicitly pass along the nil to caller -- conforms to previous impl
}
return nil // explicitly pass along the nil to caller -- conforms to previous impl
}
// IsAuthenticated indicates whether the request has been authenticated with CAS.

View file

@ -24,7 +24,7 @@ func parseLogoutRequest(data []byte) (*logoutRequest, error) {
return nil, err
}
t, err := time.Parse(time.RFC1123Z, l.RawIssueInstant)
t, err := parseDate(l.RawIssueInstant)
if err != nil {
return nil, err
}
@ -36,7 +36,19 @@ func parseLogoutRequest(data []byte) (*logoutRequest, error) {
return l, nil
}
func newLogoutRequestId() string {
func parseDate(raw string) (time.Time, error) {
t, err := time.Parse(time.RFC1123Z, raw)
if err != nil {
// if RFC1123Z does not match, we will try iso8601
t, err = time.Parse("2006-01-02T15:04:05Z0700", raw)
if err != nil {
return t, err
}
}
return t, nil
}
func newLogoutRequestID() string {
const alphabet = "abcdef0123456789"
// generate 64 character string
@ -54,7 +66,7 @@ func xmlLogoutRequest(ticket string) ([]byte, error) {
l := &logoutRequest{
Version: "2.0",
IssueInstant: time.Now().UTC(),
ID: newLogoutRequestId(),
ID: newLogoutRequestID(),
NameID: "@NOT_USED@",
SessionIndex: ticket,
}

View file

@ -6,6 +6,8 @@ import (
"github.com/golang/glog"
)
// Handler returns a standard http.HandlerFunc, which will check the authenticated status (redirect user go login if needed)
// If the user pass the authenticated check, it will call the h's ServeHTTP method
func (c *Client) Handler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if glog.V(2) {

178
vendor/gopkg.in/cas.v2/rest_client.go generated vendored Normal file
View file

@ -0,0 +1,178 @@
package cas
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"path"
"github.com/golang/glog"
)
// https://apereo.github.io/cas/4.2.x/protocol/REST-Protocol.html
// TicketGrantingTicket represents a SSO session for a user, also known as TGT
type TicketGrantingTicket string
// ServiceTicket stands for the access granted by the CAS server to an application for a specific user, also known as ST
type ServiceTicket string
// RestOptions provide options for the RestClient
type RestOptions struct {
CasURL *url.URL
ServiceURL *url.URL
Client *http.Client
URLScheme URLScheme
}
// RestClient uses the rest protocol provided by cas
type RestClient struct {
urlScheme URLScheme
serviceURL *url.URL
client *http.Client
stValidator *ServiceTicketValidator
}
// NewRestClient creates a new client for the cas rest protocol with the provided options
func NewRestClient(options *RestOptions) *RestClient {
if glog.V(2) {
glog.Infof("cas: new rest client with options %v", options)
}
var client *http.Client
if options.Client != nil {
client = options.Client
} else {
client = &http.Client{}
}
var urlScheme URLScheme
if options.URLScheme != nil {
urlScheme = options.URLScheme
} else {
urlScheme = NewDefaultURLScheme(options.CasURL)
}
return &RestClient{
urlScheme: urlScheme,
serviceURL: options.ServiceURL,
client: client,
stValidator: NewServiceTicketValidator(client, options.CasURL),
}
}
// Handle wraps a http.Handler to provide CAS Rest authentication for the handler.
func (c *RestClient) Handle(h http.Handler) http.Handler {
return &restClientHandler{
c: c,
h: h,
}
}
// HandleFunc wraps a function to provide CAS Rest authentication for the handler function.
func (c *RestClient) HandleFunc(h func(http.ResponseWriter, *http.Request)) http.Handler {
return c.Handle(http.HandlerFunc(h))
}
// RequestGrantingTicket returns a new TGT, if the username and password authentication was successful
func (c *RestClient) RequestGrantingTicket(username string, password string) (TicketGrantingTicket, error) {
// request:
// POST /cas/v1/tickets HTTP/1.0
// username=battags&password=password&additionalParam1=paramvalue
endpoint, err := c.urlScheme.RestGrantingTicket()
if err != nil {
return "", err
}
values := url.Values{}
values.Set("username", username)
values.Set("password", password)
resp, err := c.client.PostForm(endpoint.String(), values)
if err != nil {
return "", err
}
// response:
// 201 Created
// Location: http://www.whatever.com/cas/v1/tickets/{TGT id}
if resp.StatusCode != 201 {
return "", fmt.Errorf("ticket endoint returned status code %v", resp.StatusCode)
}
tgt := path.Base(resp.Header.Get("Location"))
if tgt == "" {
return "", fmt.Errorf("does not return a valid location header")
}
return TicketGrantingTicket(tgt), nil
}
// RequestServiceTicket requests a service ticket with the TGT for the configured service url
func (c *RestClient) RequestServiceTicket(tgt TicketGrantingTicket) (ServiceTicket, error) {
// request:
// POST /cas/v1/tickets/{TGT id} HTTP/1.0
// service={form encoded parameter for the service url}
endpoint, err := c.urlScheme.RestServiceTicket(string(tgt))
if err != nil {
return "", err
}
values := url.Values{}
values.Set("service", c.serviceURL.String())
resp, err := c.client.PostForm(endpoint.String(), values)
if err != nil {
return "", err
}
// response:
// 200 OK
// ST-1-FFDFHDSJKHSDFJKSDHFJKRUEYREWUIFSD2132
if resp.StatusCode != 200 {
return "", fmt.Errorf("service ticket endoint returned status code %v", resp.StatusCode)
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return ServiceTicket(data), nil
}
// ValidateServiceTicket validates the service ticket and returns an AuthenticationResponse
func (c *RestClient) ValidateServiceTicket(st ServiceTicket) (*AuthenticationResponse, error) {
return c.stValidator.ValidateTicket(c.serviceURL, string(st))
}
// Logout destroys the given granting ticket
func (c *RestClient) Logout(tgt TicketGrantingTicket) error {
// DELETE /cas/v1/tickets/TGT-fdsjfsdfjkalfewrihfdhfaie HTTP/1.0
endpoint, err := c.urlScheme.RestLogout(string(tgt))
if err != nil {
return err
}
req, err := http.NewRequest("DELETE", endpoint.String(), nil)
if err != nil {
return err
}
resp, err := c.client.Do(req)
if err != nil {
return err
}
if resp.StatusCode != 200 && resp.StatusCode != 204 {
return fmt.Errorf("could not destroy granting ticket %v, server returned %v", tgt, resp.StatusCode)
}
return nil
}

59
vendor/gopkg.in/cas.v2/rest_handler.go generated vendored Normal file
View file

@ -0,0 +1,59 @@
package cas
import (
"net/http"
"github.com/golang/glog"
)
// restClientHandler handles CAS REST Protocol over HTTP Basic Authentication
type restClientHandler struct {
c *RestClient
h http.Handler
}
// ServeHTTP handles HTTP requests, processes HTTP Basic Authentication over CAS Rest api
// and passes requests up to its child http.Handler.
func (ch *restClientHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if glog.V(2) {
glog.Infof("cas: handling %v request for %v", r.Method, r.URL)
}
username, password, ok := r.BasicAuth()
if !ok {
w.Header().Set("WWW-Authenticate", "Basic realm=\"CAS Protected Area\"")
w.WriteHeader(401)
return
}
// TODO we should implement a short cache to avoid hitting cas server on every request
// the cache could use the authorization header as key and the authenticationResponse as value
success, err := ch.authenticate(username, password)
if err != nil {
if glog.V(1) {
glog.Infof("cas: rest authentication failed %v", err)
}
w.Header().Set("WWW-Authenticate", "Basic realm=\"CAS Protected Area\"")
w.WriteHeader(401)
return
}
setAuthenticationResponse(r, success)
ch.h.ServeHTTP(w, r)
return
}
func (ch *restClientHandler) authenticate(username string, password string) (*AuthenticationResponse, error) {
tgt, err := ch.c.RequestGrantingTicket(username, password)
if err != nil {
return nil, err
}
st, err := ch.c.RequestServiceTicket(tgt)
if err != nil {
return nil, err
}
return ch.c.ValidateServiceTicket(st)
}

183
vendor/gopkg.in/cas.v2/service_validate.go generated vendored Normal file
View file

@ -0,0 +1,183 @@
package cas
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
"path"
"github.com/golang/glog"
)
// NewServiceTicketValidator create a new *ServiceTicketValidator
func NewServiceTicketValidator(client *http.Client, casURL *url.URL) *ServiceTicketValidator {
return &ServiceTicketValidator{
client: client,
casURL: casURL,
}
}
// ServiceTicketValidator is responsible for the validation of a service ticket
type ServiceTicketValidator struct {
client *http.Client
casURL *url.URL
}
// ValidateTicket validates the service ticket for the given server. The method will try to use the service validate
// endpoint of the cas >= 2 protocol, if the service validate endpoint not available, the function will use the cas 1
// validate endpoint.
func (validator *ServiceTicketValidator) ValidateTicket(serviceURL *url.URL, ticket string) (*AuthenticationResponse, error) {
if glog.V(2) {
glog.Infof("Validating ticket %v for service %v", ticket, serviceURL)
}
u, err := validator.ServiceValidateUrl(serviceURL, ticket)
if err != nil {
return nil, err
}
r, err := http.NewRequest("GET", u, nil)
if err != nil {
return nil, err
}
r.Header.Add("User-Agent", "Golang CAS client gopkg.in/cas")
if glog.V(2) {
glog.Infof("Attempting ticket validation with %v", r.URL)
}
resp, err := validator.client.Do(r)
if err != nil {
return nil, err
}
if glog.V(2) {
glog.Infof("Request %v %v returned %v",
r.Method, r.URL,
resp.Status)
}
if resp.StatusCode == http.StatusNotFound {
return validator.validateTicketCas1(serviceURL, ticket)
}
body, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("cas: validate ticket: %v", string(body))
}
if glog.V(2) {
glog.Infof("Received authentication response\n%v", string(body))
}
success, err := ParseServiceResponse(body)
if err != nil {
return nil, err
}
if glog.V(2) {
glog.Infof("Parsed ServiceResponse: %#v", success)
}
return success, nil
}
// ServiceValidateUrl creates the service validation url for the cas >= 2 protocol.
// TODO the function is only exposed, because of the clients ServiceValidateUrl function
func (validator *ServiceTicketValidator) ServiceValidateUrl(serviceURL *url.URL, ticket string) (string, error) {
u, err := validator.casURL.Parse(path.Join(validator.casURL.Path, "serviceValidate"))
if err != nil {
return "", err
}
q := u.Query()
q.Add("service", sanitisedURLString(serviceURL))
q.Add("ticket", ticket)
u.RawQuery = q.Encode()
return u.String(), nil
}
func (validator *ServiceTicketValidator) validateTicketCas1(serviceURL *url.URL, ticket string) (*AuthenticationResponse, error) {
u, err := validator.ValidateUrl(serviceURL, ticket)
if err != nil {
return nil, err
}
r, err := http.NewRequest("GET", u, nil)
if err != nil {
return nil, err
}
r.Header.Add("User-Agent", "Golang CAS client gopkg.in/cas")
if glog.V(2) {
glog.Infof("Attempting ticket validation with %v", r.URL)
}
resp, err := validator.client.Do(r)
if err != nil {
return nil, err
}
if glog.V(2) {
glog.Infof("Request %v %v returned %v",
r.Method, r.URL,
resp.Status)
}
data, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
return nil, err
}
body := string(data)
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("cas: validate ticket: %v", body)
}
if glog.V(2) {
glog.Infof("Received authentication response\n%v", body)
}
if body == "no\n\n" {
return nil, nil // not logged in
}
success := &AuthenticationResponse{
User: body[4 : len(body)-1],
}
if glog.V(2) {
glog.Infof("Parsed ServiceResponse: %#v", success)
}
return success, nil
}
// ValidateUrl creates the validation url for the cas >= 1 protocol.
// TODO the function is only exposed, because of the clients ValidateUrl function
func (validator *ServiceTicketValidator) ValidateUrl(serviceURL *url.URL, ticket string) (string, error) {
u, err := validator.casURL.Parse(path.Join(validator.casURL.Path, "validate"))
if err != nil {
return "", err
}
q := u.Query()
q.Add("service", sanitisedURLString(serviceURL))
q.Add("ticket", ticket)
u.RawQuery = q.Encode()
return u.String(), nil
}

52
vendor/gopkg.in/cas.v2/session_store.go generated vendored Normal file
View file

@ -0,0 +1,52 @@
package cas
import "sync"
// SessionStore store the session's ticket
// SessionID is retrived from cookies
type SessionStore interface {
// Get the ticket with the session id
Get(sessionID string) (string, bool)
// Set the session with a ticket
Set(sessionID, ticket string) error
// Delete the session
Delete(sessionID string) error
}
// NewMemorySessionStore create a default SessionStore that uses memory
func NewMemorySessionStore() SessionStore {
return &memorySessionStore{
sessions: make(map[string]string),
}
}
type memorySessionStore struct {
mu sync.RWMutex
sessions map[string]string
}
func (m *memorySessionStore) Get(sessionID string) (string, bool) {
m.mu.RLock()
ticket, ok := m.sessions[sessionID]
m.mu.RUnlock()
return ticket, ok
}
func (m *memorySessionStore) Set(sessionID, ticket string) error {
m.mu.Lock()
m.sessions[sessionID] = ticket
m.mu.Unlock()
return nil
}
func (m *memorySessionStore) Delete(sessionID string) error {
m.mu.Lock()
delete(m.sessions, sessionID)
m.mu.Unlock()
return nil
}

79
vendor/gopkg.in/cas.v2/url_scheme.go generated vendored Normal file
View file

@ -0,0 +1,79 @@
package cas
import (
"net/url"
"path"
)
// URLScheme creates the url which are required to handle the cas protocol.
type URLScheme interface {
Login() (*url.URL, error)
Logout() (*url.URL, error)
Validate() (*url.URL, error)
ServiceValidate() (*url.URL, error)
RestGrantingTicket() (*url.URL, error)
RestServiceTicket(tgt string) (*url.URL, error)
RestLogout(tgt string) (*url.URL, error)
}
// NewDefaultURLScheme creates a URLScheme which uses the cas default urls
func NewDefaultURLScheme(base *url.URL) *DefaultURLScheme {
return &DefaultURLScheme{
base: base,
LoginPath: "login",
LogoutPath: "logout",
ValidatePath: "validate",
ServiceValidatePath: "serviceValidate",
RestEndpoint: path.Join("v1", "tickets"),
}
}
// DefaultURLScheme is a configurable URLScheme. Use NewDefaultURLScheme to create DefaultURLScheme with the default cas
// urls.
type DefaultURLScheme struct {
base *url.URL
LoginPath string
LogoutPath string
ValidatePath string
ServiceValidatePath string
RestEndpoint string
}
// Login returns the url for the cas login page
func (scheme *DefaultURLScheme) Login() (*url.URL, error) {
return scheme.createURL(scheme.LoginPath)
}
// Logout returns the url for the cas logut page
func (scheme *DefaultURLScheme) Logout() (*url.URL, error) {
return scheme.createURL(scheme.LogoutPath)
}
// Validate returns the url for the request validation endpoint
func (scheme *DefaultURLScheme) Validate() (*url.URL, error) {
return scheme.createURL(scheme.ValidatePath)
}
// ServiceValidate returns the url for the service validation endpoint
func (scheme *DefaultURLScheme) ServiceValidate() (*url.URL, error) {
return scheme.createURL(scheme.ServiceValidatePath)
}
// RestGrantingTicket returns the url for requesting an granting ticket via rest api
func (scheme *DefaultURLScheme) RestGrantingTicket() (*url.URL, error) {
return scheme.createURL(scheme.RestEndpoint)
}
// RestServiceTicket returns the url for requesting an service ticket via rest api
func (scheme *DefaultURLScheme) RestServiceTicket(tgt string) (*url.URL, error) {
return scheme.createURL(path.Join(scheme.RestEndpoint, tgt))
}
// RestLogout returns the url for destroying an granting ticket via rest api
func (scheme *DefaultURLScheme) RestLogout(tgt string) (*url.URL, error) {
return scheme.createURL(path.Join(scheme.RestEndpoint, tgt))
}
func (scheme *DefaultURLScheme) createURL(urlPath string) (*url.URL, error) {
return scheme.base.Parse(path.Join(scheme.base.Path, urlPath))
}

19
vendor/gopkg.in/yaml.v2/.travis.yml generated vendored
View file

@ -1,12 +1,17 @@
language: go
go:
- 1.4
- 1.5
- 1.6
- 1.7
- 1.8
- 1.9
- tip
- "1.4.x"
- "1.5.x"
- "1.6.x"
- "1.7.x"
- "1.8.x"
- "1.9.x"
- "1.10.x"
- "1.11.x"
- "1.12.x"
- "1.13.x"
- "1.14.x"
- "tip"
go_import_path: gopkg.in/yaml.v2

5
vendor/gopkg.in/yaml.v2/apic.go generated vendored
View file

@ -79,6 +79,8 @@ func yaml_parser_set_encoding(parser *yaml_parser_t, encoding yaml_encoding_t) {
parser.encoding = encoding
}
var disableLineWrapping = false
// Create a new emitter object.
func yaml_emitter_initialize(emitter *yaml_emitter_t) {
*emitter = yaml_emitter_t{
@ -87,6 +89,9 @@ func yaml_emitter_initialize(emitter *yaml_emitter_t) {
states: make([]yaml_emitter_state_t, 0, initial_stack_size),
events: make([]yaml_event_t, 0, initial_queue_size),
}
if disableLineWrapping {
emitter.best_width = -1
}
}
// Destroy an emitter object.

48
vendor/gopkg.in/yaml.v2/decode.go generated vendored
View file

@ -229,6 +229,10 @@ type decoder struct {
mapType reflect.Type
terrors []string
strict bool
decodeCount int
aliasCount int
aliasDepth int
}
var (
@ -314,7 +318,43 @@ func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unm
return out, false, false
}
const (
// 400,000 decode operations is ~500kb of dense object declarations, or
// ~5kb of dense object declarations with 10000% alias expansion
alias_ratio_range_low = 400000
// 4,000,000 decode operations is ~5MB of dense object declarations, or
// ~4.5MB of dense object declarations with 10% alias expansion
alias_ratio_range_high = 4000000
// alias_ratio_range is the range over which we scale allowed alias ratios
alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)
)
func allowedAliasRatio(decodeCount int) float64 {
switch {
case decodeCount <= alias_ratio_range_low:
// allow 99% to come from alias expansion for small-to-medium documents
return 0.99
case decodeCount >= alias_ratio_range_high:
// allow 10% to come from alias expansion for very large documents
return 0.10
default:
// scale smoothly from 99% down to 10% over the range.
// this maps to 396,000 - 400,000 allowed alias-driven decodes over the range.
// 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps).
return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range)
}
}
func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) {
d.decodeCount++
if d.aliasDepth > 0 {
d.aliasCount++
}
if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {
failf("document contains excessive aliasing")
}
switch n.kind {
case documentNode:
return d.document(n, out)
@ -353,7 +393,9 @@ func (d *decoder) alias(n *node, out reflect.Value) (good bool) {
failf("anchor '%s' value contains itself", n.value)
}
d.aliases[n] = true
d.aliasDepth++
good = d.unmarshal(n.alias, out)
d.aliasDepth--
delete(d.aliases, n)
return good
}
@ -746,8 +788,7 @@ func (d *decoder) merge(n *node, out reflect.Value) {
case mappingNode:
d.unmarshal(n, out)
case aliasNode:
an, ok := d.doc.anchors[n.value]
if ok && an.kind != mappingNode {
if n.alias != nil && n.alias.kind != mappingNode {
failWantMap()
}
d.unmarshal(n, out)
@ -756,8 +797,7 @@ func (d *decoder) merge(n *node, out reflect.Value) {
for i := len(n.children) - 1; i >= 0; i-- {
ni := n.children[i]
if ni.kind == aliasNode {
an, ok := d.doc.anchors[ni.value]
if ok && an.kind != mappingNode {
if ni.alias != nil && ni.alias.kind != mappingNode {
failWantMap()
}
} else if ni.kind != mappingNode {

2
vendor/gopkg.in/yaml.v2/resolve.go generated vendored
View file

@ -81,7 +81,7 @@ func resolvableTag(tag string) bool {
return false
}
var yamlStyleFloat = regexp.MustCompile(`^[-+]?[0-9]*\.?[0-9]+([eE][-+][0-9]+)?$`)
var yamlStyleFloat = regexp.MustCompile(`^[-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?$`)
func resolve(tag string, in string) (rtag string, out interface{}) {
if !resolvableTag(tag) {

125
vendor/gopkg.in/yaml.v2/scannerc.go generated vendored
View file

@ -626,30 +626,17 @@ func trace(args ...interface{}) func() {
func yaml_parser_fetch_more_tokens(parser *yaml_parser_t) bool {
// While we need more tokens to fetch, do it.
for {
// Check if we really need to fetch more tokens.
need_more_tokens := false
if parser.tokens_head == len(parser.tokens) {
// Queue is empty.
need_more_tokens = true
} else {
// Check if any potential simple key may occupy the head position.
if !yaml_parser_stale_simple_keys(parser) {
if parser.tokens_head != len(parser.tokens) {
// If queue is non-empty, check if any potential simple key may
// occupy the head position.
head_tok_idx, ok := parser.simple_keys_by_tok[parser.tokens_parsed]
if !ok {
break
} else if valid, ok := yaml_simple_key_is_valid(parser, &parser.simple_keys[head_tok_idx]); !ok {
return false
} else if !valid {
break
}
for i := range parser.simple_keys {
simple_key := &parser.simple_keys[i]
if simple_key.possible && simple_key.token_number == parser.tokens_parsed {
need_more_tokens = true
break
}
}
}
// We are finished.
if !need_more_tokens {
break
}
// Fetch the next token.
if !yaml_parser_fetch_next_token(parser) {
@ -678,11 +665,6 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool {
return false
}
// Remove obsolete potential simple keys.
if !yaml_parser_stale_simple_keys(parser) {
return false
}
// Check the indentation level against the current column.
if !yaml_parser_unroll_indent(parser, parser.mark.column) {
return false
@ -837,29 +819,30 @@ func yaml_parser_fetch_next_token(parser *yaml_parser_t) bool {
"found character that cannot start any token")
}
// Check the list of potential simple keys and remove the positions that
// cannot contain simple keys anymore.
func yaml_parser_stale_simple_keys(parser *yaml_parser_t) bool {
// Check for a potential simple key for each flow level.
for i := range parser.simple_keys {
simple_key := &parser.simple_keys[i]
// The specification requires that a simple key
//
// - is limited to a single line,
// - is shorter than 1024 characters.
if simple_key.possible && (simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index) {
// Check if the potential simple key to be removed is required.
if simple_key.required {
return yaml_parser_set_scanner_error(parser,
"while scanning a simple key", simple_key.mark,
"could not find expected ':'")
}
simple_key.possible = false
}
func yaml_simple_key_is_valid(parser *yaml_parser_t, simple_key *yaml_simple_key_t) (valid, ok bool) {
if !simple_key.possible {
return false, true
}
return true
// The 1.2 specification says:
//
// "If the ? indicator is omitted, parsing needs to see past the
// implicit key to recognize it as such. To limit the amount of
// lookahead required, the “:” indicator must appear at most 1024
// Unicode characters beyond the start of the key. In addition, the key
// is restricted to a single line."
//
if simple_key.mark.line < parser.mark.line || simple_key.mark.index+1024 < parser.mark.index {
// Check if the potential simple key to be removed is required.
if simple_key.required {
return false, yaml_parser_set_scanner_error(parser,
"while scanning a simple key", simple_key.mark,
"could not find expected ':'")
}
simple_key.possible = false
return false, true
}
return true, true
}
// Check if a simple key may start at the current position and add it if
@ -879,13 +862,14 @@ func yaml_parser_save_simple_key(parser *yaml_parser_t) bool {
possible: true,
required: required,
token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
mark: parser.mark,
}
simple_key.mark = parser.mark
if !yaml_parser_remove_simple_key(parser) {
return false
}
parser.simple_keys[len(parser.simple_keys)-1] = simple_key
parser.simple_keys_by_tok[simple_key.token_number] = len(parser.simple_keys) - 1
}
return true
}
@ -900,19 +884,33 @@ func yaml_parser_remove_simple_key(parser *yaml_parser_t) bool {
"while scanning a simple key", parser.simple_keys[i].mark,
"could not find expected ':'")
}
// Remove the key from the stack.
parser.simple_keys[i].possible = false
delete(parser.simple_keys_by_tok, parser.simple_keys[i].token_number)
}
// Remove the key from the stack.
parser.simple_keys[i].possible = false
return true
}
// max_flow_level limits the flow_level
const max_flow_level = 10000
// Increase the flow level and resize the simple key list if needed.
func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
// Reset the simple key on the next level.
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{
possible: false,
required: false,
token_number: parser.tokens_parsed + (len(parser.tokens) - parser.tokens_head),
mark: parser.mark,
})
// Increase the flow level.
parser.flow_level++
if parser.flow_level > max_flow_level {
return yaml_parser_set_scanner_error(parser,
"while increasing flow level", parser.simple_keys[len(parser.simple_keys)-1].mark,
fmt.Sprintf("exceeded max depth of %d", max_flow_level))
}
return true
}
@ -920,11 +918,16 @@ func yaml_parser_increase_flow_level(parser *yaml_parser_t) bool {
func yaml_parser_decrease_flow_level(parser *yaml_parser_t) bool {
if parser.flow_level > 0 {
parser.flow_level--
parser.simple_keys = parser.simple_keys[:len(parser.simple_keys)-1]
last := len(parser.simple_keys) - 1
delete(parser.simple_keys_by_tok, parser.simple_keys[last].token_number)
parser.simple_keys = parser.simple_keys[:last]
}
return true
}
// max_indents limits the indents stack size
const max_indents = 10000
// Push the current indentation level to the stack and set the new level
// the current column is greater than the indentation level. In this case,
// append or insert the specified token into the token queue.
@ -939,6 +942,11 @@ func yaml_parser_roll_indent(parser *yaml_parser_t, column, number int, typ yaml
// indentation level.
parser.indents = append(parser.indents, parser.indent)
parser.indent = column
if len(parser.indents) > max_indents {
return yaml_parser_set_scanner_error(parser,
"while increasing indent level", parser.simple_keys[len(parser.simple_keys)-1].mark,
fmt.Sprintf("exceeded max depth of %d", max_indents))
}
// Create a token and insert it into the queue.
token := yaml_token_t{
@ -989,6 +997,8 @@ func yaml_parser_fetch_stream_start(parser *yaml_parser_t) bool {
// Initialize the simple key stack.
parser.simple_keys = append(parser.simple_keys, yaml_simple_key_t{})
parser.simple_keys_by_tok = make(map[int]int)
// A simple key is allowed at the beginning of the stream.
parser.simple_key_allowed = true
@ -1270,7 +1280,11 @@ func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
simple_key := &parser.simple_keys[len(parser.simple_keys)-1]
// Have we found a simple key?
if simple_key.possible {
if valid, ok := yaml_simple_key_is_valid(parser, simple_key); !ok {
return false
} else if valid {
// Create the KEY token and insert it into the queue.
token := yaml_token_t{
typ: yaml_KEY_TOKEN,
@ -1288,6 +1302,7 @@ func yaml_parser_fetch_value(parser *yaml_parser_t) bool {
// Remove the simple key.
simple_key.possible = false
delete(parser.simple_keys_by_tok, simple_key.token_number)
// A simple key cannot follow another simple key.
parser.simple_key_allowed = false

16
vendor/gopkg.in/yaml.v2/yaml.go generated vendored
View file

@ -89,7 +89,7 @@ func UnmarshalStrict(in []byte, out interface{}) (err error) {
return unmarshal(in, out, true)
}
// A Decorder reads and decodes YAML values from an input stream.
// A Decoder reads and decodes YAML values from an input stream.
type Decoder struct {
strict bool
parser *parser
@ -175,7 +175,7 @@ func unmarshal(in []byte, out interface{}, strict bool) (err error) {
// Zero valued structs will be omitted if all their public
// fields are zero, unless they implement an IsZero
// method (see the IsZeroer interface type), in which
// case the field will be included if that method returns true.
// case the field will be excluded if IsZero returns true.
//
// flow Marshal using a flow style (useful for structs,
// sequences and maps).
@ -464,3 +464,15 @@ func isZero(v reflect.Value) bool {
}
return false
}
// FutureLineWrap globally disables line wrapping when encoding long strings.
// This is a temporary and thus deprecated method introduced to faciliate
// migration towards v3, which offers more control of line lengths on
// individual encodings, and has a default matching the behavior introduced
// by this function.
//
// The default formatting of v2 was erroneously changed in v2.3.0 and reverted
// in v2.4.0, at which point this function was introduced to help migration.
func FutureLineWrap() {
disableLineWrapping = true
}

1
vendor/gopkg.in/yaml.v2/yamlh.go generated vendored
View file

@ -579,6 +579,7 @@ type yaml_parser_t struct {
simple_key_allowed bool // May a simple key occur at the current position?
simple_keys []yaml_simple_key_t // The stack of simple keys.
simple_keys_by_tok map[int]int // possible simple_key indexes indexed by token_number
// Parser stuff