github.com/cs3org/reva/v2@v2.27.7/pkg/cbox/user/rest/cache.go (about) 1 // Copyright 2018-2021 CERN 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 // 15 // In applying this license, CERN does not waive the privileges and immunities 16 // granted to it by virtue of its status as an Intergovernmental Organization 17 // or submit itself to any jurisdiction. 18 19 package rest 20 21 import ( 22 "encoding/json" 23 "errors" 24 "fmt" 25 "strconv" 26 "strings" 27 "time" 28 29 userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1" 30 "github.com/gomodule/redigo/redis" 31 ) 32 33 const ( 34 userPrefix = "user:" 35 usernamePrefix = "username:" 36 userIDPrefix = "userid:" 37 namePrefix = "name:" 38 mailPrefix = "mail:" 39 uidPrefix = "uid:" 40 userGroupsPrefix = "groups:" 41 ) 42 43 func initRedisPool(address, username, password string) *redis.Pool { 44 return &redis.Pool{ 45 46 MaxIdle: 50, 47 MaxActive: 1000, 48 IdleTimeout: 240 * time.Second, 49 50 Dial: func() (redis.Conn, error) { 51 var opts []redis.DialOption 52 if username != "" { 53 opts = append(opts, redis.DialUsername(username)) 54 } 55 if password != "" { 56 opts = append(opts, redis.DialPassword(password)) 57 } 58 59 c, err := redis.Dial("tcp", address, opts...) 60 if err != nil { 61 return nil, err 62 } 63 return c, err 64 }, 65 66 TestOnBorrow: func(c redis.Conn, t time.Time) error { 67 _, err := c.Do("PING") 68 return err 69 }, 70 } 71 } 72 73 func (m *manager) setVal(key, val string, expiration int) error { 74 conn := m.redisPool.Get() 75 defer conn.Close() 76 if conn != nil { 77 args := []interface{}{key, val} 78 if expiration != -1 { 79 args = append(args, "EX", expiration) 80 } 81 if _, err := conn.Do("SET", args...); err != nil { 82 return err 83 } 84 return nil 85 } 86 return errors.New("rest: unable to get connection from redis pool") 87 } 88 89 func (m *manager) getVal(key string) (string, error) { 90 conn := m.redisPool.Get() 91 defer conn.Close() 92 if conn != nil { 93 val, err := redis.String(conn.Do("GET", key)) 94 if err != nil { 95 return "", err 96 } 97 return val, nil 98 } 99 return "", errors.New("rest: unable to get connection from redis pool") 100 } 101 102 func (m *manager) findCachedUsers(query string) ([]*userpb.User, error) { 103 conn := m.redisPool.Get() 104 defer conn.Close() 105 if conn != nil { 106 query = fmt.Sprintf("%s*%s*", userPrefix, strings.ReplaceAll(strings.ToLower(query), " ", "_")) 107 keys, err := redis.Strings(conn.Do("KEYS", query)) 108 if err != nil { 109 return nil, err 110 } 111 var args []interface{} 112 for _, k := range keys { 113 args = append(args, k) 114 } 115 116 // Fetch the users for all these keys 117 userStrings, err := redis.Strings(conn.Do("MGET", args...)) 118 if err != nil { 119 return nil, err 120 } 121 userMap := make(map[string]*userpb.User) 122 for _, user := range userStrings { 123 u := userpb.User{} 124 if err = json.Unmarshal([]byte(user), &u); err == nil { 125 userMap[u.Id.OpaqueId] = &u 126 } 127 } 128 129 var users []*userpb.User 130 for _, u := range userMap { 131 users = append(users, u) 132 } 133 134 return users, nil 135 } 136 137 return nil, errors.New("rest: unable to get connection from redis pool") 138 } 139 140 func (m *manager) fetchCachedUserDetails(uid *userpb.UserId) (*userpb.User, error) { 141 user, err := m.getVal(userPrefix + usernamePrefix + strings.ToLower(uid.OpaqueId)) 142 if err != nil { 143 return nil, err 144 } 145 146 u := userpb.User{} 147 if err = json.Unmarshal([]byte(user), &u); err != nil { 148 return nil, err 149 } 150 return &u, nil 151 } 152 153 func (m *manager) cacheUserDetails(u *userpb.User) error { 154 encodedUser, err := json.Marshal(&u) 155 if err != nil { 156 return err 157 } 158 if err = m.setVal(userPrefix+usernamePrefix+strings.ToLower(u.Id.OpaqueId), string(encodedUser), -1); err != nil { 159 return err 160 } 161 if err = m.setVal(userPrefix+userIDPrefix+strings.ToLower(u.Id.OpaqueId), string(encodedUser), -1); err != nil { 162 return err 163 } 164 165 if u.Mail != "" { 166 if err = m.setVal(userPrefix+mailPrefix+strings.ToLower(u.Mail), string(encodedUser), -1); err != nil { 167 return err 168 } 169 } 170 if u.DisplayName != "" { 171 if err = m.setVal(userPrefix+namePrefix+u.Id.OpaqueId+"_"+strings.ReplaceAll(strings.ToLower(u.DisplayName), " ", "_"), string(encodedUser), -1); err != nil { 172 return err 173 } 174 } 175 if u.UidNumber != 0 { 176 if err = m.setVal(userPrefix+uidPrefix+strconv.FormatInt(u.UidNumber, 10), string(encodedUser), -1); err != nil { 177 return err 178 } 179 } 180 return nil 181 } 182 183 func (m *manager) fetchCachedUserByParam(field, claim string) (*userpb.User, error) { 184 user, err := m.getVal(userPrefix + field + ":" + strings.ToLower(claim)) 185 if err != nil { 186 return nil, err 187 } 188 189 u := userpb.User{} 190 if err = json.Unmarshal([]byte(user), &u); err != nil { 191 return nil, err 192 } 193 return &u, nil 194 } 195 196 func (m *manager) fetchCachedUserGroups(uid *userpb.UserId) ([]string, error) { 197 groups, err := m.getVal(userPrefix + userGroupsPrefix + strings.ToLower(uid.OpaqueId)) 198 if err != nil { 199 return nil, err 200 } 201 g := []string{} 202 if err = json.Unmarshal([]byte(groups), &g); err != nil { 203 return nil, err 204 } 205 return g, nil 206 } 207 208 func (m *manager) cacheUserGroups(uid *userpb.UserId, groups []string) error { 209 g, err := json.Marshal(&groups) 210 if err != nil { 211 return err 212 } 213 return m.setVal(userPrefix+userGroupsPrefix+strings.ToLower(uid.OpaqueId), string(g), m.conf.UserGroupsCacheExpiration*60) 214 }