Class: Orange::Middleware::AccessControl

Inherits:
Base
  • Object
show all
Defined in:
lib/orange-more/administration/middleware/access_control.rb

Overview

This middleware locks down entire contexts and puts them behind an openid login system. Currently only supports a single user id.

Instance Method Summary collapse

Instance Method Details

#access_allowed?(packet) ⇒ Boolean

Returns:

  • (Boolean)


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/orange-more/administration/middleware/access_control.rb', line 58

def access_allowed?(packet)
  return true unless @locked.include?(packet['route.context'])
  if packet['user.id'] || orange.options['main_user'].blank?
    if @single 
      return true if(main_user?(packet))
      # Current id no good. 
      packet['user.id'] = nil
      packet.session['user.id'] = nil
      return false
    # Main_user can always log in (root access)
    elsif main_user?(packet)
      orange[:users].new(packet, :open_id => packet['user.id'], :name => 'Main User') unless packet['user', false]
      return true
    else
      return orange[:users].access_allowed?(packet, packet['user.id'])
    end
  else
    return false
  end
end

#handle_openid(packet) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/orange-more/administration/middleware/access_control.rb', line 95

def handle_openid(packet)
  if packet.request.path.gsub(/\/$/, '') == @logout
    packet.session['user.id'] = nil
    packet['user.id'] = nil
    after = packet.flash('user.after_login') || '/'
    packet.reroute(after)
    return false
  end
  packet.reroute('/') if packet['user.id'] # Reroute to index if we're logged in.
  
  # If login set
  if packet.request.post?
    packet['template.disable'] = true
    # Check for openid response
    if resp = packet.env["rack.openid.response"]
      if resp.status == :success
        packet['user.id'] = resp.identity_url
        
        packet['user.openid.url'] = resp.identity_url
        packet['user.openid.response'] = resp
        # Load in any registration data gathered
        profile_data = {}
        # merge the SReg data and the AX data into a single hash of profile data
        [ OpenID::SReg::Response, OpenID::AX::FetchResponse ].each do |data_response|
          if data_response.from_success_response( resp )
            profile_data.merge! data_response.from_success_response( resp ).data
          end
        end
        packet.session['openid.profile'] = profile_data
        packet['openid.profile'] = profile_data
        if packet['user.id'] =~ /^https?:\/\/(www.)?google.com\/accounts/
          packet['user.id'] = profile_data["http://axschema.org/contact/email"]
          packet['user.id'] = packet['user.id'].first if packet['user.id'].kind_of?(Array)
        end
        
        if packet['user.id'] =~ /^https?:\/\/(www.)?yahoo.com/ || packet['user.id'] =~ /^https?:\/\/(my\.|me\.)?yahoo.com/
          packet['user.id'] = profile_data["http://axschema.org/contact/email"]
          packet['user.id'] = packet['user.id'].first if packet['user.id'].kind_of?(Array)
        end
        
        
        after = packet.flash('user.after_login') || '/'
        
        # Save id into session if we have one.
        packet.session['user.id'] = packet['user.id']
        
        # If the user was supposed to be going somewhere, redirect there
        packet.reroute(after)
        false
      else
        packet.flash['error'] = resp.status
        packet.reroute(@login)
        false
      end
    # Set WWW-Authenticate header if awaiting openid.response
    else
      packet[:status] = 401
      packet[:headers] = {}
      id = packet.request.params["openid_identifier"]
      id = "http://#{id}" unless id =~ /^https?:\/\//
      packet.add_header('WWW-Authenticate', Rack::OpenID.build_header(
            :identifier => id,
            :required => [:email, "http://axschema.org/contact/email"]
            ) 
      )
      packet[:content] = 'Got openID?'          
      return packet.finish
    end
  # Show login form, if necessary
  else
    packet[:content] = orange[:parser].haml('openid_login.haml', packet)
    return packet.finish
  end
end

#init(opts = {}) ⇒ Object

Sets up the options for the middleware

Parameters:

  • opts (Hash) (defaults to: {})

    hash of options

Options Hash (opts):

  • :openid (Boolean)

    Whether to use openid logins or not (currently only option)

  • :handle_login (Boolean)

    Whether the access control system should handle presenting the login form, or let other parts of the app do that.

  • :config_id (Boolean)

    Whether to use the id set in a config file



19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/orange-more/administration/middleware/access_control.rb', line 19

def init(opts = {})
  defs = {:locked => [:preview, :admin, :orange], :login => '/login', :logout => '/logout',
          :handle_login => true, :openid => true, :single_user => false}
  opts = opts.with_defaults!(defs)
  @openid = opts[:openid]
  @locked = opts[:locked]
  @login = opts[:login]
  @logout = opts[:logout]
  @handle = opts[:handle_login]
  @single = opts[:single_user]
  unless @single
    orange.load(Orange::UserResource.new, :users)
  end
end

#main_user?(packet) ⇒ Boolean

Returns:

  • (Boolean)


79
80
81
82
83
84
85
86
87
88
89
# File 'lib/orange-more/administration/middleware/access_control.rb', line 79

def main_user?(packet)
  return false if packet['user.id'].blank?
  id = packet['user.id'].gsub(/^https?:\/\//, '').gsub(/\/$/, '')
  users = orange.options['main_users'] || []
  users = users.dup.push(orange.options['main_user'])
  users = users.flatten.compact
  matches = users.select{|user| 
    (user == id) || (id == user.gsub(/^https?:\/\//, '').gsub(/\/$/, ''))
  }
  matches.length > 0 ? true : false
end

#need_to_handle?(packet) ⇒ Boolean

Returns:

  • (Boolean)


91
92
93
# File 'lib/orange-more/administration/middleware/access_control.rb', line 91

def need_to_handle?(packet)
  @handle && ([@login, @logout].include? packet.request.path.gsub(/\/$/, ''))
end

#packet_call(packet) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/orange-more/administration/middleware/access_control.rb', line 34

def packet_call(packet)
  packet['user.id'] ||= (packet.session['user.id'] || false)
  packet['openid.profile'] ||= (packet.session['openid.profile'] || false)
  packet['user'] = orange[:users].user_for(packet) unless packet['user.id'].blank?
  if @openid && need_to_handle?(packet)
    ret = handle_openid(packet)
    return ret unless ret.blank? # unless handle_openid returns false, exit immediately
  end
  unless access_allowed?(packet)
    if packet['user'] && packet['route.context'] == :admin
      # User doesn't have permissions, try to get to a site that he does
      site = packet['user'].orange_sites.first
      if site.class.to_s == "OrangeSubsite" 
        subsite = orange[:sitemap].url_for(packet, {:resource => 'subsites', :resource_id => site.id})
        packet.reroute("/admin#{subsite}#{packet['route.path'].gsub(/^\//, '')}")
      end
    end
    packet.flash['user.after_login'] = packet.request.path
    packet.reroute(@login)
  end
  
  pass packet
end