Git Product home page Git Product logo

future-wru's Introduction

WRU: who are you

wru logo

WRU is an identity aware reverse proxy/middleware for enterprise users. It provides seamless authentication experience between development environemnt and production environment.

What is WRU for

  • For enterprise users

    • Easy to inject users via CSV files on storage (local, AWS S3, GCP Cloud Storage)
  • Not For consumer service users

    • It is not supporting creating user
  • For testing

    • Inject user information from env vars/files. You can setup via Docker easily
    • No password required (E2E test friendly)
  • For production

    • It supports OpenID Connect, some SNS (Twitter and GitHub for now) to login.

Use as Reverse Proxy

Getting Started

You can get wru by "go get".

$ go get -u	github.com/future-architect/future-wru/cmd/wru
$ wru
Port: 8000
TLS: enabled
Debug: false
Forward To:
  / => http://localhost:8080 ()
Twitter Login: OK
GitHub Login: OK
Users (for Debug):
  (User) 'test user 1'(user1) @ R&D (scopes: admin, user, org:rd)
  (User) 'test user 2'(user2) @ HR (scopes: user, org:hr)
starting wru server at https://localhost:8000

wru command doesn't have command line options. You can control it via environment variables.

WRU modes

WRU has two modes. This absorbs the difference of usecases and your web service always get only authorized requests.

WRU for local development

dev-mode

Sample configuration:

$ export WRU_DEV_MODE=true
$ export WRU_TLS_CERT="-----BEGIN CERTIFICATE-----\naaaabbbbbcccccdddd....zzzz\n-----END CERTIFICATE-----"
$ export WRU_TLS_KEY="-----BEGIN PRIVATE KEY-----\nZZZZYYYYYYXXXX.....BBBBAAAA\n-----END PRIVATE KEY-----"
$ export WRU_FORWARD_TO="/ => http://localhost:8080"
$ export WRU_USER_1="id:user1,name:test user 1,mail:[email protected],org:R&D,scope:admin,scope:user,scope:org:rd,twitter:user1,github:user1"
$ export WRU_USER_2="id:user2,name:test user 2,mail:[email protected],org:HR,scope:user,scope:org:hr,twitter:user2,github:user2"
$ PORT=8000 HOST=https://localhost:8000 wru

WRU for production

production-mode

Sample configuration:

  • Launch at example.com (local port is 8000)
  • No HTTPS by wru (AWS ALB does)
  • A backend server is at http://server.example.com
  • User information is in S3 (and reread it every hour)
  • Session storage is in DynamoDB
  • Twitter/GitHub/OpenID Connect login is available
$ export WRU_DEV_MODE=false
$ export WRU_FORWARD_TO="/ => http://server.example.com"
$ export WRU_USER_TABLE="s3://my-app-usertable/user-list.csv?region=us-west-1"
$ export WRU_USER_TABLE_RELOAD_TERM=1h
$ export WRU_TWITTER_CONSUMER_KEY=1111111
$ export WRU_TWITTER_CONSUMER_SECRET=22222222
$ export WRU_GITHUB_CLIENT_ID=33333333
$ export WRU_GITHUB_CLIENT_SECRET=44444444
$ export WRU_OIDC_PROVIDER_URL=http://keycloak.example.com
$ export WRU_OIDC_CLIENT_ID=55555555
$ export WRU_OIDC_CLIENT_SECRET=66666666
$ PORT=8000 HOST=https://example.com wru

End Points for frontend

  • /.wru/login: Login page
  • /.wru/logout: Logout page (it works just GET access)
  • /.wru/user: User page (it supports HTML and JSON)
  • /.wru/user/sessions: User session page (it supports HTML and JSON)

Session Storage

It supports session storage feature similar to browsers' cookie.

session storage

Your web application sends data that will be in the session storage with in Wru-Set-Session-Data header field in response like this:

Wru-Set-Session-Data: access-count=10

wru filter this content (browser doesn't retrieve this header field) and store its content in session storage. This content is added to Wru-Session header field (you can modify via WRU_SERVER_SESSION_FIELD env var) like this:

Wru-Session: {"login_at":1212121,"id":"shibu","name":"Yoshiki Shibukawa","scopes":["user","admin"],data:{"access-count":"10"}}

To read all content of this field in Go, you can parse it via the following structure:

type Session struct {
	LoginAt      int64             `json:"login_at"`       // nano-seconds
	ExpireAt     int64             `json:"expire_at"`      // nano-seconds
	LastAccessAt int64             `json:"last_access_at"` // nano-seconds
	UserID       string            `json:"id"`
	DisplayName  string            `json:"name"`
	Email        string            `json:"email"`
	Organization string            `json:"org"`
	Scopes       []string          `json:"scopes"`
	Data         map[string]string `json:"data"`
}

func ParseSession(r *http.Request) (*Session, error) {
  h := r.Header.Get("Wru-Session")
  if h != "" {
    var s Session
    err := json.NewDecoder(strings.NewReader(h)).Decode(&s)
    if err != nil {
      return nil, err
    }
    return &s, nil
  }
  return nil, err
}

Configuration

Server Configuration

  • PORT: Port number that wru uses (default is 3000)
  • HOST: Host name that wru is avaialble (required). It is used for callback of OAuth/OpenID Connect.
  • WRU_DEV_MODE: Change mode (described bellow)
  • WRU_TLS_CERT and WRU_TLS_KEY: Launch TLS server

Storage Configuration

WRU stores user information on-memory. You can add user via CSV or env vars.

  • WRU_SESSION_STORAGE: Session storage. Default is in memory. It supports DynamoDB, Firestore, MongoDB.
  • WRU_USER_TABLE: This is local file path/Blob path(AWS S3, GCP Cloud Storage) to read CSV.
  • WRU_USER_TABLE_RELOAD_TERM: Reload term.
  • WRU_USER_%d: Add user via environment variable (for testing).

If you add user via env var, you use comma separated tag list:

WRU_USER_1="id:user1,name:test user 1,mail:[email protected],org:R&D,scope:admin,scope:user,scope:org:rd,twitter:user1"

User table CSV file should have specific header row.

id,name,mail,org,scopes,twitter,github,oidc
user1,test user,[email protected],R&D,"admin,user,org:rd",user1,user1,[email protected]

Backend Server Configuration

  • WRU_FORWARD_TO: Specify you backend server (required)
  • WRU_SERVER_SESSION_FIELD: Header field name that WRU adds to backend request (default is "Wru-Session")

Frontend User Experience Configuration

  • WRU_DEFAULT_LANDING_PAGE: WRU tries to redirect to referrer page after login. It is used when the path is not available (default is '/').
  • WRU_LOGIN_TIMEOUT_TERM: Login session token's expiration term (default is '10m')
  • WRU_SESSION_IDLE_TIMEOUT_TERM: Active session token's timeout term (default is '1h')
  • WRU_SESSION_ABSOLUTE_TIMEOUT_TERM: Absolute session token's timeout term (default is '720h')
  • WRU_HTML_TEMPLATE_FOLDER: Login/User pages' template (default tempalte is embedded ones)

ID Provider Configuration

To enable ID provider connection, set the following env vars. The callback address will be ${HOST}/.wru/callback. You should register the URL in the setting screen of the ID provider.

Twitter
  • WRU_TWITTER_CONSUMER_KEY
  • WRU_TWITTER_CONSUMER_SECRET
GitHub
  • WRU_GITHUB_CLIENT_ID
  • WRU_GITHUB_CLIENT_SECRET
OpenID Connect
  • WRU_OIDC_PROVIDER_URL
  • WRU_OIDC_CLIENT_ID
  • WRU_OIDC_CLIENT_SECRET

Extra Option

  • WRU_GEIIP_DATABASE: GeoIP2 or GeoLite2 file (.mmdb) to detect user location from IP address

Use as Middleware

wru can work as middleware of HTTP service. Sample is in cmd/sampleapp.

NewAuthorizationMiddleware() returns required HTTP handler (that includes, login form, callback for OAuth2 and so on) and middleware. Don't apply the middleware to the wru's handler (it causes infinity loop).

You can create *wru.Config by using the structure directly or wru.NewConfigFromEnv().

package main

import (
  "context"
  "fmt"
  "net/http"
  "os"
  "os/signal"

  "github.com/go-chi/chi/v5"
  "github.com/go-chi/chi/v5/middleware"
  "gitlab.com/osaki-lab/wru"

  // Select backend of session storage (docstore) and identity register (blob)
  _ "gocloud.dev/docstore/memdocstore"
)

func main() {
	ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
	defer stop()

	r := chi.NewRouter()
	c := &wru.Config{
		Port:    3000,
		Host:    "http://localhost:3000",
		DevMode: true,
		Users: []*wru.User{
			{
				DisplayName:  "Test User 1",
				Organization: "Secret",
				UserID:       "testuser01",
				Email:        "[email protected]",
			},
		},
	}
	wruHandler, authMiddleware := wru.NewAuthorizationMiddleware(ctx, c, os.Stdout)
	r.Use(middleware.Logger)
	r.Mount("/", wruHandler)
	r.With(authMiddleware).Get("/", func(w http.ResponseWriter, r *http.Request) {
		_, session := wru.GetSession(r)
		w.Write([]byte("welcome " + session.UserID))
	})
    http.ListenAndServe(fmt.Sprintf(":%d", c.Port), r)
}

License

Apache 2

future-wru's People

Contributors

shibukawa avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.