soap

package module
v0.0.0-...-0a0ec81 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 5, 2023 License: MPL-2.0 Imports: 22 Imported by: 0

README

gosoap

This library provides primitives for operating on a SOAP-based web service. The library supports encrypting the SOAP request using the WS-Security x.509 protocol, enabling SOAP calls against secured web services.

A basic example usage would be as follows:

include (
    "context"
    "github.com/Enflick/gosoap"
)

main() {
	var (
		certFile = flag.String("cert", "", "A PEM encoded cert file")
		keyFile  = flag.String("key", "", "A PEM encoded key file")
	)

	flag.Parse()

	wsseInfo, authErr := soap.NewWSSEAuthInfo(*certFile, *keyFile)
	if authErr != nil {
		fmt.Printf("Auth error: %s\n", authErr.Error())
		return
	}
	
	// Setup your request structure
	// ...
	//

    // Create the SOAP request
    // call.action is the SOAP action (i.e. method name)
    // service.url is the fully qualified path to the SOAP endpoint
    // call.requestData is the structure mapping to the SOAP request
    // call.ResponseData is an output structure mapping to the SOAP response
    // call.FaultData is an output structure mapping to the SOAP fault details
    soapReq := soap.NewRequest(call.action, service.url, call.requestData, call.ResponseData, call.FaultData)
    
    // Potentially add custom headers
    soapReq.AddHeader(...)
    soapReq.AddHeader(...)
    
    // Sign the request
    soapReq.SignWith(wsseInfo)
    
    // Create the SOAP client
    soapClient := soap.NewClient(&http.Client{})
    
    // Make the request
    soapResp, err := soapClient.Do(context.Background(), soapReq)
	if err != nil {
		fmt.Printf("Unable to validate: %s\n", err.Error())
		return
	} else if soapResp.StatusCode != http.StatusOK {
		fmt.Printf("Unable to validate (status code invalid): %d\n", soapResp.StatusCode)
		return
	} else if soapResp.Fault() != nil {
		fmt.Printf("SOAP fault experienced during call: %s\n", soapResp.Fault().Error())
		// We can access the FaultData struct passed in for a type-safe way to get at the details.
		return
	}
	
	// Now we can handle the response itself.
	// Do our custom processing
	// ...
	//
	
	fmt.Printf("Done!\n")
}

The code is very loosely based off the SOAP client that is part of the https://github.com/hooklift/gowsdl project.

See https://github.com/rmrobinson-textnow/gowsdl for a heavily forked version of the above gowsdl project that auto-generates code from WSDL files that uses this library for performing the SOAP requests.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidPEMFileSpecified is returned if the PEM file specified for WS signing is invalid
	ErrInvalidPEMFileSpecified = errors.New("invalid PEM key specified")
	// ErrEncryptedPEMFileSpecified is returnedd if the PEM file specified for WS signing is encrypted
	ErrEncryptedPEMFileSpecified = errors.New("encrypted PEM key specified")
	// ErrUnsupportedContentType is returned if we encounter a non-supported content type while querying
	ErrUnsupportedContentType = errors.New("unsupported content-type in response")
	// ErrTLSPrivateKeyDoesNotMatchPublicKey is returned if the private key does not match the public key
	ErrTLSPrivateKeyDoesNotMatchPublicKey = errors.New("tls: private key does not match public key")
)
View Source
var (
	// ErrUnableToSignEmptyEnvelope is returned if the envelope to be signed is empty. This is not valid.
	ErrUnableToSignEmptyEnvelope = errors.New("unable to sign, envelope is empty")
	// ErrEnvelopeMisconfigured is returned if we attempt to deserialize a SOAP envelope without a type to deserialize the body or fault into.
	ErrEnvelopeMisconfigured = errors.New("envelope content or fault pointer empty")
)
View Source
var (
	// ErrMultipartBodyEmpty is returned if a multi-part body that is empty is discovered
	ErrMultipartBodyEmpty = errors.New("multi-part body is empty")
	// ErrCannotSetBytesElement is an internal error that suggests our parse tree is malformed
	ErrCannotSetBytesElement = errors.New("cannot set the bytes element")
	// ErrMissingXOPPart is returned if the decoded body was missing the XOP header
	ErrMissingXOPPart = errors.New("did not find an xop part for this multipart message")
)
View Source
var (
	// ErrFaultDetailPresentButNotSpecified is returned if the SOAP Fault details element is present but
	// the fault was not constructed with a type for it.
	ErrFaultDetailPresentButNotSpecified = errors.New("fault detail element present but no type supplied")
)

Functions

This section is empty.

Types

type Body

type Body struct {
	// XMLName is the serialized name of this object.
	XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`

	// XMLNSWsu is the SOAP WS-Security utility namespace.
	XMLNSWsu string `xml:"xmlns:wsu,attr,omitempty"`
	// ID is a body ID used during WS-Security signing.
	ID string `xml:"wsu:Id,attr,omitempty"`

	// Fault is a SOAP fault we may detect in a response.
	Fault *Fault `xml:",omitempty"`
	// Body is a SOAP request or response body.
	Content interface{} `xml:",omitempty"`
}

Body is a SOAP envelope body.

func (*Body) UnmarshalXML

func (b *Body) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML is an overridden deserialization routine used to decode a SOAP envelope body. The elements are read from the decoder d, starting at the element start. The contents of the decode are stored in the invoking body b. Any errors encountered are returned.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is an opaque handle to a SOAP service.

func NewClient

func NewClient(http *http.Client) *Client

NewClient creates a new Client that will access a SOAP service. Requests made using this client will all be wrapped in a SOAP envelope. See https://www.w3schools.com/xml/xml_soap.asp for more details. The default HTTP client used has no timeout nor circuit breaking. Override with SettHTTPClient. You have been warned.

func (*Client) Do

func (c *Client) Do(ctx context.Context, req *Request) (*Response, error)

Do invokes the SOAP request using its internal parameters. The request argument is serialized to XML, and if the call is successful the received XML is deserialized into the response argument. Any errors that are encountered are returned. If a SOAP fault is detected, then the 'details' property of the SOAP envelope will be deserialized into the faultDetailType argument.

type Envelope

type Envelope struct {
	// XMLName is the serialized name of this object.
	XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Envelope"`

	// These are generic namespaces used by all messages.
	XMLNSXsd string `xml:"xmlns:xsd,attr,omitempty"`
	XMLNSXsi string `xml:"xmlns:xsi,attr,omitempty"`

	Header *Header
	Body   *Body
}

Envelope is a SOAP envelope.

func NewEnvelope

func NewEnvelope(content interface{}) *Envelope

NewEnvelope creates a new SOAP Envelope with the specified data as the content to serialize or deserialize. It defaults to a fault struct with no detail type. Headers are assumed to be omitted unless explicitly added via AddHeaders()

func NewEnvelopeWithFault

func NewEnvelopeWithFault(content interface{}, faultDetail interface{}) *Envelope

NewEnvelopeWithFault creates a new SOAP Envelope with the specified data as the content to serialize or deserialize. It uses the supplied fault detail struct when deserializing a potential SOAP fault. Headers are assumed to be omitted unless explicitly added via AddHeaders()

func (*Envelope) AddHeaders

func (e *Envelope) AddHeaders(elems ...interface{})

AddHeaders adds additional headers to be serialized to the resulting SOAP envelope.

type Fault

type Fault struct {
	// XMLName is the serialized name of this object.
	XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault"`

	Code   string `xml:"faultcode,omitempty"`
	String string `xml:"faultstring,omitempty"`
	Actor  string `xml:"faultactor,omitempty"`

	// DetailInternal is a handle to the internal fault detail type. Do not directly access;
	// this is made public only to allow for XML deserialization.
	// Use the Detail() method instead.
	DetailInternal *faultDetail `xml:"detail,omitempty"`
}

Fault is a SOAP fault code.

func NewFault

func NewFault() *Fault

NewFault returns a new XML fault struct

func NewFaultWithDetail

func NewFaultWithDetail(detail interface{}) *Fault

NewFaultWithDetail returns a new XML fault struct with a specified DetailInternal field

func (*Fault) Detail

func (f *Fault) Detail() interface{}

Detail exposes the type supplied during creation (if a type was supplied).

func (*Fault) Error

func (f *Fault) Error() string

Error satisfies the Error() interface allowing us to return a fault as an error.

type Header struct {
	// XMLName is the serialized name of this object.
	XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Header"`

	// Headers is an array of envelope headers to send.
	Headers []interface{} `xml:",omitempty"`
}

Header is a SOAP envelope header.

type Request

type Request struct {
	// contains filtered or unexported fields
}

Request represents a single request to a SOAP service.

func NewRequest

func NewRequest(action string, url string, body interface{}, respType interface{}, faultType interface{}) *Request

NewRequest creates a SOAP request. This differs from a standard HTTP request in several ways. First, the SOAP library takes care of handling the envelope, so when the request is created the response and fault types are supplied so they can be properly parsed during envelope handling. Second, since we may perform WSSE signing on the request we do not supply a reader, instead the body is supplied here. If signing is desired, set the WSSE credentials on the request before passing it to the Client. NOTE: if custom SOAP headers are going to be supplied, they must be added before signing.

func (*Request) AddHeader

func (r *Request) AddHeader(header interface{})

AddHeader adds the header argument to the list of elements set in the SOAP envelope Header element. This will be serialized to XML when the request is made to the service.

func (*Request) SignWith

func (r *Request) SignWith(wsseInfo *WSSEAuthInfo)

SignWith supplies the authentication data to use for signing.

type Response

type Response struct {
	*http.Response
	// contains filtered or unexported fields
}

Response contains the result of the request.

func (*Response) Body

func (r *Response) Body() interface{}

Body returns the SOAP body. The value comes from what was passed into the linked request.

func (*Response) Fault

func (r *Response) Fault() *Fault

Fault returns the SOAP fault encountered, if present

type WSSEAuthIDs

type WSSEAuthIDs struct {
	// contains filtered or unexported fields
}

WSSEAuthIDs contains generated IDs used in WS-Security X.509 signing.

type WSSEAuthInfo

type WSSEAuthInfo struct {
	// contains filtered or unexported fields
}

WSSEAuthInfo contains the information required to use WS-Security X.509 signing.

func NewWSSEAuthInfo

func NewWSSEAuthInfo(certPath string, keyPath string) (*WSSEAuthInfo, error)

NewWSSEAuthInfo retrieves the supplied certificate path and key path for signing SOAP requests. These requests will be secured using the WS-Security X.509 security standard. If the supplied certificate path does not point to a DER-encoded X.509 certificate, or if the supplied key path does not point to a PEM-encoded X.509 certificate, an error will be returned.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL