Skip to content

Commit

Permalink
Feat/forward auth (#28)
Browse files Browse the repository at this point in the history
* feat: add a simple auth forward url

* doc: update readme

* fix: tests

* fix: linter issues

* doc: update basic auth section
  • Loading branch information
DblK authored Aug 18, 2023
1 parent e4c9ddc commit 0623ac9
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ linters-settings:
line-length: 200
gocyclo:
min-complexity: 20
gocognit:
min-complexity: 30

linters:
enable:
Expand Down Expand Up @@ -57,5 +59,8 @@ issues:
linters:
- gochecknoglobals
- dupl
- path: security.go
linters:
- gocognit
include:
- EXC0002
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Here is the list of all main features so far:
- [X] Simple ticket check in NSP/NSZ (based on titledb file)
- [X] Collect basic statistics
- [X] An API to query information about your shop
- [X] Handle Basic Auth from Tinfoil through Forward Auth Endpoint

## Filtering

Expand Down Expand Up @@ -118,7 +119,7 @@ Use a reverse proxy (like [traefik](https://github.com/traefik/traefik), [caddy]

### Example for caddy

To work with `caddy`, you need to put in your `Caddyfile` something similar to this:
To work with [`caddy`](https://caddyserver.com/), you need to put in your `Caddyfile` something similar to this:

```Caddyfile
tinshop.example.com:80 {
Expand All @@ -139,10 +140,12 @@ If you want to have HTTPS, ensure `caddy` handle it (it will with Let's Encrypt)

## How can I add a `basic auth` to protect my shop?

TinShop **does not** implement basic auth by itself.
You should configure it inside your reverse proxy.
TinShop **does** handle basic auth but not by itself.
You should look for `forwardAuth` in the `config.yaml` to set the endpoint that will handle the authentication in behalf of TinShop.

For other type of protection, you can whitelist your own switch and this will do the trick.
In the future, a proper user management will be incorporated into TinShop to handle it.

In addition, for other type of protection, you can whitelist/blacklist your own switch and this will do the trick.

## I have tons of missing title displayed in `tinfoil`, what should I do?

Expand Down
6 changes: 6 additions & 0 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ security:
# You can find the uid of a switch in the log upon access
backlist:
- NOACCESSNOACCESSNOACCESSNOACCESSNOACCESSNOACCESSNOACCESSNOACCESS
# Endpoint to which a query will be sent to verify user/password/uid to
# Headers sent :
# - Authorization: same as sent by switch
# - Device-Id: Switch fingerprint
# Response with status code other than 200 will be treated as failure
forwardAuth: https://auth.tinshop.com/switch

# This section describe all custom title db to show up properly in tinfoil
customTitledb:
Expand Down
6 changes: 6 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type security struct {
Whitelist []string `mapstructure:"whitelist"`
Backlist []string `mapstructure:"backlist"`
BannedTheme []string `mapstructure:"bannedTheme"`
ForwardAuth string `mapstructure:"forwardAuth"`
}

type nsp struct {
Expand Down Expand Up @@ -261,6 +262,11 @@ func (cfg *File) VerifyNSP() bool {
return cfg.NSP.CheckVerified
}

// ForwardAuthURL returns the url of the forward auth
func (cfg *File) ForwardAuthURL() string {
return cfg.Security.ForwardAuth
}

// IsBlacklisted tells if the uid is blacklisted or not
func (cfg *File) IsBlacklisted(uid string) bool {
if len(cfg.Security.Whitelist) != 0 {
Expand Down
14 changes: 14 additions & 0 deletions mock_repository/mock_config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions repository/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type Config interface {
ShopTemplateData() ShopTemplate
SetShopTemplateData(ShopTemplate)

ForwardAuthURL() string
IsBlacklisted(string) bool
IsWhitelisted(string) bool
IsBannedTheme(string) bool
Expand Down
22 changes: 22 additions & 0 deletions security.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ func (s *TinShop) TinfoilMiddleware(next http.Handler) http.Handler {
return
}

// TODO: Here implement usage of IsWhitelisted

// Check for banned theme
var theme = strings.Join(headers["Theme"], "")
if s.Shop.Config.IsBannedTheme(theme) {
Expand All @@ -72,6 +74,26 @@ func (s *TinShop) TinfoilMiddleware(next http.Handler) http.Handler {
// Enforce true tinfoil queries
// TODO: Check Uauth and Hauth headers
log.Printf("Switch %s, %s, %s, %s, %s, %s requesting %s", headers["Theme"], headers["Uid"], headers["Version"], headers["Language"], headers["Hauth"], headers["Uauth"], r.RequestURI)

// Check user password
if s.Shop.Config.ForwardAuthURL() != "" && headers["Authorization"] != nil {
log.Println("[Security] Forwarding auth to", s.Shop.Config.ForwardAuthURL())
client := &http.Client{}
req, _ := http.NewRequest("GET", s.Shop.Config.ForwardAuthURL(), nil)
req.Header.Add("Authorization", strings.Join(headers["Authorization"], ""))
req.Header.Add("Device-Id", strings.Join(headers["Uid"], ""))
resp, err := client.Do(req)
if err != nil {
log.Print(err)
_ = shopTemplate.Execute(w, s.Shop.Config.ShopTemplateData())
return
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
_ = shopTemplate.Execute(w, s.Shop.Config.ShopTemplateData())
return
}
}
}

// Call the next handler, which can be another middleware in the chain, or the final handler.
Expand Down
25 changes: 25 additions & 0 deletions security_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ var _ = Describe("Security", func() {
Return(false).
AnyTimes()

myMockConfig.EXPECT().
ForwardAuthURL().
Return("").
AnyTimes()

myMockConfig.EXPECT().
IsBlacklisted(gomock.Any()).
Return(true).
Expand Down Expand Up @@ -160,6 +165,11 @@ var _ = Describe("Security", func() {
Return(false).
AnyTimes()

myMockConfig.EXPECT().
ForwardAuthURL().
Return("").
AnyTimes()

myMockConfig.EXPECT().
IsBlacklisted(gomock.Any()).
Return(false).
Expand Down Expand Up @@ -219,6 +229,11 @@ var _ = Describe("Security", func() {
Return(false).
AnyTimes()

myMockConfig.EXPECT().
ForwardAuthURL().
Return("").
AnyTimes()

myMockConfig.EXPECT().
IsBlacklisted(gomock.Any()).
Return(false).
Expand Down Expand Up @@ -279,6 +294,11 @@ var _ = Describe("Security", func() {
Return(false).
AnyTimes()

myMockConfig.EXPECT().
ForwardAuthURL().
Return("").
AnyTimes()

myMockConfig.EXPECT().
IsBlacklisted(gomock.Any()).
Return(false).
Expand Down Expand Up @@ -338,6 +358,11 @@ var _ = Describe("Security", func() {
Return(false).
AnyTimes()

myMockConfig.EXPECT().
ForwardAuthURL().
Return("").
AnyTimes()

myMockConfig.EXPECT().
IsBlacklisted(gomock.Any()).
Return(false).
Expand Down

0 comments on commit 0623ac9

Please sign in to comment.