Example #1
1
// AddSignedCookie adds the specified cookie to the response and also adds an
// additional 'signed' cookie that is used to validate the cookies value when
// SignedCookie is called.
func (c *Context) AddSignedCookie(cookie *http.Cookie) (*http.Cookie, error) {

	// make the signed cookie
	signedCookie := new(http.Cookie)

	// copy the cookie settings
	signedCookie.Path = cookie.Path
	signedCookie.Domain = cookie.Domain
	signedCookie.RawExpires = cookie.RawExpires
	signedCookie.Expires = cookie.Expires
	signedCookie.MaxAge = cookie.MaxAge
	signedCookie.Secure = cookie.Secure
	signedCookie.HttpOnly = cookie.HttpOnly
	signedCookie.Raw = cookie.Raw

	// set the signed cookie specifics
	signedCookie.Name = toSignedCookieName(cookie.Name)
	signedCookie.Value = Hash(cookie.Value)

	// add the cookies
	http.SetCookie(c.ResponseWriter, cookie)
	http.SetCookie(c.ResponseWriter, signedCookie)

	// return the new signed cookie (and no error)
	return signedCookie, nil

}
Example #2
1
func (s String) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Println(r.Header)
	// w.Header().Add("Set-Cookie","foo=bar; Domain=foobar.com; Path=/path; Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly");
	sessionCookie := http.Cookie{}
	sessionCookie.Name = "foo"
	sessionCookie.Value = "Bar"
	sessionCookie.Path = "foobar"
	sessionCookie.Domain = "foo.bar"
	const longForm = "Jan 2, 2006 at 3:04pm (MST)"
	sessionCookie.Expires, _ = time.Parse(longForm, "Jan 13, 2021 at 10:06pm (GMT)")
	sessionCookie.RawExpires = "Wed, 13 Jan 2021 22:23:01 GMT"
	http.SetCookie(w, &sessionCookie)
	// w.WriteHeader(201);
	fmt.Fprint(w, s)
}
Example #3
1
/**
 * クッキーを作成する
 * @function
 * @param {string} name クッキーの名前
 * @param {string} value クッキーの値
 * @param {string} domain 有効ドメイン
 * @param {string} path 有効ディレクトリ
 * @param {int} hour 有効期限(時間)
 */
func NewCookie(name string, value string, domain string, path string, hour int) *http.Cookie {
	duration := time.Hour * time.Duration(hour)
	now := time.Now()
	expire := now.Add(duration)

	cookie := new(http.Cookie)
	cookie.Name = name
	cookie.Value = value
	cookie.Domain = domain
	cookie.Path = path
	cookie.Expires = expire
	cookie.RawExpires = expire.Format(time.UnixDate)
	cookie.MaxAge = 60 * 60 * hour
	cookie.Secure = false
	cookie.HttpOnly = true
	cookie.Raw = fmt.Sprintf("%s=%s", cookie.Name, cookie.Value)
	cookie.Unparsed = []string{cookie.Raw}

	return cookie
}
Example #4
0
func newLoginSession(w http.ResponseWriter, r *http.Request, u *user) (s *session, err error) {
	sess := session{newUUID(), u}
	s = &sess
	err = nil
	sessionKey := "sessions:" + s.id
	userInfo := map[string]string{
		"Id":           u.ID,
		"Username":     u.Username,
		"EmailAddress": u.EmailAddress,
		"Role":         u.Role,
	}
	db := radix.NewClient(redisConfiguration)
	defer db.Close()
	reply := db.Command("hmset", sessionKey, userInfo)
	if reply.Error() != nil {
		errText := fmt.Sprintf("Failed to set Session data (Redis): %v", reply.Error())
		logger.Err(errText)
		err = errors.New(errText)
		return
	}
	// set login cookie
	_, err = r.Cookie("vafanLogin")
	if err != nil {
		if err == http.ErrNoCookie {
			//no cookie, set one
			err = nil
			logger.Info("Setting login cookie.")
			si, env := getSite(r)
			c := new(http.Cookie)
			c.Name = "vafanLogin"
			c.Value = s.id
			c.Path = "/"
			//c.Domain = "." + env + "." + si.Host
			if env == "production" {
				c.Domain = "." + si.Host
			} else {
				c.Domain = "." + env + "." + si.Host
			}
			http.SetCookie(w, c)
		} else {
			logger.Err(fmt.Sprintf("Failed getting login cookie (when trying to set): %v", err))
			return
		}
	} else {
		logger.Notice("Login cookie already set!")
		err = nil
	}
	return
}
Example #5
0
func cookieString(ck *http.Cookie, reset_domain *string, setCookie bool) string {
	if !setCookie {
		// inaccurate
		return ck.Name + "=" + ck.Value
	}
	if reset_domain != nil {
		dot := strings.IndexByte(*reset_domain, '.')
		if dot > 1 {
			ck.Domain = *reset_domain
		} else {
			ck.Domain = NULL
		}
	}
	return ck.String()
}
Example #6
0
func setUserCookie(u *user, w http.ResponseWriter, r *http.Request) {
	s, env := getSite(r)
	logger.Info(fmt.Sprintf("Setting a new user cookie: %v", u.ID))
	c := new(http.Cookie)
	c.Name = "vafanUser"
	c.Value = u.ID
	//c.Domain = "." + env + "." + s.Host
	if env == "production" {
		c.Domain = "." + s.Host
	} else {
		c.Domain = "." + env + "." + s.Host
	}
	c.Path = "/"
	http.SetCookie(w, c)
}
Example #7
0
// Redirects the User to the OAuth1.0a provider's Login Screen. A RequestToken
// is requested from the Provider, and included in the URL's oauth_token param.
//
// A Successful Login / Authorization should return both the oauth_token and
// the oauth_verifier to the callback URL.
func (self *OAuth1Mixin) AuthorizeRedirect(w http.ResponseWriter, r *http.Request, endpoint string) error {

	//Get a Request Token
	token, err := self.Consumer.RequestToken()
	if err != nil {
		return err
	}

	//Get the redirect URL
	url, err := self.Consumer.AuthorizeRedirect(token)
	if err != nil {
		return err
	}

	//Write the Request Token to a Cookie, so that we can
	//retrieve it after re-directing the user to the
	//providers authorization screen.
	cookie := http.Cookie{}
	cookie.Name = "_token"
	cookie.Path = "/"
	cookie.Domain = r.URL.Host
	cookie.HttpOnly = true
	cookie.Secure = Config.CookieSecure
	cookie.Value = token.Encode()
	http.SetCookie(w, &cookie)

	// redirect to the login url
	http.Redirect(w, r, url, http.StatusSeeOther)
	return nil
}
Example #8
0
func commitSession(headers Headers, env Env, key, secret, domain string) {
	cookie := new(http.Cookie)
	cookie.Name = key
	cookie.Value = encodeCookie(env["mango.session"].(map[string]interface{}), secret)
	cookie.Domain = domain
	headers.Add("Set-Cookie", cookie.String())
}
Example #9
0
// Answers to /sso, returns the SSO cookie and redirects to /startpage
func handler(w http.ResponseWriter, r *http.Request) {
	re := regexp.MustCompile("CN=([ 0-9A-Za-z_]+)")

	user := r.Header.Get("Certificate-User")
	if user == "" {
		log.Panicf("Did not get user!")
	}

	match := re.FindStringSubmatch(user)

	if len(match) != 2 {
		log.Panicf("No CN found!")
	}

	cn := match[1]

	sessionid := getSessionID(cn, r.Header.Get("X-Forwarded-For"))
	token := generate_session_token(sessionid, cn)
	signature := sign_session_token(token)

	cookie := http.Cookie{}
	cookie.Name = "PLAY_SESSION"
	cookie.Value = signature + "-" + token
	cookie.Path = "/"
	cookie.Domain = external_host
	cookie.Expires = time.Now().Add(356 * 24 * time.Hour)
	cookie.HttpOnly = true
	http.SetCookie(w, &cookie)

	http.Redirect(w, r, "/startpage", http.StatusFound)
}
Example #10
0
// cookie returns an http.Cookie containing the signed session.
func (s Session) cookie() *http.Cookie {
	var sessionValue string
	ts := s.getExpiration()
	s[TIMESTAMP_KEY] = getSessionExpirationCookie(ts)
	for key, value := range s {
		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"
	}

	sessionData := url.QueryEscape(sessionValue)
	cookie := http.Cookie{
		Name:     revel.CookiePrefix + "_SESSION",
		Value:    revel.Sign(sessionData) + "-" + sessionData,
		Path:     "/",
		HttpOnly: revel.CookieHttpOnly,
		Secure:   revel.CookieSecure,
		Expires:  ts.UTC(),
	}

	if cookieDomain != "" {
		cookie.Domain = cookieDomain
	}

	return &cookie
}
Example #11
0
func newCookie(r *http.Request, session *Session) *http.Cookie {
	cookie := new(http.Cookie)
	cookie.Name = "UH"
	cookie.Value = session.Id
	cookie.Expires = session.Expires
	cookie.Path = "/"
	cookie.Domain = r.URL.Host
	return cookie
}
Example #12
0
// parse parses a Set-Cookie header into a cookie.
// It supports space in name unlike net/http.
// Returns nil if invalid.
func parse(s string) *http.Cookie {
	var c http.Cookie
	for i, field := range strings.Split(s, ";") {
		if len(field) == 0 {
			continue
		}
		nv := strings.SplitN(field, "=", 2)
		name := strings.TrimSpace(nv[0])
		value := ""
		if len(nv) > 1 {
			value = strings.TrimSpace(nv[1])
		}
		if i == 0 {
			if len(nv) != 2 {
				continue
			}
			c.Name = name
			c.Value = value
			continue
		}
		switch strings.ToLower(name) {
		case "secure":
			c.Secure = true
		case "httponly":
			c.HttpOnly = true
		case "domain":
			c.Domain = value
		case "max-age":
			secs, err := strconv.Atoi(value)
			if err != nil || secs != 0 && value[0] == '0' {
				continue
			}
			if secs <= 0 {
				c.MaxAge = -1
			} else {
				c.MaxAge = secs
			}
		case "expires":
			exptime, err := time.Parse(time.RFC1123, value)
			if err != nil {
				exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", value)
				if err != nil {
					c.Expires = time.Time{}
					continue
				}
			}
			c.Expires = exptime.UTC()
		case "path":
			c.Path = value
		}
	}
	if c.Name == "" {
		return nil
	}
	return &c
}
Example #13
0
func cookie(val string) *http.Cookie {
	c := new(http.Cookie)
	c.Name = config.Cookie
	c.Value = val
	c.Domain = config.ServerDomain
	c.Path = config.CookiePath
	c.HttpOnly = config.CookieHttpOnly
	c.Secure = config.CookieSecure
	return c
}
Example #14
0
File: ctx.go Project: elago/ela
// set cookie
// args: name, value, max age, path, domain, secure, http only, expires
func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
	cookie := http.Cookie{}
	cookie.Name = name
	cookie.Value = url.QueryEscape(value)

	if len(others) > 0 {
		switch v := others[0].(type) {
		case int:
			cookie.MaxAge = v
		case int64:
			cookie.MaxAge = int(v)
		case int32:
			cookie.MaxAge = int(v)
		}
	}

	cookie.Path = "/"
	if len(others) > 1 {
		if v, ok := others[1].(string); ok && len(v) > 0 {
			cookie.Path = v
		}
	}

	if len(others) > 2 {
		if v, ok := others[2].(string); ok && len(v) > 0 {
			cookie.Domain = v
		}
	}

	if len(others) > 3 {
		switch v := others[3].(type) {
		case bool:
			cookie.Secure = v
		default:
			if others[3] != nil {
				cookie.Secure = true
			}
		}
	}

	if len(others) > 4 {
		if v, ok := others[4].(bool); ok && v {
			cookie.HttpOnly = true
		}
	}

	if len(others) > 5 {
		if v, ok := others[5].(time.Time); ok {
			cookie.Expires = v
			cookie.RawExpires = v.Format(time.UnixDate)
		}
	}

	ctx.w.Header().Add("Set-Cookie", cookie.String())
}
Example #15
0
func commitSession(headers Headers, env Env, key, secret string, options *CookieOptions) {
	cookie := new(http.Cookie)
	cookie.Name = key
	cookie.Value = encodeCookie(env["mango.session"].(map[string]interface{}), secret)
	cookie.Path = options.Path
	cookie.Domain = options.Domain
	cookie.MaxAge = options.MaxAge
	cookie.Secure = options.Secure
	cookie.HttpOnly = options.HttpOnly
	headers.Add("Set-Cookie", cookie.String())
}
Example #16
0
func commitSession(headers Headers, env Env, key, secret string, newValue string, options *CookieOptions) {
	cookie := new(http.Cookie)
	cookie.Name = key
	cookie.Value = newValue
	cookie.Path = options.Path
	cookie.Domain = options.Domain
	cookie.MaxAge = options.MaxAge
	cookie.Secure = options.Secure
	cookie.HttpOnly = options.HttpOnly
	headers.Add("Set-Cookie", cookie.String())
}
Example #17
0
func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
	cookie := http.Cookie{}
	cookie.Name = name
	cookie.Value = value

	if len(others) > 0 {
		switch v := others[0].(type) {
		case int:
			cookie.MaxAge = v
		case int64:
			cookie.MaxAge = int(v)
		case int32:
			cookie.MaxAge = int(v)
		}
	}

	// default "/"
	if len(others) > 1 {
		if v, ok := others[1].(string); ok && len(v) > 0 {
			cookie.Path = v
		}
	} else {
		cookie.Path = "/"
	}

	// default empty
	if len(others) > 2 {
		if v, ok := others[2].(string); ok && len(v) > 0 {
			cookie.Domain = v
		}
	}

	// default empty
	if len(others) > 3 {
		switch v := others[3].(type) {
		case bool:
			cookie.Secure = v
		default:
			if others[3] != nil {
				cookie.Secure = true
			}
		}
	}

	// default false. for session cookie default true
	if len(others) > 4 {
		if v, ok := others[4].(bool); ok && v {
			cookie.HttpOnly = true
		}
	}

	ctx.Res.Header().Add("Set-Cookie", cookie.String())
}
Example #18
0
func TestSessions(t *testing.T) {
	sessionsTestServer := func(env Env) (Status, Headers, Body) {
		counter := env.Session()["counter"].(int)
		if counter != 1 {
			t.Error("Expected session[\"counter\"] to equal:", 1, "got:", counter)
		}
		env.Session()["counter"] = counter + 1
		return 200, Headers{}, Body("Hello World!")
	}

	// Compile the stack
	sessionsStack := new(Stack)
	sessionsStack.Middleware(Sessions("my_secret", "my_key", ".my.domain.com"))
	sessionsApp := sessionsStack.Compile(sessionsTestServer)

	// Request against it
	request, err := http.NewRequest("GET", "http://localhost:3000/", nil)
	initial_cookie := new(http.Cookie)
	initial_cookie.Name = "my_key"
	initial_cookie.Value = encodeCookie(map[string]interface{}{"counter": 1}, "my_secret")
	initial_cookie.Domain = ".my.domain.com"
	request.AddCookie(initial_cookie)
	status, headers, _ := sessionsApp(Env{"mango.request": &Request{request}})

	if err != nil {
		t.Error(err)
	}

	if status != 200 {
		t.Error("Expected status to equal 200, got:", status)
	}

	// base 64 encoded, hmac-hashed, and gob encoded stuff
	cookie := headers.Get("Set-Cookie")
	if cookie == "" {
		t.Error("Expected the Set-Cookie header to be set")
	}

	unparsed := strings.Split(strings.Split(cookie, "=")[1], ";")[0]
	value := decodeCookie(unparsed, "my_secret")
	expected_value := map[string]interface{}{"counter": int(2)}
	if len(value) != len(expected_value) {
		t.Error("Expected cookie to equal:", expected_value, "got:", value)
	}

	if value["counter"].(int) != expected_value["counter"].(int) {
		t.Error("Expected cookie[\"counter\"] to equal:", expected_value["counter"], "got:", value["counter"])
	}

	if !strings.Contains(headers.Get("Set-Cookie"), "; Domain=.my.domain.com") {
		t.Error("Expected cookie ", headers.Get("Set-Cookie"), " to contain: '; Domain=.my.domain.com'")
	}
}
Example #19
0
func (res *Response) SetCookie(name string, value string, others ...interface{}) {
	cookie := http.Cookie{}
	cookie.Name = name
	cookie.Value = url.QueryEscape(value)

	if len(others) > 0 {
		switch v := others[0].(type) {
		case int:
			cookie.MaxAge = v
		case int64:
			cookie.MaxAge = int(v)
		case int32:
			cookie.MaxAge = int(v)
		}
	}

	cookie.Path = "/"
	if len(others) > 1 {
		if v, ok := others[1].(string); ok && len(v) > 0 {
			cookie.Path = v
		}
	}

	if len(others) > 2 {
		if v, ok := others[2].(string); ok && len(v) > 0 {
			cookie.Domain = v
		}
	}

	if len(others) > 3 {
		switch v := others[3].(type) {
		case bool:
			cookie.Secure = v
		default:
			if others[3] != nil {
				cookie.Secure = true
			}
		}
	}

	if len(others) > 4 {
		if v, ok := others[4].(bool); ok && v {
			cookie.HttpOnly = true
		}
	}

	res.Header().Add("Set-Cookie", cookie.String())
}
Example #20
0
func (state *SessionCookieState) createCookie(session *Session) *http.Cookie {
	cookie := http.Cookie{}
	cookie.Name = state.SessionKey
	cookie.Value = session.Id
	cookie.Path = state.Path
	cookie.Domain = state.Domain
	cookie.Secure = state.Secure
	cookie.HttpOnly = state.HttpOnly

	if session.IsExpired() {
		cookie.Expires = time.Now()
	} else {
		if state.Expires != 0 {
			cookie.Expires = time.Now().Add(state.Expires)
		}
	}

	return &cookie
}
Example #21
0
func PostLogin(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain")

	username := r.FormValue("username")
	password := r.FormValue("password")

	if username == "" {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Empty username\n"))
		return
	}

	if password == "" {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Empty Password\n"))
		return
	}

	checkedPassword, _, _, err := dba.GetUser(username)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("No Such Username"))
		return
	}

	if checkedPassword != password {
		w.WriteHeader(http.StatusBadRequest)
		w.Write([]byte("Incorrect Password"))
		return
	}

	var cookie http.Cookie
	cookie.Name = "session"
	cookie.Value = sm.GenerateNewSessionId(username)
	cookie.Domain = ""
	cookie.Path = "/"
	cookie.MaxAge = 0

	http.SetCookie(w, &cookie)

	w.WriteHeader(http.StatusOK)
	w.Write([]byte(""))
}
Example #22
0
// Prepare Cookie
func (c Cookie) pre(cookie *http.Cookie) *http.Cookie {
	var num int
	w := c.w

	if cookie.Path == "" {
		cookie.Path = "/"
	}

	if cookie.Domain != "" {
		goto release_cookie
	}

	cookie.Domain = w.Req.Host

	num = strings.LastIndex(cookie.Domain, "]:")
	if num != -1 {
		cookie.Domain = cookie.Domain[:num+1]
		goto skip_port_check
	}

	if cookie.Domain[len(cookie.Domain)-1] == ']' {
		goto skip_port_check
	}

	num = strings.LastIndex(cookie.Domain, ":")
	if num != -1 {
		cookie.Domain = cookie.Domain[:num]
	}

skip_port_check:

	cookie.Domain = strings.Trim(cookie.Domain, "[]")

	if net.ParseIP(cookie.Domain) != nil {
		cookie.Domain = ""
		goto release_cookie
	}

	if strings.Count(cookie.Domain, ".") <= 0 {
		cookie.Domain = ""
	}

release_cookie:

	return cookie
}
Example #23
0
func TestAddSignedCookie(t *testing.T) {

	context := MakeTestContext()
	cookie := new(http.Cookie)
	cookie.Name = "userId"
	cookie.Value = "2468"
	cookie.Path = "/something"
	cookie.Domain = "domain"
	cookie.RawExpires = "NOW"
	cookie.Expires = time.Now()
	cookie.MaxAge = 123
	cookie.Secure = true
	cookie.HttpOnly = true
	cookie.Raw = "userId=2468;"

	signedCookie, err := context.AddSignedCookie(cookie)

	if err != nil {
		t.Errorf("AddSignedCookie shouldn't return an error: %s", err)
		return
	}

	assertEqual(t, signedCookie.Name, fmt.Sprintf("%s_signed", cookie.Name), "Cookie name")
	assertEqual(t, signedCookie.Value, Hash(cookie.Value), "Cookie value (signed)")

	// assert the rest of the values were also copied
	assertEqual(t, signedCookie.Path, cookie.Path, "Path")
	assertEqual(t, signedCookie.Domain, cookie.Domain, "Domain")
	assertEqual(t, signedCookie.RawExpires, cookie.RawExpires, "RawExpires")
	assertEqual(t, signedCookie.Expires, cookie.Expires, "Expires")
	assertEqual(t, signedCookie.MaxAge, cookie.MaxAge, "MaxAge")
	assertEqual(t, signedCookie.Secure, cookie.Secure, "Secure")
	assertEqual(t, signedCookie.HttpOnly, cookie.HttpOnly, "HttpOnly")
	assertEqual(t, signedCookie.Raw, cookie.Raw, "Raw")

}
Example #24
0
func (handler *MinSessionHandler) genCookie() (*http.Cookie, error) {
	log().Debug("minsession generating cookie")

	handler.assureTableInitialized()

	var randReadErr error
	var otherErr error

	nbytes := make([]byte, minSessionCookieNameRandSize)
	vbytes := make([]byte, minSessionCookieValueRandSize)

	cookie_name := ""
	name_gen_needed := true
	for name_gen_needed {
		_, randReadErr = rand.Read(nbytes)
		if randReadErr != nil {
			log().Err(
				"minsession cookie generation was unable to" +
					" read the needed random bytes",
			)
			return nil, randReadErr
		}

		cookie_name = handler.Name + "-" + hex.EncodeToString(nbytes)
		// Slower than adding an else on the next if, but clearer.
		name_gen_needed = false

		_, collision := handler.table[cookie_name]
		if collision {
			// We had a collision with an existing legit cookie?
			// Is the random number generator broken?
			log().Err(
				fmt.Sprintf(
					"minsession cookie generation has"+
						" created a new cookie with a name"+
						" that collides with an already"+
						" existing cookie from the cookie"+
						" table which shares the name: %s",
					cookie_name,
				),
			)
			name_gen_needed = true
			otherErr = rngCollisionError
		}
	}

	_, randReadErr = rand.Read(vbytes)
	if randReadErr != nil {
		log().Err(
			"minsession cookie generation was unable to" +
				" read the needed random bytes",
		)
		return nil, randReadErr
	}

	var cke http.Cookie
	cke.Name = cookie_name
	// TODO delete
	log().Debug(fmt.Sprintf("got %v", handler))
	cke.Value = hex.EncodeToString(vbytes)
	cke.Path = handler.Path
	cke.Domain = handler.Domain
	cke.MaxAge = minSessionCookieMaxAge
	cke.Secure = true
	cke.HttpOnly = true

	return &cke, otherErr
}
Example #25
0
// CSRFWithConfig returns a CSRF middleware with config.
// See `CSRF()`.
func CSRFWithConfig(config CSRFConfig) echo.MiddlewareFunc {
	// Defaults
	if config.Skipper == nil {
		config.Skipper = DefaultCSRFConfig.Skipper
	}
	if config.TokenLength == 0 {
		config.TokenLength = DefaultCSRFConfig.TokenLength
	}
	if config.TokenLookup == "" {
		config.TokenLookup = DefaultCSRFConfig.TokenLookup
	}
	if config.ContextKey == "" {
		config.ContextKey = DefaultCSRFConfig.ContextKey
	}
	if config.CookieName == "" {
		config.CookieName = DefaultCSRFConfig.CookieName
	}
	if config.CookieMaxAge == 0 {
		config.CookieMaxAge = DefaultCSRFConfig.CookieMaxAge
	}

	// Initialize
	parts := strings.Split(config.TokenLookup, ":")
	extractor := csrfTokenFromHeader(parts[1])
	switch parts[0] {
	case "form":
		extractor = csrfTokenFromForm(parts[1])
	case "query":
		extractor = csrfTokenFromQuery(parts[1])
	}

	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			if config.Skipper(c) {
				return next(c)
			}

			req := c.Request()
			k, err := c.Cookie(config.CookieName)
			token := ""

			if err != nil {
				// Generate token
				token = random.String(config.TokenLength)
			} else {
				// Reuse token
				token = k.Value
			}

			switch req.Method {
			case echo.GET, echo.HEAD, echo.OPTIONS, echo.TRACE:
			default:
				// Validate token only for requests which are not defined as 'safe' by RFC7231
				clientToken, err := extractor(c)
				if err != nil {
					return err
				}
				if !validateCSRFToken(token, clientToken) {
					return echo.NewHTTPError(http.StatusForbidden, "csrf token is invalid")
				}
			}

			// Set CSRF cookie
			cookie := new(http.Cookie)
			cookie.Name = config.CookieName
			cookie.Value = token
			if config.CookiePath != "" {
				cookie.Path = config.CookiePath
			}
			if config.CookieDomain != "" {
				cookie.Domain = config.CookieDomain
			}
			cookie.Expires = time.Now().Add(time.Duration(config.CookieMaxAge) * time.Second)
			cookie.Secure = config.CookieSecure
			cookie.HttpOnly = config.CookieHTTPOnly
			c.SetCookie(cookie)

			// Store token in the context
			c.Set(config.ContextKey, token)

			// Protect clients from caching the response
			c.Response().Header().Add(echo.HeaderVary, echo.HeaderCookie)

			return next(c)
		}
	}
}