Skip to content

Commit 674fd8d

Browse files
authored
Merge pull request #60 from hazcod/feat/ws1/oauth2
Switch Workspace ONE integration to oauth2
2 parents 81d49db + 64d5972 commit 674fd8d

File tree

4 files changed

+42
-29
lines changed

4 files changed

+42
-29
lines changed

Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
all: run
2+
13
clean:
24
rm slacker || true
35

@@ -6,5 +8,4 @@ build:
68
chmod +x slacker
79

810
run:
9-
chmod +x slacker
10-
./slacker -dry -config=test.yml
11+
go run ./cmd/ -dry -config=test.yml -noreport -log=trace

README.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,15 @@ falcon:
5454

5555
# vmware workspace one
5656
ws1:
57+
# the api endpoint of your Workspace ONE instance, eg. "https://asXXXX.awmdm.com/api/"
5758
api_url: "https://xxx.awmdm.com/api/"
58-
api_key: "XXX"
59-
user: "XXX"
60-
password: "XXX"
59+
# your Workspace ONE oauth2 credentials
60+
# Groups & Settings > Configurations > Search for "oauth" > Click > Add with a Reader role
61+
client_id: "XXX"
62+
client_secret: "XXX"
63+
# the location of your Workspace ONE tenant, see 'Region-specific Token URLs'
64+
# https://docs.vmware.com/en/VMware-Workspace-ONE-UEM/services/UEM_ConsoleBasics/GUID-BF20C949-5065-4DCF-889D-1E0151016B5A.html
65+
auth_location: "emea"
6166
# what policies you want to skip
6267
# leave user or policy blank to ignore it
6368
skip:
@@ -135,6 +140,6 @@ templates:
135140
{{ end }}
136141
{{ end }}
137142
```
138-
4. Run `css -config=your-config.yml -log=debug -dry` to test.
139-
5. See the security overview popup to you in Slack!
140-
6. Now run it for real with `css -config=your-config.yml`.
143+
7. Run `css -config=your-config.yml -log=debug -dry` to test.
144+
8. See the security overview popup to you in Slack!
145+
9. Now run it for real with `css -config=your-config.yml`.

config/config.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ type Config struct {
3535

3636
WS1 struct {
3737
Endpoint string `yaml:"api_url" env:"WS1_API_URL"`
38-
APIKey string `yaml:"api_key" env:"WS1_API_KEY"`
39-
User string `yaml:"user" env:"WS1_USER"`
40-
Password string `yaml:"password" env:"WS1_PASSWORD"`
38+
// from https://docs.vmware.com/en/VMware-Workspace-ONE-UEM/services/UEM_ConsoleBasics/GUID-BF20C949-5065-4DCF-889D-1E0151016B5A.html
39+
// e.g. 'emea'
40+
AuthLocation string `yaml:"auth_location" env:"WS1_AUTH_LOCATION"`
41+
ClientID string `yaml:"client_id" env:"WS1_CLIENT_ID"`
42+
ClientSecret string `yaml:"client_secret" env:"WS1_CLIENT_SECRET"`
4143

4244
SkipFilters []struct {
4345
Policy string `yaml:"policy"`
@@ -104,5 +106,13 @@ func (c *Config) Validate() error {
104106
return errors.New("missing message")
105107
}
106108

109+
if c.WS1.ClientSecret == "" || c.WS1.ClientID == "" {
110+
return errors.New("missing WS1 client_id or client_secret")
111+
}
112+
113+
if c.WS1.AuthLocation == "" {
114+
return errors.New("missing WS1 auth_location")
115+
}
116+
107117
return nil
108118
}

pkg/ws1/extractor.go

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ package ws1
33
import (
44
"bytes"
55
"context"
6-
"encoding/base64"
76
"encoding/json"
7+
"fmt"
88
"github.com/hazcod/crowdstrike-spotlight-slacker/config"
99
"github.com/pkg/errors"
1010
"github.com/sirupsen/logrus"
11-
"io/ioutil"
11+
"golang.org/x/oauth2/clientcredentials"
12+
"io"
1213
"net/http"
1314
"strconv"
1415
"strings"
@@ -31,46 +32,41 @@ type UserDeviceFinding struct {
3132
ComplianceName string
3233
}
3334

34-
func basicAuth(username, password string) string {
35-
auth := username + ":" + password
36-
return base64.StdEncoding.EncodeToString([]byte(auth))
37-
}
38-
39-
func doAuthRequest(user, pass, apiKey, url, method string, payload interface{}) (respBytes []byte, err error) {
35+
func doAuthRequest(ctx context.Context, ws1AuthLocation, clientID, secret, url, method string, payload interface{}) (respBytes []byte, err error) {
4036
var reqPayload []byte
4137
if payload != nil {
4238
if reqPayload, err = json.Marshal(&payload); err != nil {
4339
return nil, errors.Wrap(err, "coult not encode request body")
4440
}
4541
}
4642

43+
oauth2Config := clientcredentials.Config{ClientID: clientID, ClientSecret: secret,
44+
TokenURL: fmt.Sprintf("https://%s.uemauth.vmwservices.com/connect/token", ws1AuthLocation)}
45+
httpClient := oauth2Config.Client(ctx)
46+
httpClient.Timeout = time.Second * 10
47+
4748
req, err := http.NewRequest(method, url, bytes.NewReader(reqPayload))
49+
req = req.WithContext(ctx)
4850
if err != nil {
4951
return nil, errors.Wrap(err, "request failed")
5052
}
5153

5254
req.Header.Set("Accept", "application/json")
53-
req.Header.Set("aw-tenant-code", apiKey)
54-
req.Header.Set("Authorization", "Basic "+basicAuth(user, pass))
55-
56-
httpClient := http.Client{
57-
Timeout: time.Second * 10,
58-
}
5955

6056
resp, err := httpClient.Do(req)
6157
if err != nil {
6258
return nil, errors.Wrap(err, "http request failed")
6359
}
6460

6561
if resp.StatusCode > 399 {
66-
respB, _ := ioutil.ReadAll(resp.Body)
62+
respB, _ := io.ReadAll(resp.Body)
6763
logrus.WithField("response", string(respB)).Warn("invalid response")
6864
return nil, errors.New("invalid response code: " + strconv.Itoa(resp.StatusCode))
6965
}
7066

7167
defer resp.Body.Close()
7268

73-
if respBytes, err = ioutil.ReadAll(resp.Body); err != nil {
69+
if respBytes, err = io.ReadAll(resp.Body); err != nil {
7470
return nil, errors.New("could not read response body")
7571
}
7672

@@ -79,7 +75,8 @@ func doAuthRequest(user, pass, apiKey, url, method string, payload interface{})
7975

8076
func GetMessages(config *config.Config, ctx context.Context) (map[string]WS1Result, []string, error) {
8177
deviceResponseB, err := doAuthRequest(
82-
config.WS1.User, config.WS1.Password, config.WS1.APIKey,
78+
ctx,
79+
config.WS1.AuthLocation, config.WS1.ClientID, config.WS1.ClientSecret,
8380
strings.TrimRight(config.WS1.Endpoint, "/")+"/mdm/devices/search?compliance_status=NonCompliant",
8481
http.MethodGet,
8582
nil,
@@ -89,7 +86,7 @@ func GetMessages(config *config.Config, ctx context.Context) (map[string]WS1Resu
8986
return nil, nil, errors.Wrap(err, "could not fetch WS1 devices")
9087
}
9188

92-
usersWithDevices := []string{}
89+
usersWithDevices := make([]string, 0)
9390

9491
var devicesResponse DevicesResponse
9592
if err := json.Unmarshal(deviceResponseB, &devicesResponse); err != nil {

0 commit comments

Comments
 (0)