Hi all, I''ve got a Rails app with a ApplicationController that looks like this: class ApplicationController < ActionController::Base before_filter :authorize, :except => :login def authorize unless session[:user] flash[:notice] = "Please log in" session[:jumpto] = request.parameters redirect_to :controller => "login", :action => "login" end end end So, basically, redirect a user to the login screen if they haven''t already logged in. Pretty standard stuff. But, if I want to setup a web service, how do I set session data from the client side through, say, an xmlrpc call using layered dispatching? I''ve tried messing around with the block form of the web_service, and even tried setting up a LoginApi and LoginService, but no luck. I''d like to be able to do this: require ''xmlprc/client'' rpc = XMLRPC::Client.new(''localhost'', ''http://localhost/webservice/api'', 3000) rpc.call(''login.login'', user, password) # Set session data here rpc.call(''foo.findFooById'', 2) # Go on my merry way I googled around a bit and couldn''t quite find the answer I was looking for. That, or I''m just not "getting it". What''s the best/proper way to handle this? Thanks, Dan
Hi Daniel, In my web services I just ignore the authorization, but Im on an internal app. I think what an app I worked on before ( not rails ) did was something like: def ws_auth( user, pword) # auth the user # create an entry in the db, and return some sort of unique key end def web_service_method( auth_key , ...... ) # if the auth_key doesnt exist in the db, ignore this request end then your client does: auth_key = rpc.call(''login.login'', user, password) # Set session data here rpc.call(''foo.findFooById'',auth_key , 2) # Go on my merry way not perfect, but might do for you Paul Daniel Berger wrote:> Hi all, > > I''ve got a Rails app with a ApplicationController that looks like this: > > class ApplicationController < ActionController::Base > before_filter :authorize, :except => :login > > def authorize > unless session[:user] > flash[:notice] = "Please log in" > session[:jumpto] = request.parameters > redirect_to :controller => "login", :action => "login" > end > end > end > > So, basically, redirect a user to the login screen if they haven''t > already > logged in. Pretty standard stuff. > > But, if I want to setup a web service, how do I set session data from > the > client side through, say, an xmlrpc call using layered dispatching? > I''ve tried > messing around with the block form of the web_service, and even tried > setting > up a LoginApi and LoginService, but no luck. > > I''d like to be able to do this: > > require ''xmlprc/client'' > > rpc = XMLRPC::Client.new(''localhost'', ''http://localhost/webservice/api'', > 3000) > rpc.call(''login.login'', user, password) # Set session data here > rpc.call(''foo.findFooById'', 2) # Go on my merry way > > I googled around a bit and couldn''t quite find the answer I was looking > for. > That, or I''m just not "getting it". > > What''s the best/proper way to handle this? > > Thanks, > > Dan-- Posted via http://www.ruby-forum.com/.
Chang Sau Sheong
2006-Apr-22 01:21 UTC
[Rails] web services and dealing with before_filter
What I did was to include in the authorization in the web service. I have a method like User.authenticate?(user) which returns true or false. This is used by my authentication filter as u have done. Every time someone sends in a request they must include the username/password in the request, which is then used to check if he is valid or not. For higher security you can either run it through https (haven''t tried this), encode it in base64, encrypt it using some private key algo, or use WSS4R. This method is probably not high-performing, alternatively you can use a token mechanism to check if he is a valid user (instead of checking everytime, return a token) , but if your requests are low volume it should be ok. Hope this helped. Daniel Berger wrote:> Hi all, > > I''ve got a Rails app with a ApplicationController that looks like this: > > class ApplicationController < ActionController::Base > before_filter :authorize, :except => :login > > def authorize > unless session[:user] > flash[:notice] = "Please log in" > session[:jumpto] = request.parameters > redirect_to :controller => "login", :action => "login" > end > end > end > > So, basically, redirect a user to the login screen if they haven''t > already logged in. Pretty standard stuff. > > But, if I want to setup a web service, how do I set session data from > the client side through, say, an xmlrpc call using layered > dispatching? I''ve tried messing around with the block form of the > web_service, and even tried setting up a LoginApi and LoginService, > but no luck. > > I''d like to be able to do this: > > require ''xmlprc/client'' > > rpc = XMLRPC::Client.new(''localhost'', > ''http://localhost/webservice/api'', 3000) > rpc.call(''login.login'', user, password) # Set session data here > rpc.call(''foo.findFooById'', 2) # Go on my merry way > > I googled around a bit and couldn''t quite find the answer I was > looking for. That, or I''m just not "getting it". > > What''s the best/proper way to handle this? > > Thanks, > > Dan > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-- Sau Sheong http://blog.saush.com http://read.saush.com http://jaccal.sourceforge.net
You make them supply a user/password *per request*? Ouch. What I would really like is a better way to handle before_filter''s in my controllers within my ActionWebService::Base classes somehow. Maybe there''s a way to accomplish what I want using the block form of the web_service method, but I''m not seeing it. Regards, Dan> -----Original Message----- > From: rails-bounces@lists.rubyonrails.org > [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of > Chang Sau Sheong > Sent: Friday, April 21, 2006 7:22 PM > To: rails@lists.rubyonrails.org > Subject: Re: [Rails] web services and dealing with before_filter > > > What I did was to include in the authorization in the web > service. I have a method like User.authenticate?(user) which > returns true or false. This is used by my authentication > filter as u have done. Every time someone sends in a request > they must include the username/password in the request, which > is then used to check if he is valid or not. > > For higher security you can either run it through https > (haven''t tried this), encode it in base64, encrypt it using > some private key algo, or use WSS4R. > > This method is probably not high-performing, alternatively > you can use a token mechanism to check if he is a valid user > (instead of checking everytime, return a token) , but if your > requests are low volume it should be ok. > > Hope this helped. > > Daniel Berger wrote: > > Hi all, > > > > I''ve got a Rails app with a ApplicationController that looks like > > this: > > > > class ApplicationController < ActionController::Base > > before_filter :authorize, :except => :login > > > > def authorize > > unless session[:user] > > flash[:notice] = "Please log in" > > session[:jumpto] = request.parameters > > redirect_to :controller => "login", :action => "login" > > end > > end > > end > > > > So, basically, redirect a user to the login screen if they haven''t > > already logged in. Pretty standard stuff. > > > > But, if I want to setup a web service, how do I set session > data from > > the client side through, say, an xmlrpc call using layered > > dispatching? I''ve tried messing around with the block form of the > > web_service, and even tried setting up a LoginApi and LoginService, > > but no luck. > > > > I''d like to be able to do this: > > > > require ''xmlprc/client'' > > > > rpc = XMLRPC::Client.new(''localhost'', > > ''http://localhost/webservice/api'', 3000) > rpc.call(''login.login'', user, > > password) # Set session data here > rpc.call(''foo.findFooById'', 2) # Go > > on my merry way > > > > I googled around a bit and couldn''t quite find the answer I was > > looking for. That, or I''m just not "getting it". > > > > What''s the best/proper way to handle this? > > > > Thanks, > > > > Dan > > _______________________________________________ > > Rails mailing list > > Rails@lists.rubyonrails.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > > > -- > Sau Sheong > > http://blog.saush.com > http://read.saush.com > http://jaccal.sourceforge.net > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >This communication is the property of Qwest and may contain confidential or privileged information. Unauthorized use of this communication is strictly prohibited and may be unlawful. If you have received this communication in error, please immediately notify the sender by reply e-mail and destroy all copies of the communication and any attachments.
Here''s how I ultimately decided to deal with this issue in case anyone is interested: 1) Created a LoginApi web service. In login_api.rb: class LoginApi < ActionWebService::API::Base api_method :login, :expects => [:string, :string] end 2) Created a LoginService class. In login_service.rb: class LoginService < ActionWebService::Base web_service_api LoginApi def login(cuid, password) if User.login(cuid, password) User.find_by_cuid(cuid) end end end This assumes a User.login and User.find_by_cuid method in the User model somewhere. Adjust as needed. 3) Added the appropriate line to the web service controller. In webservice_controller.rb: class WebserviceController < ApplicationController ... web_service :login, LoginService.new end 4) Within my ApplicationController (application.rb) I modified my authorize filter like so: require ''rexml/document'' include REXML class ApplicationController < ActionController::Base # User must authorize to get to any screen before_filter :authorize, :except => :login model :user private def authorize # If the http path requested is ''/webservice/api'' assume it''s # a remote call and give them a chance to login. if session[:user].nil? && request.env[''PATH_INFO''] =''/webservice/api'' doc = Document.new(request.env[''RAW_POST_DATA'']) elements = XPath.match(doc, "/methodCall/params/param/value/string") cuid, password = elements.map{ |x| x.text } session[:user] = LoginService.new.login(cuid, password) end unless session[:user] flash[:notice] = "Please log in" session[:jumpto] = request.parameters redirect_to :controller => "login", :action => "login" end end end Adjust the ''/webservice/api'' path as needed. Sample xmlrpc client: require ''xmlrpc/client'' rpc = XMLRPC::Client.new(''localhost'', ''http://localhost/webservice/api'', 3000) rpc.call(''login.Login'', ''user'', ''XXX'') # Only login once p rpc.call(''hardware.FindHardwareById'', 2) p rpc.call(''hardware.GetAllHardware'') This allows the end programmer to login just once within their code, instead of having to login on a per-request basis. I''m not sure how robust or secure this is, so I''m open to comments and suggestions. Regards, Dan> -----Original Message----- > From: rails-bounces@lists.rubyonrails.org > [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of > Berger, Daniel > Sent: Monday, April 24, 2006 12:36 PM > To: rails@lists.rubyonrails.org > Subject: RE: [Rails] web services and dealing with before_filter > > > You make them supply a user/password *per request*? Ouch. > > What I would really like is a better way to handle > before_filter''s in my controllers within my > ActionWebService::Base classes somehow. > > Maybe there''s a way to accomplish what I want using the block > form of the web_service method, but I''m not seeing it. > > Regards, > > Dan > > > -----Original Message----- > > From: rails-bounces@lists.rubyonrails.org > > [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of > > Chang Sau Sheong > > Sent: Friday, April 21, 2006 7:22 PM > > To: rails@lists.rubyonrails.org > > Subject: Re: [Rails] web services and dealing with before_filter > > > > > > What I did was to include in the authorization in the web > > service. I have a method like User.authenticate?(user) which > > returns true or false. This is used by my authentication > > filter as u have done. Every time someone sends in a request > > they must include the username/password in the request, which > > is then used to check if he is valid or not. > > > > For higher security you can either run it through https > > (haven''t tried this), encode it in base64, encrypt it using > > some private key algo, or use WSS4R. > > > > This method is probably not high-performing, alternatively > > you can use a token mechanism to check if he is a valid user > > (instead of checking everytime, return a token) , but if your > > requests are low volume it should be ok. > > > > Hope this helped. > > > > Daniel Berger wrote: > > > Hi all, > > > > > > I''ve got a Rails app with a ApplicationController that looks like > > > this: > > > > > > class ApplicationController < ActionController::Base > > > before_filter :authorize, :except => :login > > > > > > def authorize > > > unless session[:user] > > > flash[:notice] = "Please log in" > > > session[:jumpto] = request.parameters > > > redirect_to :controller => "login", :action => "login" > > > end > > > end > > > end > > > > > > So, basically, redirect a user to the login screen if they haven''t > > > already logged in. Pretty standard stuff. > > > > > > But, if I want to setup a web service, how do I set session > > data from > > > the client side through, say, an xmlrpc call using layered > > > dispatching? I''ve tried messing around with the block > form of the > > > web_service, and even tried setting up a LoginApi and > LoginService, > > > but no luck. > > > > > > I''d like to be able to do this: > > > > > > require ''xmlprc/client'' > > > > > > rpc = XMLRPC::Client.new(''localhost'', > > > ''http://localhost/webservice/api'', 3000) > > rpc.call(''login.login'', user, > > > password) # Set session data here > > rpc.call(''foo.findFooById'', 2) # Go > > > on my merry way > > > > > > I googled around a bit and couldn''t quite find the answer I was > > > looking for. That, or I''m just not "getting it". > > > > > > What''s the best/proper way to handle this? > > > > > > Thanks, > > > > > > Dan > > > _______________________________________________ > > > Rails mailing list > > > Rails@lists.rubyonrails.org > > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > > > > > > > -- > > Sau Sheong > > > > http://blog.saush.com > > http://read.saush.com > > http://jaccal.sourceforge.net > > > > _______________________________________________ > > Rails mailing list > > Rails@lists.rubyonrails.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > > > This communication is the property of Qwest and may contain > confidential or > privileged information. Unauthorized use of this > communication is strictly > prohibited and may be unlawful. If you have received this > communication > in error, please immediately notify the sender by reply > e-mail and destroy > all copies of the communication and any attachments. > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
> -----Original Message----- > From: rails-bounces@lists.rubyonrails.org > [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of > Berger, Daniel > Sent: Monday, May 01, 2006 9:58 AM > To: rails@lists.rubyonrails.org > Subject: RE: [Rails] web services and dealing with before_filter > > > Here''s how I ultimately decided to deal with this issue in > case anyone is interested:<snip> Ok, this is odd. The sample Ruby client I provided works fine, i.e. the session data is retained after the call to login.Login. However, this sample Perl client does *not* retain the session data: use strict; use warnings; use Frontier::Client; my $url = "http://localhost:3000/webservice/api"; my $client = Frontier::Client->new(url=>$url) or die $!; $client->call(''login.Login'', ''user'', ''XXX''); print $client->call(''hardware.FindHardwareById'', 2), "\n"; print $client->call(''hardware.GetAllHardware''); Why would session data be retained with the Ruby code but not the Perl code? This is Ruby 1.8.4, Webrick, Windows XP Pro, btw. Regards, Dan This communication is the property of Qwest and may contain confidential or privileged information. Unauthorized use of this communication is strictly prohibited and may be unlawful. If you have received this communication in error, please immediately notify the sender by reply e-mail and destroy all copies of the communication and any attachments.
Ruby''s xmlrpc library knows how to handle cookies. But this functionality is required neither by xmlrpc spec nor by soap spec. For interoperability purposes I''d recommend sending username and password with each request. Kent. On 5/1/06, Berger, Daniel <Daniel.Berger@qwest.com> wrote:> > > -----Original Message----- > > From: rails-bounces@lists.rubyonrails.org > > [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of > > Berger, Daniel > > Sent: Monday, May 01, 2006 9:58 AM > > To: rails@lists.rubyonrails.org > > Subject: RE: [Rails] web services and dealing with before_filter > > > > > > Here''s how I ultimately decided to deal with this issue in > > case anyone is interested: > > <snip> > > Ok, this is odd. The sample Ruby client I provided works fine, i.e. > the session data is retained after the call to login.Login. > > However, this sample Perl client does *not* retain the session data: > > use strict; > use warnings; > use Frontier::Client; > > my $url = "http://localhost:3000/webservice/api"; > my $client = Frontier::Client->new(url=>$url) or die $!; > > $client->call(''login.Login'', ''user'', ''XXX''); > print $client->call(''hardware.FindHardwareById'', 2), "\n"; > print $client->call(''hardware.GetAllHardware''); > > Why would session data be retained with the Ruby code but > not the Perl code? > > This is Ruby 1.8.4, Webrick, Windows XP Pro, btw. > > Regards, > > Dan > > > This communication is the property of Qwest and may contain confidential > or > privileged information. Unauthorized use of this communication is strictly > prohibited and may be unlawful. If you have received this communication > in error, please immediately notify the sender by reply e-mail and destroy > all copies of the communication and any attachments. > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-- Kent --- http://www.datanoise.com -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060501/df4d49f1/attachment.html
Ah, thanks Kent. Maybe I''ll tinker with the session storage options instead. Regards, Dan -----Original Message----- From: rails-bounces@lists.rubyonrails.org [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of Kent Sibilev Sent: Monday, May 01, 2006 10:50 AM To: rails@lists.rubyonrails.org Subject: Re: [Rails] web services and dealing with before_filter Ruby''s xmlrpc library knows how to handle cookies. But this functionality is required neither by xmlrpc spec nor by soap spec. For interoperability purposes I''d recommend sending username and password with each request. Kent. On 5/1/06, Berger, Daniel <Daniel.Berger@qwest.com> wrote: > -----Original Message----- > From: rails-bounces@lists.rubyonrails.org > [mailto:rails-bounces@lists.rubyonrails.org ] On Behalf Of > Berger, Daniel > Sent: Monday, May 01, 2006 9:58 AM > To: rails@lists.rubyonrails.org > Subject: RE: [Rails] web services and dealing with before_filter > > > Here''s how I ultimately decided to deal with this issue in > case anyone is interested: <snip> Ok, this is odd. The sample Ruby client I provided works fine, i.e. the session data is retained after the call to login.Login. However, this sample Perl client does *not* retain the session data: use strict; use warnings; use Frontier::Client; my $url = "http://localhost:3000/webservice/api "; my $client = Frontier::Client->new(url=>$url) or die $!; $client->call(''login.Login'', ''user'', ''XXX''); print $client->call(''hardware.FindHardwareById'', 2), "\n"; print $client->call('' hardware.GetAllHardware''); Why would session data be retained with the Ruby code but not the Perl code? This is Ruby 1.8.4, Webrick, Windows XP Pro, btw. Regards, Dan This communication is the property of Qwest and may contain confidential or privileged information. Unauthorized use of this communication is strictly prohibited and may be unlawful. If you have received this communication in error, please immediately notify the sender by reply e-mail and destroy all copies of the communication and any attachments. _______________________________________________ Rails mailing list Rails@lists.rubyonrails.org http://lists.rubyonrails.org/mailman/listinfo/rails -- Kent --- http://www.datanoise.com -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060501/89804d5e/attachment.html
Chang Sau Sheong
2006-May-02 23:45 UTC
[Rails] web services and dealing with before_filter
It sounds a bit extreme, yes, but it''s not too intrusive actually. I store the username/password before anything happens and then use it to access the web service. The user doesn''t have to repeatedly enter data. Berger, Daniel wrote:> You make them supply a user/password *per request*? Ouch. > > What I would really like is a better way to handle before_filter''s > in my controllers within my ActionWebService::Base classes somehow. > > Maybe there''s a way to accomplish what I want using the block form > of the web_service method, but I''m not seeing it. > > Regards, > > Dan > > >> -----Original Message----- >> From: rails-bounces@lists.rubyonrails.org >> [mailto:rails-bounces@lists.rubyonrails.org] On Behalf Of >> Chang Sau Sheong >> Sent: Friday, April 21, 2006 7:22 PM >> To: rails@lists.rubyonrails.org >> Subject: Re: [Rails] web services and dealing with before_filter >> >> >> What I did was to include in the authorization in the web >> service. I have a method like User.authenticate?(user) which >> returns true or false. This is used by my authentication >> filter as u have done. Every time someone sends in a request >> they must include the username/password in the request, which >> is then used to check if he is valid or not. >> >> For higher security you can either run it through https >> (haven''t tried this), encode it in base64, encrypt it using >> some private key algo, or use WSS4R. >> >> This method is probably not high-performing, alternatively >> you can use a token mechanism to check if he is a valid user >> (instead of checking everytime, return a token) , but if your >> requests are low volume it should be ok. >> >> Hope this helped. >> >> Daniel Berger wrote: >> >>> Hi all, >>> >>> I''ve got a Rails app with a ApplicationController that looks like >>> this: >>> >>> class ApplicationController < ActionController::Base >>> before_filter :authorize, :except => :login >>> >>> def authorize >>> unless session[:user] >>> flash[:notice] = "Please log in" >>> session[:jumpto] = request.parameters >>> redirect_to :controller => "login", :action => "login" >>> end >>> end >>> end >>> >>> So, basically, redirect a user to the login screen if they haven''t >>> already logged in. Pretty standard stuff. >>> >>> But, if I want to setup a web service, how do I set session >>> >> data from >> >>> the client side through, say, an xmlrpc call using layered >>> dispatching? I''ve tried messing around with the block form of the >>> web_service, and even tried setting up a LoginApi and LoginService, >>> but no luck. >>> >>> I''d like to be able to do this: >>> >>> require ''xmlprc/client'' >>> >>> rpc = XMLRPC::Client.new(''localhost'', >>> ''http://localhost/webservice/api'', 3000) >>> >> rpc.call(''login.login'', user, >> >>> password) # Set session data here >>> >> rpc.call(''foo.findFooById'', 2) # Go >> >>> on my merry way >>> >>> I googled around a bit and couldn''t quite find the answer I was >>> looking for. That, or I''m just not "getting it". >>> >>> What''s the best/proper way to handle this? >>> >>> Thanks, >>> >>> Dan >>> _______________________________________________ >>> Rails mailing list >>> Rails@lists.rubyonrails.org >>> http://lists.rubyonrails.org/mailman/listinfo/rails >>> >>> >> -- >> Sau Sheong >> >> http://blog.saush.com >> http://read.saush.com >> http://jaccal.sourceforge.net >> >> _______________________________________________ >> Rails mailing list >> Rails@lists.rubyonrails.org >> http://lists.rubyonrails.org/mailman/listinfo/rails >> >> > > > This communication is the property of Qwest and may contain confidential or > privileged information. Unauthorized use of this communication is strictly > prohibited and may be unlawful. If you have received this communication > in error, please immediately notify the sender by reply e-mail and destroy > all copies of the communication and any attachments. > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails > >-- Sau Sheong http://blog.saush.com http://www.projectible.com http://jaccal.sourceforge.net -------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060502/8b9d41ea/attachment.html