summaryrefslogtreecommitdiff
path: root/pkg/authz/check_service.go
blob: ff4e92a9db7b7ffe49d624e882f0b066e418e366 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package authz

import (
	"context"
	"strings"

	core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
	auth "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
	types "github.com/envoyproxy/go-control-plane/envoy/type/v3"
	"github.com/xlgmokha/x/pkg/log"
	"github.com/xlgmokha/x/pkg/x"
	status "google.golang.org/genproto/googleapis/rpc/status"
	"google.golang.org/grpc/codes"
)

type CheckService struct {
	auth.UnimplementedAuthorizationServer
}

func (svc *CheckService) Check(ctx context.Context, request *auth.CheckRequest) (*auth.CheckResponse, error) {
	if svc.isAllowed(ctx, request) {
		return svc.OK(ctx), nil
	}
	return svc.Denied(ctx), nil
}

// TODOD:: Replace with a PaC language
func (svc *CheckService) isPublic(ctx context.Context, r *auth.CheckRequest) bool {
	allowed := map[string]bool{
		"GET:/":                  true,
		"GET:/application.js":    true,
		"GET:/callback":          true,
		"GET:/dashboard/nav":     true,
		"GET:/favicon.ico":       true,
		"GET:/favicon.png":       true,
		"GET:/health":            true,
		"GET:/index.html":        true,
		"GET:/logo.png":          true,
		"GET:/signout":           true,
		"GET:/sparkle":           true,
		"GET:/sparkles":          true,
		"POST:/sparkles/restore": true,
	}
	ok, _ := allowed[strings.Join([]string{
		r.Attributes.Request.Http.Method,
		r.Attributes.Request.Http.Path,
	}, ":")]
	return ok
}

func (svc *CheckService) isAllowed(ctx context.Context, r *auth.CheckRequest) bool {
	if !svc.validRequest(ctx, r) {
		return false
	}

	log.WithFields(ctx, svc.fieldsFor(r))
	return svc.isLoggedIn(ctx, r) || svc.isPublic(ctx, r)
}

func (svc *CheckService) validRequest(ctx context.Context, r *auth.CheckRequest) bool {
	return x.IsPresent(r) &&
		x.IsPresent(r.Attributes) &&
		x.IsPresent(r.Attributes.Request) &&
		x.IsPresent(r.Attributes.Request.Http)
}

// TODO:: Replace this naive implementation
func (svc *CheckService) isLoggedIn(ctx context.Context, r *auth.CheckRequest) bool {
	return x.IsPresent(r.Attributes.Request.Http.Headers["cookie"])
}

func (svc *CheckService) OK(ctx context.Context) *auth.CheckResponse {
	log.WithFields(ctx, log.Fields{"authorized": true})
	return &auth.CheckResponse{
		Status: &status.Status{
			Code: int32(codes.OK),
		},
		HttpResponse: &auth.CheckResponse_OkResponse{
			OkResponse: &auth.OkHttpResponse{
				Headers:              []*core.HeaderValueOption{},
				HeadersToRemove:      []string{},
				ResponseHeadersToAdd: []*core.HeaderValueOption{},
			},
		},
	}
}

func (svc *CheckService) Denied(ctx context.Context) *auth.CheckResponse {
	log.WithFields(ctx, log.Fields{"authorized": false})
	return &auth.CheckResponse{
		Status: &status.Status{
			Code: int32(codes.PermissionDenied),
		},
		HttpResponse: &auth.CheckResponse_DeniedResponse{
			DeniedResponse: &auth.DeniedHttpResponse{
				Status: &types.HttpStatus{
					Code: types.StatusCode_Unauthorized,
				},
				Headers: []*core.HeaderValueOption{},
			},
		},
	}
}

func (svc *CheckService) fieldsFor(r *auth.CheckRequest) log.Fields {
	return log.Fields{
		"id":       r.Attributes.Request.Http.Id,
		"method":   r.Attributes.Request.Http.Method,
		"path":     r.Attributes.Request.Http.Path,
		"host":     r.Attributes.Request.Http.Host,
		"scheme":   r.Attributes.Request.Http.Scheme,
		"protocol": r.Attributes.Request.Http.Protocol,
	}
}