Skip to content

Commit

Permalink
Merge pull request #3 from willhackett/alpha/service-discovery
Browse files Browse the repository at this point in the history
Alpha/service discovery
  • Loading branch information
willhackett authored May 18, 2020
2 parents 3723b8f + 6665565 commit f063148
Show file tree
Hide file tree
Showing 26 changed files with 1,212 additions and 57 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@
vendor/

# Output binary
oauth-revokerd
oauth-revokerd

# Plugins
olric-cloud-plugin.so
2 changes: 1 addition & 1 deletion .releaserc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"branches": ["master"],
"branches": ["master", {"name": "alpha", "prerelease": true}],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
Expand Down
7 changes: 5 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ FROM golang:1.14-alpine AS build-env
WORKDIR /var/app
COPY . /var/app

RUN go build -o ./oauth-revokerd -ldflags "-X main.tag=$TAG" .
RUN CGO_ENABLED=0 \
go build \
-ldflags "-X main.tag=$TAG" \
-o oauth-revokerd .

###

Expand All @@ -15,5 +18,5 @@ RUN apk --no-cache add ca-certificates
WORKDIR /root
COPY --from=build-env /var/app/oauth-revokerd .

EXPOSE 8080
EXPOSE 8080 3320 3322
CMD ./oauth-revokerd
201 changes: 201 additions & 0 deletions app/api/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
package api

import (
"fmt"
"io"
"net/http"
"strconv"
"time"

"github.com/gorilla/mux"
log "github.com/sirupsen/logrus"
"github.com/willhackett/oauth-revokerd/app/filter"

"github.com/willhackett/oauth-revokerd/app/cache"
"github.com/willhackett/oauth-revokerd/app/config"
)

const (
errInvalidMethod = "Unsupported method"
errNotFound = "Record not found"
errUnableToProcessPayload = "Unable to process payload"
)

// API produces the methods for the the REST API
type API struct {
cache *cache.Cache
config config.Configuration
logger *log.Entry
}

func (api *API) handlePostRevocation(w http.ResponseWriter, req *http.Request) {
err := req.ParseForm()

if err != nil {
api.resolve(req, w, http.StatusBadRequest, "Cannot parse form body")
return
}

form := req.Form
jti := form.Get("jti")
expiresIn, err := strconv.ParseInt(form.Get("expires_in"), 10, 64)

if err != nil {
api.resolve(req, w, http.StatusBadRequest, "`expires_in` must be a number of seconds until the record should expire")
return
}

if jti == "" {
api.resolve(req, w, http.StatusBadRequest, "Body must include `jti` and `expires_in` values")
return
}

expiresInDuration := time.Duration(expiresIn) * time.Second

err = api.cache.Put(jti, expiresInDuration)

if err != nil {
api.resolve(req, w, http.StatusInternalServerError, "Failed to write resource")
return
}

api.resolve(req, w, http.StatusCreated, "Created")
return
}

func (api *API) handleGetRevocation(w http.ResponseWriter, req *http.Request) {
jti := req.URL.Path[len("/revocations/"):]

if jti == "" {
api.resolve(req, w, http.StatusBadRequest, "Missing `jti` from path")
return
}

expiresAt, err := api.cache.Get(jti)

if err != nil {
api.resolve(req, w, http.StatusNotFound, errNotFound)
return
}

api.resolve(req, w, http.StatusNoContent, "`jti` revocation expires at "+expiresAt.Local().String())
}

func (api *API) handlePutRevocation(w http.ResponseWriter, req *http.Request) {

w.WriteHeader(http.StatusNoContent)
io.WriteString(w, "Hello")

}

func (api *API) handleDeleteRevocation(w http.ResponseWriter, req *http.Request) {

w.WriteHeader(http.StatusNoContent)
io.WriteString(w, "Hello")

}

func (api *API) handleGetFilter(w http.ResponseWriter, req *http.Request) {
total, err := api.cache.Count()
if err != nil {
api.resolve(req, w, http.StatusInternalServerError, fmt.Sprintf("Failed to get count: %s", err.Error()))
return
}

bf, err := filter.New(total, 0.85)
if err != nil {
api.resolve(req, w, http.StatusInternalServerError, fmt.Sprintf("Failed to create filter: %s", err.Error()))
return
}

err = api.cache.Query(func(jti string) {
bf.Add([]byte(jti))
})

if err != nil {
api.resolve(req, w, http.StatusInternalServerError, fmt.Sprintf("Failed to populate filter: %s", err.Error()))
return
}

export, err := bf.Export()
if err != nil {
api.resolve(req, w, http.StatusInternalServerError, fmt.Sprintf("Failed to export filter: %s", err.Error()))
return
}

w.WriteHeader(http.StatusOK)
_, err = w.Write(export)
api.log(req, http.StatusOK, "Filter Supplied")
if err != nil {
api.resolve(req, w, http.StatusInternalServerError, fmt.Sprintf("Failed to write response: %s", err.Error()))
return
}
}

func (api *API) handleGetCount(w http.ResponseWriter, req *http.Request) {
count, err := api.cache.Count()
if err != nil {
api.resolve(req, w, http.StatusInternalServerError, err.Error())
return
}

api.resolve(req, w, http.StatusOK, strconv.Itoa(count))
}

func (api *API) log(req *http.Request, status int, message string) {
fields := log.Fields{
"path": req.URL.Path,
"x-request-id": req.Header.Get("x-request-id"),
"status": status,
"message": message,
}

log := api.logger.WithFields(fields)

switch true {
case status >= 500:
log.Error()
return
case status >= 400:
log.Warn()
return
default:
log.Info()
return
}
}

func (api *API) resolve(req *http.Request, w http.ResponseWriter, status int, message string) {
api.log(req, status, message)
w.WriteHeader(status)
io.WriteString(w, message)
}

// Init starts the server
func Init(config config.Configuration, cache *cache.Cache) {
logger := log.WithFields(log.Fields{
"name": "oauth-revokerd",
})

api := API{
cache,
config,
logger,
}

router := mux.NewRouter()

router.HandleFunc("/filter", api.handleGetFilter).Methods("GET")
router.HandleFunc("/count", api.handleGetCount).Methods("GET")
router.HandleFunc("/revocations", api.handlePostRevocation).Methods("POST")
router.HandleFunc("/revocations/{id}", api.handleGetRevocation).Methods("GET")
router.HandleFunc("/revocations/{id}", api.handlePutRevocation).Methods("PUT")
router.HandleFunc("/revocations/{id}", api.handleDeleteRevocation).Methods("DELETE")

portString := strconv.Itoa(api.config.Port)

http.Handle("/", router)

log.Println("API available at http://127.0.0.1:" + portString + "/")
log.Fatal(http.ListenAndServe(":"+portString, nil))
}
49 changes: 0 additions & 49 deletions app/api/main.go

This file was deleted.

Loading

0 comments on commit f063148

Please sign in to comment.