Skip to content

Commit 7f6a343

Browse files
authored
Merge pull request #164 from SenseUnit/auth_enhancements
Auth enhancements 2
2 parents 6253deb + 0d15d31 commit 7f6a343

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@ Authentication parameters are passed as URI via `-auth` parameter. Scheme of URI
284284
* `method` - override HTTP request method.
285285
* `qs` - provide query string to the URL in request.
286286
* `x-forwarded` - boolean parameter specifying if X-Forwarded headers should be populated.
287+
* `reject-static` - auth provider which rejects auth and returns pre-defined response. Useful as a last auth chain element with other providers in order to customize rejection response. Example: `-auth reject-static://?code=403&body=denied.html&headers=denied.hdr`. Parameters:
288+
* `code` - optional parameter specifying HTTP response code. Default is 403.
289+
* `body` - optional parameter specifying file with response body.
290+
* `headers` - optional parameter specifying file with response headers. It uses format identical to request header file format used by `curl` program.
287291
288292
## Scripting
289293

auth/auth.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ func NewAuth(paramstr string, logger *clog.CondLogger) (Auth, error) {
3838
return NoAuth{}, nil
3939
case "reject-http", "reject-https":
4040
return NewRejectHTTPAuth(url, logger)
41+
case "reject-static":
42+
return NewStaticRejectAuth(url, logger)
4143
default:
4244
return nil, errors.New("Unknown auth scheme")
4345
}

auth/rejectstatic.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package auth
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"context"
7+
"fmt"
8+
"io"
9+
"net/http"
10+
"net/url"
11+
"os"
12+
"strconv"
13+
14+
clog "github.com/SenseUnit/dumbproxy/log"
15+
)
16+
17+
type StaticRejectAuth struct {
18+
code int
19+
body string
20+
hdrs string
21+
logger *clog.CondLogger
22+
}
23+
24+
func NewStaticRejectAuth(u *url.URL, logger *clog.CondLogger) (*StaticRejectAuth, error) {
25+
values, err := url.ParseQuery(u.RawQuery)
26+
if err != nil {
27+
return nil, err
28+
}
29+
code := 403
30+
if values.Has("code") {
31+
parsedCode, err := strconv.Atoi(values.Get("code"))
32+
if err != nil {
33+
return nil, fmt.Errorf("unable to parse code parameter: %w", err)
34+
}
35+
code = parsedCode
36+
}
37+
return &StaticRejectAuth{
38+
code: code,
39+
body: values.Get("body"),
40+
hdrs: values.Get("headers"),
41+
logger: logger,
42+
}, nil
43+
}
44+
45+
func (a *StaticRejectAuth) Validate(ctx context.Context, w http.ResponseWriter, r *http.Request) (string, bool) {
46+
if a.hdrs != "" {
47+
f, err := os.Open(a.hdrs)
48+
if err != nil {
49+
a.logger.Error("unable to open file with auth rejection headers: %v", err)
50+
} else {
51+
defer f.Close()
52+
if err := applyHeaders(f, w.Header()); err != nil {
53+
a.logger.Error("header processing failed: %v", err)
54+
}
55+
56+
}
57+
}
58+
w.WriteHeader(a.code)
59+
if a.body != "" {
60+
f, err := os.Open(a.body)
61+
if err != nil {
62+
a.logger.Error("unable to open file with auth rejection body: %v", err)
63+
return "", false
64+
}
65+
defer f.Close()
66+
_, err = io.Copy(w, f)
67+
if err != nil {
68+
a.logger.Debug("auth rejection body write failed: %v", err)
69+
}
70+
}
71+
return "", false
72+
}
73+
74+
func applyHeaders(r io.Reader, h http.Header) error {
75+
scanner := bufio.NewScanner(r)
76+
for scanner.Scan() {
77+
line := scanner.Bytes()
78+
name, value, found := bytes.Cut(line, []byte{':'})
79+
if found {
80+
value = bytes.TrimLeft(value, " \t")
81+
if len(value) == 0 {
82+
// Explicitly disabled header
83+
h[string(name)] = nil
84+
} else {
85+
// Normal header value
86+
h[string(name)] = append(h[string(name)], string(value))
87+
}
88+
} else {
89+
name, _, found := bytes.Cut(line, []byte{';'})
90+
if found {
91+
// send a header with an empty value
92+
h[string(name)] = append(h[string(name)], "")
93+
} else {
94+
return fmt.Errorf("malformed header line %q", string(line))
95+
}
96+
}
97+
}
98+
if err := scanner.Err(); err != nil {
99+
return fmt.Errorf("header parsing failed: %w", err)
100+
}
101+
return nil
102+
}
103+
104+
func (_ *StaticRejectAuth) Valid(_, _, _ string) bool {
105+
return false
106+
}
107+
108+
func (_ *StaticRejectAuth) Stop() {}

0 commit comments

Comments
 (0)