I'm currently designing and prototyping the architecture for a web application that comprises of three parts, a Restful API (JSON, XML) interface served from a Rails app, a Backbone.js application being supported by a second Rails app, and an Android application that accesses data via the API.
Whereas the usual process of authenticating the user (redirecting to the login page) will work for the Backbone.js application, I want to use a single access token from the Android application to authenticate the user. I can see how upon first use the Android app would require a username and password, passing back from the CAS server additional information that would contain the pre-generated single access token. What I can't work out is how I would pass the single access token along with a request from the client and have that authenticated against CAS without redirecting to a login page etc.
What I need to know is whether this possible with CAS or is there a method that is more the "CAS way" that I can use to achieve the same result?
I've experimented with Devise and the CAS plugin devise_cas_authenticatable but this appears to be broken with the latest version of Devise. Ideally I want to use sorcery with my own implementation of single access token generation, all hooked up to CAS. I'm very new to CAS and what it can do so I'm trying to sound out what's possible first and then I'll contribute back to rubycas-client and sorcery if any new development is required that I'm able to code up.
Thanks in advance
I believe you are looking for Proxy Granting Tokens (Section 3.3). This allows one application to proxy a valid authentication to another application. The RubyCAS client supports this via:
class ApplicationController < ActionController::Base
before_filter :authenticate!
protected
def authenticate!
# This triggers RubyCAS client to request a proxy granting ticket
CASClient::Frameworks::Rails::Filter.client.proxy_callback_url = "myservice.com"
CASClient::Frameworks::Rails::Filter.filter(self)
if session[:cas_pgt]
# You will want to pass this as a URL param to your remote service
# whenever you call it. We store it on our base ActiveResource model
# and automatically append to the url params of all requests.
end
# Username is available in session[:cas_user]
end
end
This solution does not use devise.
Related
I am developing a native Android app that must interact with a Salesforce org through a SOAP API. Currently, for users of the app to login, they must provide a security token alongside their username and password. This makes the login/signup process uncomfortably long and complicated. As far as I can see, the only solution is to whitelist every IP address in my Salesforce org. I would have thought this is a security issue, so I was wondering if there was a better solution.
As far as I can tell, one solution could be to configure my app to log in through a proxy, and then just whitelist the address of that proxy. It was while researching this that I found this https://serverfault.com/questions/514716/whats-the-minimum-required-squid-config-to-make-a-public-proxy-server that made me think that perhaps there is some other more established way to do this, that I am not aware of.
Basically, my question is, is there any way for an android app running on any phone to make requests to an external API that all appear to come from one IP address (possibly through a proxy server) (without doing anything "dodgy")?
Looks like you're solving wrong problem. Why do you want to bypass SF security features so badly.
Try logging in to SF using REST, not SOAP. The session id you'll receive can be used in any API. So if you log in with OAuth2 you might not need security token. You'd need consumer id and secret (but that's just a pair of values you securely generate in SF, not bound to any particular user. You can even use production's values to login to sandboxes).
There's A LOT of reading if you want to do it right. And some prerequisite step of creating a "Connected App". If possible check if your Android library doesn't have something built-in for OAuth logins (to SF, Gmail, Facebook, LinkedIn, Twitter... you can find OAuth/OpenId in few places)
If you want pure background connection without user realising he's communicating with Salesforce - probably the "Username and password" OAuth flow is best for you. That should be minimal changes in your code compared to SOAP login call. It's weak in a sense you still need to have a password (either user's password or some dedicated integration account) - but there's chance that no security token will be needed. Give it a go (examples below) and check user's login history for errors.
If your users have proper SF accounts then maybe another OAuth flow is better. One that ideally displays them with SF login page they trust and just redirects back to your app when login succeeded. (you probably saw something like this if you recently used SF Data Loader?). That way your app doesn't see the password, just the result. And it'll work even if your client wants to use custom domain, decides to enable Single Sign-On...
Sorry, authentication, authorization are massive topics. But there is a better way so I'd want you to make a conscious decision before you code yourself into a corner... If help materials are too dry / too new & full of keywords then maybe try passing some trailheads:
https://trailhead.salesforce.com/content/learn/modules/identity_basics
https://trailhead.salesforce.com/content/learn/modules/api_basics (read intro and REST API part)
https://trailhead.salesforce.com/en/content/learn/modules/mobile_sdk_introduction/mobilesdk_intro_security
Your SOAP login looks probably like that:
POST
https://test.salesforce.com/services/Soap/c/45.0/
HEADERS
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
PAYLOAD
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:enterprise.soap.sforce.com">
<soapenv:Body>
<urn:login>
<urn:username>uptonogood#example.com</urn:username>
<urn:password>Nice_Try!111 + security token</urn:password>
</urn:login>
</soapenv:Body>
</soapenv:Envelope>
Corresponding OAuth login (forced to return XML although mobile app should "like" JSON better so if you want - ditch the Accept header I've added)
POST
https://test.salesforce.com/services/oauth2/token
HEADERS
Content-Type:application/x-www-form-urlencoded
Accept:application/xml
PAYLOAD
grant_type=password&
client_id=3MVG9fTLmJ60pJ5JaGv0NNHD5nh6P...&
client_secret=3437814...&
username=uptonogood#example.com&
password=Nice_Try!111
The proper way to do this would be to have your own backend through which you proxy your requests.
e.g.:
Android app -> Your backend -> Salesforce
I am currently working on implementing a mobile app for our site that uses Ruby on Rails and Devise. The idea here is, at first, create a mobile login form that on successful login opens a web frame that is authenticated and allows the normal use of the (mobile optimised) site. Theoretically that should be possible.
I am having trouble with the following issues:
How do you get the pure session key for the user session via a json request? What methods can be used to manually generate it from devise, something that the sign_in(:user, user) method does?
Is it even possible to take that key and put it into the browser cookie the way it normally happens in devise, but on the mobile side?
I know that this is not the standard method of making mobile applications for the site, but I believe it should be possible.
You might want to consider using Devise Token Auth and treating your mobile application like just another webapp that requests permission from your main site. DTA is particularly nice since it takes care of managing the session tokens (renewing/expiring) and passing them onto the app requiring access. The issue is overriding your session controllers so that it automatically logs in after you already log in on the mobile app (or just rewriting your log in so it occurs in conjunction with the Rails site, rather than before). Considering you're already using Devise, this may also be more refactoring than you'd like.
If you want to put your authentication form on the mobile UI and pass the credentials over to the web frame, you need a way to pass data from the mobile app to the web frame.
How you accomplish this depends on what platform you're building on. I'm not really a mobile developer so I don't know for certain how difficult / easy these options are:
When opening the web frame, instantiate it with session data
Find a way to call methods on the client from the web frame. Something like getSessionData.
You could generate a fingerprint for the web frame, have the mobile UI send this data to the server, and then have the web frame authenticate with the server by sending the fingerprint.
Again, I'm not entirely sure how possible all these options are.
You should use token authorization and Android deep linking. It will allow you to login in the web browser and send a token to your app via deep linking.
OK, so I decided to make a webframe solution as follows, basically you post the login and password to a certain sign_in method specially designed to generate one-time sign in tokens for the application. You need two methods in the system to do that:
routes.rb
devise_scope :user do
get "sign_in_with_token/:token" => "sessions#sign_in_with_token"
post "get_login_token" => "sessions#get_login_token"
end
sessions_controller.rb (don't forget to add the method that increases the failed_sign_in_count on wrong password, otherwise that can allow brute force attacks)
def get_login_token
user = User.find_by_email(sign_in_params["login"])
password = sign_in_params["password"]
if user and user.valid_password?(password)
token = SecureRandom.hex(16)
user.update_attribute(:authentication_token, token)
render json: {token: token}, status: 200
else
render json: {error: "error"}, status: 403
end
end
and the method to sign in with that token
def sign_in_with_token
#user = User.where(authentication_token: params[:token], email: Base64.decode64(params[:email])).first
if #user
#user.update_attribute(:authentication_token, nil)
sign_in(#user, bypass: true)
end
redirect_to '/' # or user_root_url
end
That way the mobile app will work like this:
use the generic web frame to send ajax requests to the server and get that token for the user email if password is correct.
make a /sign_in_with_token/#{token from ajax}?email=#{base46 encoded email} link inside the app.
open that link inside the web frame and use the app as though you were logged in normally. Now the app can save email and password locally and use that logic to get the token again for another session. Later logging in will also be able to set the app id so that push notifications can be sent.
Appreciate any feedback or criticism on this solution.
Hello all i am making an android app in whiich i have multiple account login at a time now my question is that i for multiple logins i should use sessions to verify every account user that is logged in. Now i am using express on the server side i have read a lot of documentation on storing sessions in node.js
Express-session (Though it is only good for development but not for production but not for my app)
Cookie-session
connect-Redis
connect-mongo
I have also heard about json web tokens where i can generate unique tokens and then i can pass the tokens to the client using res.json({user_id:"user1", token: "generated_token here"})
I have also heard about passport but dont know how it is going to do this also as in passport i use express-session by default will it be good for production or not ??
Now my first question is i have read all of there docs and nowhere it is mentioned where i am creating unique tokens for every user that is signing up.
Second question as i am using my server for android app there will be no use of cookie i will be sending user token as in parameter req.body.token now how to cmpare this with current user_id.
Actually i dont get the flow of control i mean how everything is going on in session in node.js. Also what is this secret is this thing generating unique tokens or what. Also i mean about 100000 of users are registered for my app now please tell me accordingly which way should i use for my app.
I have asked this question previously but there i did not mention that as i am not making a website how to do this(As in my case there will be no use of tokens)
I know this question i am asking is very vague but please bear with me i just want to understand how sessions are used in node.js
Thanks Anways
I'll try to answer this, but it is vague (as you pointed out). I'm going to make an assumption that your Android app is a native Android app and is going to be connecting to some sort of NodeJS backend in the cloud that is based on ExpressJS. If that's not the case, please clarify your thoughts in an update to your question.
The best idea for this specific scenario is to look to the cloud provide. Azure App Service Mobile Apps, for example, allows you to implement authentication - it eventually returns a JSON Web Token (http://jwt.io) to authenticate each request.
If you don't want to be beholden to a cloud provider, but want to run it yourself, you are going to have to implement the token generation and checking yourself. This generally follows the form:
Set up a WebAPI endpoint (maybe /signin) which takes whatever token the identity provider gives you, verifies the information and returns a JWT - there is an NPM module (jsonwebtoken) for producing the JWT. Ensure the JWT includes the identity of your user. I tend to use email address for the identity.
Your Android application will do a WebAPI request to your backend with an Authorization header, the value of which is "Bearer "
Your NodeJS API will use JWT authorization to validate the JWT and extract the user identity so you can use it in your API logic.
The important thing to note in this specific scenario is that your backend code is implementing a WebAPI - there are no cookies nor sessions in the API. The only thing that is linking the user from the client code to the backend code is the JWT.
As a short piece of code, here is how you verify a JWT:
var express = require('express');
var app = express();
var jwt = require('express-jwt');
var jwtCheck = jwt({
secret: new Buffer('your-jwt-secret', 'base64'),
audience: 'your-jwt-audience'
});
app.get('/api/protected', jwtCheck, (req, res) => {
// Your code here
});
app.listen(process.env.PORT || 3000);
I know there is a lot of information about this topic, but I can't find any that is up to date.
I see topics like this one relating to rails and android authentication but I see that TokenAuthenticatable is now removed from devise.
My question is simple: is there a good way to authenticate users from native Android and iPhone apps using Rails 4? Does anyone know of good tutorials or articles that provide a solution ?
Adam Waite Adding a bounty:
I have just opened a 500 bounty on this question because I can't find the correct practice for authenticating a user from an iOS app to a Rails API anywhere. This is what I was considering doing but have no idea if it's secure or not?!:
Let's assume we have a User record. A user has signed up for an account which has created a User record in the database with an email column and a password_digest column.
When the user signs-in I would like that user to remain authenticated on the mobile app until explicitly signing-out.
I imagine we're going to need a token based authentication. I would perhaps create an ApiKey record when the User is created and have that saved as an association on the User record.
When the user signs in/up, the response will contain an API token (something like SecureRandom.hex) which will be saved in the iOS Keychain and used with all subsequent requests to verify the user by passing it in a header and verifying it using something like:
before_filter :restrict_access
private
def restrict_access
authenticate_or_request_with_http_token do |token, options|
ApiKey.exists?(access_token: token)
end
Is this secure? Should I be refreshing the token with every request and including it in the response?
What other options do I have? What do the likes of Facebook, Twitter and Pinterest do?
I am aware of OAuth2.0, but is that not for granting external applications?
Is there a gem that manages any of this?
Sorry, completely unsure here.
500 to the best answer.
Gist of a solution from my research. Feel free to edit, correct, invalidate, etc.
SessionsController < ApplicationController
skip_before_filter :authenticate_user, :only => [:create]
def create
user = User.where("username = ? OR email = ?", params[:username_or_email], params[:username_or_email]).first
if user && user.authenticate(params[:password])
api_key = user.find_api_key
if !api_key.secret_key || api_key.is_expired?
api_key.set_expiry_date
api_key.generate_secret_key
end
api_key.save
render json: api_key, status: 201
else
status: 401
end
end
Note the ApiAuth.authentic? method and the request object. The request must be signed with an HMAC algorithm on the client.
ApplicationController < ActionController::Base
respond_to :json
force_ssl
protect_from_forgery with: :null_session
before_filter :authenticate_user
private
def authenticate_user
if authenticate_user_from_secret_key
return true
else
head :unauthorized
end
end
def authenticate_user_from_secret_key
userid = ApiAuth.access_id(request)
currentuser = userid && User.find_by_id(userid)
if ApiAuth.authentic?(request, currentuser.find_api_key.secret_key)
return true
else
return false
end
false
end
User creation/registration
UsersController < ApplicationController
skip_before_filter :authenticate_user, :only => [:create]
def create
user = User.create(user_params)
if !user.new_record?
render json: user.find_apit_key, status: 201
else
# error
end
end
Api key model. Similar to api key model in #352 railscast only difference is ApiAuth key generation.
class ApiKey < ActiveRecord::Base
before_create :generate_secret_key, :set_expiry_date
belongs_to :user
def generate_secret_key
begin
self.secret_key = ApiAuth.generate_secret_key
end while self.class.exists?(secret_key: secret_key)
end
User model.
class User < ActiveRecord::Base
has_secure_password
before_save :ensure_api_key
has_many :api_keys
def find_api_key
self.api_keys.active.ios.first_or_create
end
On the client side the HMAC algorithm must be used to sign requests.
The code is from:
[SHA1 HMAC Key generation/authentication] https://github.com/mgomes/api_auth
[Controllers & Models] https://github.com/danahartweg/authenticatable_rest_api
I've had this issue, I'm an API developer. You could do it the hard way with tokens and custom authorization, but I will tell you what we do with our application, which serves users in the six digit figure.
At least for iOS, the device will handle sessions for you, meaning that if a user on an iOS app makes a POST request to /users/sign_in with the parameters
user: {
password: 'mypassword',
email: 'testuser#example.com',
remember_me: true # optional
}
the iOS device will store the session for you, safely and persistently.
Now, if you want to go the OAuth 2 route, I actually maintain a gem for rails 4 called OAuth 2 providable, to which I added a pretty cool feature that allows you to have the user pass through the "authorization" screen, because obviously if you developed the software you don't need the user to confirm that they trust you.
If you do decide to use OAuth 2, you will need to use what is call the implicit access token.
This is the long and very boring OAuth2 spec for that
The rails 4 project can be found on github
https://github.com/bwheeler96/devise-oauth2-provider-rails4
If you're not on rails 4, you can use the original gem
https://github.com/socialcast/devise_oauth2_providable
By the way, the gem needs work so if there's anyone reading this who wants to help make it better, please by all means fork this repository
You are on the right track, but the user's token should only be used to identify which user is making the request. You still need some kind of authentication since, as you speculate with changing the token on each request, a hacker could intercept the data stream, get the token, and then "be" that user in subsequent requests.
By changing the token on each request, you eliminate the interception issue, but once someone has intercepted the token, they can then further exploit the system by continuing to intercept it and even modifying the response. One solution to this is to use HMAC (which is used by Amazon Web Services). It is an algorithm that provides a signature (hash) for your request that is unique for every request, doesn't require a changing key, and cannot be predicted for future requests.
There is a ruby gem for rails that implements HMAC on the server side for signing HMAC requests as well as generating them when doing server-to-server communications. For client-to-server requests as in your case, you need to generate the signature on the iOS or Android side and authenticate them on the server.
Consider the ApiAuth gem to do the work on the server side. On the iOS client side, consider the HBHMAC library for generating the signature. Take a look at the ApiAuth's specific implementation as it adds a timestamp to the data to prevent replay attacks, so you may need to add a field to your data before passing it to HBHMAC.
In summary, using HMAC authentication will avoid man in the middle attacks and replay attacks by utilizing a one-way hashing algorithm that prevents attackers from generating authentic requests even if they are able to intercept valid requests.
If you want to use OAuth2.0 in ruby on rails, you would be use Doorkeeper, you can see an example (not free) here:
http://railscasts.com/episodes/353-oauth-with-doorkeeper
But you can use a token with SecureRandom.hex, a example (not free) for this is here (in level 6):
https://www.codeschool.com/courses/surviving-apis-with-rails
I hope my answer help you!
In my asp.net mvc4 project, I am using ApiControllers to serve both web clients and mobile clients. To secure the web services, I am using the [Authorize] annotation.
So for now, the web client is working fine. However, when I tend to invoke some Web API from a mobile application (e.g. Android), I got an error.
when I looked back at code snippet:
[Authorize]
public List<double> GetSomeInfo(int param1, string param2)
{
User user = SessionData.CurrentUser;
// do something using user.UserId
// ....
}
Session Data does hold user connected properties only when he is connected to the Web App. But in the case of mobile clients, Session Data is null. So, is there any appropriate method to resolve this problem.
In my opinion, I think that userId should be provided as a parameter for any Web API that may need it to do achieve some treatment.
What do you think ?
You are talking about two different things :
Session
As Darrel said, Web Api was not design to support Asp.net Session. HTTP and Rest Services are stateless – and as a result each HTTP request should carry enough information by itself for its recipient to process it to be in complete harmony with the stateless nature of HTTP.
So, do not rely on Session Variables, but add more paramters in your request.
Of course, there are a way to use session in Web Api, I suggest you to to use it.
Authentication
Because working with only paramaters ( such as UserId, AccountId, ...) is not very secure, you have to use Authentication and Authorization. I highly suggest you to read the security section in asp.net web api web site. Web Api support many authentications (Basic, OAuth, Windows, Custom, ...). You have to choose what is the best for you.
Web API was not designed to support sessions as they are a HTTP anti-pattern. You can get the currently authenticated user by accessing Thread.CurrentPrincipal if you have setup the necessary authentication mechanisms.