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

upgrade go and dependencies #176

Merged
merged 17 commits into from
May 15, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/after-merge-dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
steps:
- name: Fetch dependabot metadata
id: dependabot-metadata
uses: dependabot/fetch-metadata@v1.6.0
uses: dependabot/fetch-metadata@v2.1.0
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"

Expand Down
27 changes: 27 additions & 0 deletions .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: golangci-lint
on:
push:
branches:
- main
- master
pull_request:

permissions:
contents: read
# Optional: allow read access to pull request. Use with `only-new-issues` option.
# pull-requests: read

jobs:
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '>=1.22'
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.58
args: --issues-exit-code=0 # FIXME
8 changes: 4 additions & 4 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ jobs:
fetch-depth: 0

- name: set up go
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: 1.21
go-version: 1.22

- name: cache go modules
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
key: "${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}"
restore-keys: |
${{ runner.os }}-go-

Expand Down
77 changes: 40 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Gobis-middlewares [![GoDoc](https://godoc.org/github.com/orange-cloudfoundry/gobis-middlewares?status.svg)](https://godoc.org/github.com/orange-cloudfoundry/gobis-middlewares)

This is a set of middlewares created for [gobis](https://github.com/orange-cloudfoundry/gobis) useable on your on project containing gobis.
This is a set of middlewares created for [gobis](https://github.com/orange-cloudfoundry/gobis) usable on your on project containing gobis.

**Note**: They are loaded by default on [gobis-server](https://github.com/orange-cloudfoundry/gobis-server)

List:
- [basic2token](#basic2token): Give the ability to connect an user over basic auth, retrieve a token from an oauth2 server with user information and forward the request with this token.
- [basic2token](#basic2token): Give the ability to connect a user over basic auth, retrieve a token from an OAuth2 server with user information and forward the request with this token.
- [basic auth](#basic-auth)
- [casbin](#casbin): An authorization library that supports access control models like ACL, RBAC, ABAC
- [cef trace](#cef-trace): Produce access log in CEF format for siem.
Expand All @@ -24,48 +24,51 @@ List:

**Pro tip**:

You can set multiple middleware params programmatically by using a dummy structure containing each config you wanna set, example:
You can set multiple middleware params programmatically by using a dummy structure containing each config you want to set, example:

```go
package main

import (
"github.com/orange-cloudfoundry/gobis-middlewares/trace"
"github.com/orange-cloudfoundry/gobis-middlewares/cors"
"github.com/orange-cloudfoundry/gobis"
"github.com/orange-cloudfoundry/gobis"
"github.com/orange-cloudfoundry/gobis-middlewares/cors"
"github.com/orange-cloudfoundry/gobis-middlewares/trace"
)
func main(){
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: struct {
trace.TraceConfig
cors.CorsConfig
}{
TraceConfig: trace.TraceConfig{
Trace: &trace.TraceOptions{
Enabled: true,
},
},
CorsConfig: cors.CorsConfig{
Cors: &cors.CorsOptions{
Enabled: true,
},
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(trace.NewTrace(), cors.NewCors()))

func main() {
configHandler := gobis.DefaultHandlerConfig{
Routes: []gobis.ProxyRoute{
{
Name: "myapi",
Path: "/app/**",
Url: "http://www.mocky.io/v2/595625d22900008702cd71e8",
MiddlewareParams: struct {
trace.TraceConfig
cors.CorsConfig
}{
TraceConfig: trace.TraceConfig{
Trace: &trace.TraceOptions{
Enabled: true,
},
},
CorsConfig: cors.CorsConfig{
Cors: &cors.CorsOptions{
Enabled: true,
},
},
},
},
},
}
gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFactory(trace.NewTrace(), cors.NewCors()))
}
```

## Basic2Token

Give the ability to connect an user over basic auth, retrieve a token from an oauth2 server with user information and forward the request with this token.
Give the ability to connect a user over basic auth, retrieve a token from an OAuth2 server with user information and forward the request with this token.

This was made to transparently convert a basic auth authentication to an oauth2 one.
This was made to transparently convert a basic auth authentication to an OAuth2 one.

See godoc for [Basic2TokenOptions](https://godoc.org/github.com/orange-cloudfoundry/gobis-middlewares/basic2token#Basic2TokenOptions) to know more about parameters.

Expand Down Expand Up @@ -117,7 +120,7 @@ middleware_params:

### Tips

- If key `scope` is found in the response of the oauth2 server, thoses scopes will be loaded as groups and others middlewares will
- If key `scope` is found in the response of the oauth2 server, theses scopes will be loaded as groups and others middlewares will
be able to find groups for the current user by using [context groups](https://godoc.org/github.com/orange-cloudfoundry/gobis#Groups)
- Logged user is accessible by other middleware through [context username](https://godoc.org/github.com/orange-cloudfoundry/gobis#Username)

Expand Down Expand Up @@ -469,7 +472,7 @@ middleware_params:

## Infopage

Add an endpoint on upstream to see information like headers set by gobis and user informations set by middlewares (Useful for frontend)
Add an endpoint on upstream to see information like headers set by gobis and user information set by middlewares (Useful for frontend)

See godoc for [CorsOptions](https://godoc.org/github.com/orange-cloudfoundry/gobis-middlewares/infopage#InfoPageOptions) to know more about parameters.

Expand Down Expand Up @@ -556,7 +559,7 @@ gobisHandler, err := gobis.NewDefaultHandler(configHandler, gobis.NewRouterFacto
### Credits

- https://github.com/auth0/go-jwt-middleware
- https://github.com/dgrijalva/jwt-go
- https://github.com/golang-jwt/jwt

### Use in config file

Expand Down
44 changes: 22 additions & 22 deletions authpubtkt/auth_pubtkt.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,72 +13,72 @@ type AuthPubTktConfig struct {
AuthPubTkt *AuthPubTktOptions `mapstructure:"auth_pubtkt" json:"auth_pubtkt" yaml:"auth_pubtkt"`
}
type AuthPubTktOptions struct {
// enable auth pubtkt
// Enabled enable auth pubtkt
Enabled bool `mapstructure:"enabled" json:"enabled" yaml:"enabled"`
// A DSA or RSA public key in PEM format
// PublicKey A DSA or RSA public key in PEM format
// This public key will be used to verify ticket signatures
PublicKey string `mapstructure:"public_key" json:"public_key" yaml:"public_key"`
// String indicating what digest algorithm to use when verifying ticket signatures
// Digest String indicating what digest algorithm to use when verifying ticket signatures
// Valid values are SHA1, DSS1, SHA224, SHA256, SHA384, and SHA512
// If not specified, the old defaults of SHA1 (for an RSA public key) or DSS1 (for a DSA public key) will be used.
Digest string `mapstructure:"digest" json:"digest" yaml:"digest"`
// URL that users without a valid ticket will be redirected to
// LoginURL URL that users without a valid ticket will be redirected to
// The originally requested URL will be appended as a GET parameter (normally named "back", but can be changed with BackArgName)
LoginURL string `mapstructure:"login_url" json:"login_url" yaml:"login_url"`
// URL that users whose ticket has expired will be redirected to
// TimeoutURL URL that users whose ticket has expired will be redirected to
// If not set, LoginURL is used
TimeoutURL string `mapstructure:"timeout_url" json:"timeout_url" yaml:"timeout_url"`
// Same as TimeoutURL, but in case the request was a POST
// PostTimeoutURL Same as TimeoutURL, but in case the request was a POST
// If not set, TimeoutURL is used (and if that is not set either, LoginURL)
PostTimeoutURL string `mapstructure:"post_timeout_url" json:"post_timeout_url" yaml:"post_timeout_url"`
// URL that users whose ticket doesn't contain any of the required tokens (as set with Token) will be redirected to
// UnauthURL URL that users whose ticket doesn't contain any of the required tokens (as set with Token) will be redirected to
UnauthURL string `mapstructure:"unauth_url" json:"unauth_url" yaml:"unauth_url"`
// URL that users whose ticket is within the grace period (as set with the graceperiod key in the ticket) before the actual expiry will be redirected to.
// RefreshURL URL that users whose ticket is within the grace period (as set with the graceperiod key in the ticket) before the actual expiry will be redirected to.
// Only GET requests are redirected; POST requests are accepted normally. The script at this URL should check the ticket and issue a new one
// If not set, LoginURL is used
RefreshURL string `mapstructure:"refresh_url" json:"refresh_url" yaml:"refresh_url"`
// A space separated list of headers to use for finding the ticket (case insensitive).
// Headers A space separated list of headers to use for finding the ticket (case-insensitive).
// If this header specified is Cookie then the format of the value expects to be a valid cookie (subject to the CookieName directive).
// Any other header assumes the value is a simple URL-encoded value of the ticket.
// The first header that has content is tried and any other tickets in other header(s) are ignored.
// example, use Cookie first, fallback to X-My-Auth: Header: []string{"Cookie", "X-My-Auth"}
// Default: Cookie
Headers []string `mapstructure:"headers" json:"headers" yaml:"headers"`
// Name of the authentication cookie to use
// CookieName Name of the authentication cookie to use
// Default: auth_pubtkt
CookieName string `mapstructure:"cookie_name" json:"cookie_name" yaml:"cookie_name"`
// Name of the GET argument with the originally requested URL (when redirecting to the login page)
// BackArgName Name of the GET argument with the originally requested URL (when redirecting to the login page)
// Default: back
BackArgName string `mapstructure:"back_arg_name" json:"back_arg_name" yaml:"back_arg_name"`
// only accept tickets in HTTPS requests
// RequireSSL only accept tickets in HTTPS requests
// Default: false
RequireSSL bool `mapstructure:"require_ssl" json:"require_ssl" yaml:"require_ssl"`
// token that must be present in a ticket for access to be granted
// Tokens token that must be present in a ticket for access to be granted
// Multiple tokens may be specified; only one of them needs to be present in the ticket (i.e. any token can match, not all tokens need to match)
Tokens []string `mapstructure:"tokens" json:"tokens" yaml:"tokens"`
// if on, a fake Authorization header will be added to each request (username from ticket, fixed string "password" as the password).
// FakeBasicAuth if on, a fake Authorization header will be added to each request (username from ticket, fixed string "password" as the password).
// This can be used in reverse proxy situations, and to prevent PHP from stripping username information from the request (which would then not be available for logging purposes)
// Default: false
FakeBasicAuth bool `mapstructure:"fake_basic_auth" json:"fake_basic_auth" yaml:"fake_basic_auth"`
// if on, the value from the ticket's "bauth" field will be added to the request as a Basic Authorization header.
// PassthruBasicAuth if on, the value from the ticket's "bauth" field will be added to the request as a Basic Authorization header.
// This can be used in reverse proxy situations where one needs complete control over the username and password (see also FakeBasicAuth, which should not be used at the same time).
// Default: false
PassthruBasicAuth bool `mapstructure:"passthru_basic_auth" json:"passthru_basic_auth" yaml:"passthru_basic_auth"`
// if set, the bauth value will be decrypted using the given key before it is added to the Authorization header.
// PassthruBasicKey if set, the bauth value will be decrypted using the given key before it is added to the Authorization header.
// length must be exactly 16 characters (AES 128)
PassthruBasicKey string `mapstructure:"passthru_basic_key" json:"passthru_basic_key" yaml:"passthru_basic_key"`
// If set it will crypt/encrypt the cookie with this passphrase (not a key but a passphrase like in openssl)
// CypherPass If set it will crypt/encrypt the cookie with this passphrase (not a key but a passphrase like in openssl)
CypherPass string `mapstructure:"cypher_pass" json:"cypher_pass" yaml:"cypher_pass"`
// Method of encryption under aes, it can be either cbc or ecb
// CypherMethod Method of encryption under aes, it can be either cbc or ecb
CypherMethod string `mapstructure:"cypher_method" json:"cypher_method" yaml:"cypher_method"`
// If true it will check if ip which created the token is the correct ip who use it
// CheckIpEnabled If true it will check if ip which created the token is the correct ip who use it
// Default: false
CheckIpEnabled bool `mapstructure:"check_ip_enabled" json:"check_ip_enabled" yaml:"check_ip_enabled"`
// If true and TKTCheckIpEnabled is true it will check ip from header X-Forwarded-For instead client remote ip
// CheckXForwardedIp If true and TKTCheckIpEnabled is true, it will check the IP from the X-Forwarded-For header instead of the client remote IP
// default: false
CheckXForwardedIp bool `mapstructure:"check_xforwarded_ip" json:"check_xforwarded_ip" yaml:"check_xforwarded_ip"`
// Passthrough if a previous middleware already set user context
// This is helpful when you want add user with basic auth middleware
// TrustCurrentUser Passthrough if a previous middleware already set user context
// This is helpful when you want to add a user with basic auth middleware
TrustCurrentUser bool `mapstructure:"trust_current_user" json:"trust_current_user" yaml:"trust_current_user"`
}

Expand Down
27 changes: 11 additions & 16 deletions basic2token/basic2token.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/orange-cloudfoundry/gobis"
"github.com/orange-cloudfoundry/gobis-middlewares/utils"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
Expand All @@ -19,23 +18,23 @@ type Basic2TokenConfig struct {
}
type Basic2TokenOptions struct {
utils.ClientRouteOption `mapstructure:",squash"`
// Uri to retrieve access token e.g.: https://my.uaa.local/oauth/token
// AccessTokenUri Uri to retrieve access token e.g.: https://my.uaa.local/oauth/token
AccessTokenUri string `mapstructure:"access_token_uri" json:"access_token_uri" yaml:"access_token_uri"`
// Client id which will connect user on behalf him
// ClientId Client id which will connect user on behalf him
ClientId string `mapstructure:"client_id" json:"client_id" yaml:"client_id"`
// Client secret which will connect user on behalf him
// ClientSecret Client secret which will connect user on behalf him
ClientSecret string `mapstructure:"client_secret" json:"client_secret" yaml:"client_secret"`
// Some oauth server can be configured to use a different of token
// if you want an opaque token from uaa you will set this value to "opaque"
// TokenFormat Some OAuth servers can be configured to use a different token format;
// if you want an opaque token from UAA you will set this value to "opaque"
TokenFormat string `mapstructure:"token_format" json:"token_format" yaml:"token_format"`
// Permit to basic2token to detect if a oauth token has been already set
// TokenType Permit to basic2token to detect if a oauth token has been already set
// If token was already given it will forward to the next handler without trying to acquire a new token
// Default: bearer
TokenType string `mapstructure:"token_type" json:"token_type" yaml:"token_type"`
// By default request token is sent by post form, set to true to send as json
// ParamsAsJson By default request token is sent by post form, set to true to send as JSON
ParamsAsJson bool `mapstructure:"params_as_json" json:"params_as_json" yaml:"params_as_json"`
// Passthrough if a previous middleware already set user context
// This is helpful when you want add user with basic auth middleware
// TrustCurrentUser Passthrough if a previous middleware already set user context
// This is helpful when you want to add a user with basic auth middleware
TrustCurrentUser bool `mapstructure:"trust_current_user" json:"trust_current_user" yaml:"trust_current_user"`
}
type AccessTokenResponse struct {
Expand Down Expand Up @@ -73,26 +72,22 @@ func (a Basic2TokenAuth) Auth(user, password string, origRequest *http.Request)
resp, err := a.client.Do(req)
if err != nil {
panic(fmt.Sprintf("Error when getting token for %s: %s", user, err.Error()))
return false
}
if resp.StatusCode < 200 || resp.StatusCode > 299 {
if resp.StatusCode == 401 || resp.StatusCode == 403 {
return false
}
b, _ := ioutil.ReadAll(resp.Body)
b, _ := io.ReadAll(resp.Body)
panic(fmt.Sprintf("Error from oauth server %d: %s", resp.StatusCode, string(b)))
return false
}
b, err := ioutil.ReadAll(resp.Body)
b, err := io.ReadAll(resp.Body)
if err != nil {
panic(fmt.Sprintf("Error when getting token for %s: %s", user, err.Error()))
return false
}
var accessResp AccessTokenResponse
err = json.Unmarshal(b, &accessResp)
if err != nil {
panic(fmt.Sprintf("Error when getting token for %s: %s", user, err.Error()))
return false
}
tokenType := accessResp.TokenType
if tokenType == "" {
Expand Down
4 changes: 3 additions & 1 deletion basicauth/basic_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package basicauth
import (
"crypto/sha256"
"crypto/subtle"
"errors"
"fmt"
"github.com/goji/httpauth"
"github.com/orange-cloudfoundry/gobis"
Expand Down Expand Up @@ -40,7 +41,8 @@ func (b BasicAuthOptions) Auth(user, password string, passthrough bool, req *htt
if err == nil {
return true
}
if _, ok := err.(blowfish.KeySizeError); ok {
var keySizeError blowfish.KeySizeError
if errors.As(err, &keySizeError) {
panic(fmt.Sprintf(
"orange-cloudfoundry/gobis/middlewares: Basic auth middleware, invalid crypted password for user '%s': %s",
foundUser.User,
Expand Down
8 changes: 4 additions & 4 deletions casbin/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ type CasbinOption struct {
type CasbinPolicy struct {
// Type of policy, with default config it can be p (target) or g (role)
Type string `mapstructure:"type" json:"type" yaml:"type"`
// Subject of the policy, this can be a username retrieve basic auth or a role name
// For example if use ldap middleware you can use username or a group where the user is member of
// Sub Subject of the policy. This can be a username retrieve basic auth or a role name.
// For example, when using LDAP middleware, you can use username or a group where the user is member of.
Sub string `mapstructure:"sub" json:"sub" yaml:"sub"`
// Object of the policy, with default perm config it will be the following path set in your route
// Obj Object of the policy, with default perm config it will be the following path set in your route
// e.g.: with path = "/app/**" object will be /* to allow everything after /app
Obj string `mapstructure:"obj" json:"obj" yaml:"obj"`
// Operation of the policy, with default config it will be an http method like GET, POST, ... or * for evything
// Act Operation of the policy, with default config it will be a HTTP method like GET, POST, ... or * for everything
Act string `mapstructure:"act" json:"act" yaml:"act"`
}

Expand Down
Loading
Loading