blob: 2464828e65467ba54eb7909e40bb4c78fb36d83d [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001// Copyright 2015 The etcd Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package auth
16
17import (
18 "context"
19 "encoding/json"
20 "path"
21
22 etcderr "github.com/coreos/etcd/error"
23 "github.com/coreos/etcd/etcdserver"
24 "github.com/coreos/etcd/etcdserver/etcdserverpb"
25)
26
27func (s *store) ensureAuthDirectories() error {
28 if s.ensuredOnce {
29 return nil
30 }
31 for _, res := range []string{StorePermsPrefix, StorePermsPrefix + "/users/", StorePermsPrefix + "/roles/"} {
32 ctx, cancel := context.WithTimeout(context.Background(), s.timeout)
33 defer cancel()
34 pe := false
35 rr := etcdserverpb.Request{
36 Method: "PUT",
37 Path: res,
38 Dir: true,
39 PrevExist: &pe,
40 }
41 _, err := s.server.Do(ctx, rr)
42 if err != nil {
43 if e, ok := err.(*etcderr.Error); ok {
44 if e.ErrorCode == etcderr.EcodeNodeExist {
45 continue
46 }
47 }
48 plog.Errorf("failed to create auth directories in the store (%v)", err)
49 return err
50 }
51 }
52 ctx, cancel := context.WithTimeout(context.Background(), s.timeout)
53 defer cancel()
54 pe := false
55 rr := etcdserverpb.Request{
56 Method: "PUT",
57 Path: StorePermsPrefix + "/enabled",
58 Val: "false",
59 PrevExist: &pe,
60 }
61 _, err := s.server.Do(ctx, rr)
62 if err != nil {
63 if e, ok := err.(*etcderr.Error); ok {
64 if e.ErrorCode == etcderr.EcodeNodeExist {
65 s.ensuredOnce = true
66 return nil
67 }
68 }
69 return err
70 }
71 s.ensuredOnce = true
72 return nil
73}
74
75func (s *store) enableAuth() error {
76 _, err := s.updateResource("/enabled", true)
77 return err
78}
79func (s *store) disableAuth() error {
80 _, err := s.updateResource("/enabled", false)
81 return err
82}
83
84func (s *store) detectAuth() bool {
85 if s.server == nil {
86 return false
87 }
88 value, err := s.requestResource("/enabled", false, false)
89 if err != nil {
90 if e, ok := err.(*etcderr.Error); ok {
91 if e.ErrorCode == etcderr.EcodeKeyNotFound {
92 return false
93 }
94 }
95 plog.Errorf("failed to detect auth settings (%s)", err)
96 return false
97 }
98
99 var u bool
100 err = json.Unmarshal([]byte(*value.Event.Node.Value), &u)
101 if err != nil {
102 plog.Errorf("internal bookkeeping value for enabled isn't valid JSON (%v)", err)
103 return false
104 }
105 return u
106}
107
108func (s *store) requestResource(res string, dir, quorum bool) (etcdserver.Response, error) {
109 ctx, cancel := context.WithTimeout(context.Background(), s.timeout)
110 defer cancel()
111 p := path.Join(StorePermsPrefix, res)
112 method := "GET"
113 if quorum {
114 method = "QGET"
115 }
116 rr := etcdserverpb.Request{
117 Method: method,
118 Path: p,
119 Dir: dir,
120 }
121 return s.server.Do(ctx, rr)
122}
123
124func (s *store) updateResource(res string, value interface{}) (etcdserver.Response, error) {
125 return s.setResource(res, value, true)
126}
127func (s *store) createResource(res string, value interface{}) (etcdserver.Response, error) {
128 return s.setResource(res, value, false)
129}
130func (s *store) setResource(res string, value interface{}, prevexist bool) (etcdserver.Response, error) {
131 err := s.ensureAuthDirectories()
132 if err != nil {
133 return etcdserver.Response{}, err
134 }
135 ctx, cancel := context.WithTimeout(context.Background(), s.timeout)
136 defer cancel()
137 data, err := json.Marshal(value)
138 if err != nil {
139 return etcdserver.Response{}, err
140 }
141 p := path.Join(StorePermsPrefix, res)
142 rr := etcdserverpb.Request{
143 Method: "PUT",
144 Path: p,
145 Val: string(data),
146 PrevExist: &prevexist,
147 }
148 return s.server.Do(ctx, rr)
149}
150
151func (s *store) deleteResource(res string) (etcdserver.Response, error) {
152 err := s.ensureAuthDirectories()
153 if err != nil {
154 return etcdserver.Response{}, err
155 }
156 ctx, cancel := context.WithTimeout(context.Background(), s.timeout)
157 defer cancel()
158 pex := true
159 p := path.Join(StorePermsPrefix, res)
160 rr := etcdserverpb.Request{
161 Method: "DELETE",
162 Path: p,
163 PrevExist: &pex,
164 }
165 return s.server.Do(ctx, rr)
166}