Giter Club home page Giter Club logo

rubycas-client's Introduction

In Need of New Maintainer

Unfortunately, those of us who have been maintaining this project no longer have time to give it the attention it needs. If you are interested in taking over maintainence of it, please let us know!

Otherwise, we recommend you consider one of the following alternatives:

rack-cas

omniauth-cas

<img src=“https://secure.travis-ci.org/rubycas/rubycas-client.png” alt=“Build Status” /> <img src=“https://codeclimate.com/badge.png” />

RubyCAS-Client

Authors

Matt Zukowski <matt AT roughest DOT net> and Matt Campbell <matt AT soupmatt DOT com>; inspired by code by Ola Bini <ola.bini AT ki DOT se> and Matt Walker <mwalker AT tamu DOT edu>

Copyright

Portions contributed by Matt Zukowski are copyright © 2009 Urbacon Ltd. Portions contributed by Matt Campbell, Rich Yarger and Rahul Joshi are copyright © 2011 Vibes Media LLC. Other portions are copyright of their respective authors.

License

MIT License

Websites

github.com/rubycas/rubycas-client github.com/rubycas/rubycas-client/wiki rubydoc.info/github/rubycas/rubycas-client/master/frames

RubyCAS-Client is a Ruby client library for Yale’s Central Authentication Service (CAS) protocol.

CAS provides a secure single sign on solution for web-based applications. The user logs in to your organization’s CAS server, and is automatically authenticated for all other CAS-enabled applications.

For general information about the open CAS protocol, please have a look at www.ja-sig.org/products/cas.

If your organization does not already have a CAS server, you may be interested in RubyCAS-Client’s sister project, RubyCAS-Server.

The RubyCAS-Client package includes adapters for Rails and Merb, although the client library itself can be adapted for other frameworks (for example an implementation for Camping is available via the Picnic library).

Getting help and reporting problems

If you need help, try posting to the RubyCAS discussion group at groups.google.com/group/rubycas-server.

To report problems, please use the Google Code issue tracker at code.google.com/p/rubycas-client/issues/list.

API documentation (i.e. the RDocs) are available at rubycas-client.rubyforge.org

Installation

The current version of RubyCAS-Client should work with Rails 2.3.6 and up. For compatibility with older Rails try using an older version of the client.

You can download the latest version of RubyCAS-Client from the project’s rubyforge page at rubyforge.org/projects/rubycas-client.

However, if you’re using Rails, it’s easier to install the CAS client as a plugin:

cd <your rails app>
./script/plugin install git://github.com/rubycas/rubycas-client.git

Alternatively, the library is also installable as a RubyGem:

gem install rubycas-client

If your Rails application is under Subversion control, you can also install the plugin as an svn:external, ensuring that you always have the latest bleeding-edge version of RubyCAS-Client:

./script/plugin install -x http://svn.github.com/rubycas/rubycas-client.git

Usage Examples

If you’d rather jump right in, have a look at the example Rails and Merb applications pre-configured for CAS authentication:

github.com/rubycas/rubycas-client/tree/master/examples

Otherwise, continue reading for a step-by-step guide for integrating RubyCAS-Client with Rails:

Using RubyCAS-Client in Rails controllers

Note that from this point on we are assuming that you have a working CAS server up and running!

After installing RubyCAS-Client as a plugin (see above), add the following to your app’s config/environment.rb (make sure that you put it at the bottom of the file, after the Rails Initializer):

CASClient::Frameworks::Rails::Filter.configure(
  :cas_base_url => "https://cas.example.foo/"
)

(Change the :cas_base_url value to your CAS server’s base URL; also note that many CAS servers are configured with a base URL that looks more like “cas.example.foo/cas”.)

Then, in your app/controllers/application.rb (or in whichever controller you want to add the CAS filter for):

before_filter CASClient::Frameworks::Rails::Filter

That’s it. You should now find that you are redirected to your CAS login page whenever you try to access any action in your protected controller. You can of course qualify the before_filter as you would with any other ActionController filter. For example:

before_filter CASClient::Frameworks::Rails::Filter, :except => [ :unprotected_action, :another_unprotected_action ]

Once the user has been authenticated, their authenticated username is available under session[:cas_user], If you want to do something with this username (for example load a user record from the database), you can append another filter method that checks for this value and does whatever you need it to do.

Note: If Rails complains about missing constants, try adding this before the CASClient configuration:

require 'casclient'
require 'casclient/frameworks/rails/filter'

A more complicated example

Here is a more complicated configuration showing most of the configuration options along with their default values (this does not show proxy options, which are covered in the next section):

# enable detailed CAS logging
cas_logger = CASClient::Logger.new(::Rails.root+'/log/cas.log')
cas_logger.level = Logger::DEBUG

CASClient::Frameworks::Rails::Filter.configure(
  :cas_base_url  => "https://cas.example.foo/",
  :login_url     => "https://cas.example.foo/login",
  :logout_url    => "https://cas.example.foo/logout",
  :validate_url  => "https://cas.example.foo/proxyValidate",
  :username_session_key => :cas_user,
  :extra_attributes_session_key => :cas_extra_attributes,
  :logger => cas_logger,
  :enable_single_sign_out => true,
  :service_url => "https://mysite.service.com"
)

Note that normally it is not necessary to specify :login_url, :logout_url, and :validate_url. These values are automatically set to standard CAS defaults based on the given :cas_base_url.

The :username_session_key value determines the key under which you can find the CAS username in the Rails session hash.

Any additional info that the CAS server might have supplied about the user during authentication will be found under the :extra_attributes_session_key value in the Rails session hash (i.e. given the above configuration, you would find this info under session[:cas_extra_attributes]).

An arbitrary Logger instance can be given as the :logger parameter. In the example above we log all CAS activity to a log/cas.log file in your Rails app’s directory.

The service url sets the service parameter that will be sent to CAS for every authentication. This can be useful if you are implementing the single logout feature (supported by some CAS Servers) or would like to funnel all authentications through a specific action.

Re-authenticating on every request (i.e. the “single sign-out problem”)

By default, the Rails filter will only authenticate with the CAS server when no session value exists. Once the user has been authenticated, no further CAS forwarding is done until the user’s session is wiped. This saves you the trouble of having to do this check yourself (since in most cases it is not advisable to go through the CAS server on every request – this is slow and would potentially lead to problems, for example for AJAX requests). However, the disadvantage is that the filter no longer checks to make sure that the user’s CAS session is still actually open. In other words it is possible for the user’s authentication session to be closed on the CAS server without the client application knowing about it.

To address this, RubyCAS-Client now supports the new “Single Sign-Out” functionality in CAS 3.1, allowing the server to notify the client application that the CAS session is closed. The client will automatically intercept Single Sign-Out requsts from the CAS server, but in order for this to work you must configure your Rails application as follows:

  1. The Rails session store must be set to ActiveRecord: config.action_controller.session_store = :active_record_store

  2. The server must be able to read and write to Rails.root/tmp/sessions. If you are in a clustered environment, the contents of this directory must be shared between all server instances.

  3. Cross-site request forgery protection must be disabled. In your application.rb: self.allow_forgery_protection = false. (Or rather you may want to disable forgery protection only for actions that are behind the CAS filter.)

  4. Finally, you must add :enable_single_sign_out => true to your CAS client config (a similar option must be enabled on the CAS server, if you’re using RubyCAS-Server).

The best way to debug single-sign out functionality is to configure your CAS client with logging (see above) and then watch the log to ensure that single-sign out requests from the server are being processed correctly.

Alternatively, it is possible to disable authentication persistence in the client by setting the :authenticate_on_every_request configuration option to true as, in the example in the previous section. However, this is not recommended as it will almost certainly have a deleterious impact on performance and can interfere with certain HTTP transactions (AJAX requests, for example).

Defining a ‘logout’ action

Your Rails application’s controller(s) will probably have some sort of logout function. Here you can do any necessary local cleanup, and then call CASClient::Frameworks::Rails::Filter.logout(controller). For example:

class ApplicationController < ActionController::Base

  # ...

  def logout
    # optionally do some local cleanup here
    # ...

    CASClient::Frameworks::Rails::Filter.logout(self)
  end
end

By default, the logout method will clear the local Rails session, do some local CAS cleanup, and redirect to the CAS logout page. Additionally, the request.referer value from the controller instance is passed to the CAS server as a ‘destination’ parameter. This allows RubyCAS server to provide a follow-up login page allowing the user to log back in to the service they just logged out from using a different username and password. Other CAS server implemenations may use this ‘destination’ parameter in different ways.

Gatewayed (i.e. optional) authentication

“Gatewaying” essentially allows for optional CAS authentication. Users who already have a pre-existing CAS SSO session will be automatically authenticated for the gatewayed service, while those who do not will be allowed to access the service without authentication. This is useful for example when you want to show some additional private content on a homepage to authenticated users, but also want anonymous users to be able to access the page without first logging in.

To allow users to access a page without authenticatin, simply use CASClient::Frameworks::Rails::GatewayFilter in place of CASClient::Frameworks::Rails::Filter in your controller. For example, you may want to require CAS authentication for all actions in a controller except the index action:

class ExampleController < ApplicationController
  before_filter CASClient::Frameworks::Rails::GatewayFilter, :only => :index
  before_filter CASClient::Frameworks::Rails::Filter, :except => :index

  # ...
end

To provide a login URL for unauthenticated users:

<%= link_to("Login", CASClient::Frameworks::Rails::Filter.login_url(controller)) %>

How to act as a CAS proxy

CAS 2.0 has a built-in mechanism that allows a CAS-authenticated application to pass on its authentication to other applications. An example where this is useful might be a portal site, where the user logs in to a central website and then gets forwarded to various other sites that run independently of the portal system (but are always accessed via the portal). The exact mechanism behind this is rather complicated so I won’t go over it here. If you wish to learn more about CAS proxying, a great walkthrough is available at www.ja-sig.org/wiki/display/CAS/Proxy+CAS+Walkthrough.

RubyCAS-Client fully supports proxying, so a CAS-protected Rails application can act as a CAS proxy.

Additionally, RubyCAS-Client comes with a controller that can act as a CAS proxy callback receiver. This is necessary because when your application requests to act as a CAS proxy, the CAS server must contact your application to deposit the proxy-granting-ticket (PGT). Note that in this case the CAS server CONTACTS YOU, rather than you contacting the CAS server (as in all other CAS operations).

Confused? Don’t worry, you don’t really have to understand this to use it. To enable your Rails app to act as a CAS proxy, all you need to do is this:

In your config/environment.rb:

# enable detailed CAS logging for easier troubleshooting
cas_logger = CASClient::Logger.new(::Rails.root+'/log/cas.log')
cas_logger.level = Logger::DEBUG

CASClient::Frameworks::Rails::Filter.configure(
  :cas_base_url => "https://cas.example.foo/",
  :proxy_callback_url => "https://cas-proxy-callback.example.foo/cas_proxy_callback/receive_pgt",
  :logger => cas_logger
)

In config/routes.rb make sure that you have a route that will allow requests to /cas_proxy_callback/:action to be routed to the CasProxyCallbackController. This should work as-is with the standard Rails routes setup, but if you have disabled the default route, you should add the following:

map.cas_proxy_callback 'cas_proxy_callback/:action', :controller => 'cas_proxy_callback'

Now here’s a big giant caveat: your CAS callback application and your CAS proxy application must run on separate Rails servers. In other words, if you want a Rails app to act as a CAS ticket-granting proxy, the cas_proxy_callback controller must run on a different server. This is because Rails does not properly support handling of concurrent requests. The CAS proxy mechanism acts in such a way that if your proxy application and your callback controller were on the same server you would end up with a deadlock (the CAS server would be waiting for its callback to be accepted by your Rails server, but your Rails server wouldn’t respond to the CAS server’s callback until the CAS server responded back first).

The simplest workaround is this:

Run rails using a server that handles multiple concurrent requests. In development, you can use Phusion Passenger Standalone, POW (pow.cx/), unicorn and many others. In production, I imagine you already support multiple concurrent requests.

That’s it. The proxy_callback_controller doesn’t require any additional configuration. It doesn’t access the database or anything of that sort.

Once your user logs in to CAS via your application, you can do the following to obtain a service ticket that can then be used to authenticate another application:

service_uri = "http://some-other-application.example.foo"
proxy_granting_ticket = session[:cas_pgt]
proxy_ticket = CASClient::Frameworks::Rails::Filter.client.request_proxy_ticket(proxy_granting_ticket, service_uri)

proxy_ticket should now contain a valid proxy ticket. You can use it to authenticate other services by sending it together with the service URI as parameters to your target application:

http://some-other-application.example.foo?service=#{CGI::escape(proxy_ticket.service)}&ticket=#{proxy_ticket.ticket}

This is of course assuming that some-other-application.example.foo is also protected by the CAS filter. Note that you should always URI-encode your service parameter inside URIs!

Note that #request_proxy_ticket returns a CASClient::ProxyTicket object, which is why we need to call #ticket on it to retrieve the actual service ticket string.

Additional proxying notes and caveats

The proxy url must be an https address. Otherwise CAS will refuse to communicate with it. This means that if you are using the bundled cas_proxy_callback controller, you will have to host your application on an https-enabled server. This can be a bit tricky with Rails. WEBrick’s SSL support is difficult to configure, and Mongrel doesn’t support SSL at all. One workaround is to use a reverse proxy like Pound, which will accept https connections and locally re-route them to your Rails application. Also, note that self-signed SSL certificates likely won’t work. You will probably need to use a real certificate purchased from a trusted CA authority (there are ways around this, but good luck :)

SSL Support

Make sure you have the Ruby OpenSSL library installed. Otherwise you may get errors like:

no such file to load -- net/https

To install the library on an Debian/Ubuntu system:

sudo apt-get install libopenssl-ruby

For other platforms you’ll have to figure it out yourself.

Testing

In some cases, especially those using Cucumber or other tools that simply can’t work with CAS, it may be necessary to work around CAS instead.

In your test or Cucumber step definition, simply fake out CAS.

CASClient::Frameworks::Rails::Filter.fake("homer")

This functionality was present in the original version of this plugin. The value of the username is stored in session (or the user specified field) and session for backwards-compatibility.

If you need to fake out extra attributes, you can do so like this:

CASClient::Frameworks::Rails::Filter.fake("homer", {:role => "user", :email => "[email protected]"})

And the extra attributes will get put in the proper place in the session.

License

RubyCAS-Client is licensed for use under the terms of the MIT License. See the LICENSE.txt file bundled with the official RubyCAS-Client distribution for details.

rubycas-client's People

Contributors

amkirwan avatar antono avatar billgathen avatar brodock avatar bryanlarsen avatar cassiuschen avatar craigpg avatar deathwish avatar gbaptista avatar geoffgarside avatar gisikw avatar jamesarosen avatar jcwilk avatar joel1di1 avatar jorahood avatar krausefx avatar moofish32 avatar mscottford avatar napcs avatar narnach avatar ryarger avatar shadowbq avatar soupmatt avatar tpickett66 avatar weppos avatar yurikoval avatar zbrimhall avatar zuk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rubycas-client's Issues

invalid byte sequence in UTF-8

I received this error : CASClient::BadResponseException MALFORMED CAS RESPONSE when trying to connect to my CAS server.

I presume it's the server fault but since i can't modify it i had to monkey-patch the casclient/responses.rb to make this change :

def check_and_parse_xml(raw_xml)
    raw_xml = raw_xml.encode('UTF-8', :invalid => :replace, :undef => :replace, :replace => '?')
    ...
end

Is there a cleaner way to do it ?

ArgumentError (comparison of String with Time failed)

ArgumentError (comparison of String with Time failed):
/Users/kingjim/.rbenv/versions/1.9.3-p547/lib/ruby/gems/1.9.1/bundler/gems/rubycas-client-195a4b703330/lib/casclient/frameworks/rails/filter.rb:258:in >' /Users/kingjim/.rbenv/versions/1.9.3-p547/lib/ruby/gems/1.9.1/bundler/gems/rubycas-client-195a4b703330/lib/casclient/frameworks/rails/filter.rb:258:inredirect_to_cas_for_authentication'
/Users/kingjim/.rbenv/versions/1.9.3-p547/lib/ruby/gems/1.9.1/bundler/gems/rubycas-client-195a4b703330/lib/casclient/frameworks/rails/filter.rb:243:in unauthorized!' /Users/kingjim/.rbenv/versions/1.9.3-p547/lib/ruby/gems/1.9.1/bundler/gems/rubycas-client-195a4b703330/lib/casclient/frameworks/rails/filter.rb:129:infilter'
/Users/kingjim/.rbenv/versions/1.9.3-p547/lib/ruby/gems/1.9.1/bundler/gems/rubycas-client-195a4b703330/lib/casclient/frameworks/rails/filter.rb:15:in before' activesupport (4.1.6) lib/active_support/callbacks.rb:447:inpublic_send'
activesupport (4.1.6) lib/active_support/callbacks.rb:447:in block in make_lambda' activesupport (4.1.6) lib/active_support/callbacks.rb:160:incall'
activesupport (4.1.6) lib/active_support/callbacks.rb:160:in block in halting' activesupport (4.1.6) lib/active_support/callbacks.rb:229:incall'
activesupport (4.1.6) lib/active_support/callbacks.rb:229:in block in halting' activesupport (4.1.6) lib/active_support/callbacks.rb:229:incall'
activesupport (4.1.6) lib/active_support/callbacks.rb:229:in block in halting' activesupport (4.1.6) lib/active_support/callbacks.rb:166:incall'
activesupport (4.1.6) lib/active_support/callbacks.rb:166:in block in halting' activesupport (4.1.6) lib/active_support/callbacks.rb:166:incall'
activesupport (4.1.6) lib/active_support/callbacks.rb:166:in block in halting' activesupport (4.1.6) lib/active_support/callbacks.rb:166:incall'
activesupport (4.1.6) lib/active_support/callbacks.rb:166:in block in halting' activesupport (4.1.6) lib/active_support/callbacks.rb:86:incall'
activesupport (4.1.6) lib/active_support/callbacks.rb:86:in run_callbacks' actionpack (4.1.6) lib/abstract_controller/callbacks.rb:19:inprocess_action'
actionpack (4.1.6) lib/action_controller/metal/rescue.rb:29:in process_action' actionpack (4.1.6) lib/action_controller/metal/instrumentation.rb:31:inblock in process_action'
activesupport (4.1.6) lib/active_support/notifications.rb:159:in block in instrument' activesupport (4.1.6) lib/active_support/notifications/instrumenter.rb:20:ininstrument'
activesupport (4.1.6) lib/active_support/notifications.rb:159:in instrument' actionpack (4.1.6) lib/action_controller/metal/instrumentation.rb:30:inprocess_action'
actionpack (4.1.6) lib/action_controller/metal/params_wrapper.rb:250:in process_action' activerecord (4.1.6) lib/active_record/railties/controller_runtime.rb:18:inprocess_action'
actionpack (4.1.6) lib/abstract_controller/base.rb:136:in process' actionview (4.1.6) lib/action_view/rendering.rb:30:inprocess'
actionpack (4.1.6) lib/action_controller/metal.rb:196:in dispatch' actionpack (4.1.6) lib/action_controller/metal/rack_delegation.rb:13:indispatch'
actionpack (4.1.6) lib/action_controller/metal.rb:232:in block in action' actionpack (4.1.6) lib/action_dispatch/routing/route_set.rb:82:incall'
actionpack (4.1.6) lib/action_dispatch/routing/route_set.rb:82:in dispatch' actionpack (4.1.6) lib/action_dispatch/routing/route_set.rb:50:incall'
actionpack (4.1.6) lib/action_dispatch/journey/router.rb:73:in block in call' actionpack (4.1.6) lib/action_dispatch/journey/router.rb:59:ineach'
actionpack (4.1.6) lib/action_dispatch/journey/router.rb:59:in call' actionpack (4.1.6) lib/action_dispatch/routing/route_set.rb:678:incall'
warden (1.2.3) lib/warden/manager.rb:35:in block in call' warden (1.2.3) lib/warden/manager.rb:34:incatch'
warden (1.2.3) lib/warden/manager.rb:34:in call' rack (1.5.5) lib/rack/etag.rb:23:incall'
rack (1.5.5) lib/rack/conditionalget.rb:25:in call' rack (1.5.5) lib/rack/head.rb:11:incall'
actionpack (4.1.6) lib/action_dispatch/middleware/params_parser.rb:27:in call' actionpack (4.1.6) lib/action_dispatch/middleware/flash.rb:254:incall'
rack (1.5.5) lib/rack/session/abstract/id.rb:225:in context' rack (1.5.5) lib/rack/session/abstract/id.rb:220:incall'
actionpack (4.1.6) lib/action_dispatch/middleware/cookies.rb:560:in call' activerecord (4.1.6) lib/active_record/query_cache.rb:36:incall'
activerecord (4.1.6) lib/active_record/connection_adapters/abstract/connection_pool.rb:621:in call' activerecord (4.1.6) lib/active_record/migration.rb:380:incall'
actionpack (4.1.6) lib/action_dispatch/middleware/callbacks.rb:29:in block in call' activesupport (4.1.6) lib/active_support/callbacks.rb:82:inrun_callbacks'
actionpack (4.1.6) lib/action_dispatch/middleware/callbacks.rb:27:in call' actionpack (4.1.6) lib/action_dispatch/middleware/reloader.rb:73:incall'
actionpack (4.1.6) lib/action_dispatch/middleware/remote_ip.rb:76:in call' actionpack (4.1.6) lib/action_dispatch/middleware/debug_exceptions.rb:17:incall'
actionpack (4.1.6) lib/action_dispatch/middleware/show_exceptions.rb:30:in call' railties (4.1.6) lib/rails/rack/logger.rb:38:incall_app'
railties (4.1.6) lib/rails/rack/logger.rb:20:in block in call' activesupport (4.1.6) lib/active_support/tagged_logging.rb:68:inblock in tagged'
activesupport (4.1.6) lib/active_support/tagged_logging.rb:26:in tagged' activesupport (4.1.6) lib/active_support/tagged_logging.rb:68:intagged'
railties (4.1.6) lib/rails/rack/logger.rb:20:in call' actionpack (4.1.6) lib/action_dispatch/middleware/request_id.rb:21:incall'
rack (1.5.5) lib/rack/methodoverride.rb:21:in call' rack (1.5.5) lib/rack/runtime.rb:17:incall'
activesupport (4.1.6) lib/active_support/cache/strategy/local_cache_middleware.rb:26:in call' rack (1.5.5) lib/rack/lock.rb:17:incall'
actionpack (4.1.6) lib/action_dispatch/middleware/static.rb:64:in call' rack (1.5.5) lib/rack/sendfile.rb:112:incall'
railties (4.1.6) lib/rails/engine.rb:514:in call' railties (4.1.6) lib/rails/application.rb:144:incall'
rack (1.5.5) lib/rack/lock.rb:17:in call' rack (1.5.5) lib/rack/content_length.rb:14:incall'
rack (1.5.5) lib/rack/handler/webrick.rb:60:in service' /Users/kingjim/.rbenv/versions/1.9.3-p547/lib/ruby/1.9.1/webrick/httpserver.rb:138:inservice'
/Users/kingjim/.rbenv/versions/1.9.3-p547/lib/ruby/1.9.1/webrick/httpserver.rb:94:in run' /Users/kingjim/.rbenv/versions/1.9.3-p547/lib/ruby/1.9.1/webrick/server.rb:191:inblock in start_thread'

Use of class level configuration, singleton pattern makes testing difficult

The way the code is put together implies There Will Only Ever Be One Filter.

This is particularly annoying to test, as:

  • You have to proxy the implementation to apply common stubbing techniques (Try RubyCAS::Filter.any_instance.expects(...) for example)
  • @@config is global state
  • The common way in which RubyCAS::Filter is recommended to be used (in a before_filter), and how it relies on the global configuration behaviour is complex

Having looked at the origins of this, I under it's from the depths of 2006 or earlier, but it could do with a bit of love to remove the singleton nature and configuration pattern in favour of something more DI flavoured.

ie:

    class YourController
      before_filter :configurize, :restrict
      
      def configurize
        client = CASClient.new()
        @filter = RubyCAS::Filter.new(client, config.rubycas)
      end




      def restrict
        @filter.filter(self)
      end
    end

Mass assignment error when using activerecord store

I believe this was a new default adopted in Rails 3.1 or 3.2. The fix is easy, however.

ActiveModel::MassAssignmentSecurity::Error (Can't mass-assign protected attributes: pgt_iou, pgt_id)

I believe we just need to:

class CasPgtiou < ActiveRecord::Base
  attr_accessible :pgt_iou, :pgt_id
end

Issue with using fake

If I try using the fake command for some reason it can't respond to routes. Can this function not be used in a functional test?

Unauthorized filter fails with format of class Mime:Type

Making a JSON request, the client filter attempts to handle an unauthorised user by returning a redirect for HTML, and an error code for JSON.

The key line is ~221 in filter.rb

format = controller.request.format.to_sym

In our setup (Rails 3.2), the format object is a mime type class, its to_s is 'json', but its to_sym is nil

controller.request.format.class # => "Mime::Type". 
controller.request.format.to_sym #=> nil
controller.request.format.to_s #=> json

Thus, all unauth'd JSON requests fail to get the correct code, and try to consume a login page (after following a 302).

This might well be a bug in a particular version of ActionPack, but defensively, this fixes it

if controller.request.format.to_sym.nil?
  controller.request.format = controller.request.format.to_s
end

Harry

Pos-logout redirect parameter

I needed to configure the logout to redirect to the last accessed page in my application, but I noticed that the logout_url method in client.rb sets the parameter "destination" for the CAS server to redirect after logging out. But some CAS servers, specifically the jasig.org/cas doesn't look into that parameter, it looks into "service" instead.

Can you please update the gem to send the parameter 'service' as well?

undefined method `response' for #<CASClient::ServiceTicket:0x007f3634267e80>

To install CAS login for my application I used the instructions listed at https://github.com/rubycas/rubycas-client-rails#readme

When trying to login I get redirected properly to the CAS authentication page but after a successful login I get the following NoMethodError
undefined method `response' for #CASClient::ServiceTicket:0x007f3634267e80

I looked around a bunch to figure out a solution to the following error but was unable to find anything that works.
Please suggest!

Unable to run specs from a fresh clone of the project

I've run the bundle command. Now, when I run rake spec, I get the following error:

/usr/local/var/rbenv/versions/2.1.1/bin/ruby -S rspec ./spec/casclient/client_spec.rb ./spec/casclient/frameworks/rails/filter_spec.rb ./spec/casclient/tickets/storage/active_record_ticket_store_spec.rb ./spec/casclient/tickets/storage_spec.rb ./spec/casclient/validation_response_spec.rb ./spec/support/local_hash_ticket_store_spec.rb
/Users/adam/br/sandbox/rubycas-client/lib/casclient/tickets/storage/active_record_ticket_store.rb:69:in `<module:Storage>': uninitialized constant ActiveRecord::SessionStore (NameError)
from /Users/adam/br/sandbox/rubycas-client/lib/casclient/tickets/storage/active_record_ticket_store.rb:3:in `<module:Tickets>'
from /Users/adam/br/sandbox/rubycas-client/lib/casclient/tickets/storage/active_record_ticket_store.rb:2:in `<module:CASClient>'
from /Users/adam/br/sandbox/rubycas-client/lib/casclient/tickets/storage/active_record_ticket_store.rb:1:in `<top (required)>'
from /Users/adam/br/sandbox/rubycas-client/spec/casclient/tickets/storage/active_record_ticket_store_spec.rb:2:in `require'
from /Users/adam/br/sandbox/rubycas-client/spec/casclient/tickets/storage/active_record_ticket_store_spec.rb:2:in `<top (required)>'
from /usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `load'
from /usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `block in load_spec_files'
from /usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `each'
from /usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/configuration.rb:896:in `load_spec_files'
from /usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/command_line.rb:22:in `run'
from /usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/runner.rb:80:in `run'
from /usr/local/var/rbenv/versions/2.1.1/lib/ruby/gems/2.1.0/gems/rspec-core-2.14.8/lib/rspec/core/runner.rb:17:in `block in autorun'

Obviously there is something step I have to take, that I'm not aware of. I can see that there's a database.yml file in the specs directory, but there is no rake task to create or migrate the database. What do I need to do?

Single sign out doesn't destroy session

Is there something special to do so that single sign out destroys the session hash? I've written support for single sign out into my application and can confirm it's being handled by my application in the logs but it doesn't seem to destroy the user's associated session hash.

Is it supposed to? How does one check that a CAS session has been expired via the single sign out?

Boolean extra attributes are broken under ruby 1.9

Boolean attributes are encoded into the validation response like

<is_truthy><![CDATA[--- true
]]></is_truthy>

when running under ruby 1.9 the "is_truthy" extra attribute is set to "--- true" rather than actually being true.

Can you please provide an explanation as to why the session_store and the tmp/session must be shared?

I am trying to implement single sign out.. and I'm confused as to why the /tmp/session directory must be shared between all servers?

Why isn't it enough that the session_store be shared?

https://github.com/rubycas/rubycas-client#re-authenticating-on-every-request-ie-the-single-sign-out-problem

Also, is it possible to use memcache instead of the database for a shared session store? Currently, I use memcache because it is MUCH faster than the database.

I would like to continue to do so.

Thanks for a great gem!

Using redis with rubycas-client

I'm thinking of forking and adding in an option to use redis as a datastore for SSO sessions instead of the tmp/sessions directory in Rails. Redis would be a better option for this sort of temporary session, and also simply for the fact that it will work on Heroku much better (given that your app is run by multiple nodes) for Single Sign Out.

is this reasoning sound?

cas:user is nil when parsing xml response

When using CAS-client following the instructions, I've reached a point where I've got a positive response from an external CAS server:

    CAS server responded with #<Net::HTTPOK 200 OK readbody=true>:

And the XML is like this:

    <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
      <cas:authenticationSuccess>
        <cas:attributes>
          <cas:user>4oaz8QMucIrlFOU7dr3QpWkqbRY=</cas:user>
          <cas:ccc></cas:ccc>
          <cas:tipo>EDITED_OUT</cas:tipo>
          <cas:acceso>cd</cas:acceso>
          <cas:identificador>EDITED_OUT</cas:identificador>
          <cas:txtBienvenida>EDITED_OUT</cas:txtBienvenida>
          <cas:usuarioValidado>S</cas:usuarioValidado>
          <cas:correo>EDITED_OUT</cas:correo>
          <cas:tlf>EDITED_OUT</cas:tlf>
          <cas:tipoAcceso>2</cas:tipoAcceso>
          <cas:xusuario>EDITED_OUT</cas:xusuario>
          <!-- En caso de que el usuario disponga de certificado digital -->

          <cas:nif>EDITED_OUT</cas:nif>
          <cas:email>EDITED_OUT</cas:email>
          <cas:apellido1>EDITED_OUT</cas:apellido1>
          <cas:apellido2>EDITED_OUT</cas:apellido2>
          <cas:anagramaFiscal>EDITED_OUT</cas:anagramaFiscal>
          <cas:nombre>EDITED_OUT</cas:nombre>

          <!-- Faltan las fechas -->

          <cas:tipoCertificado>EDITED_OUT</cas:tipoCertificado>
          <cas:emisor>EDITED_OUT</cas:emisor>
          <cas:usoCertificado>EDITED_OUT</cas:usoCertificado>
          <cas:apellidosResponsable>EDITED_OUT</cas:apellidosResponsable>

          <!-- Faltan las fechas -->

          <cas:politica>1.3.6.1.4.1.5734.3.5</cas:politica>
          <cas:subject>EDITED_OUT</cas:subject>
          <cas:versionPolitica>45</cas:versionPolitica>
          <cas:organizacionEmisora>FNMT</cas:organizacionEmisora>
          <cas:idPolitica>DEFAULT</cas:idPolitica>
          <cas:numSerie>EDITED_OUT</cas:numSerie>
          <cas:clasificacion>FNMT</cas:clasificacion>
          <cas:tipoAfirma>0</cas:tipoAfirma>
        </cas:attributes>
      </cas:authenticationSuccess>
    </cas:serviceResponse>

Then I get this log message from rubycas-client:

    Ticket "EDITED_OUT" for service "EDITED_OUT" belonging to user nil is VALID.

And then this error dump:

    TypeError (can't dup NilClass):
      org/jruby/RubyKernel.java:1894:in `dup'
      ----CUTTED----

Examining the code, I've come to the conclusion that the error is in filter.rb line 64:

    controller.session[client.username_session_key] = st.user.dup

Debugging, I examined the contents of the st object:

    (rdb:2) st.is_valid?
    true
    (rdb:2) st.user
    nil
    (rdb:2) st
    #<CASClient::ServiceTicket:0x7e054262
      @renew=nil,
      @extra_attributes={
        "user"=>"4oaz8QMucIrlFOU7dr3QpWkqbRY="
        "ccc"=>nil,
        "tipo"=>"CIUDADANO",
        "acceso"=>"cd",
        "identificador"=>"EDITED_OUT",
        "txtBienvenida"=>"EDITED_OUT",
        "usuarioValidado"=>"S", 
        "correo"=>"EDITED_OUT",
        "tlf"=>"EDITED_OUT",
        "tipoAcceso"=>"2",
        "xusuario"=>"EDITED_OUT",
        "nif"=>"EDITED_OUT", 
        "email"=>"EDITED_OUT",
        "apellido1"=>"EDITED_OUT",
        "apellido2"=>"EDITED_OUT",      
        "anagramaFiscal"=>"EDITED_OUT",         
        "nombre"=>"EDITED_OUT",
        "tipoCertificado"=>"FNMT PF",       
        "emisor"=>"EDITED_OUT",
        "usoCertificado"=>"EDITED_OUT",
        "apellidosResponsable"=>"EDITED_OUT",
        "politica"=>"1.3.6.1.4.1.5734.3.5",
        "subject"=>"EDITED_OUT",
        "versionPolitica"=>"45",
        "organizacionEmisora"=>"FNMT",
        "idPolitica"=>"DEFAULT",
        "numSerie"=>"EDITED_OUT",
        "clasificacion"=>"FNMT",
        "tipoAfirma"=>"0"
      },
      @service="EDITED_OUT",
      @failure_code=nil,
      @ticket="EDITED_OUT",
      @pgt_iou=nil,
      @user=nil,
      @failure_message=nil,
      @success=true
    >

Then, researching the xml parsing and responses.rb, I arrived to this in line 55:

    cas_user = @xml.elements["cas:user"]

cas_user is always nil because there is no cas:user element in the XML root, but there's one as child of cas:attributes, thus this:

    @xml.elements["cas:attributes/cas:user"]

returns something, in my case, something that looks like a digest of some kind, though I don't know how it's encoded or what info is there.

My question is, if that cas:attributes/cas:user attribute is the one that the client is trying to parse from the XML, or if it's something else. Also, I'd like to know if that XML format I pasted above is CAS-2.0 protocol compliant or if the error comes from a badly-formed XML. It's strange that rubycas-client stores all the "useful data" inside the extra_attributes.

I'm using the following:

Thanks your your help.

Can't find constant CASClient::Frameworks

I am having some issues regarding CASClient::Frameworks not being found. As such, whether I put

CASClient::Frameworks::Rails::Filter.configure(
  :cas_base_url => "http://localhost:4000/"
)

in environment.rb after the initialize or in an initializer, it can't find CASClient::Frameworks. I get the error

uninitialized constant CASClient::Frameworks (NameError)

When I take that line out and load the console, I still can't seem to find that constant. When I do

ruby-1.8.7-p330 :006 > CASClient.constants
 => ["BadResponseException", "CASException", "LoggerWrapper", "Logger", "ServiceTicket", "ProxyGrantingTicket", "XmlResponse", "ProxyResponse", "Client", "ProxyTicket", "ValidationResponse", "VERSION", "LoginResponse"] 

I have the gem installed. Is there some other initialization process that is not taking place here? I am running Rails 3 - is this some rails 3 related issue?

Chris

CAS client occupies almost all session storage space (cookie overflow)

http://code.google.com/p/rubycas-client/issues/detail?id=42

What steps will reproduce the problem?

  1. Clean Rails app + rubycas client set up as a before filter on some controller.
  2. In /etc/rubycas/config.yml - SQL authenticator + 2-3 varchar(255) columns containing about a hundred characters each. These 2-3 columns are returned as extra attributes.
  3. Login via CAS login window.

What is the expected output? What do you see instead?
Expected output is normal behavior, instead I see an exception about cookie overflow.

What version of the product are you using? On what operating system?
Rails 3, Ruby 1.9.2 (via RVM), rubycas-client installed as a plugin.

Please provide any additional information below.

When using cookie storage for sessions (Rails defailt), rubycas-related info occupies more than 3K of it (and 4K is the limit). That's how we get CookieOverflow exception after adding a couple of strings to extra attributes.

To see how much session storage is occupied:

  1. switch to db session storage:
  • config/initializers/session_store.rb:
    Rails.application.config.session_store :active_record_store
  • rake db:sessions:create;
  • rake db:migrate;
  1. log in into the app using CAS;
  2. From the rails console:
    • rails c;
    • s = ActiveRecord::SessionStore::Session.first;
    • ActiveRecord::SessionStore::Session.marshal(s.data).length;
  3. What is actually taking most of the storage space:

ActiveRecord::SessionStore::Session.marshal(s.data["cas_last_valid_ticket"].response.xml).length

Current solution: switched to db session storage.

Possible solutions:

A) maybe it is possible to store some key attributes in the session and re-create ServiceTicket from them instead of storing the whole object in session;

B) use compression for xml.

undefined method `response' for #<CASClient::ServiceTicket:0x1082e9290>

The issue is possibly in rubycas-client-rails, but personally think there should be some integration tests with rubycas-client-rails, so that we know of any incompatibilities before hand.

cheers,
jim.

rubycas-client-rails (0.1.0) lib/rubycas-client-rails.rb:79:in filter' activesupport (3.0.8) lib/active_support/callbacks.rb:326:inbefore'
activesupport (3.0.8) lib/active_support/callbacks.rb:315:in send' activesupport (3.0.8) lib/active_support/callbacks.rb:315:in_callback_before_15'
activesupport (3.0.8) lib/active_support/callbacks.rb:432:in _run__1847252116__process_action__1446005089__callbacks' activesupport (3.0.8) lib/active_support/callbacks.rb:410:insend'
activesupport (3.0.8) lib/active_support/callbacks.rb:410:in _run_process_action_callbacks' activesupport (3.0.8) lib/active_support/callbacks.rb:94:insend'
activesupport (3.0.8) lib/active_support/callbacks.rb:94:in run_callbacks' actionpack (3.0.8) lib/abstract_controller/callbacks.rb:17:inprocess_action'
actionpack (3.0.8) lib/action_controller/metal/instrumentation.rb:30:in process_action' activesupport (3.0.8) lib/active_support/notifications.rb:52:ininstrument'
activesupport (3.0.8) lib/active_support/notifications/instrumenter.rb:21:in instrument' activesupport (3.0.8) lib/active_support/notifications.rb:52:ininstrument'
actionpack (3.0.8) lib/action_controller/metal/instrumentation.rb:29:in process_action' actionpack (3.0.8) lib/action_controller/metal/rescue.rb:17:inprocess_action'
actionpack (3.0.8) lib/abstract_controller/base.rb:119:in process' actionpack (3.0.8) lib/abstract_controller/rendering.rb:41:inprocess'
actionpack (3.0.8) lib/action_controller/metal.rb:138:in dispatch' actionpack (3.0.8) lib/action_controller/metal/rack_delegation.rb:14:indispatch'
actionpack (3.0.8) lib/action_controller/metal.rb:178:in action' actionpack (3.0.8) lib/action_dispatch/routing/route_set.rb:62:incall'
actionpack (3.0.8) lib/action_dispatch/routing/route_set.rb:62:in dispatch' actionpack (3.0.8) lib/action_dispatch/routing/route_set.rb:27:incall'
rack-mount (0.6.14) lib/rack/mount/route_set.rb:148:in call' rack-mount (0.6.14) lib/rack/mount/code_generation.rb:93:inrecognize'
rack-mount (0.6.14) lib/rack/mount/code_generation.rb:68:in optimized_each' rack-mount (0.6.14) lib/rack/mount/code_generation.rb:92:inrecognize'
rack-mount (0.6.14) lib/rack/mount/route_set.rb:139:in call' actionpack (3.0.8) lib/action_dispatch/routing/route_set.rb:493:incall'
actionpack (3.0.8) lib/action_dispatch/middleware/best_standards_support.rb:17:in call' actionpack (3.0.8) lib/action_dispatch/middleware/head.rb:14:incall'
rack (1.2.4) lib/rack/methodoverride.rb:24:in call' actionpack (3.0.8) lib/action_dispatch/middleware/params_parser.rb:21:incall'
actionpack (3.0.8) lib/action_dispatch/middleware/flash.rb:182:in call' actionpack (3.0.8) lib/action_dispatch/middleware/session/abstract_store.rb:149:incall'
actionpack (3.0.8) lib/action_dispatch/middleware/cookies.rb:302:in call' activerecord (3.0.8) lib/active_record/query_cache.rb:32:incall'
activerecord (3.0.8) lib/active_record/connection_adapters/abstract/query_cache.rb:28:in cache' activerecord (3.0.8) lib/active_record/query_cache.rb:12:incache'
activerecord (3.0.8) lib/active_record/query_cache.rb:31:in call' activerecord (3.0.8) lib/active_record/connection_adapters/abstract/connection_pool.rb:354:incall'
actionpack (3.0.8) lib/action_dispatch/middleware/callbacks.rb:46:in call' activesupport (3.0.8) lib/active_support/callbacks.rb:416:in_run_call_callbacks'
actionpack (3.0.8) lib/action_dispatch/middleware/callbacks.rb:44:in call' rack (1.2.4) lib/rack/sendfile.rb:106:incall'
actionpack (3.0.8) lib/action_dispatch/middleware/remote_ip.rb:48:in call' actionpack (3.0.8) lib/action_dispatch/middleware/show_exceptions.rb:47:incall'
railties (3.0.8) lib/rails/rack/logger.rb:13:in call' rack (1.2.4) lib/rack/runtime.rb:17:incall'
activesupport (3.0.8) lib/active_support/cache/strategy/local_cache.rb:72:in call' rack (1.2.4) lib/rack/lock.rb:11:incall'
rack (1.2.4) lib/rack/lock.rb:11:in synchronize' rack (1.2.4) lib/rack/lock.rb:11:incall'
actionpack (3.0.8) lib/action_dispatch/middleware/static.rb:30:in call' railties (3.0.8) lib/rails/application.rb:168:incall'
railties (3.0.8) lib/rails/application.rb:77:in send' railties (3.0.8) lib/rails/application.rb:77:inmethod_missing'
railties (3.0.8) lib/rails/rack/log_tailer.rb:14:in call' rack (1.2.4) lib/rack/content_length.rb:13:incall'
rack (1.2.4) lib/rack/chunked.rb:15:in call' rack (1.2.4) lib/rack/handler/mongrel.rb:67:inprocess'
mongrel (1.1.5) lib/mongrel.rb:159:in process_client' mongrel (1.1.5) lib/mongrel.rb:158:ineach'
mongrel (1.1.5) lib/mongrel.rb:158:in process_client' mongrel (1.1.5) lib/mongrel.rb:285:inrun'
mongrel (1.1.5) lib/mongrel.rb:285:in initialize' mongrel (1.1.5) lib/mongrel.rb:285:innew'
mongrel (1.1.5) lib/mongrel.rb:285:in run' mongrel (1.1.5) lib/mongrel.rb:268:ininitialize'
mongrel (1.1.5) lib/mongrel.rb:268:in new' mongrel (1.1.5) lib/mongrel.rb:268:inrun'
rack (1.2.4) lib/rack/handler/mongrel.rb:38:in run' rack (1.2.4) lib/rack/server.rb:217:instart'
railties (3.0.8) lib/rails/commands/server.rb:65:in start' railties (3.0.8) lib/rails/commands.rb:30 railties (3.0.8) lib/rails/commands.rb:27:intap'
railties (3.0.8) lib/rails/commands.rb:27
/script/rails:6:in require' /script/rails:6 ruby-debug-ide (0.4.16) lib/ruby-debug-ide.rb:112:indebug_load'
ruby-debug-ide (0.4.16) lib/ruby-debug-ide.rb:112:in debug_program' ruby-debug-ide (0.4.16) bin/rdebug-ide:87 /usr/bin/rdebug-ide:19:inload'
/usr/bin/rdebug-ide:19

Tried to load unspecified class: Time

Tried to load unspecified class: Time

E, [2024-02-20T07:57:41.217929 #7] ERROR -- : ["/usr/local/lib/ruby/3.2.0/psych/class_loader.rb:99:in find'\", \"/usr/local/lib/ruby/3.2.0/psych/class_loader.rb:28:in load'", "/usr/local/lib/ruby/3.2.0/psych/scalar_scanner.rb:116:in parse_time'\", \"/usr/local/lib/ruby/3.2.0/psych/scalar_scanner.rb:59:in tokenize'", "/usr/local/lib/ruby/3.2.0/psych/visitors/to_ruby.rb:65:in deserialize'\", \"/usr/local/lib/ruby/3.2.0/psych/visitors/to_ruby.rb:130:in visit_Psych_Nodes_Scalar'", "/usr/local/lib/ruby/3.2.0/psych/visitors/visitor.rb:30:in visit'\", \"/usr/local/lib/ruby/3.2.0/psych/visitors/visitor.rb:6:in accept'", "/usr/local/lib/ruby/3.2.0/psych/visitors/to_ruby.rb:35:in accept'\", \"/usr/local/lib/ruby/3.2.0/psych/visitors/to_ruby.rb:320:in visit_Psych_Nodes_Document'", "/usr/local/lib/ruby/3.2.0/psych/visitors/visitor.rb:30:in visit'\", \"/usr/local/lib/ruby/3.2.0/psych/visitors/visitor.rb:6:in accept'", "/usr/local/lib/ruby/3.2.0/psych/visitors/to_ruby.rb:35:in accept'\", \"/usr/local/lib/ruby/3.2.0/psych.rb:334:in safe_load'", "/usr/local/lib/ruby/3.2.0/psych.rb:369:in load'\", \"/mnt/talemetry_match_api/vendor/ruby/3.2.0/gems/rubycas-client-2.3.9/lib/casclient/responses.rb:96:in parse_extra_attribute_value'", "/mnt/talemetry_match_api/vendor/ruby/3.2.0/gems/rubycas-client-2.3.9/lib/casclient/responses.rb:80:in block in parse'\", \"/mnt/talemetry_match_api/vendor/ruby/3.2.0/gems/rubycas-client-2.3.9/lib/casclient/responses.rb:79:in each'", "/mnt/talemetry_match_api/vendor/ruby/3.2.0/gems/rubycas-client-2.3.9/lib/casclient/responses.rb:79:in parse'\", \"/mnt/talemetry_match_api/vendor/ruby/3.2.0/gems/rubycas-client-2.3.9/lib/casclient/responses.rb:35:in initialize'", "/mnt/talemetry_match_api/vendor/ruby/3.2.0/gems/rubycas-client-2.3.9/lib/casclient/client.rb:265:in new'\", \"/mnt/talemetry_match_api/vendor/ruby/3.2.0/gems/rubycas-client-2.3.9/lib/casclient/client.rb:265:in request_cas_response'", "/mnt/talemetry_match_api/vendor/ruby/3.2.0/gems/rubycas-client-2.3.9/lib/casclient/client.rb:123:in validate_service_ticket'\", \"/mnt/talemetry_match_api/lib/cas_authenticator.rb:7:in validate_ticket'", "/mnt/talemetry_match_api/lib/cas_authenticator.rb:12:in `validate_credentials'", ]

parse_extra_attribute_value method in the lib/casclient/responses.rb is using YAML.load(value). With ruby 3.2 we have to explicitly specify the classes with YAML.load

Example - YAML.load_file(some_file_name, permitted_classes: [Matrix, OpenStruct, Symbol, Time])

Request: bump the version of gem

I'm using rubycas-client (so helpful! thanks!) w/ bundler to fetch from github repository.
Because I want to use the fake out function.
Could you bump the version?

NoMethodError: `initialize': undefined method `session_class=' for ActiveRecord::SessionStore:Module

I recently upgraded from Rails 3.2 to Rails 4. I am getting following error now:

/usr/share/rvm/gems/ruby-2.3.7@m3/gems/rubycas-client-2.3.10.rc1/lib/casclient/tickets/storage/active_record_ticket_store.rb:20:in 'initialize': undefined method 'session_class=' for ActiveRecord::SessionStore:Module (NoMethodError)

When I looked a bit into it, I found that for rails/activerecord-session_store, method of setting session has changed: Active record session store commit

But, this gem hasn't updated it. The gem still uses following code:
active record ticket store and storage

There is another gem for rubycas-client which uses something like this: mdsol | rubycas-client's storage

As per #78, some folks can use it and others can not. Can someone confirm if this is compatible with Rails 4 (specifically Rails 4.0.8) and if yes, what steps are required to fix thee issue?

Unable to programmatically authenticate

Programmatic authentication fails because RubyCAS server returns a 303 instead of a 302. I am not sure if a 303 is a valid response per the CAS protocol. Some sample code to repro:

username = "me"
password = "secret"
service_url = "http://myservice.example.com"
response = client.login_to_service({:username => username, :password => password}, service_url)
response.is_success? # false

This is only because the server returns a 303. The user is correctly authenticated. In the server logs I see:

I, [2012-07-10T22:58:30.053325 #18113]  INFO -- : Login ticket 'LT-1341961109r33014B38A614C87BEA' successfully validated
I, [2012-07-10T22:58:30.069214 #18113]  INFO -- : Credentials for username 'me' successfully validated using CASServer::Authenticators::DeviseWithLegacy.
I, [2012-07-10T22:58:30.108557 #18113]  INFO -- : Redirecting authenticated user 'me' at '107.19.11.144' to service 'http://localhost:3030/resource'

Doing a little more digging, the response is a #<Net::HTTPSeeOther 303 See Other readbody=true> In the LoginResponse class, we are doing this to check for successful authentication:

if not ((http_response.kind_of?(Net::HTTPSuccess) || http_response.kind_of?(Net::HTTPFound)) && @ticket.present?)

From some brief research, it would appear that a 303 is a satisfactory response from the server, so that is why I have filed the ticket here instead of with rubycas-server.

Incorrect local storage for temporary session files

As of this bug dated 2008: http://code.google.com/p/rubycas-client/issues/detail?id=23 the problem went back in Rails 3.1:

The following line (storage.rb 72):

    DEFAULT_TMP_DIR = defined?(Rails.root) ? "#{Rails.root}/tmp" : "#{Dir.pwd}/tmp"

Will return "/tmp" because Rails.root will not be defined at that run time.

The solution that best repaired it was removing the constant and putting it as a local variable inside initialize method, maintaining the functionality and repairing the wrong behaviour.

FYI, I'm using Rails 3.1 with Ruby 1.9.3-p0

I will attach a pull request in a minutes

Investigate vulnerability affecting other CAS clients

I've quoted the email below from the CAS mailing list.

From: Marvin Addison [email protected]
Subject: [cas-announce] CAS Client Security Vulnerability CVE-2014-4172
Date: August 11, 2014 at 11:03:48 AM CDT
To: [email protected]

A critical security vulnerability has been discovered in several Jasig
CAS clients that allows URL parameter injection due to improper URL
encoding at the back-channel ticket validation step of the CAS
protocol. The following CVE number has been assigned to track this
vulnerability:

CVE-2014-4172

Affected Software

Jasig Java CAS Client
Vulnerable versions: <3.3.2
Fix version: 3.3.2, http://search.maven.org/#browse%7C1586013685

.NET CAS Client
Vulnerable versions: <1.0.2
Fix version: 1.0.2,
http://downloads.jasig.org/cas-clients/dotnet/dotnet-client-1.0.2-bin.zip

phpCAS
Vulnerable versions: <1.3.3
Fix version: 1.3.3,
http://downloads.jasig.org/cas-clients/php/1.3.3/CAS-1.3.3.tgz

There may be other CAS clients that are vulnerable.

Impact

The nature of the vulnerability allows malicious remote (network)
agents to craft attack URLs that bypass security constraints of the
CAS protocol. The following attack scenarios are known and have been
demonstrated:

  1. A malicious service that can obtain a valid ticket can use it to
    access another service in violation of the CAS protocol requirement
    that a ticket issued for a service can only be used to access the
    service for which the ticket was granted. This type of access amounts
    to an illicit proxy: the attacker is proxying authentication for the
    target.
  2. A malicious user can request a ticket for service A and use it to
    access service B with the access privileges of A.

Attacks like scenario 1 could result in unauthorized data disclosure,
while scenario 2 could result in privilege escalation. Other attack
scenarios may be possible.

Remediation

Upgrade affected CAS clients as soon as possible. Consider mitigation
if upgrading is not possible.

Mitigation

The CAS Service Management facility [1], which is enabled by default,
can be used to restrict services that are permitted to use CAS (i.e.
allowed to request tickets). Whitelisting trusted services can reduce
the scope of attacks like scenario 1 above.

The following servlet filter may provide additional defense at the CAS
server against some forms of this attack:

https://github.com/Jasig/cas-server-security-filter/tree/cas-server-security-filter-1.0.0

Best,
Marvin Addison
CAS Developer

[1] http://jasig.github.io/cas/4.0.0/installation/Service-Management.html

extra attributes from Jasig Cas 3.5

Hi,

I'm unable to get extra_attributes from my Jasig Cas 3.5; with phpcas I've no problem, is there an incompatibility with Jasig CAS ?

Best regards,

Wrong variable names at AbstractTicketStore, get_session_for_service_ticket method

You're receiving "st" as parameter, and using "si" in the read_service_session_lookup(si) call, and also at the logger. This crashes obviously.

Happened to me while attempting to use the single sign out. Without this fixed, i don't know how anyone could make that feature work.

def get_session_for_service_ticket(st)
session_id = read_service_session_lookup(si)
if session_id
session = ActiveRecord::SessionStore::Session.find_by_session_id(session_id)
else
log.warn("Couldn't destroy session with SessionIndex #{si} because no corresponding session id could be looked up.")
end
[session_id, session]
end

I'm using the gem 2.3.8 btw.

Best regards, Alan //

[FIX INCLUDED] Some query strings in a referrer cause an exception when logging out.

When logging out of RubyCAS with a referrer that has a query string containing just a key (e.g. foo.html?12345) an exception is generated by hash_to_query.

To fix, simply replace the offending line with the one below (around line 250 of casclient/client.rb):

vals.each {|v| pairs << (v.nil? ? CGI.escape(k) : "#{CGI.escape(k)}=#{CGI.escape(v)}")}

AbstractTicketStore NameError

When running a rails console in production mode I'm getting this NameError

$ rails c production
...snip.../vendor/bundle/ruby/1.8/gems/rubycas-client-2.3.7/lib/casclient/tickets/storage/active_record_ticket_store.rb:12: uninitialized constant CASClient::Tickets::Storage::AbstractTicketStore (NameError)
from ...snip.../vendor/bundle/ruby/1.8/gems/railties-3.1.3/lib/rails/application.rb:83:in `require_environment!'
from ...snip.../vendor/bundle/ruby/1.8/gems/railties-3.1.3/lib/rails/commands.rb:39
from script/rails:6:in `require'
from script/rails:6

running with REE 2011.03

Its fine in development mode and test mode, just seems to explode in production mode which was a lovely surprise.

segfault

I'm seeing a segfault, and I've traced it down to the following method CASClient::Client#request_cas_response(uri, type)
The segfault happens at this point in the method:

raw_res = https.start do |conn|
  conn.get("#{uri.path}?#{uri.query}")
end

This is on OS X, running ruby 1.8.7 (2009-06-12 patchlevel 174) [i686-darwin10.7.0]
Using rubycas-client (2.2.1) in a Rails app (version 3.0.6)

I'm wondering if anyone else is experiencing this. Or if there are certain gem or gem version combo that we could/should avoid when using rubycas-client.

Here's the Gemfile for our app:

source 'http://rubygems.org'

gem 'bundler'
gem 'rails', '3.0.6'

gem 'patron'
gem 'ruote', '2.1.11'
gem 'ruote-couch', '2.1.11'
gem 'ruote-redis', '2.1.11'
gem 'yajl-ruby'
gem 'couchrest', '1.0.1'
gem 'couchrest_model', '1.0.0'
gem 'haml'
gem 'sass'
gem 'compass'
gem 'compass-960-plugin'
gem 'lemonade'
gem 'rubycas-client'
gem 'bluecloth'
gem 'cancan', '= 1.3.4'
gem 'fastercsv'
gem 'memcache-client'
gem 'linguistics'
gem 'rubyzip', 
  :require => 'zip/zip'
gem 'rest-client'
gem 'unicorn'
gem 'paypal_adaptive'
gem 'exception_notification', 
  :require => 'exception_notifier'

group :daemon do
  gem 'daemons-mikehale', 
    :require => 'daemons'
end

group :development do
  gem 'ruby-debug'
  gem 'ruby-prof'
  gem 'rspec-rails'
end

group :test do
  gem 'fakeweb'
  gem 'ruby-debug'
  gem 'rspec'
  gem 'rspec-rails'

  gem 'cucumber', '0.9.2'
  gem 'cucumber-rails', '0.3.2'

  gem 'database_cleaner'

  gem 'capybara', '0.3.9'

  gem 'webrat' 
  gem 'launchy'
end

Thanks.

authenticate_on_every_request and Gateway

If using the gateway filter a request is made for every action, even though authenticate_on_every_request is set to false.

Not sure if this is necessary for the protocol (I don't think so), but obviously this has serious performance issues for us.

Cheers,
Jim.

skip_before_filter doesn't work

class ApplicationController < ActionController::Base
before_filter CASClient::Frameworks::Rails::Filter
end

class MyController < ApplicationController
before_filter CASClient::Frameworks::Rails::Filter, :except => :index

def index
# But here before_filter is triggered !
end
end

above code i want to skip the index action but it does't work what to do?

NoMethodError (undefined method `strip' for nil:NilClass)

I, [2015-04-13T08:22:12.459667 #6465] INFO -- : Processing by SsoCasController#service as HTML
I, [2015-04-13T08:22:12.459757 #6465] INFO -- : Parameters: {"ticket"=>"ST-14289133322406-B8NK5MLfd9CPSNRhIRJuPJeF8h4N9poIHP7BzRXL"}
I, [2015-04-13T08:22:12.486353 #6465] INFO -- : Completed 500 Internal Server Error in 26ms
F, [2015-04-13T08:22:12.490253 #6465] FATAL -- :
NoMethodError (undefined method strip' for nil:NilClass): rubycas-client (2.3.9) lib/casclient/responses.rb:56:inparse'
rubycas-client (2.3.9) lib/casclient/responses.rb:35:in initialize' rubycas-client (2.3.9) lib/casclient/client.rb:265:innew'
rubycas-client (2.3.9) lib/casclient/client.rb:265:in request_cas_response' rubycas-client (2.3.9) lib/casclient/client.rb:123:invalidate_service_ticket'
/home/deployer2/.rvm/gems/ruby-2.1.5/bundler/gems/devise_cas_authenticatable-a164536b8ba4/lib/devise_cas_authenticatable/model.rb:19:in authenticate_with_cas_ticket' /home/deployer2/.rvm/gems/ruby-2.1.5/bundler/gems/devise_cas_authenticatable-a164536b8ba4/lib/devise_cas_authenticatable/strategy.rb:19:inauthenticate!'
warden (1.2.3) lib/warden/strategies/base.rb:53:in _run!' warden (1.2.3) lib/warden/proxy.rb:354:inblock in _run_strategies_for'
warden (1.2.3) lib/warden/proxy.rb:349:in each' warden (1.2.3) lib/warden/proxy.rb:349:in_run_strategies_for'
warden (1.2.3) lib/warden/proxy.rb:319:in _perform_authentication' warden (1.2.3) lib/warden/proxy.rb:104:inauthenticate'
devise (3.4.1) lib/devise/controllers/helpers.rb:120:in current_user' devise (3.4.1) lib/devise/controllers/helpers.rb:116:inuser_signed_in?'
activesupport (4.2.0) lib/active_support/callbacks.rb:427:in block in make_lambda' activesupport (4.2.0) lib/active_support/callbacks.rb:412:incall'
activesupport (4.2.0) lib/active_support/callbacks.rb:412:in block in invert_lambda' activesupport (4.2.0) lib/active_support/callbacks.rb:144:incall'
activesupport (4.2.0) lib/active_support/callbacks.rb:144:in block (2 levels) in halting_and_conditional' activesupport (4.2.0) lib/active_support/callbacks.rb:144:ineach'
activesupport (4.2.0) lib/active_support/callbacks.rb:144:in all?' activesupport (4.2.0) lib/active_support/callbacks.rb:144:inblock in halting_and_conditional'
activesupport (4.2.0) lib/active_support/callbacks.rb:234:in call' activesupport (4.2.0) lib/active_support/callbacks.rb:234:inblock in halting'
activesupport (4.2.0) lib/active_support/callbacks.rb:234:in call' activesupport (4.2.0) lib/active_support/callbacks.rb:234:inblock in halting'
activesupport (4.2.0) lib/active_support/callbacks.rb:169:in call' activesupport (4.2.0) lib/active_support/callbacks.rb:169:inblock in halting'
activesupport (4.2.0) lib/active_support/callbacks.rb:169:in call' activesupport (4.2.0) lib/active_support/callbacks.rb:169:inblock in halting'
activesupport (4.2.0) lib/active_support/callbacks.rb:169:in call' activesupport (4.2.0) lib/active_support/callbacks.rb:169:inblock in halting'
activesupport (4.2.0) lib/active_support/callbacks.rb:151:in call' activesupport (4.2.0) lib/active_support/callbacks.rb:151:inblock in halting_and_conditional'
activesupport (4.2.0) lib/active_support/callbacks.rb:169:in call' activesupport (4.2.0) lib/active_support/callbacks.rb:169:inblock in halting'
activesupport (4.2.0) lib/active_support/callbacks.rb:151:in call' activesupport (4.2.0) lib/active_support/callbacks.rb:151:inblock in halting_and_conditional'
activesupport (4.2.0) lib/active_support/callbacks.rb:151:in call' activesupport (4.2.0) lib/active_support/callbacks.rb:151:inblock in halting_and_conditional'
activesupport (4.2.0) lib/active_support/callbacks.rb:151:in call' activesupport (4.2.0) lib/active_support/callbacks.rb:151:inblock in halting_and_conditional'
activesupport (4.2.0) lib/active_support/callbacks.rb:92:in call' activesupport (4.2.0) lib/active_support/callbacks.rb:92:in_run_callbacks'
activesupport (4.2.0) lib/active_support/callbacks.rb:734:in _run_process_action_callbacks' activesupport (4.2.0) lib/active_support/callbacks.rb:81:inrun_callbacks'
actionpack (4.2.0) lib/abstract_controller/callbacks.rb:19:in process_action' actionpack (4.2.0) lib/action_controller/metal/rescue.rb:29:inprocess_action'
actionpack (4.2.0) lib/action_controller/metal/instrumentation.rb:31:in block in process_action' activesupport (4.2.0) lib/active_support/notifications.rb:164:inblock in instrument'
activesupport (4.2.0) lib/active_support/notifications/instrumenter.rb:20:in instrument' activesupport (4.2.0) lib/active_support/notifications.rb:164:ininstrument'
actionpack (4.2.0) lib/action_controller/metal/instrumentation.rb:30:in process_action' actionpack (4.2.0) lib/action_controller/metal/params_wrapper.rb:250:inprocess_action'
actionpack (4.2.0) lib/abstract_controller/base.rb:137:in process' actionview (4.2.0) lib/action_view/rendering.rb:30:inprocess'
actionpack (4.2.0) lib/action_controller/metal.rb:195:in dispatch' actionpack (4.2.0) lib/action_controller/metal/rack_delegation.rb:13:indispatch'
actionpack (4.2.0) lib/action_controller/metal.rb:236:in block in action' actionpack (4.2.0) lib/action_dispatch/routing/route_set.rb:73:incall'
actionpack (4.2.0) lib/action_dispatch/routing/route_set.rb:73:in dispatch' actionpack (4.2.0) lib/action_dispatch/routing/route_set.rb:42:inserve'
actionpack (4.2.0) lib/action_dispatch/routing/mapper.rb:49:in serve' actionpack (4.2.0) lib/action_dispatch/journey/router.rb:43:inblock in serve'
actionpack (4.2.0) lib/action_dispatch/journey/router.rb:30:in each' actionpack (4.2.0) lib/action_dispatch/journey/router.rb:30:inserve'
actionpack (4.2.0) lib/action_dispatch/routing/route_set.rb:802:in call' apipie-rails (0.3.2) lib/apipie/static_dispatcher.rb:65:incall'
/home/deployer2/.rvm/gems/ruby-2.1.5/bundler/gems/devise_cas_authenticatable-a164536b8ba4/lib/devise_cas_authenticatable/single_sign_out/rack.rb:14:in call' apipie-rails (0.3.2) lib/apipie/extractor/recorder.rb:132:incall'
warden (1.2.3) lib/warden/manager.rb:35:in block in call' warden (1.2.3) lib/warden/manager.rb:34:incatch'
warden (1.2.3) lib/warden/manager.rb:34:in call' rack (1.6.0) lib/rack/etag.rb:24:incall'
rack (1.6.0) lib/rack/conditionalget.rb:25:in call' rack (1.6.0) lib/rack/head.rb:13:incall'
actionpack (4.2.0) lib/action_dispatch/middleware/params_parser.rb:27:in call' actionpack (4.2.0) lib/action_dispatch/middleware/flash.rb:260:incall'
rack (1.6.0) lib/rack/session/abstract/id.rb:225:in context' rack (1.6.0) lib/rack/session/abstract/id.rb:220:incall'
actionpack (4.2.0) lib/action_dispatch/middleware/cookies.rb:560:in call' actionpack (4.2.0) lib/action_dispatch/middleware/callbacks.rb:29:inblock in call'
activesupport (4.2.0) lib/active_support/callbacks.rb:88:in call' activesupport (4.2.0) lib/active_support/callbacks.rb:88:in_run_callbacks'
activesupport (4.2.0) lib/active_support/callbacks.rb:734:in _run_call_callbacks' activesupport (4.2.0) lib/active_support/callbacks.rb:81:inrun_callbacks'
actionpack (4.2.0) lib/action_dispatch/middleware/callbacks.rb:27:in call' actionpack (4.2.0) lib/action_dispatch/middleware/remote_ip.rb:78:incall'
actionpack (4.2.0) lib/action_dispatch/middleware/debug_exceptions.rb:17:in call' actionpack (4.2.0) lib/action_dispatch/middleware/show_exceptions.rb:30:incall'
railties (4.2.0) lib/rails/rack/logger.rb:38:in call_app' railties (4.2.0) lib/rails/rack/logger.rb:20:inblock in call'
activesupport (4.2.0) lib/active_support/tagged_logging.rb:68:in block in tagged' activesupport (4.2.0) lib/active_support/tagged_logging.rb:26:intagged'
activesupport (4.2.0) lib/active_support/tagged_logging.rb:68:in tagged' railties (4.2.0) lib/rails/rack/logger.rb:20:incall'
actionpack (4.2.0) lib/action_dispatch/middleware/request_id.rb:21:in call' rack (1.6.0) lib/rack/methodoverride.rb:22:incall'
rack (1.6.0) lib/rack/runtime.rb:18:in call' rack (1.6.0) lib/rack/sendfile.rb:113:incall'
railties (4.2.0) lib/rails/engine.rb:518:in call' railties (4.2.0) lib/rails/application.rb:164:incall'
/usr/local/rvm/gems/ruby-1.9.3-p551/gems/passenger-4.0.59/lib/phusion_passenger/rack/thread_handler_extension.rb:74:in process_request' /usr/local/rvm/gems/ruby-1.9.3-p551/gems/passenger-4.0.59/lib/phusion_passenger/request_handler/thread_handler.rb:141:inaccept_and_process_next_request'
/usr/local/rvm/gems/ruby-1.9.3-p551/gems/passenger-4.0.59/lib/phusion_passenger/request_handler/thread_handler.rb:109:in main_loop' /usr/local/rvm/gems/ruby-1.9.3-p551/gems/passenger-4.0.59/lib/phusion_passenger/request_handler.rb:455:inblock (3 levels) in start_thread

File.exists? removed in Ruby 3.2

After upgrading to Ruby 3.2, we had the following error pop up in Sentry:

NoMethodError: undefined method `exists?' for File:Class (NoMethodError)

          File.delete(ssl_filename) if File.exists?(ssl_filename)
                                           ^^^^^^^^
Did you mean?  exist?
  from rubycas-client (2.3.9) lib/casclient/tickets/storage.rb:129:in `cleanup_service_session_lookup'

According to Ruby 3.2's changelogs, File.exists has been removed:

Removed methods
The following deprecated methods are removed.

[...]
File.exists? [Feature #17391]


There are two references to File.exists? in the codebase, which need to be updated to File.exist?

return IO.read(ssl_filename) if File.exists?(ssl_filename)
end
# Removes a stored relationship between a ServiceTicket and a local
# Rails session id. This should be called when the session is being
# closed.
#
# See #store_service_session_lookup.
def cleanup_service_session_lookup(st)
raise CASException, "No service_ticket specified." if st.nil?
st = st.ticket if st.kind_of? ServiceTicket
ssl_filename = filename_of_service_session_lookup(st)
File.delete(ssl_filename) if File.exists?(ssl_filename)

Cant skip CASClient::Frameworks::Rails::Filter

I have before_filter CASClient::Frameworks::Rails::Filter in my application controller and can't skip it in my an ajax call in another controller using skip_before_filter CASClient::Frameworks::Rails::Filter.

Why is proxyValidate hardcoded?

I got a report from my CAS admin that my service was the only one using the "proxyValidate" endpoint. All others were using "serviceValidate".

It seems this endpoint is hardcoded in lib/casclient/client.rb: validate_url. Why is this? I understand that I can easily override this, so I'm really interested in the design choice here.

The LoggerWrapper initialize method is broken

There is no set_logger method on LoggerWrapper, set_logger should be set_real_logger. Currently when initializing the LoggerWrapper with a "real" logger, it will try to set the logger via the method_missing which will silently swallow the bug.

set_logger(real_logger)

Looks like there was an attempt to fix this in the past, but I suspect the fix highlighted other issues which were no-longer silently swallowed, but appeared to be brought about by the fix...
acd4f94

Although perhaps warnings were coming from the attempt to access the instance variable by use of the instance variable, instance_variable_defined?(@real_logger) should be instance_variable_defined?(:@real_logger). Perhaps the defined? method would be more appropriate here.

undefined method `destroy' for {}:Hash

This was all fine till Rails3.0.0.4.beta
Today I upgraded the rails to rc and now its blowing up while logging out.

NoMethodError in SessionsController#logout

undefined method `destroy' for {}:Hash

app/controllers/sessions_controller.rb:16:in `logout'

sessions_controller.rb

class SessionsController < ApplicationController

  before_filter CASClient::Frameworks::Rails::GatewayFilter, :only => :index
  before_filter CASClient::Frameworks::Rails::Filter, :except => :index

  def index
    redirect_to root_url
  end

  def login_complete
    redirect_to root_url
  end

  def logout
    reset_session
    CASClient::Frameworks::Rails::Filter.logout(self, root_url) and return
  end
end

Cut a release with Rails 4.1 support?

👋 Thanks for all your work on this project! 😀

Master has been working well for us on Rails 4.1 - my team would love to be able to get rid of the ref: in our Gemfile and switch to an officially released version.

Think we could get a release out from latest master?

Thanks! 🍪 🍰 🍺

Rails generator to create cas_pgtious table is not working

When I run rails g rubycas generator is not found. I tried a few things to manually have it included/discovered but nothing worked. I havent done much with generators before. I think we just need to move it to lib/generators/

I looked around for documentation, but couldnt find any. Let me know if you think the above is the right approach and I wouldnt mind sending a pull request with that and updated docs.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.