Clearance Gem | Expire a Session after Closing the Browser in Rails 5? - ruby-on-rails

How do I automatically sign out when the user closes the browser ? Is there any configuration changes in clearance gem that would enable this.

Create A Cookie - Create or set a cookie on user machine having cookie
name, cookie value and the time when cookie should get deleted
automatically (EXPIRES atribute, this is optional). If this is not
specified the cookie is called a session cookie and it expires (gets
deleted) when user's session ends, i.e. when the browser is closed
Source
In other words, if you don't set an expiration date on a cookie, it should "expire" when the browser is closed.
I've never used Clearance, but the ReadMe shows this configuration option in /config/initializers/clearance.rb:
Clearance.configure do |config|
config.allow_sign_up = true
config.cookie_domain = ".example.com"
config.cookie_expiration = lambda { |cookies| 1.year.from_now.utc }
config.cookie_name = "remember_token"
config.cookie_path = "/"
config.routes = true
config.httponly = false
config.mailer_sender = "reply#example.com"
config.password_strategy = Clearance::PasswordStrategies::BCrypt
config.redirect_url = "/"
config.rotate_csrf_on_sign_in = false
config.secure_cookie = false
config.sign_in_guards = []
config.user_model = User
end
If I were you, I'd attempt to set the cookie_expiration to nil. However, if it requires an expiration, you might want to fork the gem and see if the private API here can be altered to your needs.
If you don't want to do that, you can create a guard in Clearance. When a user signs in, set your own cookie with no expiry date. When the user closes the browser, that should delete your custom cookie. Then, in your guard, when the authentication occurs again, you should be able to check for your custom cookie and (upon not finding it) reject the auth and redirect to sign_in.

Related

How to not make the user re-login every time browser closes?

This might be a basic/dumb question, but I don't know the right keyword to Google. What I want is that when I authenticate the user to my web app, they can close the browser, and when they open it back, they can still use my website - they are not logged out (yet).
I have been following the tutorials in IdentityServer docs (https://identityserver4.readthedocs.io/en/latest/quickstarts/2_interactive_aspnetcore.html), and so far I have managed to get the whole IDP-API-Client working. I have inspect the token that I get from IDP, it's valid for 2 weeks, so what am I missing here, why do I get logged out when I close the browser?
My guess is that I need to store the token to the cookie, but how do I save it, and how do I force the web application to always check for the cookie?
The IS4 tutorial has this:
services.AddAuthentication(o =>
{
o.DefaultScheme = "Cookies";
o.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies")
.AddOpenIdConnect("oidc", o =>
{
o.Authority = "https://localhost:5001";
o.ClientId = "mymvcclient";
o.ClientSecret = "mymvcclientsecret";
o.ResponseType = "code";
o.SaveTokens = true;
o.Scope.Add("myapi");
o.Scope.Add("offline_access");
});
I assume that's just creating a cookie, but how do I specify for it to save my token, and read the token from the cookie when user opens my web application?
Yea there is an option called ExpireTimeSpan in your cookie handler, which defaults to 14 days. You can change it to anytime longer than that by just setting a value to it:
...
.AddCookie("Cookies", options => {
options.ExpireTimeSpan = TimeSpan.FromDays(30);
options.SlidingExpiration = false;
})
.AddOpenIdConnect("oidc", options => {
...
options.UseTokenLifetime = false;
...
})...
The above sets the cookie expiration to 30 days, instead of the default 2 weeks.
You also want to make sure the UseTokenLifetime option from the OIDC is set to false, which is the default for now I think. Tokens coming back from the Identity Server, for example, tend to have short lives. If you set it to true, which was default before, then it would override whatever expiration you set earlier.
The best term to look for on this is probably "persistent sessions", or just session management in general. This is something handled by ASP.NET Core, not really IdentityServer. There are several mechanisms to maintain session state on the server, which you'd need for example not to lose all sessions when a server restart happens.
I've had the best luck using the ITicketStore interface, which allows persisting the sessions to a database. The cookie ends up with a session ID which is validated on each request for expiration.

Session Authentication not working in Play when using Silhouette

I am using Silhouette security library. My Play server seem to send empty Session information in response. What am I doing wrong?
Following is the print on Play's console just before sending response.
Session(Map(authenticator -> 1-jtwBvA+LsLKE2rnkT/nMH1aQF9xc1twhECrma9mj3NUhUdVDmh/4wxQ2MxDOjcxkvEMTi1k63Dg5ezl+9FzDE3miaM5DbOrhyqAyGu4+30mHHV3QdPKA3IQQx5UdL1Hu85fZRI4f3Ef+q6xAgboDps0uBob5ojzo5Oqy8FNsoexn7Wr9iRyTr5xrMrLvl9GNQa+rA3q8qvW84sJaSei2iydrP2OjUbnnzo+zgrHLB3Bn7KJxOcFH4h9CikZNk/FHbtDm4uxzcK3paK1CuuIWLE8yvcYdavJ+4ejV5IaJ8QesJQRFgBktD9L/A2bc03eaA8wm)))
But in the the browser window, I notice that the value is empty.
Set-Cookie: PLAY_SESSION=; Max-Age=-86400;
Note that my browser earlier already had a PLAY_SESSION cookie from previous test runs. However, I would expect that the client application (Angular) would override old cookies with new cookies. Am I correct?
Following is the code snippet which creates, initialised and embed session information
val AuthenticatorFuture: Future[SessionAuthenticator] = silhouette.env.authenticatorService.create(loginInfo) //create authenticator
AuthenticatorFuture.flatMap(authenticator => { //got the authenticator
val securityTokenFuture: Future[Session] = silhouette.env.authenticatorService.init(authenticator) //init authenticator
securityTokenFuture.flatMap(securityToken=> {
println("adding security token: ",securityToken)
val result:Future[AuthenticatorResult] = silhouette.env.authenticatorService.embed(securityToken, Ok(Json.toJson(JsonResultSuccess("found user"))))
result
The Environment is defined as
trait SessionEnv extends Env {
type I = User
type A = SessionAuthenticator
}
As is passed to my controller as
silhouette: Silhouette[SessionEnv]
I created is at compile time as follows
val configSession = SessionAuthenticatorSettings()
val sessionAuthenticatorService = new SessionAuthenticatorService(configSession,fingerprintGenerator,authenticatorEncoder,new DefaultSessionCookieBaker(),clock)
val sessionEnv = com.mohiva.play.silhouette.api.Environment[SessionEnv](userIdentityService,sessionAuthenticatorService,Seq(),EventBus())
The issue is probably expected behavior of Play Framework as Silhouette doesn't modify the session cookie. I noticed that the browser already had a previous expired cookie and it sends it in the signin request. When Silhouette authenticator sees the expired cookie, it sends an empty value back. I think this is to make the browser discard the previous cookie.

prevent user login after registration using django-allauth

i'm using django-allauth for my django app. by default, when a user successfully sign's up, they are automatically logged in. how do you override the default behaviour and prevent the user from logging in after after successful signup. After the user signs up, he/she must be redirected to the login page. ive disabled email verification. Thank you.
# settings.py
LOGIN_REDIRECT_URL = 'welcome'
ACCOUNT_AUTHENTICATED_LOGIN_REDIRECTS = False
ACCOUNT_LOGOUT_REDIRECT_URL = 'thanks'
ACCOUNT_EMAIL_REQUIRED = False
ACCOUNT_EMAIL_VERIFICATION = 'none'
If you don't need the email verification, you can skip the login like this:
First in your urls.py, you must override the url to the default SignupView with a url to your own view:
url(r^'accounts/signup/$', views.CustomSignupView.as_view(), name="account_signup")
Then in your views.py, you have a custom view that will return a path to your frontpage instead of continuing to login the user.
class CustomSignupView(SignupView):
def form_valid(self, form):
self.user = form.save(self.request)
return redirect('/frontpage')

How can I integrate ASP pages and queries into an iOS app?

I have a rather puzzling scenario right now, of figuring out how to integrate several large queries (many different items for each) into an iOS app that communicates with a C#-based REST API. I am trying to pull up several reports in the app, and if I recreate all these queries within the API along with recreating the interface in iOS, it could be quite time-consuming. The page that accesses the reports is a classic ASP page and includes a security header to ensure that the user session has been validated through the login page. Is there a way to set this up as a UIWebView and somehow validate a session upon loading of the UIWebView? Otherwise it will be quite a long, arduous process.
Could a cookie possibly be transferred over after the user has logged in using NSURLRequest to the UIWebView?
Each page has code to check if the session is authenticated
<%
if Session("portallogin") <> "good" then
response.redirect("example.com")
end if
%>
Here is some of the relevant login code that is responsible for initial authentication
'Get the username and password sent as well as user ip
On Error resume next
Session("login") = "bad" 'init to bad
sent_username = Request("username")
sent_password = Request("password")
source = Request.form("source")
remember_me = Request("remember_me")
userip = Request.ServerVariables("REMOTE_ADDR")
sent_username = replace(sent_username,"'","'")
sent_username = protectval(sent_username)
sent_password = protectval(sent_password)
if rs.BOF and rs.EOF then
Session("login") = "bad"
response.cookies("user")("name") = ""
response.Cookies("user")("pword") = ""
else
arr = rs.GetRows()
password = arr(0,0)
memberid = arr(1,0)
expired = arr(2,0)
if sent_password = password then
Session("login") = "good"
if expired = "True" Then
%>
'''''''''''''''''''
if session is good
'''''''''''''''''''
Session("username") = sent_username
Session("maintuser") = sent_username
Session("b2buser") = sent_username
Session("password") = sent_password
Session("memberid") = memberid
Session("customernumber") = customernumber
Session("cno") = cno
Session("login") = "good"
if remember_me = "on" Then
response.cookies("entry")("doorway") = cook(sent_username)
response.Cookies("entry")("michael") = cook(sent_password)
response.Cookies("entry")("remember_me") = cook("CHECKED")
Response.Cookies("entry").Expires = Now() + 365
else
response.cookies("entry")("doorway") = ""
response.Cookies("entry")("michael") = ""
response.Cookies("entry")("remember_me") = ""
Response.Cookies("entry").Expires = Now() + 5
end if
As most of the parameters reference the Request collection you could put the parameters in the querystring and thus make them part of the base url for UIWebView. So your URL request would look like
file.asp?username=xxx&password=yyy&source=zzz&remember_me=on
you would need to change line 7 in your sample file to be
source = Request("source")
but it would still work for existing requests.
The obvious problem with this code is that you have a username and password stored in your app which could be intercepted and abused. So be aware of that. I would not recommend this approach.
A better solution would be to consider rewriting the login function to store a temporary GUID and a timestamp in the database which could then be passed in the request as part of the querystring. Your authentication code could then be modified to check if that GUID is valid and update the timestamp associated with the GUID (or check for the session if they are using the old access method for that page).

FbGraph cannot update status

I wrote a Rails application. I used omniauth for authentication.
session.rb
auth = request.env["omniauth.auth"]
user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
session[:user_id] = user.id
Everything seems normal as well, but when I want to change my facebook status, fbgraph cannot do that. I wrote this code
provider = User.find_by_provider_and_name('facebook', current_user.name)
#facebook = FbGraph::User.me(provider.token)
#facebook.feed!("loanminder-test-message-#{Time.now.utc}")
And the exception is like that
FbGraph::InvalidToken in LoansController#show
OAuthException :: Error validating access token: Session does not
match current stored session. This may be because the user changed the
password since the time the session was created or Facebook has
changed the session for security reasons.
How can I solve the problem, how can I change my status via Rails?
Your stored token is no longer being accepted. You will need to prompt the user to login again and use a new access token, or use the following token
app_id|secret
where if your app ID is 942523352 and your secret is bc76876876f67676ae0 then you access token is
942523352|bc76876876f67676ae0

Resources