webdav: parse and return sharepoint error response

fixes #3176
This commit is contained in:
Henning Surmeier 2019-10-02 15:05:40 +02:00 committed by Nick Craig-Wood
parent 15b1feea9d
commit eff11b44cf

View File

@ -5,6 +5,7 @@ import (
"bytes"
"context"
"encoding/xml"
"fmt"
"html/template"
"net/http"
"net/http/cookiejar"
@ -32,13 +33,13 @@ type CookieResponse struct {
FedAuth http.Cookie
}
// SuccessResponse hold a response from the sharepoint webdav
type SuccessResponse struct {
// SharepointSuccessResponse holds a response from a successful microsoft login
type SharepointSuccessResponse struct {
XMLName xml.Name `xml:"Envelope"`
Succ SuccessResponseBody `xml:"Body"`
Body SuccessResponseBody `xml:"Body"`
}
// SuccessResponseBody is the body of a success response, it holds the token
// SuccessResponseBody is the body of a successful response, it holds the token
type SuccessResponseBody struct {
XMLName xml.Name
Type string `xml:"RequestSecurityTokenResponse>TokenType"`
@ -47,6 +48,24 @@ type SuccessResponseBody struct {
Token string `xml:"RequestSecurityTokenResponse>RequestedSecurityToken>BinarySecurityToken"`
}
// SharepointError holds a error response microsoft login
type SharepointError struct {
XMLName xml.Name `xml:"Envelope"`
Body ErrorResponseBody `xml:"Body"`
}
func (e *SharepointError) Error() string {
return fmt.Sprintf("%s: %s (%s)", e.Body.FaultCode, e.Body.Reason, e.Body.Detail)
}
// ErrorResponseBody contains the body of a erroneous repsonse
type ErrorResponseBody struct {
XMLName xml.Name
FaultCode string `xml:"Fault>Code>Subcode>Value"`
Reason string `xml:"Fault>Reason>Text"`
Detail string `xml:"Fault>Detail>error>internalerror>text"`
}
// reqString is a template that gets populated with the user data in order to retrieve a "BinarySecurityToken"
const reqString = `<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing"
@ -100,7 +119,7 @@ func (ca *CookieAuth) Cookies(ctx context.Context) (*CookieResponse, error) {
return ca.getSPCookie(tokenResp)
}
func (ca *CookieAuth) getSPCookie(conf *SuccessResponse) (*CookieResponse, error) {
func (ca *CookieAuth) getSPCookie(conf *SharepointSuccessResponse) (*CookieResponse, error) {
spRoot, err := url.Parse(ca.endpoint)
if err != nil {
return nil, errors.Wrap(err, "Error while constructing endpoint URL")
@ -123,7 +142,7 @@ func (ca *CookieAuth) getSPCookie(conf *SuccessResponse) (*CookieResponse, error
}
// Send the previously acquired Token as a Post parameter
if _, err = client.Post(u.String(), "text/xml", strings.NewReader(conf.Succ.Token)); err != nil {
if _, err = client.Post(u.String(), "text/xml", strings.NewReader(conf.Body.Token)); err != nil {
return nil, errors.Wrap(err, "Error while grabbing cookies from endpoint: %v")
}
@ -141,7 +160,7 @@ func (ca *CookieAuth) getSPCookie(conf *SuccessResponse) (*CookieResponse, error
return &cookieResponse, nil
}
func (ca *CookieAuth) getSPToken(ctx context.Context) (conf *SuccessResponse, err error) {
func (ca *CookieAuth) getSPToken(ctx context.Context) (conf *SharepointSuccessResponse, err error) {
reqData := map[string]interface{}{
"Username": ca.user,
"Password": ca.pass,
@ -177,12 +196,21 @@ func (ca *CookieAuth) getSPToken(ctx context.Context) (conf *SuccessResponse, er
}
s := respBuf.Bytes()
conf = &SuccessResponse{}
conf = &SharepointSuccessResponse{}
err = xml.Unmarshal(s, conf)
if err != nil {
// FIXME: Try to parse with FailedResponse struct (check for server error code)
return nil, errors.Wrap(err, "Error while reading endpoint response")
if conf.Body.Token == "" {
// xml Unmarshal won't fail if the response doesn't contain a token
// However, the token will be empty
sErr := &SharepointError{}
errSErr := xml.Unmarshal(s, sErr)
if errSErr == nil {
return nil, sErr
}
}
if err != nil {
return nil, errors.Wrap(err, "Error while reading endpoint response")
}
return
}