18 Nov 2011
•
General
•
Reinventing the wheel
•
Security
•
Web
Sort of. Here is a way to do it, but I don't a practical use for this hack right now. But it is fun anyway :)
Here we go!
I was thinking about ways to distribute trust, and played a bit with CA generation and OpenSSL, when it occured to me: it depends more on a key pair than on a certificate! If I consider that I trust a key instead of a certificate, I begin to see a way (certificates are only restrictions on the trust between keys).
It is really easy to get multiple certification authorities to sign a certificate for the same key (even for the same subject name in some cases). You send the certificate signing request to two certificate authorities, and you get two certificates, for the same keys and same subject names. But the issuer, dates, serial and signature are different. That's why a certificate has only one certification chain.
But what will happen if I delegates the certification to another key? Here is the idea:
- create a first key pair
- create a CSR for this key pair, and add the certification authority extension
- ask the certification authorities to sign this CSR
- you now have multiple certificates, for one key pair, all of them with the same subject name, and with certification authority powers
- create a second key pair
- create a CSR for this key pair, with a subject name for your email/domain name/organisation/whatever
- sign this CSR with the first key pair, and any of the CA certificates you obtained before
You are now the proud owner of a valid certificate for your domain name, with multiple certification chains going up to each of the root CAs. Why? The issuer's subject name and public key is the same for all of the generated CAs, and they're included in the end certificate. Any generated CA certificate can be used to verify that signature, and all the certification paths will work. Cool, huh?
Okay, but...
- Creating a sub CA is very expensive (if you want it to be recognized by all the browsers)
- good luck with creating multiple sub CA and getting away with it
- Assuming that certification authorities accept it, the sub CA private key could be thrown away after signing the certificate. But who will create and delete the subCA key? you, one of the CAs?
- In the case of TLS, serving all the certification chains will have no impact: the browsers take the first matching sub CA in the list for the verification, they will not retry with another sub CA if they don't find a root (but if you serve one certification chain at a time, it will work).
See, I said "no practical use" :)
31 Aug 2011
•
Reinventing the wheel
•
Ruby
•
Smalltalk
If you don't know JTalk yet, you're missing something. It's an awesome piece of work: a Smalltalk to Javascript compiler and a Smalltalk editor running in Javascript, IN YOUR BROWSER! Go check it out, now!
Now that you've played a bit with JTalk, let's get started.
If you're like me, you're a bit annoyed by WebDAV, the proposed solution to save changes to disk. And if you're like me, you would like to use Jtalk with Rails, and because you're a lazy ass like me, you use WEBrick instead of Apache for your development.
Let's hack something up to replace WebDAV!
Create a Rails application
[sourcecode language="bash"]
rails new jtalkonrails
cd jtalkonrails
bundle install
rm public/index.html
rails generate controller home index
printf "Jtalkonrails::Application.routes.draw do\n root :to => \"home#index\"\nend\n" > config/routes.rb
[/sourcecode]
(I should really make a script out of all my rails initialization commands, one of these days...)
Add Jtalk to your application
[sourcecode language="bash"]
cd public/
wget http://github.com/NicolasPetton/jtalk/tarball/master --no-check-certificate
tar zxvf master
cp -R NicolasPetton-jtalk-20cd63e/st .
cp -R NicolasPetton-jtalk-20cd63e/js .
cp -R NicolasPetton-jtalk-20cd63e/css .
cp -R NicolasPetton-jtalk-20cd63e/ide .
rm -rf NicolasPetton-jtalk-20cd63e
[/sourcecode]
JTalk stores source code in three forms: Smalltalk code, Javascript code and smaller Javascript code ("*.deploy.js").
Jtalk hello world: the Counter example
now, edit app/views/layouts/application.html.erb so that it looks like this:
[sourcecode language="html"]
<!DOCTYPE html>
<html>
<head>
<title>Jtalk On Rails</title>
<%= stylesheet_link_tag :all %>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tag %>
<script src="js/jtalk.js" type="text/javascript"></script>
<script type="text/javascript"> loadJtalk()</script>
</head>
<body>
<button onclick="smalltalk.Browser._open()">Class browser</button>
<div id="counters"></div>
<script type="text/javascript">
jQuery(document).ready(function() {'#counters'._asJQuery()._append_(smalltalk.Counter._new())});
</script>
<%= yield %>
</body>
</html>
[/sourcecode]
Here, we included a button to open the code browser, and added a Counter in a div. Oh, I forgot to tell you: Jtalk works seamlessly with JQuery :)
Now, go check it out, and you will seee the counter and be able to increase and decrease the value displayed (yes, that's a counter).
Editing the code
Click on the "Class browser" button to start the IDE. Select the "Examples" category, the "Counter" class, the "actions" method category, and the "increase method". You will see in the text box below the source code of the increase method:
[sourcecode language="smalltalk"]
increase
count := count + 1.
header contents: [:html | html with: count asString]
[/sourcecode]
Edit that method to increase by steps of 2 instead of 1, and hit "Save". Now, the counter on your page will increase by steps of 2.
Unfortunately, on the next page refresh, you will lose these changes. That's why the "Commit category" button is there.
It will take the updated files (here, Examples.st, Examples.js and Examples.deploy.js) and make a PUT request to their original URL.
A PUT, you said? Well, I can work something out with a PUT.
Saving the code
Let's create a new controller, called Uploader:
[sourcecode language="bash"]
rails generate controller uploader jtalk
[/sourcecode]
And edit config/routes.rb as follows:
[sourcecode language="ruby"]
Jtalkonrails::Application.routes.draw do
root :to => "home#index"
if Rails.env == 'development'
put 'st/:id' => 'uploader#jtalk'
put 'js/:id' => 'uploader#jtalk'
put 'js/:id.:deploy' => 'uploader#jtalk'
end
end
[/sourcecode]
Now the PUT requests are redirected to our controller, but only in the development environment. You do not want to make your JS editable from the browser in a production app. DO NOT WANT!
The only thing left is the controller itself:
[sourcecode language="ruby"]
class UploaderController < ApplicationController
def jtalk
path = Rails.root.join('public')
if(params[:format] == "js")
path = path.join("js")
elsif(params[:format] == "st")
path = path.join("st")
end
if(params[:deploy])
path = path.join(params[:id]+".deploy."+params[:format])
else
path = path.join(params[:id]+"."+params[:format])
end
File.open(path, "w") do |f|
f.write(request.body.read())
end
head 200
end
end
[/sourcecode]
Here, we build the file path from the parameters. I use request.body.read() to get the file content because Rails seems to truncate the beginning of the file.
Profit
Now, go back to the web page, click on "Commit category", and refresh the page. Your changes were saved! You can enjoy editing your frontend directly from the webpage itself, in the code browser, and more importantly, write your whole frontend in Smalltalk! It's still missing the workflow "edit-try-debug-edit-continue", but it already feels just like a "normal" Smalltalk environment. It feels like home :)
Post Scriptum
If you want to add a new category, it's easy: create a file Mycategory.js and put it in public/js, with this content:
[sourcecode language="javascript"]
smalltalk.addClass('Myclass', smalltalk.Object, [], 'Mycategory');
[/sourcecode]
and change your initialization from loadJtalk() to loadJtalk(new Array("Mycategory.js")). The new category will now appear in the code browser, and clicking on "Commit category" will create the deployment file and Smalltalk source file.
My Windows development environment is a bit complex. I work on multiple projects, at multiple versions, with different compiler environments, and with dependencies on different libraries and versions of these libraries.
Now, how do I specify where the compiler must search the libraries, and which version to use? Most of the time, I will add it directly in the project configuration. Easy at first, but quickly,I find myself writing by hand the path to each library (and header) in each project and each configuration of this project. And then, writing by hand the different names of the libraries (mylibrary.lib, mylibraryd.lib, mylibrary-static.lib, mylibrary-MTD.lib, etc).
And when I want to update to a new version of the library? If I'm lucky, I just have to change the library and header paths (in every project using the library). If not, I also have to change the name, because of the library developer's convention.
The first solution to these problems was to use a batch file to launch Visual Studio and MSYS, and set some environment variables in this file. I quickly ended up with one big file containing two environment variables (include path and lib path) per library, possibly more if there were some big changes in the library names. My Visual Studio configuration was cluttered with $(MYLIBRARY_LIBPATH), $(MYLIBRARY_INCLUDEPATH), $(MYLIBRARY_NAME). It is unreadable, and again, impossible to maintain.
My solution comes from the Unix world, where you have a correct organization for your development files:
- one folder containing the subfolders include, bin and lib
- library names including version, and a symlink (without the version number) to the latest version of the lib
Can I do that on Windows? YES \o/
Here is the trick: normal links on Windows won't work, but the mklink tool can create symlinks. And Visual Studio will recognize those as files and folders while looking for libraries.
Now, how would I organize my development environment? I chose to use (and abuse) symlinks, to create include, lib and bin folders for each project and configuration, and use generic names for the libraries.
- I create a folder containing include, lib and bin
- in the include/ folder, I put symlinks to the header file or the subfolder for each library I will use in that project
- in the lib directory, I create symlinks to the library version I want, one symlink per static/dynamic, MT/MD, Debug/Release version. But I could create one lib folder per static/dynamic, etc. A bit complex, but feasible (most of the time, I use only debug and release version, so it's still manageable).
With this setup, I only set the INCLUDE and LIB environment variables, and I use directly the library names I need.
Here is an example script I use to create different library folders for x86 and x64 libs:
[sourcecode language="text"]
echo "Building include and library directories for Windows %PLATFORM%"
@mkdir %PLATFORM%
@mkdir %PLATFORM%\include
@mkdir %PLATFORM%\lib
@mklink /D %PLATFORM%\include\boost %BOOST%\boost
@for %%i in (%BOOST%\lib\*.lib) do (mklink %PLATFORM%\lib\%%~ni.lib %%~fi)
@mklink /D %PLATFORM%\include\cpptest %CPPTEST%\include\cpptest
@for %%i in (%CPPTEST%\lib\*.lib) do (mklink %PLATFORM%\lib\%%~ni.lib %%~fi)
[/sourcecode]
I set up the BOOST and CPPTEST environment variables in another file. Then, I launch Visual Studio from another script which includes it.
There may be better ways, and that system will evolve in the future, but I'm pretty comfortable with it right now :)
Depending on my needs, I may grab from the bottom of my disk the package manager I wrote back in school, and make a big solution to download, build and link libs and personal projects. But later, I have some procrastination planned right now.
In the previous post, I showed how you could build a provider with oauth-plugin and Rails. Now, I will demonstrate how to build a consumer (it's a lot easier).
I will assume that your provider is already running on localhost:3000. The consumer will run on localhost:4000 (run it with "rails server -p 4000").
Here we go!
[sourcecode language="bash"]
rails new consumer
cd consumer
[/sourcecode]
Put this in your Gemfile:
[sourcecode language="ruby"]
source 'http://rubygems.org'
gem 'rails', '3.0.7'
gem 'sqlite3'
gem 'devise'
gem "oauth-plugin", ">= 0.4.0.pre1"
[/sourcecode]
And run these commands:
[sourcecode language="bash"]
bundle install
rails generate devise:install
rails generate devise User
rake db:migrate
rails generate controller welcome index
rm public/index.html
[/sourcecode]
And here is your routes.rb:
[sourcecode language="ruby"]
Provider::Application.routes.draw do
devise_for :users
root :to => "welcome#index"
end
[/sourcecode]
Create the consumer
[sourcecode language="bash"]
rails generate oauth_consumer user
rake db:migrate
[/sourcecode]
in app/controllers/oauth_consumers_controller.rb, replace:
[sourcecode language="ruby"]
before_filter :login_required, :only=>:index
[/sourcecode]
by
[sourcecode language="ruby"]
before_filter :authenticate_user!, :only=>:index
[/sourcecode]
Uncomment the methods for devise (go_back, logged_in? currentuser=, deny_access!) in app/controllers/oauth_consumers_controller.rb.
Add to app/models/user.rb:
[sourcecode language="ruby"]
has_one :test, :class_name=>"TestToken", :dependent=>:destroy
[/sourcecode]
Now go to http://localhost:3000/oauth_clients/ to register your first application with these parameters:
Name: Test consumer
Main Application URL: http://localhost:4000/
Callback URL: http://localhost:4000/oauth_consumers/test/callback
You're redirected to http://localhost:3000/oauth_clients/1. It shows:
Consumer Key: CRcIJ15MwSqlDTxsH8MpO3En4wjaOxkqeofLioH4
Consumer Secret: C7uci8xkyMShCf4SNXWPclKbBo3ml1Zf2W2XWu4W
Request Token URL: http://localhost:3000/oauth/request_token
Access Token URL: http://localhost:3000/oauth/access_token
Authorize URL: http://localhost:3000/oauth/authorize
Now, you need to put the key and secret in config/initializers/oauth_consumers.rb:
[sourcecode language="ruby"]
OAUTH_CREDENTIALS={
:test =>{
:key => "CRcIJ15MwSqlDTxsH8MpO3En4wjaOxkqeofLioH4",
:secret => "C7uci8xkyMShCf4SNXWPclKbBo3ml1Zf2W2XWu4W",
:expose => true
}
}
[/sourcecode]
Create app/models/test_token.rb. This model will store the token for your provider. If you want to provide helpful methods, take inspiration from lib/oauth/models/consumers/services/.
[sourcecode language="ruby"]
class TestToken < ConsumerToken
TEST_SETTINGS={
:site => "http://localhost:3000",
:request_token_path => "/oauth/request_token",
:access_token_path => "/oauth/access_token",
:authorize_path => "/oauth/authorize"
}
def self.consumer(options={})
@consumer ||= OAuth::Consumer.new(credentials[:key], credentials[:secret], TEST_SETTINGS.merge(options))
end
end
[/sourcecode]
You should now be able to use the URLs "/oauth_consumers/test/client/", "/oauth_consumers/test/callback", "/oauth_consumers/test/callback2"," /oauth_consumers/test/edit",
and "/oauth_consumers/test".
Modify the welcome controller t get the provider data:
[sourcecode language="ruby"]
class WelcomeController < ApplicationController
def index
# cf http://oauth.rubyforge.org/rdoc/classes/OAuth/AccessToken.html
@consumer_tokens=TestToken.all :conditions=>{:user_id=>current_user.id}
@token = @consumer_tokens.first.client
logger.info "private data: "+@token.get("/data/index").body
end
end
[/sourcecode]
To connect a user to an external service link or redirect them to:
/oauth_consumers/[SERVICE_NAME]
Where SERVICE_NAME is the name you set in the OAUTH_CREDENTIALS hash. This will request the request token and redirect the user to the services authorization screen. When the user accepts the get redirected back to:
/oauth_consumers/[SERVICE_NAME]/callback
That's it
This tutorial is really short, and could be explained a bit more, but I'll leave that for another post. You have enough to start tinkering with OAuth. Have fun!
These days, I have been playing a lot with Oauth and its RoR implementation, oauth-plugin. Its documentation is a bit short, so here is a tutorial to show how to use it, both in provider and consumer mode. And we will even make them communicate with each other.
We will now build an Oauth provider using oauth-plugin for authorization and Devise for authentication. And we will add a controller protected by Oauth.
Starting up
A few instructions to create the application. You won't need an explanation for this:
[sourcecode language="bash"]
rails new provider
cd provider
[/sourcecode]
Put this in your Gemfile:
[sourcecode language="ruby"]
source 'http://rubygems.org'
gem 'rails', '3.0.7'
gem 'sqlite3'
gem 'devise'
gem "oauth-plugin", ">= 0.4.0.pre1"
[/sourcecode]
And a few more commands:
[sourcecode language="bash"]
bundle install
rails generate devise:install
rails generate devise User
rake db:migrate
rails generate controller welcome index
rm public/index.html
[/sourcecode]
And don't forget 'root :to => "welcome#index"' in config/routes.rb.
Create the provider
[sourcecode language="bash"]
rails generate oauth_provider oauth
rake db:migrate
[/sourcecode]
You could put something else than "oauth" as parameter, but for the moment, the generator has some bugs (it always generate the class OauthController, but with a different name). I'll check more recent versions of the code.
Now, modify config/application.rb and add:
[sourcecode language="ruby"]
require 'oauth/rack/oauth_filter'
config.middleware.use OAuth::Rack::OAuthFilter
[/sourcecode]
Put in app/models/user.rb:
[sourcecode language="ruby"]
has_many :client_applications
has_many :tokens, :class_name=>"OauthToken",:order=>"authorized_at desc",:include=>[:client_application]
[/sourcecode]
Put in app/controllers/oauth_controller.rb:
[sourcecode language="ruby"]
alias :logged_in? :user_signed_in?
alias :login_required :authenticate_user!
[/sourcecode]
and uncomment authenticate_user.
Put in app/controllers/oauth_clients_controller.rb:
[sourcecode language="ruby"]
alias :login_required :authenticate_user!
[/sourcecode]
And now some data
Create a new controller:
[sourcecode language="bash"]
rails generate controller data index
[/sourcecode]
And now, edit your controller:
[sourcecode language="ruby"]
class DataController < ApplicationController
before_filter :oauth_required
def index
@data = { "coincoin" => "o< o<" }
respond_to do |format|
format.json { render :json => @data }
end
end
end
[/sourcecode]
UPDATE
I discovered a few bugs in this tutorial, so here are the fixes.
oauth-plugin needs the function current_user=, so add this to your ApplicationController:
[sourcecode language="ruby"]
def current_user=(user)
current_user = user
end
[/sourcecode]
Next, to handle revocation, you need to add this to config/routes.rb:
[sourcecode language="ruby"]
post 'oauth/revoke'
[/sourcecode]
And at last, you need to fix the rack filter. The current code doesn't verify the token validity, and lets revoked tokens access your data.
You have to modify lib/oauth/rack/oauth_filter.rb in the oauth-plugin gem folder.
Replace the line 46:
[sourcecode language="ruby"]
oauth_token = client_application.tokens.first(:conditions=>{:token => request_proxy.token})
[/sourcecode]
by
[sourcecode language="ruby"]
oauth_token = ClientApplication.find_token(request_proxy.token)
[/sourcecode]
And that's it!
You now have a working provider. OauthController handles all the communication with the consumers. OauthClientsController manages the registration of new consumers. They both have customizable views: oauth for the authorization part (for users) and oauth clients for the consumers. And you just need the oauth_required filter to manage access to your data.
And now, you can go to /users/sign_up, then /users/sign_in, then /oauth_clients to register a new client application. You just need to give a name for your application, your URL, and a callback URL.
In the next post, we will build a consumer, and this consumer will access the provider's data.