vitess.io/vitess@v0.16.2/go/acl/acl.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package acl contains functions to enforce access control lists. 18 // It allows you to register multiple security policies for enforcing 19 // ACLs for users or HTTP requests. The specific policy to use must be 20 // specified from a command line argument and cannot be changed on-the-fly. 21 // 22 // For actual authentication and authorization, you would need to implement your 23 // own policy as a package that calls RegisterPolicy(), and compile it into all 24 // Vitess binaries that you use. 25 // 26 // By default (when no security_policy is specified), everyone is allowed to do 27 // anything. 28 // 29 // For convenience, there are two other built-in policies that also do NOT do 30 // any authentication, but allow you to globally disable some roles entirely: 31 // - `deny-all` disallows all roles for everyone. Note that access is still 32 // allowed to endpoints that are considered "public" (no ACL check at all). 33 // - `read-only` allows anyone to act as DEBUGGING or MONITORING, but no one 34 // is allowed to act as ADMIN. It also disallows any other custom roles that 35 // are requested. 36 package acl 37 38 import ( 39 "fmt" 40 "net/http" 41 "sync" 42 43 "github.com/spf13/pflag" 44 45 "vitess.io/vitess/go/vt/log" 46 ) 47 48 // This is a list of predefined roles. Applications are free 49 // to invent more roles, as long as the acl policies they use can 50 // understand what they mean. 51 const ( 52 ADMIN = "admin" 53 DEBUGGING = "debugging" 54 MONITORING = "monitoring" 55 ) 56 57 var ( 58 securityPolicy string 59 policies = make(map[string]Policy) 60 once sync.Once 61 currentPolicy Policy 62 ) 63 64 // Policy defines the interface that needs to be satisfied by 65 // ACL policy implementors. 66 type Policy interface { 67 // CheckAccessActor can be called to verify if an actor 68 // has access to the role. 69 CheckAccessActor(actor, role string) error 70 // CheckAccessHTTP can be called to verify if an actor in 71 // the http request has access to the role. 72 CheckAccessHTTP(req *http.Request, role string) error 73 } 74 75 func RegisterFlags(fs *pflag.FlagSet) { 76 fs.StringVar(&securityPolicy, "security_policy", securityPolicy, "the name of a registered security policy to use for controlling access to URLs - empty means allow all for anyone (built-in policies: deny-all, read-only)") 77 } 78 79 // RegisterPolicy registers a security policy. This function must be called 80 // before the first call to CheckAccess happens, preferably through an init. 81 // This will ensure that the requested policy can be found by other acl 82 // functions when needed. 83 func RegisterPolicy(name string, policy Policy) { 84 if _, ok := policies[name]; ok { 85 log.Fatalf("policy %s is already registered", name) 86 } 87 policies[name] = policy 88 } 89 90 func savePolicy() { 91 if securityPolicy == "" { 92 // Setting the policy to nil means Allow All from Anyone. 93 currentPolicy = nil 94 return 95 } 96 if policy, ok := policies[securityPolicy]; ok { 97 currentPolicy = policy 98 return 99 } 100 log.Warningf("security_policy %q not found; using fallback policy (deny-all)", securityPolicy) 101 currentPolicy = denyAllPolicy{} 102 } 103 104 // CheckAccessActor uses the current security policy to 105 // verify if an actor has access to the role. 106 func CheckAccessActor(actor, role string) error { 107 once.Do(savePolicy) 108 if currentPolicy != nil { 109 return currentPolicy.CheckAccessActor(actor, role) 110 } 111 return nil 112 } 113 114 // CheckAccessHTTP uses the current security policy to 115 // verify if an actor in an http request has access to 116 // the role. 117 func CheckAccessHTTP(req *http.Request, role string) error { 118 once.Do(savePolicy) 119 if currentPolicy != nil { 120 return currentPolicy.CheckAccessHTTP(req, role) 121 } 122 return nil 123 } 124 125 // SendError is a convenience function that sends an ACL 126 // error as an HTTP response. 127 func SendError(w http.ResponseWriter, err error) { 128 w.WriteHeader(http.StatusForbidden) 129 fmt.Fprintf(w, "Access denied: %v\n", err) 130 }