Skip to content
This repository has been archived by the owner on Feb 15, 2024. It is now read-only.

Use native EZproxy support to terminate sessions #73

Merged
merged 1 commit into from
Jun 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/lint-and-build-code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ jobs:
- name: Build with (mostly) default options
# Note: We use the `-mod=vendor` flag to explicitly request that our
# top-level vendor folder be used instead of fetching remote packages
run: go build -v -mod=vendor ./cmd/brick
run: |
go build -v -mod=vendor ./cmd/brick
go build -v -mod=vendor ./cmd/es
go build -v -mod=vendor ./cmd/ezproxy

- name: Build using project Makefile
run: make all
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

# Linux binaries
/brick
/es
/ezproxy
/ezproxy-mock

# Local Visual Studio Code editor settings (e.g., ignored words for Spelling extension)
/.vscode
Expand Down
16 changes: 8 additions & 8 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
SHELL = /bin/bash

# Space-separated list of cmd/BINARY_NAME directories to build
WHAT = brick
WHAT = brick es ezproxy

# TODO: This will need to be standardized across all cmd files in order to
# work as intended.
Expand All @@ -53,7 +53,7 @@ GOLANGCI_LINT_VERSION = v1.27.0

# The default `go build` process embeds debugging information. Building
# without that debugging information reduces the binary size by around 28%.
BUILDCMD = go build -mod=vendor -a -ldflags="-s -w -X $(VERSION_VAR_PKG).version=$(VERSION)"
BUILDCMD = go build -mod=vendor -a -ldflags="-s -w -X $(VERSION_VAR_PKG).Version=$(VERSION)"
GOCLEANCMD = go clean -mod=vendor ./...
GITCLEANCMD = git clean -xfd
CHECKSUMCMD = sha256sum -b
Expand Down Expand Up @@ -149,11 +149,11 @@ windows:

@for target in $(WHAT); do \
mkdir -p $(OUTPUTDIR)/$$target && \
echo "Building 386 binaries" && \
echo "Building $$target 386 binary" && \
env GOOS=windows GOARCH=386 $(BUILDCMD) -o $(OUTPUTDIR)/$$target/$$target-$(VERSION)-windows-386.exe ${PWD}/cmd/$$target && \
echo "Building amd64 binaries" && \
echo "Building $$target amd64 binary" && \
env GOOS=windows GOARCH=amd64 $(BUILDCMD) -o $(OUTPUTDIR)/$$target/$$target-$(VERSION)-windows-amd64.exe ${PWD}/cmd/$$target && \
echo "Generating checksum files" && \
echo "Generating $$target checksum files" && \
$(CHECKSUMCMD) $(OUTPUTDIR)/$$target/$$target-$(VERSION)-windows-386.exe > $(OUTPUTDIR)/$$target/$$target-$(VERSION)-windows-386.exe.sha256 && \
$(CHECKSUMCMD) $(OUTPUTDIR)/$$target/$$target-$(VERSION)-windows-amd64.exe > $(OUTPUTDIR)/$$target/$$target-$(VERSION)-windows-amd64.exe.sha256; \
done
Expand All @@ -167,11 +167,11 @@ linux:

@for target in $(WHAT); do \
mkdir -p $(OUTPUTDIR)/$$target && \
echo "Building 386 binaries" && \
echo "Building $$target 386 binary" && \
env GOOS=linux GOARCH=386 $(BUILDCMD) -o $(OUTPUTDIR)/$$target/$$target-$(VERSION)-linux-386 ${PWD}/cmd/$$target && \
echo "Building amd64 binaries" && \
echo "Building $$target amd64 binary" && \
env GOOS=linux GOARCH=amd64 $(BUILDCMD) -o $(OUTPUTDIR)/$$target/$$target-$(VERSION)-linux-amd64 ${PWD}/cmd/$$target && \
echo "Generating checksum files" && \
echo "Generating $$target checksum files" && \
$(CHECKSUMCMD) $(OUTPUTDIR)/$$target/$$target-$(VERSION)-linux-386 > $(OUTPUTDIR)/$$target/$$target-$(VERSION)-linux-386.sha256 && \
$(CHECKSUMCMD) $(OUTPUTDIR)/$$target/$$target-$(VERSION)-linux-amd64 > $(OUTPUTDIR)/$$target/$$target-$(VERSION)-linux-amd64.sha256; \
done
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ Automatically disable EZproxy user accounts via incoming webhook requests.
<!-- omit in toc -->
## Table of contents

- [Project home](#project-home)
- [Status](#status)
- [Overview](#overview)
- [Project home](#project-home)
- [Features](#features)
- [Current](#current)
- [Missing](#missing)
Expand All @@ -28,6 +28,12 @@ Automatically disable EZproxy user accounts via incoming webhook requests.
- [License](#license)
- [References](#references)

## Project home

See [our GitHub repo](https://github.com/atc0005/brick) for the latest code,
to file an issue or submit improvements for review and potential inclusion
into the project.

## Status

Alpha quality; most
Expand Down Expand Up @@ -63,12 +69,6 @@ See also:
- [High-level overview](docs/start-here.md)
- our other [documentation](#documentation) for further instructions

## Project home

See [our GitHub repo](https://github.com/atc0005/brick) for the latest code,
to file an issue or submit improvements for review and potential inclusion
into the project.

## Features

### Current
Expand Down
91 changes: 45 additions & 46 deletions cmd/brick/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"time"
Expand Down Expand Up @@ -90,6 +91,11 @@ func disableUserHandler(
disabledUsers *files.DisabledUsers,
ignoredSources files.IgnoredSources,
notifyWorkQueue chan<- events.Record,
terminateSessions bool,
ezproxyActiveFilePath string,
ezproxySessionsSearchDelay int,
ezproxySessionSearchRetries int,
ezproxyExecutable string,
) http.HandlerFunc {

return func(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -121,9 +127,9 @@ func disableUserHandler(
// have the option of displaying it in a raw format (e.g.,
// troubleshooting), replace the Body with a new io.ReadCloser to
// allow later access to r.Body for JSON-decoding purposes
requestBody, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
requestBody, requestBodyReadErr := ioutil.ReadAll(r.Body)
if requestBodyReadErr != nil {
http.Error(w, requestBodyReadErr.Error(), http.StatusBadRequest)
return
}

Expand All @@ -135,8 +141,7 @@ func disableUserHandler(
// error, respond to the client with the error message and appropriate
// status code.
var payloadV2 events.SplunkAlertPayloadV2
err = json.NewDecoder(r.Body).Decode(&payloadV2)
if err != nil {
if err := json.NewDecoder(r.Body).Decode(&payloadV2); err != nil {
log.Errorf("Error decoding r.Body into payloadV2:\n%v\n\n", err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
Expand All @@ -154,8 +159,25 @@ func disableUserHandler(

}

// inform sender that the payload was received
fmt.Fprintln(w, "OK: Payload received")
// Explicitly confirm that the payload was received so that the sender
// can go ahead and disconnect. This prevents holding up the sender
// while this application performs further (unrelated from the
// sender's perspective) processing.
//
// FIXME: Is having a newline here best practice, or no?
if _, err := io.WriteString(w, "OK: Payload received\n"); err != nil {
log.Error("disableUserHandler: Failed to send OK status response to payload sender")
}

// Manually flush http.ResponseWriter in an additional effort to
// prevent undue wait time for payload sender
if f, ok := w.(http.Flusher); ok {
log.Debug("disableUserHandler: Manually flushing http.ResponseWriter")
f.Flush()
} else {
log.Warn("disableUserHandler: http.Flusher interface not available, cannot flush http.ResponseWriter")
log.Warn("disableUserHandler: Not flushing http.ResponseWriter may cause a noticeable delay between requests")
}

// if we made it this far, the payload checks out and we should be
// able to safely retrieve values that we need. We will also append
Expand All @@ -174,50 +196,27 @@ func disableUserHandler(
Headers: r.Header,
}

log.Debugf(
"disableUserHandler: Received disable request from %q for user %q from IP %q.",
alert.PayloadSenderIP,
alert.Username,
alert.UserIP,
)

// Send to Notification Manager for processing
record := events.Record{
Alert: alert,
Note: "disable request received",
}
go func() { notifyWorkQueue <- record }()

if err := files.ProcessEvent(
// All return values from subfunction calls are dropped into the
// notifyWorkQueue channel; nothing is returned here for further
// processing.
//
// NOTE: Because this is executed in a goroutine, the client (e.g.,
// monitoring system) gets a near-immediate response back and the
// connection is closed. There are probably other/better ways to
// achieve that specific result without using a goroutine, but the
// effect is worth noting for further exploration later.
go files.ProcessDisableEvent(
alert,
disabledUsers,
reportedUserEventsLog,
ignoredSources,
notifyWorkQueue,
); err != nil {

// TODO: Ensure that any errors bubble-up to *something* that will
// get the errors in front of us. A later step in this app's
// design is to expose errors via an endpoint so that monitoring
// systems like Nagios can poll for unresolved errors. Perhaps
// CRITICAL for failed writes, WARNING for writes pending a
// delayed retry (based on the assumption that a later re-check in
// the monitoring system will find the pending write no longer
// present, signaling an OK state).
log.Error(err.Error())

// FIXME: This is likely a duplicate of something handled further
// down?
go func() {
notifyWorkQueue <- events.Record{
Alert: alert,
Error: err,
Note: "ProcessEvent() failure",
}
}()

return
}
terminateSessions,
ezproxyActiveFilePath,
ezproxySessionsSearchDelay,
ezproxySessionSearchRetries,
ezproxyExecutable,
)

}
}
10 changes: 7 additions & 3 deletions cmd/brick/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,8 @@ func main() {
syscall.SIGTERM, // full restart
)

// Where events.EventRecord values will be sent for processing. We
// use a buffered channel in an effort to reduce the delay for client
// requests.
// Where events will be sent for processing. We use a buffered channel in
// an effort to reduce the delay for client requests.
notifyWorkQueue := make(chan events.Record, config.NotifyMgrQueueDepth)

// Create "notifications manager" function as persistent goroutine to
Expand Down Expand Up @@ -155,6 +154,11 @@ func main() {
disabledUsers,
ignoredSources,
notifyWorkQueue,
appConfig.EZproxyTerminateSessions(),
appConfig.EZproxyActiveFilePath(),
appConfig.EZproxySearchDelay(),
appConfig.EZproxySearchRetries(),
appConfig.EZproxyExecutablePath(),
),
)

Expand Down
Loading