sessions

package
v3.0.0-rc.3+incompatible Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 24, 2016 License: Apache-2.0 Imports: 11 Imported by: 0

README

Folder Information

This folder contains the sessions support for Iris. The folder name is plural (session's') so the /sessions/providers, because you can use both of them at the same time.

Package information

This package is new and unique, if you notice a bug or issue post it here.

  • Cleans the temp memory when a sessions is iddle, and re-loccate it , fast, to the temp memory when it's necessary. Also most used/regular sessions are going front in the memory's list.

  • Supports redisstore and normal memory routing. If redisstore is used but fails to connect then ,automatically, switching to the memory storage.

A session can be defined as a server-side storage of information that is desired to persist throughout the user's interaction with the web site or web application.

Instead of storing large and constantly changing information via cookies in the user's browser, only a unique identifier is stored on the client side (called a "session id"). This session id is passed to the web server every time the browser makes an HTTP request (ie a page link or AJAX request). The web application pairs this session id with it's internal database/memory and retrieves the stored variables for use by the requested page.


You will see two different ways to use the sessions, I'm using the first. No performance differences.

How to use - easy way

Example memory


package main

import (
	"github.com/kataras/iris"
)

func main() {

	// these are  the defaults
	//iris.Config().Session.Provider = "memory"
	//iris.Config().Session.Secret = "irissessionid"
	//iris.Config().Session.Life = time.Duration(60) *time.Minute

	iris.Get("/set", func(c *iris.Context) {

		//set session values
		c.Session().Set("name", "iris")

		//test if setted here
		c.Write("All ok session setted to: %s", c.Session().GetString("name"))
	})

	iris.Get("/get", func(c *iris.Context) {
		name := c.Session().GetString("name")

		c.Write("The name on the /set was: %s", name)
	})

	iris.Get("/delete", func(c *iris.Context) {
		//get the session for this context

		c.Session().Delete("name")

	})

	iris.Get("/clear", func(c *iris.Context) {

		// removes all entries
		c.Session().Clear()
	})

	iris.Get("/destroy", func(c *iris.Context) {
		//destroy, removes the entire session and cookie
		c.SessionDestroy()
	})

	println("Server is listening at :8080")
	iris.Listen("8080")
}


Example default redis


package main

import (
	"github.com/kataras/iris"
)

func main() {

	iris.Config().Session.Provider = "redis"

	iris.Get("/set", func(c *iris.Context) {

		//set session values
		c.Session().Set("name", "iris")

		//test if setted here
		c.Write("All ok session setted to: %s", c.Session().GetString("name"))
	})

	iris.Get("/get", func(c *iris.Context) {
		name := c.Session().GetString("name")

		c.Write("The name on the /set was: %s", name)
	})

	iris.Get("/delete", func(c *iris.Context) {
		//get the session for this context

		c.Session().Delete("name")

	})

	iris.Get("/clear", func(c *iris.Context) {

		// removes all entries
		c.Session().Clear()
	})

	iris.Get("/destroy", func(c *iris.Context) {
		//destroy, removes the entire session and cookie
		c.SessionDestroy()
	})

	println("Server is listening at :8080")
	iris.Listen("8080")
}

Example customized redis

// Config the redis config
type Config struct {
	// Network "tcp"
	Network string
	// Addr "127.0.01:6379"
	Addr string
	// Password string .If no password then no 'AUTH'. Default ""
	Password string
	// If Database is empty "" then no 'SELECT'. Default ""
	Database string
	// MaxIdle 0 no limit
	MaxIdle int
	// MaxActive 0 no limit
	MaxActive int
	// IdleTimeout 5 * time.Minute
	IdleTimeout time.Duration
	// Prefix "myprefix-for-this-website". Default ""
	Prefix string
	// MaxAgeSeconds how much long the redis should keep the session in seconds. Default 2520.0 (42minutes)
	MaxAgeSeconds int
}


package main

import (
	"github.com/kataras/iris"
	"github.com/kataras/iris/sessions/providers/redis"
)

func init() {
	redis.Config.Addr = "127.0.0.1:2222"
	redis.Config.MaxAgeSeconds = 5000.0
}

func main() {

	iris.Config().Session.Provider = "redis"

	iris.Get("/set", func(c *iris.Context) {

		//set session values
		c.Session().Set("name", "iris")

		//test if setted here
		c.Write("All ok session setted to: %s", c.Session().GetString("name"))
	})

	iris.Get("/get", func(c *iris.Context) {
		name := c.Session().GetString("name")

		c.Write("The name on the /set was: %s", name)
	})

	iris.Get("/delete", func(c *iris.Context) {
		//get the session for this context

		c.Session().Delete("name")

	})

	iris.Get("/clear", func(c *iris.Context) {

		// removes all entries
		c.Session().Clear()
	})

	iris.Get("/destroy", func(c *iris.Context) {
		//destroy, removes the entire session and cookie
		c.SessionDestroy()
	})

	println("Server is listening at :8080")
	iris.Listen("8080")
}

How to use - hard way

// New creates & returns a new Manager and start its GC
// accepts 4 parameters
// first is the providerName (string) ["memory","redis"]
// second is the cookieName, the session's name (string) ["mysessionsecretcookieid"]
// third is the gcDuration (time.Duration)
// when this time passes it removes from
// temporary memory GC the value which hasn't be used for a long time(gcDuration)
// this is for the client's/browser's Cookie life time(expires) also

New(provider string, cName string, gcDuration time.Duration) *sessions.Manager

Example memory


package main

import (
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/sessions"

	_ "github.com/kataras/iris/sessions/providers/memory" // here we add the memory provider and store
)

var sess *sessions.Manager

func init() {
	sess = sessions.New("memory", "irissessionid", time.Duration(60)*time.Minute)
}

func main() {

	iris.Get("/set", func(c *iris.Context) {
		//get the session for this context
		session := sess.Start(c)

		//set session values
		session.Set("name", "kataras")

		//test if setted here
		c.Write("All ok session setted to: %s", session.Get("name"))
	})

	iris.Get("/get", func(c *iris.Context) {
		//get the session for this context
		session := sess.Start(c)

		var name string

		//get the session value
		if v := session.Get("name"); v != nil {
			name = v.(string)
		}
		// OR just name = session.GetString("name")

		c.Write("The name on the /set was: %s", name)
	})

		iris.Get("/delete", func(c *iris.Context) {
		//get the session for this context
		session := sess.Start(c)

		session.Delete("name")

	})

	iris.Get("/clear", func(c *iris.Context) {
		//get the session for this context
		session := sess.Start(c)
		// removes all entries
		session.Clear()
	})

	iris.Get("/destroy", func(c *iris.Context) {
		//destroy, removes the entire session and cookie
		sess.Destroy(c)
	})

	iris.Listen("8080")
}

// session.GetAll() returns all values a map[interface{}]interface{}
// session.VisitAll(func(key interface{}, value interface{}) { /* loops for each entry */})

}



Example redis with default configuration

The default redis client points to 127.0.0.1:6379


package main

import (
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/sessions"

	_ "github.com/kataras/iris/sessions/providers/redis"
    // here we add the redis  provider and store
    //with the default redis client points to 127.0.0.1:6379
)

var sess *sessions.Manager

func init() {
	sess = sessions.New("redis", "irissessionid", time.Duration(60)*time.Minute)
}

//... usage: same as memory

Example redis with custom configuration

type Config struct {
	// Network "tcp"
	Network string
	// Addr "127.0.01:6379"
	Addr string
	// Password string .If no password then no 'AUTH'. Default ""
	Password string
	// If Database is empty "" then no 'SELECT'. Default ""
	Database string
	// MaxIdle 0 no limit
	MaxIdle int
	// MaxActive 0 no limit
	MaxActive int
	// IdleTimeout 5 * time.Minute
	IdleTimeout time.Duration
	//Prefix "myprefix-for-this-website". Default ""
	Prefix string
	// MaxAgeSeconds how much long the redis should keep the session in seconds. Default 2520.0 (42minutes)
	MaxAgeSeconds int
}
package main

import (
	"time"

	"github.com/kataras/iris"
	"github.com/kataras/iris/sessions"

     "github.com/kataras/iris/sessions/providers/redis"
    // here we add the redis  provider and store
    //with the default redis client points to 127.0.0.1:6379
)

var sess *sessions.Manager

func init() {
    // you can config the redis after init also, but before any client's request
    // but it's always a good idea to do it before sessions.New...
    redis.Config.Network = "tcp"
    redis.Config.Addr = "127.0.0.1:6379"
    redis.Config.Prefix = "myprefix-for-this-website"

	sess = sessions.New("redis", "irissessionid", time.Duration(60)*time.Minute)
}

//...usage: same as memory
Security: Prevent session hijacking

This section is external

cookie only and token

Through this simple example of hijacking a session, you can see that it's very dangerous because it allows attackers to do whatever they want. So how can we prevent session hijacking?

The first step is to only set session ids in cookies, instead of in URL rewrites. Also, we should set the httponly cookie property to true. This restricts client side scripts that want access to the session id. Using these techniques, cookies cannot be accessed by XSS and it won't be as easy as we showed to get a session id from a cookie manager.

The second step is to add a token to every request. Similar to the way we dealt with repeat forms in previous sections, we add a hidden field that contains a token. When a request is sent to the server, we can verify this token to prove that the request is unique.

h := md5.New()
salt:="secret%^7&8888"
io.WriteString(h,salt+time.Now().String())
token:=fmt.Sprintf("%x",h.Sum(nil))
if r.Form["token"]!=token{
    // ask to log in
}
session.Set("token",token)

Session id timeout

Another solution is to add a create time for every session, and to replace expired session ids with new ones. This can prevent session hijacking under certain circumstances.


createtime := session.Get("createtime")
if createtime == nil {
    session.Set("createtime", time.Now().Unix())
} else if (createtime.(int64) + 60) < (time.Now().Unix()) {
    sess.Destroy(c)
    session = sess.Start(c)
}

We set a value to save the create time and check if it's expired (I set 60 seconds here). This step can often thwart session hijacking attempts.

Combine the two solutions above and you will be able to prevent most session hijacking attempts from succeeding. On the one hand, session ids that are frequently reset will result in an attacker always getting expired and useless session ids; on the other hand, by setting the httponly property on cookies and ensuring that session ids can only be passed via cookies, all URL based attacks are mitigated.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrProviderNotFound returns an error with message: 'Provider was not found. Please try to _ import one'
	ErrProviderNotFound = errors.New("Provider with name '%s' was not found. Please try to _ import this")
	// ErrProviderRegister returns an error with message: 'On provider registration. Trace: nil or empty named provider are not acceptable'
	ErrProviderRegister = errors.New("On provider registration. Trace: nil or empty named provider are not acceptable")
	// ErrProviderAlreadyExists returns an error with message: 'On provider registration. Trace: provider with name '%s' already exists, maybe you register it twice'
	ErrProviderAlreadyExists = errors.New("On provider registration. Trace: provider with name '%s' already exists, maybe you register it twice")
)

Functions

func Register

func Register(provider IProvider)

Register registers a provider

Types

type IManager

type IManager interface {
	Start(context.IContext) store.IStore
	Destroy(context.IContext)
	GC()
}

IManager is the interface which Manager should implement

type IProvider

type IProvider interface {
	Name() string
	Init(string) (store.IStore, error)
	Read(string) (store.IStore, error)
	Destroy(string) error
	Update(string) error
	GC(time.Duration)
}

IProvider the type which Provider must implement

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager implements the IManager interface contains the cookie's name, the provider and a duration for GC and cookie life expire

func New

func New(cfg ...config.Sessions) *Manager

New creates & returns a new Manager and start its GC

func (*Manager) Destroy

func (m *Manager) Destroy(ctx context.IContext)

Destroy kills the session and remove the associated cookie

func (*Manager) GC

func (m *Manager) GC()

GC tick-tock for the store cleanup it's a blocking function, so run it with go routine, it's totally safe

func (*Manager) Start

func (m *Manager) Start(ctx context.IContext) store.IStore

Start starts the session

type Provider

type Provider struct {
	NewStore  func(sessionId string, cookieLifeDuration time.Duration) store.IStore
	OnDestroy func(store store.IStore) // this is called when .Destroy
	// contains filtered or unexported fields
}

Provider implements the IProvider contains the temp sessions memory, the store and some options for the cookies

func NewProvider

func NewProvider(name string) *Provider

NewProvider returns a new empty Provider

func (*Provider) Destroy

func (p *Provider) Destroy(sid string) error

Destroy always returns a nil error, for now.

func (*Provider) GC

func (p *Provider) GC(duration time.Duration)

GC clears the memory

func (*Provider) Init

func (p *Provider) Init(sid string) (store.IStore, error)

Init creates the store for the first time for this session and returns it

func (*Provider) Name

func (p *Provider) Name() string

Name the provider's name, example: 'memory' or 'redis'

func (*Provider) Read

func (p *Provider) Read(sid string) (store.IStore, error)

Read returns the store which sid parameter is belongs

func (*Provider) Update

func (p *Provider) Update(sid string) error

Update updates the lastAccessedTime, and moves the memory place element to the front always returns a nil error, for now

Directories

Path Synopsis
providers
Package store the package is in diffent folder to reduce the import cycles from the ./context/context.go *
Package store the package is in diffent folder to reduce the import cycles from the ./context/context.go *

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL