github.com/cs3org/reva/v2@v2.27.7/pkg/siteacc/html/session.go (about) 1 // Copyright 2018-2020 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 html 20 21 import ( 22 "net/http" 23 "net/url" 24 "strings" 25 "time" 26 27 "github.com/cs3org/reva/v2/pkg/siteacc/data" 28 "github.com/google/uuid" 29 "github.com/pkg/errors" 30 ) 31 32 // Session stores all data associated with an HTML session. 33 type Session struct { 34 ID string 35 MigrationID string 36 RemoteAddress string 37 CreationTime time.Time 38 Timeout time.Duration 39 40 Data map[string]interface{} 41 42 loggedInUser *SessionUser 43 44 expirationTime time.Time 45 halflifeTime time.Time 46 47 sessionCookieName string 48 } 49 50 // SessionUser holds information about the logged in user 51 type SessionUser struct { 52 Account *data.Account 53 Site *data.Site 54 } 55 56 func getRemoteAddress(r *http.Request) string { 57 // Remove the port number from the remote address 58 remoteAddress := "" 59 if address := strings.Split(r.RemoteAddr, ":"); len(address) == 2 { 60 remoteAddress = address[0] 61 } 62 return remoteAddress 63 } 64 65 // LoggedInUser retrieves the currently logged in user or nil if none is logged in. 66 func (sess *Session) LoggedInUser() *SessionUser { 67 return sess.loggedInUser 68 } 69 70 // LoginUser logs in the provided user. 71 func (sess *Session) LoginUser(acc *data.Account, site *data.Site) { 72 sess.loggedInUser = &SessionUser{ 73 Account: acc, 74 Site: site, 75 } 76 } 77 78 // LogoutUser logs out the currently logged in user. 79 func (sess *Session) LogoutUser() { 80 sess.loggedInUser = nil 81 } 82 83 // IsUserLoggedIn tells whether a user is currently logged in. 84 func (sess *Session) IsUserLoggedIn() bool { 85 return sess.loggedInUser != nil 86 } 87 88 // Save stores the session ID in a cookie using a response writer. 89 func (sess *Session) Save(cookiePath string, w http.ResponseWriter) { 90 fullURL, _ := url.Parse(cookiePath) 91 http.SetCookie(w, &http.Cookie{ 92 Name: sess.sessionCookieName, 93 Secure: !strings.EqualFold(fullURL.Hostname(), "localhost"), 94 Value: sess.ID, 95 MaxAge: int(sess.Timeout / time.Second), 96 Domain: fullURL.Hostname(), 97 Path: fullURL.Path, 98 SameSite: http.SameSiteLaxMode, 99 }) 100 } 101 102 // VerifyRequest checks whether the provided request matches the stored session. 103 func (sess *Session) VerifyRequest(r *http.Request, verifyRemoteAddress bool) error { 104 cookie, err := r.Cookie(sess.sessionCookieName) 105 if err != nil { 106 return errors.Wrap(err, "unable to retrieve client session ID") 107 } 108 if cookie.Value != sess.ID { 109 return errors.Errorf("the session ID doesn't match") 110 } 111 112 if verifyRemoteAddress && sess.RemoteAddress != "" { 113 if !strings.EqualFold(getRemoteAddress(r), sess.RemoteAddress) { 114 return errors.Errorf("remote address has changed (%v != %v)", r.RemoteAddr, sess.RemoteAddress) 115 } 116 } 117 118 return nil 119 } 120 121 // HalftimePassed checks whether the session has passed the first half of its lifetime. 122 func (sess *Session) HalftimePassed() bool { 123 return time.Now().After(sess.halflifeTime) 124 } 125 126 // HasExpired checks whether the session has reached is timeout. 127 func (sess *Session) HasExpired() bool { 128 return time.Now().After(sess.expirationTime) 129 } 130 131 // NewSession creates a new session, giving it a random ID. 132 func NewSession(name string, timeout time.Duration, r *http.Request) *Session { 133 session := &Session{ 134 ID: uuid.NewString(), 135 MigrationID: "", 136 RemoteAddress: getRemoteAddress(r), 137 CreationTime: time.Now(), 138 Timeout: timeout, 139 Data: make(map[string]interface{}, 10), 140 loggedInUser: nil, 141 expirationTime: time.Now().Add(timeout), 142 halflifeTime: time.Now().Add(timeout / 2), 143 sessionCookieName: name, 144 } 145 return session 146 }