diff options
author | Heiko Bernloehr <Heiko.Bernloehr@FreeIT.de> | 2012-11-14 22:49:41 +0100 |
---|---|---|
committer | Heiko Bernloehr <Heiko.Bernloehr@FreeIT.de> | 2012-11-14 23:08:26 +0100 |
commit | 9298117acdf82c9529a12a3ab41baf9d1e86c2f4 (patch) | |
tree | 0bbd1e0513c8e8a57cb841ae83e3e99b7e874e86 | |
parent | c07fcb616e0db81472889488189dc2f440020ef6 (diff) | |
download | ecs2-9298117acdf82c9529a12a3ab41baf9d1e86c2f4.tar.gz ecs2-9298117acdf82c9529a12a3ab41baf9d1e86c2f4.zip |
Introduced security fix for redirects.
Now redirects are integrity secured by sha1 message digest.
A redirecting participant uses the /sys/auths resource realm
attribute to store a message digest over all relevant
redirect parameters (for details see [1]). The target
participant uses this message digest again and verifies the
integrity of the received redirect parameters
(Location-Header).
[1] see ECSA documentation at ECS->System resources->Auths
-rw-r--r-- | app/controllers/application_controller.rb | 7 | ||||
-rw-r--r-- | app/models/message.rb | 22 | ||||
-rw-r--r-- | db/migrate/20100922104919_rename_touch_from_ressource_monitors.rb | 27 | ||||
-rw-r--r-- | test/fixtures/ressources.yml | 5 | ||||
-rw-r--r-- | test/functional/messages_controller_test.rb | 146 | ||||
-rw-r--r-- | test/unit/message_test.rb | 41 |
6 files changed, 203 insertions, 45 deletions
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index b098493..ab65daa 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -116,26 +116,31 @@ protected # error pages def rescue_body_401 + @http_error= $! logger.error $!.to_s render :text => "#{$!.to_s}\n", :layout => false, :status => 401 end def rescue_body_500 + @http_error= $! logger.error $!.to_s render :text => "#{$!.to_s}\n", :layout => false, :status => 500 end def rescue_body_400 + @http_error= $! logger.error $!.to_s render :text => "#{$!.to_s}\n" , :layout => false, :status => 400 end def rescue_body_403 + @http_error= $! logger.error $!.to_s render :text => "#{$!.to_s}\n" , :layout => false, :status => 403 end def rescue_body_404 + @http_error= $! logger.error $!.to_s if $!.to_s.blank? render :text => "The server does not know the ressource\nor the message queue in question is empty.\n" , :layout => false, :status => 404 @@ -145,11 +150,13 @@ protected end def rescue_body_409 + @http_error= $! logger.error $!.to_s render :text => "#{$!.to_s}\n" , :layout => false, :status => 409 end def rescue_body_415(controller_binding) + @http_error= $! logger.error $!.to_s if $!.to_s.blank? render :text => "The format of the client data is not supported by the server.\nIf your format is right please doublecheck the encoding !\nIt has to be UTF8 !\n", :layout => false, :status => 415 diff --git a/app/models/message.rb b/app/models/message.rb index 4a89778..69067d0 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -200,7 +200,8 @@ class Message < ActiveRecord::Base # Preprocess request body if it's a /sys/auths resource. # Generate a one touch token (hash) def post_create_auths_resource(participant) - ttl = 60.seconds + ttl_min = 5.seconds + ttl = ttl_min + 60.seconds unless Mime::Type.lookup(self.content_type).to_sym == :json raise Ecs::InvalidMimetypeException, "Body format has to be in JSON" end @@ -210,9 +211,17 @@ class Message < ActiveRecord::Base raise Ecs::InvalidMessageException, "Invalid JSON body" end bks = b.keys - unless bks.include?("url") - raise Ecs::InvalidMessageException, "Missing url key" + + # NOTE Assures that there are at least url or realm set -> backward compatibility + unless bks.include?("url") or bks.include?("realm") + raise Ecs::InvalidMessageException, "You have to provide realm or url attribute" + end + if bks.include?("realm") and !b["realm"].empty? and !bks.include?("url") + b["url"]= b["realm"] + elsif bks.include?("url") and !b["url"].empty? and !bks.include?("realm") + b["realm"]= b["url"] end + #msg_id = URI.split(b["url"])[5][1..-1].sub(/[^\/]*\/[^\/]*\/(.*)/, '\1').to_i #begin # Message.find(msg_id) @@ -224,10 +233,13 @@ class Message < ActiveRecord::Base b["sov"] = Time.now.xmlschema b["eov"] = (Time.now + ttl).xmlschema when (bks.include?("sov") and !bks.include?("eov")) + if Time.parse(b["sov"]) < Time.now + raise Ecs::InvalidMessageException, 'sov time is younger then current time' + end b["eov"] = (Time.parse(b["sov"]) + ttl).xmlschema when (!bks.include?("sov") and bks.include?("eov")) - if Time.parse(b["eov"]) < Time.now - raise Ecs::InvalidMessageException, 'eov time is younger then current time' + if Time.parse(b["eov"]) < (Time.now + ttl_min) + raise Ecs::InvalidMessageException, 'eov time is too young' end b["sov"] = Time.now.xmlschema when (bks.include?("sov") and bks.include?("eov")) diff --git a/db/migrate/20100922104919_rename_touch_from_ressource_monitors.rb b/db/migrate/20100922104919_rename_touch_from_ressource_monitors.rb deleted file mode 100644 index 829eea7..0000000 --- a/db/migrate/20100922104919_rename_touch_from_ressource_monitors.rb +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright (C) 2007, 2008, 2009, 2010 Heiko Bernloehr (FreeIT.de). -# -# This file is part of ECS. -# -# ECS is free software: you can redistribute it and/or modify it -# under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of -# the License, or (at your option) any later version. -# -# ECS is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public -# License along with ECS. If not, see <http://www.gnu.org/licenses/>. - - -class RenameTouchFromRessourceMonitors < ActiveRecord::Migration - def self.up - rename_column :ressource_monitors, :touch, :monitor_counter - end - - def self.down - raise ActiveRecord::IrreversibleMigration - end -end diff --git a/test/fixtures/ressources.yml b/test/fixtures/ressources.yml index d66f17a..f3869d1 100644 --- a/test/fixtures/ressources.yml +++ b/test/fixtures/ressources.yml @@ -42,3 +42,8 @@ cc_course: postroute: false events: true +sys_auths: + namespace: sys + ressource: auths + postroute: false + events: false diff --git a/test/functional/messages_controller_test.rb b/test/functional/messages_controller_test.rb index af6293b..2522617 100644 --- a/test/functional/messages_controller_test.rb +++ b/test/functional/messages_controller_test.rb @@ -85,9 +85,9 @@ class MessagesControllerTest < ActionController::TestCase @request.env["CONTENT_TYPE"] = "text/html" @request.env["X-EcsAuthId"] = identities(:stgt_id1).name @request.env["X-EcsReceiverCommunities"] = communities(:suv).name + @request.set_REQUEST_URI("/numlab/exercises") mm_count = MembershipMessage.all.count post :create - assert_response 201 assert_equal assigns(:record).sender, assigns(:participant).id assert_equal mm_count+1, MembershipMessage.all.count @@ -98,6 +98,7 @@ class MessagesControllerTest < ActionController::TestCase @request.env["CONTENT_TYPE"] = "text/html" @request.env["X-EcsAuthId"] = identities(:stgt_id1).name @request.env["X-EcsReceiverCommunities"] = communities(:suv).name + "," + communities(:public).name + @request.set_REQUEST_URI("/numlab/exercises") mm_count = MembershipMessage.all.count post :create assert_response 201 @@ -110,6 +111,7 @@ class MessagesControllerTest < ActionController::TestCase @request.env["CONTENT_TYPE"] = "text/html" @request.env["X-EcsAuthId"] = identities(:stgt_id1).name @request.env["X-EcsReceiverCommunities"] = communities(:suv).name + "," + communities(:public).id.to_s + @request.set_REQUEST_URI("/numlab/exercises") mm_count = MembershipMessage.all.count post :create assert_response 201 @@ -121,6 +123,7 @@ class MessagesControllerTest < ActionController::TestCase @request.env["RAW_POST_DATA"] = "hallole" @request.env["X-EcsAuthId"] = identities(:stgt_id1).name @request.env["X-EcsReceiverMemberships"] = memberships(:ulm_wuv).id.to_s + @request.set_REQUEST_URI("/numlab/exercises") post :create assert_response 400 end @@ -129,6 +132,7 @@ class MessagesControllerTest < ActionController::TestCase @request.env["CONTENT_TYPE"] = "text/html" @request.env["X-EcsAuthId"] = identities(:stgt_id1).name @request.env["X-EcsReceiverMemberships"] = memberships(:ulm_wuv).id.to_s + @request.set_REQUEST_URI("/numlab/exercises") post :create assert_response 400 end @@ -302,18 +306,138 @@ class MessagesControllerTest < ActionController::TestCase assert_equal "Hallo Ihr da im Radio.", @response.body.strip end +# Auths tests +# + + test "create_auths" do + @request.env["RAW_POST_DATA"] = <<-'HERE' + { + "url":"https://ilias.uni-stuttgart.de/goto.php?target=crs_95034&client_id=USTGT", + "realm":"https://ilias.uni-stuttgart.de/goto.php?target=crs_95034&client_id=USTGT" + } + HERE + @request.env["CONTENT_TYPE"] = "application/json" + @request.env["X-EcsAuthId"] = identities(:stgt_id1).name + @request.env["X-EcsReceiverMemberships"] = memberships(:ulm_wuv).id.to_s + @request.set_REQUEST_URI("/sys/auths") + mm_count = MembershipMessage.all.count + post :create + assert_response 201 + end + + test "create_auths_url" do + @request.env["RAW_POST_DATA"] = <<-'HERE' + { + "url":"https://ilias.uni-stuttgart.de/goto.php?target=crs_95034&client_id=USTGT" + } + HERE + @request.env["CONTENT_TYPE"] = "application/json" + @request.env["X-EcsAuthId"] = identities(:stgt_id1).name + @request.env["X-EcsReceiverMemberships"] = memberships(:ulm_wuv).id.to_s + @request.set_REQUEST_URI("/sys/auths") + mm_count = MembershipMessage.all.count + post :create + assert_response 201 + end + + test "create_auths_realm" do + @request.env["RAW_POST_DATA"] = <<-'HERE' + { + "realm":"https://ilias.uni-stuttgart.de/goto.php?target=crs_95034&client_id=USTGT" + } + HERE + @request.env["CONTENT_TYPE"] = "application/json" + @request.env["X-EcsAuthId"] = identities(:stgt_id1).name + @request.env["X-EcsReceiverMemberships"] = memberships(:ulm_wuv).id.to_s + @request.set_REQUEST_URI("/sys/auths") + mm_count = MembershipMessage.all.count + post :create + assert_response 201 + end + + test "create_auths_invalid_json_mimetype" do + @request.env["RAW_POST_DATA"] = <<-'HERE' + { + "realm":"https://ilias.uni-stuttgart.de/goto.php?target=crs_95034&client_id=USTGT" + } + HERE + @request.env["CONTENT_TYPE"] = "text/html" + @request.env["X-EcsAuthId"] = identities(:stgt_id1).name + @request.env["X-EcsReceiverMemberships"] = memberships(:ulm_wuv).id.to_s + @request.set_REQUEST_URI("/sys/auths") + mm_count = MembershipMessage.all.count + post :create + assert_response 415 + assert_equal "Body format has to be in JSON", assigns(:http_error).to_s + end + + test "create_auths_invalid_json_body" do + @request.env["RAW_POST_DATA"] = <<-'HERE' + { + "realm"::"https://ilias.uni-stuttgart.de/goto.php?target=crs_95034&client_id=USTGT" + } + HERE + @request.env["CONTENT_TYPE"] = "application/json" + @request.env["X-EcsAuthId"] = identities(:stgt_id1).name + @request.env["X-EcsReceiverMemberships"] = memberships(:ulm_wuv).id.to_s + @request.set_REQUEST_URI("/sys/auths") + mm_count = MembershipMessage.all.count + post :create + assert_response 400 + assert_equal "Invalid JSON body", assigns(:http_error).to_s + end + + test "create_auths_eov_younger_than_sov" do + @request.env["RAW_POST_DATA"] = <<-'HERE' + { + "realm":"https://ilias.uni-stuttgart.de/goto.php?target=crs_95034&client_id=USTGT", + "sov": "2011-03-08T23:25:27+01:00", + "eov": "2011-03-08T23:25:17+01:00" + } + HERE + @request.env["CONTENT_TYPE"] = "application/json" + @request.env["X-EcsAuthId"] = identities(:stgt_id1).name + @request.env["X-EcsReceiverMemberships"] = memberships(:ulm_wuv).id.to_s + @request.set_REQUEST_URI("/sys/auths") + mm_count = MembershipMessage.all.count + post :create + assert_response 400 + assert_equal "invalid times either in sov or eov", assigns(:http_error).to_s + end -# test "create_auths" do -# @request.env["RAW_POST_DATA"] = '{"url":"http://freeit.de/course1"}' -# @request.env["CONTENT_TYPE"] = "application/json" -# @request.env["X-EcsAuthId"] = identities(:stgt_id1).name -# @request.env["X-EcsReceiverMemberships"] = memberships(:ulm_wuv).id.to_s -# @request.set_REQUEST_URI("/sys/auths") -# mm_count = MembershipMessage.all.count -# post :create -# assert_response 201 -# end + test "create_auths_sov_younger_than_current_time" do + @request.env["RAW_POST_DATA"] = <<-'HERE' + { + "realm":"https://ilias.uni-stuttgart.de/goto.php?target=crs_95034&client_id=USTGT", + "sov": "2011-03-08T23:25:27+01:00" + } + HERE + @request.env["CONTENT_TYPE"] = "application/json" + @request.env["X-EcsAuthId"] = identities(:stgt_id1).name + @request.env["X-EcsReceiverMemberships"] = memberships(:ulm_wuv).id.to_s + @request.set_REQUEST_URI("/sys/auths") + mm_count = MembershipMessage.all.count + post :create + assert_response 400 + assert_equal "sov time is younger then current time", assigns(:http_error).to_s + end + test "create_auths_eov_too_young" do + @request.env["RAW_POST_DATA"] = <<-"HERE" + { + "realm":"https://ilias.uni-stuttgart.de/goto.php?target=crs_95034&client_id=USTGT", + "eov": "#{(Time.now + 1.second).xmlschema}" + } + HERE + @request.env["CONTENT_TYPE"] = "application/json" + @request.env["X-EcsAuthId"] = identities(:stgt_id1).name + @request.env["X-EcsReceiverMemberships"] = memberships(:ulm_wuv).id.to_s + @request.set_REQUEST_URI("/sys/auths") + mm_count = MembershipMessage.all.count + post :create + assert_response 400 + assert_equal "eov time is too young", assigns(:http_error).to_s + end # anonymous clients # diff --git a/test/unit/message_test.rb b/test/unit/message_test.rb index f1ca8d2..fbe0b21 100644 --- a/test/unit/message_test.rb +++ b/test/unit/message_test.rb @@ -59,6 +59,43 @@ class MessageTest < ActiveSupport::TestCase # number of receivers have to be two assert_equal 2, Participant.for_message(messages(:numlab_ex1)).uniq.length end -end - +# Auths +# + test "create_auths" do + headers={ + "X-EcsReceiverMemberships" => "7,2", + "CONTENT_TYPE" => "application/json" + } + raw_post= Hash.new + raw_post[:realm]= <<-'HERE' + { + "realm":"https://ilias.uni-stuttgart.de/goto.php?target=crs_95034&client_id=USTGT" + } + HERE + raw_post[:url]= <<-'HERE' + { + "url":"https://ilias.uni-stuttgart.de/goto.php?target=crs_95034&client_id=USTGT" + } + HERE + raw_post.each do |k,v| + request= TestRequest.new(headers, v) + msg= nil + assert_nothing_raised do + msg= Message.create__(request, "sys", "auths", participants(:ilias_stgt)) + end + assert Mime::Type.lookup(msg.content_type)== :json, "Content-Type is not application/json" + assert_equal participants(:ilias_stgt).id, msg.sender, "Unexpected creator of the message" + json= nil + assert_nothing_raised do + json= ActiveSupport::JSON.decode(msg.body) + end + assert json.keys.include?(k.to_s) + assert_equal "https://ilias.uni-stuttgart.de/goto.php?target=crs_95034&client_id=USTGT", json[k.to_s] + assert json.keys.include?(k.to_s) + assert_equal "https://ilias.uni-stuttgart.de/goto.php?target=crs_95034&client_id=USTGT", json[k.to_s] + assert json.keys.include?("pid") + assert_equal participants(:ilias_stgt).id, json["pid"] + end + end +end |