saml_camel 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9587f9aa4978c5bfc1ff83fd93490b77cfada4a0
4
- data.tar.gz: d005f8ba385cd0443baeda86c668d002c7907857
3
+ metadata.gz: 60103dee96fb0b95caeb04551deac81568e5149a
4
+ data.tar.gz: eb15b9fc8c642e88bf0ff8be268f206de1be3b73
5
5
  SHA512:
6
- metadata.gz: 012d8b91632f47e689f385cb1de8f82e7e99696579e11491ce94e54de0823f0b56f727bd25b5e748cc1c288db6debaf57f2aa5df3d7b83a3ffdc1a20514b779a
7
- data.tar.gz: de3c6af5a1395e1a44502b9f85101f8e42d238362443ff7826037ec96d783712329ae028370365b2b514f4f338287e04247a3e906ae1b0dd04ac0e4bb8e2817e
6
+ metadata.gz: acda10e48b2cabdb24f187ffaf3fde6dbb5992efe032f56ca623098999b754c9094fe94271cbeac50097f00679a87710db95ebe96be7a22b0904607a7b62c165
7
+ data.tar.gz: 8ea077c92e5d0fcf0df9bcae2d086a5635152ceb3d37afbc7a0e7e4777a3d9dda32b651280d9bc54f12ecdf4f859c640c658e68ff972521d0473e25f9d465233
data/README.md CHANGED
@@ -14,6 +14,13 @@ $ bundle
14
14
 
15
15
 
16
16
  ## Usage
17
+ ### IMPORTANT!
18
+ 1. in your environments config (`config/development.rb` for example) ensure that you have caching configured as follows
19
+ ```ruby
20
+ config.action_controller.perform_caching = true
21
+ config.cache_store = :memory_store
22
+ ```
23
+
17
24
  1. run `rake saml_camel:generate_saml` to generate metadata files for each environment. you can also specify a specifc/custom environment like this `rake saml_camel:generate_saml environment=acceptance`
18
25
 
19
26
  **Note: these steps will use development as an example, if you use seperate metadata per environemtn, you will repeat each step for your chosed environement**
@@ -57,7 +64,7 @@ end
57
64
  ```
58
65
 
59
66
 
60
- 7. to logout simply make a post to `localhost:3000/saml/logout`. This will kill the local saml session, and the session with the identity provider. You can specify a return url in `saml/development/settings.json`
67
+ 7. to logout simply make a post to `localhost:3000/saml/logout`. This will kill the local saml session, and the session with the identity provider.
61
68
 
62
69
  7. response attributes found in `session[:saml_attributes]`
63
70
 
@@ -8,39 +8,48 @@ module SamlCamel::SamlHelpers
8
8
  #this generates a call to the idp, which will then be returned to the consume action the in saml_contorller
9
9
  def saml_request(host_request)
10
10
  relay_state = SecureRandom.base64.chomp.gsub( /\n/, '' ) #set relay state to secure against replay attack
11
- session[:relay_state] = relay_state
12
11
  request = OneLogin::RubySaml::Authrequest.new
13
12
 
14
- secure_cookie = (Rails.env == "development" || Rails.env == "test") ? false : true
15
- cookies.encrypted[:saml_camel_redirect] = {
16
- value: host_request.url,
17
- secure: secure_cookie,
18
- httponly: true
19
- }
20
-
21
- cookies.encrypted[:saml_camel_relay] = {
22
- value: relay_state,
23
- secure: secure_cookie,
24
- httponly: true
25
- }
26
-
27
- saml_request = request.create(SamlCamel::Transaction.saml_settings) + "&RelayState=#{relay_state}"
28
- redirect_to(saml_request)
13
+ #store relay state, ip address and original url request in memory to be used for verification and redirect after response
14
+ permit_key = session[:session_id].to_sym
15
+ Rails.cache.fetch(permit_key, expires_in: 5.minutes) do
16
+ {ip_address: host_request.remote_ip, relay_state: relay_state, redirect_url: host_request.url }
17
+ end
18
+ saml_request_url = request.create(SamlCamel::Transaction.saml_settings) + "&RelayState=#{Rails.cache.fetch(permit_key)[:relay_state]}"
19
+ redirect_to(saml_request_url)
29
20
  end
30
21
 
31
22
 
32
- def valid_relay_state(param_relay_state)
33
- stored_relay = cookies.encrypted[:saml_camel_relay]
34
- cookies.delete :saml_camel_relay
35
- param_relay_state == stored_relay
23
+ #validates the user ip address and relay state given to IDP. Prevents Replay Attacks.
24
+ def valid_state(param_relay_state, remote_ip)
25
+ permit_key = session[:session_id].to_sym
26
+ saml_cache = Rails.cache.fetch(permit_key)
27
+ stored_relay = saml_cache[:relay_state]
28
+ stored_ip = saml_cache[:ip_address]
29
+
30
+ SamlCamel::Logging.saml_state({stored_relay: stored_relay, request_relay: param_relay_state, stored_ip: stored_ip, remote_ip: remote_ip})
31
+ param_relay_state == stored_relay && remote_ip == stored_ip
36
32
  end
37
33
 
38
34
 
39
- def saml_protect
40
- saml_request(request) unless (session[:saml_success] || session[:sp_session]) #keeps us from looping, and maintains sp session
41
- session[:saml_success] = nil
35
+ #Make it so sp sessions only last 1 hour, sp_session is set on a succesfull saml response.
36
+ #We check that the session time is less than in hour if so we refresh, otherwise we delete the session
37
+ def expired_session?
38
+ if session[:sp_session]
39
+ if (Time.now - Time.parse(session[:sp_session])) < 1.hour
40
+ session[:sp_session] = Time.now
41
+ return true
42
+ end
43
+ end
42
44
  end
43
45
 
44
46
 
47
+ #saml_protect is what is called in the app. it initiates the saml request if there is no active session, or if a user has been idle for over an hour
48
+ #TODO re-factor in future
49
+ def saml_protect
50
+ not_expired = expired_session?
51
+ saml_request(request) unless (session[:saml_success] || session[:sp_session] || not_expired) #keeps us from looping, and maintains sp session
52
+ session[:saml_success] = nil
53
+ end
45
54
 
46
55
  end
@@ -7,30 +7,34 @@ module SamlCamel
7
7
  before_action :saml_protect, only: [:attr_check]
8
8
 
9
9
 
10
- #TODO ROUTABLE STUFF GOES IN THE SHIB CONTROLLER, METHODS CALLED BUT NOT ROUTED GO TO SAML_CONTROLLER
10
+ #convinence route to see attributes that are coming through
11
11
  def index
12
12
  @attributes = session[:saml_attributes]
13
13
  end
14
14
 
15
- def consume
16
- raise "Invalid RelayState" unless valid_relay_state(params[:RelayState])
17
- redirect_path = cookies.encrypted[:saml_camel_redirect]
18
15
 
19
- cookies.delete :saml_camel_redirect
16
+ #consumes the saml response from the IDP
17
+ def consume
18
+ raise "Invalid RelayState" unless valid_state(params[:RelayState], request.remote_ip)
19
+ permit_key = session[:session_id].to_sym
20
+ redirect_path = Rails.cache.fetch(permit_key)[:redirect_url]
21
+ Rails.cache.delete(permit_key) #we no longer need cache at this stage
20
22
  response = OneLogin::RubySaml::Response.new(params[:SAMLResponse], :settings => saml_settings)
21
23
  response.settings = saml_settings
22
-
23
24
  if response.is_valid? # validate the SAML Response
24
25
  # authorize_success, log the user
25
26
  session[:saml_success] = true
26
- session[:sp_session] = true
27
+ session[:sp_session] = Time.now
28
+
27
29
  session[:saml_attributes] = SamlCamel::Transaction.map_attributes(response.attributes)
28
30
  SamlCamel::Logging.successfull_auth(session[:saml_attributes])
29
31
 
30
32
  #TODO account for nil redirect
31
33
  redirect_to redirect_path
32
34
  else # otherwise list out the errors in the response
33
- #TODO how do we handle errors?
35
+ permit_key = session[:session_id].to_sym
36
+ Rails.cache.delete(permit_key)
37
+
34
38
  session[:saml_success] = false
35
39
  response.errors
36
40
  SamlCamel::Logging.auth_failure(response.errors)
@@ -38,25 +42,33 @@ module SamlCamel
38
42
  redirect_to main_app.try('root_path')
39
43
  end
40
44
  rescue => e
45
+ permit_key = session[:session_id].to_sym
46
+ Rails.cache.delete(permit_key)
41
47
  session[:saml_success] = false
48
+
42
49
  SamlCamel::Logging.auth_failure(e)
43
50
  redirect_to action: "failure", locals:{errors: e}
44
51
  end
45
52
 
53
+
54
+ #route to show saml failures
46
55
  def failure
47
56
  @error = params[:locals][:errors]
48
- # byebug
49
57
  end
50
58
 
59
+
60
+ #kills SP session and redirects to IDP to kill idp session
51
61
  def logout
52
62
  SamlCamel::Logging.logout(session[:saml_attributes])
53
63
  session[:saml_attributes] = nil
54
64
  session[:sp_session] = nil
65
+ cookies.delete :saml_camel_timestamp
55
66
 
56
67
  # return_url = SamlCamel::Transaction.logout #this methods logs the user out of the IDP, and returns a url to be redirected to
57
68
  redirect_to "https://shib.oit.duke.edu/cgi-bin/logout.pl"
58
69
  end
59
70
 
71
+
60
72
  def attr_check
61
73
  end
62
74
 
@@ -25,5 +25,12 @@ module SamlCamel
25
25
  logger.debug("Unknown error logging user logout. Most likely anonymous user clicked a logout button.")
26
26
  end
27
27
 
28
+ def self.saml_state(data)
29
+ logger = Logger.new("log/saml.log")
30
+ logger.info("Stored Relay: #{data[:stored_relay]} | RequestRelay: #{data[:request_relay]} | Stored IP: #{data[:stored_ip]} RemoteIP: #{data[:remote_ip]}")
31
+ rescue
32
+ logger.debug("Unknown Error During relay state logging.")
33
+ end
34
+
28
35
  end
29
36
  end
data/config/routes.rb CHANGED
@@ -5,3 +5,5 @@ SamlCamel::Engine.routes.draw do
5
5
  post "/consumeSaml" => "saml#consume"
6
6
  post "/logout" => "saml#logout"
7
7
  end
8
+ #TODO check ip_address stored by the IDP
9
+ #TODO chceck ip address on every check ra
@@ -1,3 +1,3 @@
1
1
  module SamlCamel
2
- VERSION = '0.1.4'
2
+ VERSION = '0.1.5'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: saml_camel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - 'Danai Adkisson '
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-10 00:00:00.000000000 Z
11
+ date: 2018-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails