func (c *client) CreateUser(u *User) (*User, error) {
	startURL, err := url.Parse(c.endpointURL.String())
	if err != nil {
		return nil, err
	}
	if u == nil {
		err = ErrUserNotSpecified
		return nil, err
	}
	startURL.Path = path.Join(startURL.Path, "/Users")
	resp, err := c.sendRequestWithBody(http.MethodPost, startURL.String(), *u)
	if err != nil {
		return nil, err
	}
	var newUser User
	err = json.Unmarshal(resp, &newUser)
	if err != nil {
		return nil, err
	}
	if newUser.ID == "" {
		return c.FindUserByEmail(u.Username)
	}
	return &newUser, nil
}
CreateUser will create the user specified
package aws
import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	log "github.com/sirupsen/logrus"
)
var (
	ErrUserNotFound      = errors.New("user not found")
	ErrGroupNotFound     = errors.New("group not found")
	ErrNoGroupsFound     = errors.New("no groups found")
	ErrUserNotSpecified  = errors.New("user not specified")
	ErrGroupNotSpecified = errors.New("group not specified")
)
type OperationType string
const (
	OperationAdd OperationType = "add"
	OperationRemove = "remove"
)
type Client interface {
	AddUserToGroup(*User, *Group) error
	CreateGroup(*Group) (*Group, error)
	CreateUser(*User) (*User, error)
	DeleteGroup(*Group) error
	DeleteUser(*User) error
	FindGroupByDisplayName(string) (*Group, error)
	FindUserByEmail(string) (*User, error)
	FindUserByID(string) (*User, error)
	GetUsers() ([]*User, error)
	GetGroupMembers(*Group) ([]*User, error)
	IsUserInGroup(*User, *Group) (bool, error)
	GetGroups() ([]*Group, error)
	UpdateUser(*User) (*User, error)
	RemoveUserFromGroup(*User, *Group) error
}
type client struct {
	httpClient  HttpClient
	endpointURL *url.URL
	bearerToken string
}
func NewClient(c HttpClient, config *Config) (Client, error) {
	u, err := url.Parse(config.Endpoint)
	if err != nil {
		return nil, err
	}
	return &client{
		httpClient:  c,
		endpointURL: u,
		bearerToken: config.Token,
	}, nil
}
func (c *client) sendRequestWithBody(method string, url string, body interface{}) (response []byte, err error) {
	d, err := json.Marshal(body)
	if err != nil {
		return
	}
	r, err := http.NewRequest(method, url, bytes.NewBuffer(d))
	if err != nil {
		return
	}
	log.WithFields(log.Fields{"url": url, "method": method})
	r.Header.Set("Content-Type", "application/scim+json")
	r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.bearerToken))
	resp, err := c.httpClient.Do(r)
	if err != nil {
		return
	}
	defer resp.Body.Close()
	response, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}
	if resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusNoContent {
		err = fmt.Errorf("status of http response was %d", resp.StatusCode)
	}
	return
}
func (c *client) sendRequest(method string, url string) (response []byte, err error) {
	r, err := http.NewRequest(method, url, nil)
	if err != nil {
		return
	}
	log.WithFields(log.Fields{"url": url, "method": method})
	r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.bearerToken))
	resp, err := c.httpClient.Do(r)
	if err != nil {
		return
	}
	defer resp.Body.Close()
	response, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return
	}
	if resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusNoContent {
		err = fmt.Errorf("status of http response was %d", resp.StatusCode)
	}
	return
}
func (c *client) IsUserInGroup(u *User, g *Group) (bool, error) {
	if g == nil {
		return false, ErrGroupNotSpecified
	}
	if u == nil {
		return false, ErrUserNotSpecified
	}
	startURL, err := url.Parse(c.endpointURL.String())
	if err != nil {
		return false, err
	}
	filter := fmt.Sprintf("id eq \"%s\" and members eq \"%s\"", g.ID, u.ID)
	startURL.Path = path.Join(startURL.Path, "/Groups")
	q := startURL.Query()
	q.Add("filter", filter)
	startURL.RawQuery = q.Encode()
	resp, err := c.sendRequest(http.MethodGet, startURL.String())
	if err != nil {
		return false, err
	}
	var r GroupFilterResults
	err = json.Unmarshal(resp, &r)
	if err != nil {
		return false, err
	}
	return r.TotalResults > 0, nil
}
func (c *client) groupChangeOperation(op OperationType, u *User, g *Group) error {
	if g == nil {
		return ErrGroupNotSpecified
	}
	if u == nil {
		return ErrUserNotSpecified
	}
	log.WithFields(log.Fields{"operations": op, "user": u.Username, "group": g.DisplayName}).Debug("Group Change")
	gc := &GroupMemberChange{
		Schemas: []string{"urn:ietf:params:scim:api:messages:2.0:PatchOp"},
		Operations: []GroupMemberChangeOperation{
			{
				Operation: string(op),
				Path:      "members",
				Members: []GroupMemberChangeMember{
					{Value: u.ID},
				},
			},
		},
	}
	startURL, err := url.Parse(c.endpointURL.String())
	if err != nil {
		return err
	}
	startURL.Path = path.Join(startURL.Path, fmt.Sprintf("/Groups/%s", g.ID))
	_, err = c.sendRequestWithBody(http.MethodPatch, startURL.String(), *gc)
	if err != nil {
		return err
	}
	return nil
}
func (c *client) AddUserToGroup(u *User, g *Group) error {
	return c.groupChangeOperation(OperationAdd, u, g)
}
func (c *client) RemoveUserFromGroup(u *User, g *Group) error {
	return c.groupChangeOperation(OperationRemove, u, g)
}
func (c *client) FindUserByEmail(email string) (*User, error) {
	startURL, err := url.Parse(c.endpointURL.String())
	if err != nil {
		return nil, err
	}
	filter := fmt.Sprintf("userName eq \"%s\"", email)
	startURL.Path = path.Join(startURL.Path, "/Users")
	q := startURL.Query()
	q.Add("filter", filter)
	startURL.RawQuery = q.Encode()
	resp, err := c.sendRequest(http.MethodGet, startURL.String())
	if err != nil {
		return nil, err
	}
	var r UserFilterResults
	err = json.Unmarshal(resp, &r)
	if err != nil {
		return nil, err
	}
	if r.TotalResults != 1 {
		return nil, ErrUserNotFound
	}
	return &r.Resources[0], nil
}
func (c *client) FindUserByID(id string) (*User, error) {
	startURL, err := url.Parse(c.endpointURL.String())
	if err != nil {
		return nil, err
	}
	startURL.Path = path.Join(startURL.Path, fmt.Sprintf("/Users/%s", id))
	resp, err := c.sendRequest(http.MethodGet, startURL.String())
	if err != nil {
		return nil, err
	}
	var r UserFilterResults
	err = json.Unmarshal(resp, &r)
	if err != nil {
		return nil, err
	}
	if r.TotalResults != 1 {
		return nil, ErrUserNotFound
	}
	return &r.Resources[0], nil
}
func (c *client) FindGroupByDisplayName(name string) (*Group, error) {
	startURL, err := url.Parse(c.endpointURL.String())
	if err != nil {
		return nil, err
	}
	filter := fmt.Sprintf("displayName eq \"%s\"", name)
	startURL.Path = path.Join(startURL.Path, "/Groups")
	q := startURL.Query()
	q.Add("filter", filter)
	startURL.RawQuery = q.Encode()
	resp, err := c.sendRequest(http.MethodGet, startURL.String())
	if err != nil {
		return nil, err
	}
	var r GroupFilterResults
	err = json.Unmarshal(resp, &r)
	if err != nil {
		return nil, err
	}
	if r.TotalResults != 1 {
		return nil, ErrGroupNotFound
	}
	return &r.Resources[0], nil
}