Skip to content

Commit 0623ac9

Browse files
authored
Feat/forward auth (#28)
* feat: add a simple auth forward url * doc: update readme * fix: tests * fix: linter issues * doc: update basic auth section
1 parent e4c9ddc commit 0623ac9

File tree

8 files changed

+86
-4
lines changed

8 files changed

+86
-4
lines changed

.golangci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ linters-settings:
33
line-length: 200
44
gocyclo:
55
min-complexity: 20
6+
gocognit:
7+
min-complexity: 30
68

79
linters:
810
enable:
@@ -57,5 +59,8 @@ issues:
5759
linters:
5860
- gochecknoglobals
5961
- dupl
62+
- path: security.go
63+
linters:
64+
- gocognit
6065
include:
6166
- EXC0002

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Here is the list of all main features so far:
4949
- [X] Simple ticket check in NSP/NSZ (based on titledb file)
5050
- [X] Collect basic statistics
5151
- [X] An API to query information about your shop
52+
- [X] Handle Basic Auth from Tinfoil through Forward Auth Endpoint
5253

5354
## Filtering
5455

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

119120
### Example for caddy
120121

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

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

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

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

145-
For other type of protection, you can whitelist your own switch and this will do the trick.
146+
In the future, a proper user management will be incorporated into TinShop to handle it.
147+
148+
In addition, for other type of protection, you can whitelist/blacklist your own switch and this will do the trick.
146149

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

config.example.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ security:
6262
# You can find the uid of a switch in the log upon access
6363
backlist:
6464
- NOACCESSNOACCESSNOACCESSNOACCESSNOACCESSNOACCESSNOACCESSNOACCESS
65+
# Endpoint to which a query will be sent to verify user/password/uid to
66+
# Headers sent :
67+
# - Authorization: same as sent by switch
68+
# - Device-Id: Switch fingerprint
69+
# Response with status code other than 200 will be treated as failure
70+
forwardAuth: https://auth.tinshop.com/switch
6571

6672
# This section describe all custom title db to show up properly in tinfoil
6773
customTitledb:

config/config.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type security struct {
2828
Whitelist []string `mapstructure:"whitelist"`
2929
Backlist []string `mapstructure:"backlist"`
3030
BannedTheme []string `mapstructure:"bannedTheme"`
31+
ForwardAuth string `mapstructure:"forwardAuth"`
3132
}
3233

3334
type nsp struct {
@@ -261,6 +262,11 @@ func (cfg *File) VerifyNSP() bool {
261262
return cfg.NSP.CheckVerified
262263
}
263264

265+
// ForwardAuthURL returns the url of the forward auth
266+
func (cfg *File) ForwardAuthURL() string {
267+
return cfg.Security.ForwardAuth
268+
}
269+
264270
// IsBlacklisted tells if the uid is blacklisted or not
265271
func (cfg *File) IsBlacklisted(uid string) bool {
266272
if len(cfg.Security.Whitelist) != 0 {

mock_repository/mock_config.go

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

repository/interfaces.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ type Config interface {
4545
ShopTemplateData() ShopTemplate
4646
SetShopTemplateData(ShopTemplate)
4747

48+
ForwardAuthURL() string
4849
IsBlacklisted(string) bool
4950
IsWhitelisted(string) bool
5051
IsBannedTheme(string) bool

security.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ func (s *TinShop) TinfoilMiddleware(next http.Handler) http.Handler {
4747
return
4848
}
4949

50+
// TODO: Here implement usage of IsWhitelisted
51+
5052
// Check for banned theme
5153
var theme = strings.Join(headers["Theme"], "")
5254
if s.Shop.Config.IsBannedTheme(theme) {
@@ -72,6 +74,26 @@ func (s *TinShop) TinfoilMiddleware(next http.Handler) http.Handler {
7274
// Enforce true tinfoil queries
7375
// TODO: Check Uauth and Hauth headers
7476
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)
77+
78+
// Check user password
79+
if s.Shop.Config.ForwardAuthURL() != "" && headers["Authorization"] != nil {
80+
log.Println("[Security] Forwarding auth to", s.Shop.Config.ForwardAuthURL())
81+
client := &http.Client{}
82+
req, _ := http.NewRequest("GET", s.Shop.Config.ForwardAuthURL(), nil)
83+
req.Header.Add("Authorization", strings.Join(headers["Authorization"], ""))
84+
req.Header.Add("Device-Id", strings.Join(headers["Uid"], ""))
85+
resp, err := client.Do(req)
86+
if err != nil {
87+
log.Print(err)
88+
_ = shopTemplate.Execute(w, s.Shop.Config.ShopTemplateData())
89+
return
90+
}
91+
defer resp.Body.Close()
92+
if resp.StatusCode != 200 {
93+
_ = shopTemplate.Execute(w, s.Shop.Config.ShopTemplateData())
94+
return
95+
}
96+
}
7597
}
7698

7799
// Call the next handler, which can be another middleware in the chain, or the final handler.

security_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ var _ = Describe("Security", func() {
106106
Return(false).
107107
AnyTimes()
108108

109+
myMockConfig.EXPECT().
110+
ForwardAuthURL().
111+
Return("").
112+
AnyTimes()
113+
109114
myMockConfig.EXPECT().
110115
IsBlacklisted(gomock.Any()).
111116
Return(true).
@@ -160,6 +165,11 @@ var _ = Describe("Security", func() {
160165
Return(false).
161166
AnyTimes()
162167

168+
myMockConfig.EXPECT().
169+
ForwardAuthURL().
170+
Return("").
171+
AnyTimes()
172+
163173
myMockConfig.EXPECT().
164174
IsBlacklisted(gomock.Any()).
165175
Return(false).
@@ -219,6 +229,11 @@ var _ = Describe("Security", func() {
219229
Return(false).
220230
AnyTimes()
221231

232+
myMockConfig.EXPECT().
233+
ForwardAuthURL().
234+
Return("").
235+
AnyTimes()
236+
222237
myMockConfig.EXPECT().
223238
IsBlacklisted(gomock.Any()).
224239
Return(false).
@@ -279,6 +294,11 @@ var _ = Describe("Security", func() {
279294
Return(false).
280295
AnyTimes()
281296

297+
myMockConfig.EXPECT().
298+
ForwardAuthURL().
299+
Return("").
300+
AnyTimes()
301+
282302
myMockConfig.EXPECT().
283303
IsBlacklisted(gomock.Any()).
284304
Return(false).
@@ -338,6 +358,11 @@ var _ = Describe("Security", func() {
338358
Return(false).
339359
AnyTimes()
340360

361+
myMockConfig.EXPECT().
362+
ForwardAuthURL().
363+
Return("").
364+
AnyTimes()
365+
341366
myMockConfig.EXPECT().
342367
IsBlacklisted(gomock.Any()).
343368
Return(false).

0 commit comments

Comments
 (0)