1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 2017-2018 Couchbase, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <libcouchbase/couchbase.h>
19 #include "auth-priv.h"
20 #include <sstream>
21
22 using namespace lcb;
23
24 lcb_AUTHENTICATOR *
lcbauth_new()25 lcbauth_new()
26 {
27 return new Authenticator();
28 }
29
30 lcb_error_t
lcbauth_add_pass(lcb_AUTHENTICATOR * auth,const char * u,const char * p,int flags)31 lcbauth_add_pass(lcb_AUTHENTICATOR *auth, const char *u, const char *p, int flags)
32 {
33 return auth->add(u, p, flags);
34 }
35
36 lcb_error_t
add(const char * u,const char * p,int flags)37 Authenticator::add(const char *u, const char *p, int flags)
38 {
39 if (!u) {
40 return LCB_EINVAL;
41 }
42
43 if (!(flags & (LCBAUTH_F_BUCKET|LCBAUTH_F_CLUSTER))) {
44 return LCB_EINVAL;
45 }
46
47 if (m_mode == LCBAUTH_MODE_RBAC && (flags & LCBAUTH_F_BUCKET)) {
48 return LCB_OPTIONS_CONFLICT;
49 }
50
51 if (flags & LCBAUTH_F_CLUSTER) {
52 if (p) {
53 m_username = u;
54 m_password = p;
55 } else {
56 m_username.clear();
57 m_password.clear();
58 }
59 }
60
61 if (flags & LCBAUTH_F_BUCKET) {
62 if (p) {
63 m_buckets[u] = p;
64 } else {
65 m_buckets.erase(u);
66 }
67 }
68
69 return LCB_SUCCESS;
70 }
71
72 static const std::string EmptyString;
73
cache_key(const char * host,const char * port,const char * bucket)74 std::string cache_key(const char *host, const char *port, const char *bucket) {
75 std::stringstream key;
76 key << ":" << (host ? host : "?nullhost?");
77 key << ":" << (port ? port : "?nullport?");
78 key << ":" << (bucket ? bucket : "?nullbucket?");
79 return key.str();
80 }
81
username_for(const char * host,const char * port,const char * bucket,bool use_cache)82 const std::string Authenticator::username_for(const char *host, const char *port, const char *bucket, bool use_cache)
83 {
84 switch (m_mode) {
85 case LCBAUTH_MODE_RBAC:
86 return m_username;
87 case LCBAUTH_MODE_DYNAMIC:
88 if (m_usercb != NULL) {
89 if (!use_cache) {
90 return m_usercb(m_cookie, host, port, bucket);
91 }
92 std::string key = cache_key(host, port, bucket);
93 if (user_cache_.find(key) == user_cache_.end()) {
94 std::string username = m_usercb(m_cookie, host, port, bucket);
95 user_cache_[key] = username;
96 return username;
97 } else {
98 return user_cache_[key];
99 }
100 }
101 break;
102 case LCBAUTH_MODE_CLASSIC:
103 // Find bucket specific credentials:
104 const Map::const_iterator it = m_buckets.find(bucket);
105 if (it != m_buckets.end()) {
106 return it->first;
107 }
108 break;
109 }
110 return EmptyString;
111 }
112
password_for(const char * host,const char * port,const char * bucket,bool use_cache)113 const std::string Authenticator::password_for(const char *host, const char *port, const char *bucket, bool use_cache)
114 {
115 switch (m_mode) {
116 case LCBAUTH_MODE_RBAC:
117 return m_password;
118 case LCBAUTH_MODE_DYNAMIC:
119 if (m_passcb != NULL) {
120 if (!use_cache) {
121 return m_passcb(m_cookie, host, port, bucket);
122 }
123 std::string key = cache_key(host, port, bucket);
124 if (pass_cache_.find(key) == pass_cache_.end()) {
125 std::string password = m_passcb(m_cookie, host, port, bucket);
126 pass_cache_[key] = password;
127 return password;
128 } else {
129 return pass_cache_[key];
130 }
131 }
132 break;
133 case LCBAUTH_MODE_CLASSIC:
134 const Map::const_iterator it = m_buckets.find(bucket);
135 if (it != m_buckets.end()) {
136 return it->second;
137 }
138 break;
139 }
140 return EmptyString;
141 }
142
invalidate_cache_for(const char * host,const char * port,const char * bucket)143 void Authenticator::invalidate_cache_for(const char *host, const char *port, const char *bucket)
144 {
145 if (m_mode == LCBAUTH_MODE_DYNAMIC) {
146 std::string key = cache_key(host, port, bucket);
147 pass_cache_.erase(key);
148 user_cache_.erase(key);
149 }
150 }
151
reset_cache()152 void Authenticator::reset_cache()
153 {
154 pass_cache_.clear();
155 user_cache_.clear();
156 }
157
158 void
lcbauth_ref(lcb_AUTHENTICATOR * auth)159 lcbauth_ref(lcb_AUTHENTICATOR *auth)
160 {
161 auth->incref();
162 }
163
164 void
lcbauth_unref(lcb_AUTHENTICATOR * auth)165 lcbauth_unref(lcb_AUTHENTICATOR *auth)
166 {
167 auth->decref();
168 }
169
Authenticator(const Authenticator & other)170 Authenticator::Authenticator(const Authenticator &other)
171 : m_buckets(other.m_buckets), m_username(other.m_username), m_password(other.m_password), m_refcount(1),
172 m_mode(other.m_mode), m_usercb(other.m_usercb), m_passcb(other.m_passcb), m_cookie(other.m_cookie),
173 user_cache_(), pass_cache_()
174 {
175 }
176
177 lcb_AUTHENTICATOR *
lcbauth_clone(const lcb_AUTHENTICATOR * src)178 lcbauth_clone(const lcb_AUTHENTICATOR *src) {
179 return new Authenticator(*src);
180 }
181
182 lcb_error_t
lcbauth_set_mode(lcb_AUTHENTICATOR * src,lcbauth_MODE mode)183 lcbauth_set_mode(lcb_AUTHENTICATOR *src, lcbauth_MODE mode) {
184 return src->set_mode(mode);
185 }
186
lcbauth_set_callbacks(lcb_AUTHENTICATOR * auth,void * cookie,lcb_AUTHCALLBACK usercb,lcb_AUTHCALLBACK passcb)187 lcb_error_t lcbauth_set_callbacks(lcb_AUTHENTICATOR *auth, void *cookie, lcb_AUTHCALLBACK usercb,
188 lcb_AUTHCALLBACK passcb)
189 {
190 return auth->set_callbacks(cookie, usercb, passcb);
191 }
192