X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=blobdiff_plain;f=src%2Ffoundation%2Fapi%2Frevel%2Fsession_adapter_cookie.go;fp=src%2Ffoundation%2Fapi%2Frevel%2Fsession_adapter_cookie.go;h=ebe871d3ec1f35f910c9daa6efad4a919083846b;hb=1d1ee6961c93781e1187d8c7faa868da6b2f01f4;hp=0000000000000000000000000000000000000000;hpb=56dd5e0f2164b37b40ac1daa188ccc618b4cbd19;p=iec.git diff --git a/src/foundation/api/revel/session_adapter_cookie.go b/src/foundation/api/revel/session_adapter_cookie.go new file mode 100644 index 0000000..ebe871d --- /dev/null +++ b/src/foundation/api/revel/session_adapter_cookie.go @@ -0,0 +1,144 @@ +package revel + +import ( + "fmt" + "github.com/revel/revel/session" + "net/http" + "net/url" + "strconv" + "strings" + "time" +) + + +type ( + // The session cookie engine + SessionCookieEngine struct { + ExpireAfterDuration time.Duration + } +) + +// A logger for the session engine +var sessionEngineLog = RevelLog.New("section", "session-engine") + +// Create a new instance to test +func init() { + RegisterSessionEngine(initCookieEngine, "revel-cookie") +} + +// For testing purposes this engine is used +func NewSessionCookieEngine() *SessionCookieEngine { + ce := &SessionCookieEngine{} + return ce +} + +// Called when the the application starts, retrieves data from the app config so cannot be run until then +func initCookieEngine() SessionEngine { + ce := &SessionCookieEngine{} + + var err error + if expiresString, ok := Config.String("session.expires"); !ok { + ce.ExpireAfterDuration = 30 * 24 * time.Hour + } else if expiresString == session.SessionValueName { + ce.ExpireAfterDuration = 0 + } else if ce.ExpireAfterDuration, err = time.ParseDuration(expiresString); err != nil { + panic(fmt.Errorf("session.expires invalid: %s", err)) + } + + return ce +} + +// Decode the session information from the cookie retrieved from the controller request +func (cse *SessionCookieEngine) Decode(c *Controller) { + // Decode the session from a cookie. + c.Session = map[string]interface{}{} + sessionMap := c.Session + if cookie, err := c.Request.Cookie(CookiePrefix + session.SessionCookieSuffix); err != nil { + return + } else { + cse.DecodeCookie(cookie, sessionMap) + c.Session = sessionMap + } +} + +// Encode the session information to the cookie, set the cookie on the controller +func (cse *SessionCookieEngine) Encode(c *Controller) { + + c.SetCookie(cse.GetCookie(c.Session)) +} + +// Exposed only for testing purposes +func (cse *SessionCookieEngine) DecodeCookie(cookie ServerCookie, s session.Session) { + // Decode the session from a cookie. + // Separate the data from the signature. + cookieValue := cookie.GetValue() + hyphen := strings.Index(cookieValue, "-") + if hyphen == -1 || hyphen >= len(cookieValue)-1 { + return + } + sig, data := cookieValue[:hyphen], cookieValue[hyphen+1:] + + // Verify the signature. + if !Verify(data, sig) { + sessionEngineLog.Warn("Session cookie signature failed") + return + } + + // Parse the cookie into a temp map, and then load it into the session object + tempMap := map[string]string{} + ParseKeyValueCookie(data, func(key, val string) { + tempMap[key] = val + }) + s.Load(tempMap) + + // Check timeout after unpacking values - if timeout missing (or removed) destroy all session + // objects + if s.SessionTimeoutExpiredOrMissing() { + // If this fails we need to delete all the keys from the session + for key := range s { + delete(s, key) + } + } +} + +// Convert session to cookie +func (cse *SessionCookieEngine) GetCookie(s session.Session) *http.Cookie { + var sessionValue string + ts := s.GetExpiration(cse.ExpireAfterDuration) + if ts.IsZero() { + s[session.TimestampKey] = session.SessionValueName + } else { + s[session.TimestampKey] = strconv.FormatInt(ts.Unix(), 10) + } + + // Convert the key to a string map + stringMap := s.Serialize() + + for key, value := range stringMap { + if strings.ContainsAny(key, ":\x00") { + panic("Session keys may not have colons or null bytes") + } + if strings.Contains(value, "\x00") { + panic("Session values may not have null bytes") + } + sessionValue += "\x00" + key + ":" + value + "\x00" + } + + if len(sessionValue) > 1024*4 { + sessionEngineLog.Error("SessionCookieEngine.Cookie, session data has exceeded 4k limit (%d) cookie data will not be reliable", "length", len(sessionValue)) + } + + sessionData := url.QueryEscape(sessionValue) + sessionCookie := &http.Cookie{ + Name: CookiePrefix + session.SessionCookieSuffix, + Value: Sign(sessionData) + "-" + sessionData, + Domain: CookieDomain, + Path: "/", + HttpOnly: true, + Secure: CookieSecure, + Expires: ts.UTC(), + MaxAge: int(cse.ExpireAfterDuration.Seconds()), + } + return sessionCookie + +}