Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What Would gorilla/sessions v2 Look Like? #105

Closed
11 tasks
elithrar opened this issue Jan 27, 2017 · 25 comments
Closed
11 tasks

What Would gorilla/sessions v2 Look Like? #105

elithrar opened this issue Jan 27, 2017 · 25 comments

Comments

@elithrar
Copy link
Contributor

elithrar commented Jan 27, 2017

With Go 1.7's request.Context() requiring a (non-trivial!) breaking API change, I figured it would be a good time to discuss what a "v2" of this package would look like. Further, with golang/dep on the horizon, vendoring/pinning dependencies is more common-place, allowing us to 'safely' leave v1 API users as-is whilst improving the library for others.

What I see as key changes:

  • Supporting request.Context (only)
  • Enriching the Store interface: New, Get, Save, Delete rather than relying on MaxAge to trigger it
  • Better built-in stores: BoltDB instead of a FilesystemStore (still uses the filesystem, but is a more scalable store)
  • Improved crypto interface: enforce algorithms, key size, and don't give users a choice. De-emphasize encrypting (an option, rather than a first-class param in New)
  • Fix the order of - Save(w, r) rather than (r, w)
  • Improve the user-experience around Save (forgetting to save sucks, and is common enough!)
  • Make sessions.Values better (setters, getters, rather than a map)
  • Simplify the internal registry: call it a cache (what it really is), and perhaps have it auto-save at the end of a request?
  • Out of the box middleware that makes a session available? Checks for one?
  • JSON as the default encoder, not gob. Faster, less overhead (in bytes); retain gob for those who really need to store blobs.
  • Potentially supporting more than just cookies for non-cookie stores (Bearer tokens, but not JWTs).

There is no schedule for this yet. Open to feedback.

@kisielk
Copy link
Contributor

kisielk commented Jan 28, 2017

I agree with pretty much all of this.

@elithrar
Copy link
Contributor Author

Great. I'd also likely simplify gorilla/securecookie as part of this: the internals have grown over time, and moving from the current AES-CTR + MAC approach to either HMAC-SHA-512/256 or ChaCha20+Poly1305 (https://godoc.org/golang.org/x/crypto/chacha20poly1305) and thus simplifying the crypto.

securecookie is otherwise a small lib; I think it was a mistake growing the error interface the way we did, but alas.

@alexedwards
Copy link

+1 for pretty much all of these.

You've probably already considered this, but one thing I learnt from building SCS was that although using JSON for the default encoding is sensible from a performance view it has the potential to make things more complicated for users (assuming a map[interface{}]interface{} is still used behind the scenes).

For example, retrieving a previously stored time.Time object. With gob encoding, the user can just retrieve the interface{} value and assert it to a time.Time. It's fairly simple and straightforward. With underlying JSON encoding, the user needs to know to type assert the interface{} value to a string and then call time.Parse(time.RFC3339, ...) to get it back to a time.Time object.

Similarly, dealing with integers and floats and json.Number is a bit of a pain.

You could implement helpers (like I did in SCS), or there's probably something clever that can be done with a custom JSON unmarshaller. Either way, it would be good to keep usage no more difficult than it is with gob encoding.

A couple of further suggestions.

It would be nice if both absolute and idle timeouts could be supported (in line with the OWASP recommendations).

For the non-cookie stores, there would ideally be an clear and baked-in way to renew session IDs after login/logouts etc to help prevent session fixation attacks (possibly as part of the interface along with New, Save etc). At the moment this isn't possible (at least as far as I can see) without a clunky workaround of creating a new session with a different name and copying the data over.

@elithrar
Copy link
Contributor Author

Thanks for the input @alexedwards -

  • gob was (is!) the most compatible, so I may yet keep it, and just make changing between them a little easier.

It would be nice if both absolute and idle timeouts could be supported (in line with the OWASP recommendations).

Yes, agreed. Some opts.MaxAge and opts.IdleTimeout would be useful. I'd need to think about how to employ that without also performing a Set-Cookie on every response too.

For the non-cookie stores, there would ideally be an clear and baked-in way to renew session IDs after login/logouts etc to help prevent session fixation attacks (possibly as part of the interface along with New, Save etc).

Agree - a Refresh method would be useful here, or an argument to Save that achieves the same effect (issues a new ID).

@elithrar
Copy link
Contributor Author

gorilla/securecookie#43 tracks a "v2" of securecookie that will underpin some of this work

@ccahoon
Copy link

ccahoon commented Mar 9, 2017

This looks great. One question: have you considered/what are the tradeoffs of putting included stores with non stdlib imports (cookie, boltdb) into separate packages?

Thank you for all your work!

@elithrar
Copy link
Contributor Author

elithrar commented Mar 9, 2017

@ccahoon The stores would each be in separate packages ("sub-packages") so that if you don't use BoltDB, it's not imported.

@elithrar
Copy link
Contributor Author

elithrar commented Mar 24, 2017 via email

@niondir
Copy link

niondir commented Jul 17, 2017

I think especially supporting the golang context package would be a big step forward. It's even backwards compatible, since all interfaces already accept a request to get the value.

Any timeline on this?

@elithrar elithrar added this to the gorilla/sessions v2.0 milestone Sep 30, 2017
@elithrar
Copy link
Contributor Author

@niondir No timeline. I want to wait until golang/dep hits 1.0 so I existing users have a clear way to pin to pre-2.0. As it is, those pulling from master will see a ton of breakage immediately, which is going to be painful as gorilla/sessions sees use from a wide range of developers (newbie Gophers to experienced).

@romainmenke
Copy link

romainmenke commented Dec 18, 2017

A way to disable the in memory cache would be great. This package is unusable in applications that run multiple instances.

@elithrar
Copy link
Contributor Author

elithrar commented Dec 18, 2017 via email

@romainmenke
Copy link

@elithrar My bad, have been looking at too many packages that utilise an in memory cache that is shared across requests. Looking through the source code it was not immediately clear that the Registry was isolated to a single request. Thx for pointing this out!

@dhui
Copy link

dhui commented Jan 11, 2018

Is dep 1.0 still a blocker? According to the status in the readme, dep is safe for production usage: https://github.com/golang/dep#current-status
Namely, the manifest and lock files are stable. See: https://github.com/golang/dep/wiki/Roadmap#timeline

My understanding is that if gorilla/sessions starts using dep, downstream packages shouldn't be affected. See: https://github.com/golang/dep/blob/master/docs/FAQ.md#my-dependers-dont-use-dep-yet-what-should-i-do

Any downstream package that's using the master branch should be aware that they've signed up for backwards incompatible changes. The other option would be to create a new repo/package if preserving backwards compatibility is paramount.

@elithrar
Copy link
Contributor Author

elithrar commented Jan 11, 2018 via email

@dhui
Copy link

dhui commented Jan 11, 2018

dep ensure -add github.com/gorilla/sessions@^1.0.0 should properly pin the package.
But yeah, anyone who's used (or using) go get will have a problem and I guess it's too early to force all of the downstream packages to start using dep.

What do you think about creating a v2 branch to start all of the v2 work, tagging new releases off of the v2 branch, and requiring v2 users to use dep? The v2 branch could be merged back into master when dep is part of the toolchain.

@elithrar
Copy link
Contributor Author

elithrar commented Jan 11, 2018 via email

@dhui
Copy link

dhui commented Jan 12, 2018

Cool, lemme know where I can help out by tagging me on any issue in sessions or securecookie

@elithrar
Copy link
Contributor Author

elithrar commented Jan 12, 2018 via email

@dhui
Copy link

dhui commented Jan 12, 2018

I think most of the improvements listed in the issue description are good to have.
The changes I find the most useful (in-order) are:

  1. Enriching the Store interface
    • The store API needs to be revamped and re-designed. An implementer of a session store shouldn't be responsible for setting the HTTP cookie in the response. Cookie management and the session lifecycle should be handled by the sessions package, not by the store.
    • Session stores should only have one concern which is the persistence of the session data. Pushing core functionality (even parts of it) to the stores will result in inconsistent behaviors between 3rd party stores and make it harder to change core functionality in the future.
    • Simplifying the Store receiver methods to not use http.Request and http.ResponseWriter would be a breaking change.
  2. Supporting request.Context (only)
    • Would the registry/cache still be necessary if request.Context was used?
    • A cleaner way to cache sessions would be to implement the cache as a session store which "wraps" an existing session store. Then the developer can choose between different caching implementations or use multiple caching layers. e.g. an in-process-memory cache, memcached, and SQL store
  3. Out of the box middleware that makes a session available
    • I'd also have the middleware save the session which would address this improvement: "Improve the user-experience around Save (forgetting to save sucks, and is common enough!)"
    • And help with the "Enriching the Store interface" improvement
  4. Improved crypto interface
  5. JSON as the default encoder

Regarding "Make sessions.Values better (setters, getters, rather than a map)", I'd like to keep the sessions.Values map but also expose type-casting getters and setters. The developer may have their own way of handling type-casting failures.

@elithrar
Copy link
Contributor Author

Thanks for the feedback @dhui

The store API needs to be revamped and re-designed. An implementer of a session store shouldn't be responsible for setting the HTTP cookie in the response. Cookie management and the session lifecycle should be handled by the sessions package, not by the store.
Session stores should only have one concern which is the persistence of the session data. Pushing core functionality (even parts of it) to the stores will result in inconsistent behaviors between 3rd party stores and make it harder to change core functionality in the future.

Agree. Stores need the session ID (to allow lookup), TTL (to allow expiry) and the session payload itself. There are a few approaches here - I'll omit context.Context from the signatures for now as that warrants further discussion.

type Store interface {
    Get(id string) (*Session, error)
    Save(session *Session) error
    Expire(id string) (bool, error)
}

Stores would need to care about marshalling *Session to the correct format: we could alternatively send id string, exp time.Time, data []byte where data is already marshalled, but I feel marshalling is within the purvey of a Store.

Supporting request.Context (only)
Would the registry/cache still be necessary if request.Context was used?

No, but that goes back to the larger, breaking change. We would only support context.Context in v2 as gorilla/context does not cooperate when used alongside request.WithContext due to the way it shallow clones a request.

Out of the box middleware that makes a session available

How would it make it available? In the request context? If so, fetching it from there is the same amount of code—except, with type assertions as context.Value is an interface{}—as calling sessions.Get(ctx, name).

Saving, on the other hand, can be done (mostly) automatically, although if a user writes to the response body before the middleware runs, we'll run into issues. The middleware would need to hijack the http.ResponseWriter and defer writes so that it can Save. There's also the fact that you may not wish to Save on every request.

Improved crypto interface
I'm a fan of having safe defaults but allowing the developer to customize security for their usecase. A good way of doing this is by exposing a separate "unsafe" or "hazmat" package. Inspired by https://golang.org/pkg/unsafe/ and https://cryptography.io/en/latest/

I'd need to see an extremely convincing argument for this. I don't see any sensible use-case for why a developer needs to customize the cryptographic primitives of a sessions library. You should not need to replace the CSPRNG, and you shouldn't need to change the AEAD. We'll use HMAC-SHA-512 for auth-only mode & XSalsa20-Poly1305 for encrypted mode (AEAD).

JSON as the default encoder

Yes!

Regarding "Make sessions.Values better (setters, getters, rather than a map)", I'd like to keep the sessions.Values map but also expose type-casting getters and setters. The developer may have their own way of handling type-casting failures.

Agree!

@dhui
Copy link

dhui commented Jan 17, 2018

You're welcome! Thanks for being open and receptive to different ideas!

Stores would need to care about marshalling *Session to the correct format: we could alternatively send id string, exp time.Time, data []byte where data is already marshalled, but I feel marshalling is within the purvey of a Store.

Agreed. I think the Store should be responsible for storing the data since there may be more efficient storage mechanisms for the store besides []byte. The Session will need all relevant fields exported for stores to support marshalling and unmarshalling.

How would it make it available? In the request context?

Yeah, I'm a fan of the middleware setting the Session using an unexported context key type in request.Context(). That way, there's a bit less boiler plate code for the consuming developer.
Something like sessions.SessionFromRequest(http.Request) (*Session, error). We could also drop the error and create a new Session if it's used w/o the middleware, but that could lead to subtle bugs if there are multiple calls using the same request.

The middleware would need to hijack the http.ResponseWriter and defer writes so that it can Save.

I'm not familiar w/ the Hijacker interface, but it seems like we'd want compatibility with HTTP/2 connections. I'm not sure if wrapping the ResponseWriter to set the cookie after WriteHeader() called is the best route.

There's also the fact that you may not wish to Save on every request.

Good point regarding the middleware. We could have 2 middlewares:

  1. one that saves and sets the cookie
  2. one only verifies the session).

I'd need to see an extremely convincing argument for this.

Haha, I don't think I have one but I'll try... My best argument is that there's no one size fits all for security. Security is about making trade-offs between usability, performance, and protection against expected attack vectors. The best person to make that decision is the the app developer. Providing a clean crypto interface (sane defaults and allowing customization with ample warnings) would allow developers to customize security for their usecase. e.g. They could use HSMs and/or TRNGs if they wanted to although it's probably overkill for sessions...

One other thing regarding the crypto interface: make sure there's a way to change/upgrade the algorithm, key size, and work factor. These things are always change, so a system that can auto upgrade the algo, key size, and work factor will save a lot of future headaches.

@elithrar elithrar removed the ready label Jun 30, 2019
@stale
Copy link

stale bot commented Aug 29, 2019

This issue has been automatically marked as stale because it hasn't seen a recent update. It'll be automatically closed in a few days.

@stale
Copy link

stale bot commented Oct 28, 2019

This issue has been automatically marked as stale because it hasn't seen a recent update. It'll be automatically closed in a few days.

@stale stale bot added the stale label Oct 28, 2019
@stale stale bot closed this as completed Nov 4, 2019
@dradtke
Copy link

dradtke commented Jan 8, 2020

Should this be reopened?

monfresh added a commit to transcom/mymove that referenced this issue Apr 14, 2020
**Why**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.
Reference: gorilla/sessions#105

The name of the Redis key that holds the session data is based on the
format `scs:session:token`, where `token` is the session cookie value.
In order to revoke an individual session, we need to know the token
corresponding to the user's session. To facilitate that lookup, I
added a new `session-id` to the RequestLogger.
monfresh added a commit to transcom/mymove that referenced this issue Apr 14, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

The name of the Redis key that holds the session data is based on the
format `scs:session:token`, where `token` is the session cookie value.
In order to revoke an individual session, we need to know the token
corresponding to the user's session. To facilitate that lookup, I
added a new `session-id` to the RequestLogger.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [] Verify that the value in the `Expires/Max-Age` column is `Session`
- [] Verify that the HttpOnly column is checked
- [] Verify that the Path is `/`
- [] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-cli`, then type `KEYS *`
- [] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
- [] Verify that there is a `session-id` entry in the
`middleware/request_logger.go` output that is the same value as the
current browser cookie, not the previous one before the user signed in
5. Sign out
- [] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [] Verify you can create a New milmove User
- [] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
monfresh added a commit to transcom/mymove that referenced this issue Apr 14, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

The name of the Redis key that holds the session data is based on the
format `scs:session:token`, where `token` is the session cookie value.
In order to revoke an individual session, we need to know the token
corresponding to the user's session. To facilitate that lookup, I
added a new `session-id` to the RequestLogger.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [ ] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [ ] Verify that the value in the `Expires/Max-Age` column is `Session`
- [ ] Verify that the HttpOnly column is checked
- [ ] Verify that the Path is `/`
- [ ] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-cli`, then type `KEYS *`
- [ ] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [ ] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [ ] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that there is a `session-id` entry in the
`middleware/request_logger.go` output that is the same value as the
current browser cookie, not the previous one before the user signed in
5. Sign out
- [ ] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [ ] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [ ] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [ ] Verify you can create a New milmove User
- [ ] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
monfresh added a commit to transcom/mymove that referenced this issue Apr 14, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

The name of the Redis key that holds the session data is based on the
format `scs:session:token`, where `token` is the session cookie value.
In order to revoke an individual session, we need to know the token
corresponding to the user's session. To facilitate that lookup, I
added a new `session-id` to the RequestLogger.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [ ] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [ ] Verify that the value in the `Expires/Max-Age` column is `Session`
- [ ] Verify that the HttpOnly column is checked
- [ ] Verify that the Path is `/`
- [ ] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-cli`, then type `KEYS *`
- [ ] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [ ] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [ ] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that there is a `session-id` entry in the
`middleware/request_logger.go` output that is the same value as the
current browser cookie, not the previous one before the user signed in
5. Sign out
- [ ] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [ ] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [ ] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [ ] Verify you can create a New milmove User
- [ ] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
monfresh added a commit to transcom/mymove that referenced this issue Apr 14, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

The name of the Redis key that holds the session data is based on the
format `scs:session:token`, where `token` is the session cookie value.
In order to revoke an individual session, we need to know the token
corresponding to the user's session. To facilitate that lookup, I
added a new `session-id` to the RequestLogger.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [ ] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [ ] Verify that the value in the `Expires/Max-Age` column is `Session`
- [ ] Verify that the HttpOnly column is checked
- [ ] Verify that the Path is `/`
- [ ] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-cli`, then type `KEYS *`
- [ ] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [ ] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [ ] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that there is a `session-id` entry in the
`middleware/request_logger.go` output that is the same value as the
current browser cookie, not the previous one before the user signed in
5. Sign out
- [ ] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [ ] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [ ] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [ ] Verify you can create a New milmove User
- [ ] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
monfresh added a commit to transcom/mymove that referenced this issue Apr 14, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

The name of the Redis key that holds the session data is based on the
format `scs:session:token`, where `token` is the session cookie value.
In order to revoke an individual session, we need to know the token
corresponding to the user's session. To facilitate that lookup, I
added a new `session-id` to the RequestLogger.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [ ] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [ ] Verify that the value in the `Expires/Max-Age` column is `Session`
- [ ] Verify that the HttpOnly column is checked
- [ ] Verify that the Path is `/`
- [ ] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-cli`, then type `KEYS *`
- [ ] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [ ] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [ ] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that there is a `session-id` entry in the
`middleware/request_logger.go` output that is the same value as the
current browser cookie, not the previous one before the user signed in
5. Sign out
- [ ] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [ ] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [ ] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [ ] Verify you can create a New milmove User
- [ ] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
monfresh added a commit to transcom/mymove that referenced this issue Apr 21, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

The name of the Redis key that holds the session data is based on the
format `scs:session:token`, where `token` is the session cookie value.
In order to revoke an individual session, we need to know the token
corresponding to the user's session. To facilitate that lookup, I
added a new `session-id` to the RequestLogger.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [ ] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [ ] Verify that the value in the `Expires/Max-Age` column is `Session`
- [ ] Verify that the HttpOnly column is checked
- [ ] Verify that the Path is `/`
- [ ] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-cli`, then type `KEYS *`
- [ ] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [ ] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [ ] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that there is a `session-id` entry in the
`middleware/request_logger.go` output that is the same value as the
current browser cookie, not the previous one before the user signed in
5. Sign out
- [ ] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [ ] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [ ] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [ ] Verify you can create a New milmove User
- [ ] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
monfresh added a commit to transcom/mymove that referenced this issue Apr 27, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

The name of the Redis key that holds the session data is based on the
format `scs:session:token`, where `token` is the session cookie value.
In order to revoke an individual session, we need to know the token
corresponding to the user's session. To facilitate that lookup, I
added a new `session-id` to the RequestLogger.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [ ] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [ ] Verify that the value in the `Expires/Max-Age` column is `Session`
- [ ] Verify that the HttpOnly column is checked
- [ ] Verify that the Path is `/`
- [ ] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-cli`, then type `KEYS *`
- [ ] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [ ] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [ ] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that there is a `session-id` entry in the
`middleware/request_logger.go` output that is the same value as the
current browser cookie, not the previous one before the user signed in
5. Sign out
- [ ] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [ ] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [ ] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [ ] Verify you can create a New milmove User
- [ ] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
monfresh added a commit to transcom/mymove that referenced this issue May 13, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

The name of the Redis key that holds the session data is based on the
format `scs:session:token`, where `token` is the session cookie value.
In order to revoke an individual session, we need to know the token
corresponding to the user's session. To facilitate that lookup, I
added a new `session-id` to the RequestLogger.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [ ] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [ ] Verify that the value in the `Expires/Max-Age` column is `Session`
- [ ] Verify that the HttpOnly column is checked
- [ ] Verify that the Path is `/`
- [ ] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-cli`, then type `KEYS *`
- [ ] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [ ] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [ ] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that there is a `session-id` entry in the
`middleware/request_logger.go` output that is the same value as the
current browser cookie, not the previous one before the user signed in
5. Sign out
- [ ] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [ ] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [ ] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [ ] Verify you can create a New milmove User
- [ ] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
monfresh added a commit to transcom/mymove that referenced this issue May 27, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

The name of the Redis key that holds the session data is based on the
format `scs:session:token`, where `token` is the session cookie value.
In order to revoke an individual session, we need to know the token
corresponding to the user's session. To facilitate that lookup, I
added a new `session-id` to the RequestLogger.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [ ] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [ ] Verify that the value in the `Expires/Max-Age` column is `Session`
- [ ] Verify that the HttpOnly column is checked
- [ ] Verify that the Path is `/`
- [ ] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-cli`, then type `KEYS *`
- [ ] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [ ] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [ ] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that there is a `session-id` entry in the
`middleware/request_logger.go` output that is the same value as the
current browser cookie, not the previous one before the user signed in
5. Sign out
- [ ] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [ ] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [ ] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [ ] Verify you can create a New milmove User
- [ ] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
monfresh added a commit to transcom/mymove that referenced this issue Jun 1, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

Note that this PR does not provide the ability to limit concurrent
sessions or revoke individual sessions via the admin interface. That
work is being done in a separate branch.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [ ] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [ ] Verify that the value in the `Expires/Max-Age` column is `Session`
- [ ] Verify that the HttpOnly column is checked
- [ ] Verify that the Path is `/`
- [ ] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-dev`, then type `KEYS *`
- [ ] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [ ] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [ ] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
5. Sign out
- [ ] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [ ] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [ ] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [ ] Verify you can create a New milmove User
- [ ] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**Logging into multiple apps at the same time**
1. Log in to http://milmovelocal:3000/
2. In a separate tab, log in to http://officelocal:3000
3. In a separate tab, log in to http://adminlocal:3000
4. Refresh each tab. Verify that you are still signed into each app.

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
monfresh added a commit to transcom/mymove that referenced this issue Jun 3, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

Note that this PR does not provide the ability to limit concurrent
sessions or revoke individual sessions via the admin interface. That
work is being done in a separate branch.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [ ] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [ ] Verify that the value in the `Expires/Max-Age` column is `Session`
- [ ] Verify that the HttpOnly column is checked
- [ ] Verify that the Path is `/`
- [ ] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-dev`, then type `KEYS *`
- [ ] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [ ] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [ ] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
5. Sign out
- [ ] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [ ] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [ ] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [ ] Verify you can create a New milmove User
- [ ] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**Logging into multiple apps at the same time**
1. Log in to http://milmovelocal:3000/
2. In a separate tab, log in to http://officelocal:3000
3. In a separate tab, log in to http://adminlocal:3000
4. Refresh each tab. Verify that you are still signed into each app.

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
monfresh added a commit to transcom/mymove that referenced this issue Jun 15, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

Note that this PR does not provide the ability to limit concurrent
sessions or revoke individual sessions via the admin interface. That
work is being done in a separate branch.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [ ] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [ ] Verify that the value in the `Expires/Max-Age` column is `Session`
- [ ] Verify that the HttpOnly column is checked
- [ ] Verify that the Path is `/`
- [ ] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-dev`, then type `KEYS *`
- [ ] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [ ] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [ ] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
5. Sign out
- [ ] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [ ] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [ ] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [ ] Verify you can create a New milmove User
- [ ] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**Logging into multiple apps at the same time**
1. Log in to http://milmovelocal:3000/
2. In a separate tab, log in to http://officelocal:3000
3. In a separate tab, log in to http://adminlocal:3000
4. Refresh each tab. Verify that you are still signed into each app.

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
monfresh added a commit to transcom/mymove that referenced this issue Jun 16, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

Note that this PR does not provide the ability to limit concurrent
sessions or revoke individual sessions via the admin interface. That
work is being done in a separate branch.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [ ] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [ ] Verify that the value in the `Expires/Max-Age` column is `Session`
- [ ] Verify that the HttpOnly column is checked
- [ ] Verify that the Path is `/`
- [ ] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-dev`, then type `KEYS *`
- [ ] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [ ] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [ ] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
5. Sign out
- [ ] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [ ] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [ ] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [ ] Verify you can create a New milmove User
- [ ] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**Logging into multiple apps at the same time**
1. Log in to http://milmovelocal:3000/
2. In a separate tab, log in to http://officelocal:3000
3. In a separate tab, log in to http://adminlocal:3000
4. Refresh each tab. Verify that you are still signed into each app.

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
monfresh added a commit to transcom/mymove that referenced this issue Jun 16, 2020
**Description**:
In order to obtain an ATO (Authority to Operate) for MilMove, we need
to provide a way to revoke individual user sessions. Currently,
session management is provided by JWTs per ADR 15, but JWTs aren't
designed to be revoked on an individual basis. Instead, we need to
store session data on the server.

In this PR, we have chosen Redis because it automatically deletes
expired sessions. With Postgres, we would need to run a routine
periodically to clean up stale sessions.

After researching various session management solutions, I chose
`scs` because it was the easiest to integrate, and it supports various
stores out of the box. It is the second most popular repo after
`gorilla/sessions`. I didn't pick `gorilla/sessions` because it suffers
from memory leak issues, and uses its own `context` instead of the
`request.Context()` provided by Golang. The maintainers are aware of
the issues and have opened a GitHub issue to propose improvements for
v2. However, it doesn't look like any progress has been made over the
past 2 years, while `scs` has implemented most of those improvements.

Note that this PR does not provide the ability to limit concurrent
sessions or revoke individual sessions via the admin interface. That
work is being done in a separate branch.

**Setup**:
`docker pull redis`

**Reviewer Notes**:
Things to test:

**milmovelocal auth**
1. Go to milmovelocal:3000
- [ ] Verify that a session cookie named "mil_session_token" is present
(Developer Tools -> Application tab -> Cookies (under Storage in the
left sidebar))
- [ ] Verify that the value in the `Expires/Max-Age` column is `Session`
- [ ] Verify that the HttpOnly column is checked
- [ ] Verify that the Path is `/`
- [ ] Verify that `SameSite` is `Lax`
2. In your Terminal, run `redis-dev`, then type `KEYS *`
- [ ] Verify there is an entry labeled `scs:session:token`, where
`token` is the `Value` of the `mil_session_token` cookie
3. Sign in
- [ ] Verify that after successful sign in, the `Value` of the
`mil_session_token` cookie changes
4. Run `KEYS *` again in the Redis console
- [ ] Verify that the previous entry is gone and that a new one
corresponding to the new session cookie is present
5. Sign out
- [ ] Verify that the previous entry in Redis is gone and that a new one
corresponding to the new session cookie is present
- [ ] Verify that the session cookie changed in the browser
6. In `serve.go`, on line 504, change the IdleTimeout from 15 minutes
to 1 minute
7. Sign in, then wait a little over a minute
8. Try to make a new request without refreshing the browser, for
example, filling out the moves form and clicking the Next button
- [ ] Verify that you are not able to make a request and that you see
an Unauthorized Error. Ideally, the user would be redirected to the
sign in page. I'm working on implementing that.

**devlocal auth**
- [ ] Verify you can sign in and out via devlocal auth flow:
http://milmovelocal:3000/devlocal-auth/login
- [ ] Verify you can create a New milmove User
- [ ] Verify you can create a New dps User

**Role based auth**
1. In your `.envrc.local`, add
`export FEATURE_FLAG_ROLE_BASED_AUTH=true`
2. Stop the server, run `direnv allow`
3. run `echo $FEATURE_FLAG_ROLE_BASED_AUTH` to make sure it's `true`
4. run `make server_run`
5. Go to milmovelocal:3000 and make sure you can sign in and out

**Logging into multiple apps at the same time**
1. Log in to http://milmovelocal:3000/
2. In a separate tab, log in to http://officelocal:3000
3. In a separate tab, log in to http://adminlocal:3000
4. Refresh each tab. Verify that you are still signed into each app.

**References**:
[gorilla sessions issues](gorilla/sessions#105)
[scs repo](https://github.com/alexedwards/scs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants