Skip to content

Commit

Permalink
Merge pull request #30 from devopsfaith/jwt_example
Browse files Browse the repository at this point in the history
JWT example
  • Loading branch information
alombarte authored May 22, 2017
2 parents 92cc18c + 0f0b50a commit b9b5987
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
**/krakend_negroni*
**/krakend_httpcache*
**/krakend_rss*
**/krakend_jwt*
server.rsa.crt
server.rsa.key
*.json
Expand Down
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: all deps test build benchmark coveralls build_gin_example build_dns_example build_mux_example build_gorilla_example build_negroni_example build_httpcache_example build_rss_example
.PHONY: all deps test build benchmark coveralls build_gin_example build_dns_example build_mux_example build_gorilla_example build_negroni_example build_httpcache_example build_rss_example build_jwt_example

PACKAGES = $(shell go list ./... | grep -v /examples/)

Expand All @@ -21,7 +21,7 @@ test:
benchmark:
go test -bench=. -benchtime=3s $(PACKAGES)

build: build_gin_example build_dns_example build_mux_example build_gorilla_example build_negroni_example build_httpcache_example build_rss_example
build: build_gin_example build_dns_example build_mux_example build_gorilla_example build_negroni_example build_httpcache_example build_rss_example build_jwt_example

build_gin_example:
cd examples/gin/ && make && cd ../.. && cp examples/gin/krakend_gin_example* .
Expand All @@ -44,6 +44,9 @@ build_httpcache_example:
build_rss_example:
cd examples/rss/ && make && cd ../.. && cp examples/rss/krakend_rss_example* .

build_jwt_example:
cd examples/jwt/ && make && cd ../.. && cp examples/jwt/krakend_jwt_example* .

coveralls: all
go get github.com/mattn/goveralls
sh coverage.sh --coveralls
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ Visit the [framework overview](/docs/OVERVIEW.md) for more details about the com
2. [mux router](/examples/mux/README.md)
3. [gorilla router](/examples/gorilla/README.md)
4. [negroni middlewares](/examples/negroni/README.md)
5. [dns srv service discovery](/examples/dns/README.md)
6. [rss backends](/examples/rss/README.md)
7. [jwt middlewares](/examples/jwt/README.md)
8. [httpcache based proxies](/examples/httpcache/README.md)

## Configuration file

Expand Down
25 changes: 25 additions & 0 deletions examples/jwt/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.PHONY: all deps build

# This Makefile is a simple example that demonstrates usual steps to build a binary that can be run in the same
# architecture that was compiled in. The "ldflags" in the build assure that any needed dependency is included in the
# binary and no external dependencies are needed to run the service.

KRAKEND_VERSION=$(shell git describe --always --long --dirty --tags)
BIN_NAME=krakend_jwt_example_${KRAKEND_VERSION}

all: deps build

deps:
go get "github.com/devopsfaith/krakend/config/viper"
go get "github.com/devopsfaith/krakend/proxy"
go get "github.com/devopsfaith/krakend/router/gin"
go get "github.com/devopsfaith/krakend/logging/gologging"
go get "github.com/gin-gonic/contrib/secure"
go get "github.com/aviddiviner/gin-limit"
go get "gopkg.in/gin-contrib/cors.v1"
go get "github.com/dgrijalva/jwt-go"
go get "github.com/gin-gonic/contrib/jwt"

build:
go build -ldflags="-X github.com/devopsfaith/krakend/core.KrakendVersion=${KRAKEND_VERSION}" -o ${BIN_NAME}
@echo "You can now use ./${BIN_NAME}"
44 changes: 44 additions & 0 deletions examples/jwt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
Krakend JWT example
====

## Build

Go 1.8 is a requirement

$ make

## Run

Running it as a common executable, logs are send to the stdOut and some options are available at the CLI.

Notice this example starts a dedicated service just for issuing signed JWT.

$ ./krakend_jwt_example
Usage of ./krakend_jwt_example_92cc18c:
-c string
Path to the configuration filename (default "/etc/krakend/configuration.json")
-cors-headers string
Comma-separated list of CORS allowed headers (default "Origin,Authorization,Content-Type")
-cors-headers-exposed string
Comma-separated list of CORS exposed headers (default "Content-Length")
-cors-methods string
Comma-separated list of CORS allowed methods (default "HEAD,GET,POST,PUT,PATCH,DELETE")
-cors-origins string
Comma-separated list of CORS allowed origins (default "http://example.com")
-cors-ttl duration
Max age for the CORS layer (default 12h0m0s)
-d Enable the debug
-hosts string
Comma-separated list of allowed hosts (default "127.0.0.1:8080,example.com,ssl.example.com")
-jwt-issuer string
Issuer for the jwt (default "http://example.com/")
-jwt-port int
Port for the jwt generator api (default 8090)
-jwt-secret string
Secret for signing jwt (default "KrakenDrulez123.4567890!")
-jwt-ttl duration
Expiration for the JWT (default 1h0m0s)
-l string
Logging level (default "ERROR")
-p int
Port of the service
135 changes: 135 additions & 0 deletions examples/jwt/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package main

import (
"flag"
"fmt"
"log"
"os"
"strings"
"time"

"github.com/aviddiviner/gin-limit"
jwt_lib "github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/contrib/jwt"
"github.com/gin-gonic/contrib/secure"
"github.com/gin-gonic/gin"
"gopkg.in/gin-contrib/cors.v1"

"github.com/devopsfaith/krakend/config"
"github.com/devopsfaith/krakend/config/viper"
"github.com/devopsfaith/krakend/logging"
"github.com/devopsfaith/krakend/logging/gologging"
"github.com/devopsfaith/krakend/proxy"
krakendgin "github.com/devopsfaith/krakend/router/gin"
)

func main() {
port := flag.Int("p", 0, "Port of the service")
logLevel := flag.String("l", "ERROR", "Logging level")
allowedHosts := flag.String("hosts", "127.0.0.1:8080,example.com,ssl.example.com", "Comma-separated list of allowed hosts")
allowedOrigins := flag.String("cors-origins", "http://example.com", "Comma-separated list of CORS allowed origins")
allowedMethods := flag.String("cors-methods", "HEAD,GET,POST,PUT,PATCH,DELETE", "Comma-separated list of CORS allowed methods")
allowedHeaders := flag.String("cors-headers", "Origin,Authorization,Content-Type", "Comma-separated list of CORS allowed headers")
exposedHeaders := flag.String("cors-headers-exposed", "Content-Length", "Comma-separated list of CORS exposed headers")
corsTTL := flag.Duration("cors-ttl", 12*time.Hour, "Max age for the CORS layer")
jwtSecret := flag.String("jwt-secret", "KrakenDrulez123.4567890!", "Secret for signing jwt")
jwtIssuer := flag.String("jwt-issuer", "http://example.com/", "Issuer for the jwt")
jwtPort := flag.Int("jwt-port", 8090, "Port for the jwt generator api")
jwsTTL := flag.Duration("jwt-ttl", 1*time.Hour, "Expiration for the JWT")
debug := flag.Bool("d", false, "Enable the debug")
configFile := flag.String("c", "/etc/krakend/configuration.json", "Path to the configuration filename")
flag.Parse()

parser := viper.New()
serviceConfig, err := parser.Parse(*configFile)
if err != nil {
log.Fatal("ERROR:", err.Error())
}
serviceConfig.Debug = serviceConfig.Debug || *debug
if *port != 0 {
serviceConfig.Port = *port
}

logger, err := gologging.NewLogger(*logLevel, os.Stdout, "[KRAKEND]")
if err != nil {
log.Fatal("ERROR:", err.Error())
}

go func() {
jwtGenerator := JWTGenerator{[]byte(*jwtSecret), *jwtIssuer, *jwsTTL, *jwtPort}
log.Fatal(jwtGenerator.Run())
}()

routerFactory := krakendgin.NewFactory(krakendgin.Config{
Engine: gin.Default(),
ProxyFactory: customProxyFactory{logger, proxy.DefaultFactory(logger)},
Logger: logger,
HandlerFactory: krakendgin.EndpointHandler,
Middlewares: []gin.HandlerFunc{
secure.Secure(secure.Options{
AllowedHosts: strings.Split(*allowedHosts, ","),
SSLRedirect: false,
SSLHost: "ssl.example.com",
SSLProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
STSSeconds: 315360000,
STSIncludeSubdomains: true,
FrameDeny: true,
ContentTypeNosniff: true,
BrowserXssFilter: true,
ContentSecurityPolicy: "default-src 'self'",
}),
limit.MaxAllowed(20),
cors.New(cors.Config{
AllowOrigins: strings.Split(*allowedOrigins, ","),
AllowMethods: strings.Split(*allowedMethods, ","),
AllowHeaders: strings.Split(*allowedHeaders, ","),
ExposeHeaders: strings.Split(*exposedHeaders, ","),
AllowCredentials: true,
MaxAge: *corsTTL,
}),
jwt.Auth(*jwtSecret),
},
})

routerFactory.New().Run(serviceConfig)
}

// customProxyFactory adds a logging middleware wrapping the internal factory
type customProxyFactory struct {
logger logging.Logger
factory proxy.Factory
}

// New implements the Factory interface
func (cf customProxyFactory) New(cfg *config.EndpointConfig) (p proxy.Proxy, err error) {
p, err = cf.factory.New(cfg)
if err == nil {
p = proxy.NewLoggingMiddleware(cf.logger, cfg.Endpoint)(p)
}
return
}

type JWTGenerator struct {
jwtSecret []byte
jwtIssuer string
jwsTTL time.Duration
jwtPort int
}

func (j *JWTGenerator) Run() error {
engine := gin.Default()
engine.GET("/token/:id", func(c *gin.Context) {
token := jwt_lib.New(jwt_lib.GetSigningMethod("HS256"))
token.Claims = jwt_lib.MapClaims{
"Id": c.Param("id"),
"iss": j.jwtIssuer,
"exp": time.Now().Add(j.jwsTTL).Unix(),
}
tokenString, err := token.SignedString(j.jwtSecret)
if err != nil {
c.JSON(500, gin.H{"message": "Could not generate token"})
}
c.JSON(200, gin.H{"token": tokenString})
})
return engine.Run(fmt.Sprintf(":%d", j.jwtPort))
}

0 comments on commit b9b5987

Please sign in to comment.