ucb_rails_security 2.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +6 -0
- data/Manifest +56 -0
- data/README +195 -0
- data/Rakefile +21 -0
- data/TODO +3 -0
- data/generators/ucb_rails_security/templates/controllers/ucb_security/base_controller.rb +17 -0
- data/generators/ucb_rails_security/templates/controllers/ucb_security/ldap_search_controller.rb +10 -0
- data/generators/ucb_rails_security/templates/controllers/ucb_security/role_users_controller.rb +27 -0
- data/generators/ucb_rails_security/templates/controllers/ucb_security/roles_controller.rb +52 -0
- data/generators/ucb_rails_security/templates/controllers/ucb_security/user_roles_controller.rb +29 -0
- data/generators/ucb_rails_security/templates/controllers/ucb_security/users_controller.rb +59 -0
- data/generators/ucb_rails_security/templates/db/migrate/xxx_create_ucb_rails_security_tables.rb +31 -0
- data/generators/ucb_rails_security/templates/helpers/ucb_security/base_helper.rb +23 -0
- data/generators/ucb_rails_security/templates/helpers/ucb_security/builder.rb +25 -0
- data/generators/ucb_rails_security/templates/helpers/ucb_security/roles_helper.rb +2 -0
- data/generators/ucb_rails_security/templates/helpers/ucb_security/users_helper.rb +2 -0
- data/generators/ucb_rails_security/templates/initializers/ucb_security_config.rb +20 -0
- data/generators/ucb_rails_security/templates/javascripts/ucb_security.js +99 -0
- data/generators/ucb_rails_security/templates/models/ldap_search.rb +48 -0
- data/generators/ucb_rails_security/templates/models/role.rb +32 -0
- data/generators/ucb_rails_security/templates/models/user.rb +106 -0
- data/generators/ucb_rails_security/templates/models/user_roles.rb +3 -0
- data/generators/ucb_rails_security/templates/stylesheets/ucb_security.css +347 -0
- data/generators/ucb_rails_security/templates/views/layouts/ucb_security/_main_navigation.html.erb +10 -0
- data/generators/ucb_rails_security/templates/views/layouts/ucb_security/application.html.erb +24 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/ldap_search/index.html.erb +62 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/role_users/_new.html.erb +11 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/role_users/edit.html.erb +37 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/roles/_users.html.erb +14 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/roles/edit.html.erb +19 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/roles/index.html.erb +34 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/roles/new.html.erb +19 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/roles/show.html.erb +27 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/user_roles/edit.html.erb +17 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/users/edit.html.erb +23 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/users/index.html.erb +43 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/users/new.html.erb +29 -0
- data/generators/ucb_rails_security/templates/views/ucb_security/users/show.html.erb +43 -0
- data/generators/ucb_rails_security/ucb_rails_security_generator.rb +191 -0
- data/init.rb +9 -0
- data/lib/helpers/rspec_helpers.rb +119 -0
- data/lib/tasks/ucb_rails_security.rake +22 -0
- data/lib/ucb_rails_security.rb +60 -0
- data/lib/ucb_rails_security_casauthentication.rb +117 -0
- data/lib/ucb_rails_security_logger.rb +33 -0
- data/lib/ucb_rs_controller_methods.rb +496 -0
- data/rdoc_includes/application_controller_rb.txt +9 -0
- data/rspec/_all_specs.rb +5 -0
- data/rspec/_setup.rb +36 -0
- data/rspec/filter_ldap_spec.rb +87 -0
- data/rspec/filter_role_spec.rb +56 -0
- data/rspec/filter_spec.rb +37 -0
- data/rspec/filter_user_spec.rb +55 -0
- data/rspec/logged_in_status_spec.rb +226 -0
- data/rspec/ucb_rails_security_casauthentication_spec.rb +83 -0
- data/rspec/ucb_rails_security_spec.rb +34 -0
- data/test/test_rails-2.0.x/test/test_helper.rb +38 -0
- data/test/test_rails-2.1.x/test/test_helper.rb +38 -0
- data/ucb_rails_security.gemspec +41 -0
- metadata +147 -0
@@ -0,0 +1,99 @@
|
|
1
|
+
|
2
|
+
var DoubleSelectList = {
|
3
|
+
/* Takes the dom Ids of two Select Elements. Moves the
|
4
|
+
* options from the Element with fromId that are selected
|
5
|
+
* to the Element with toId
|
6
|
+
*/
|
7
|
+
moveSelected: function(fromId, toId) {
|
8
|
+
var fromList = $(fromId)
|
9
|
+
var toList = $(toId)
|
10
|
+
|
11
|
+
if (!fromList) {
|
12
|
+
throw new Error("Dom id for fromId not found: " + fromId)
|
13
|
+
} else if (!toList) {
|
14
|
+
throw new Error("Dom id for toId not found: " + toId)
|
15
|
+
}
|
16
|
+
|
17
|
+
this._transferSelected(fromList, toList);
|
18
|
+
},
|
19
|
+
/* Takes the dom Ids of two Select Elements. Moves all the
|
20
|
+
* options from the Element with fromId to the Element
|
21
|
+
* with toId
|
22
|
+
*/
|
23
|
+
moveAll: function(fromId, toId) {
|
24
|
+
var fromList = $(fromId)
|
25
|
+
var toList = $(toId)
|
26
|
+
|
27
|
+
if (!fromList) {
|
28
|
+
throw new Error("Dom id for fromId not found: " + fromId)
|
29
|
+
} else if (!toList) {
|
30
|
+
throw new Error("Dom id for toId not found: " + toId)
|
31
|
+
}
|
32
|
+
|
33
|
+
this._transferAll(fromList, toList);
|
34
|
+
},
|
35
|
+
/*
|
36
|
+
* Takes an array of Option elements and sets their selected attribute to true/false.
|
37
|
+
*
|
38
|
+
* setSelectedToFalse([<option selected=true></option>], false)
|
39
|
+
* => [<option selected=false></option>]
|
40
|
+
*/
|
41
|
+
setOptionsSelectedAttribute: function(selectOptions, selectedValue) {
|
42
|
+
return selectOptions.map(
|
43
|
+
function(elem) {
|
44
|
+
elem.selected = selectedValue;
|
45
|
+
return elem;
|
46
|
+
}
|
47
|
+
);
|
48
|
+
|
49
|
+
},
|
50
|
+
/**
|
51
|
+
* When the form is submitted, we want to make sure the values from both
|
52
|
+
* select lists are sent to our controller/action. Only select options
|
53
|
+
* that have their selected attribute set to true actually get submitted.
|
54
|
+
* We call this function the first time the page loads and as soon as the
|
55
|
+
* submit button is clicked, it updates the selected attribute of both
|
56
|
+
* select lists to true
|
57
|
+
*/
|
58
|
+
initSubmitCallback: function(buttonId, fromId, toId) {
|
59
|
+
var fromOptions = $(fromId).childElements();
|
60
|
+
var toOptions = $(toId).childElements();
|
61
|
+
$(buttonId).observe('click', function() { fromOptions.each(function(elem) {elem.selected = true}) })
|
62
|
+
$(buttonId).observe('click', function() { toOptions.each(function(elem) {elem.selected = true}) })
|
63
|
+
},
|
64
|
+
|
65
|
+
|
66
|
+
/************************************************************************
|
67
|
+
* Private Methods
|
68
|
+
************************************************************************/
|
69
|
+
|
70
|
+
_transferAll: function(fromList, toList) {
|
71
|
+
var fromOptions = fromList.childElements();
|
72
|
+
var toOptions = toList.childElements();
|
73
|
+
var newOptions = new Array(fromOptions, toOptions).flatten();
|
74
|
+
|
75
|
+
newOptions = newOptions.sort(this._optionsSorter);
|
76
|
+
newOptions = this.setOptionsSelectedAttribute(newOptions, false);
|
77
|
+
toOptions.each( function(elem) { elem.remove(); } );
|
78
|
+
newOptions.each( function(elem) { toList.insert(elem); } );
|
79
|
+
},
|
80
|
+
_transferSelected: function(fromList, toList) {
|
81
|
+
var selFromOptions = fromList.childElements().select(
|
82
|
+
function(elem) { return elem.selected }
|
83
|
+
);
|
84
|
+
selFromOptions = this.setOptionsSelectedAttribute(selFromOptions, false);
|
85
|
+
|
86
|
+
var toOptions = toList.childElements();
|
87
|
+
var newOptions = new Array(selFromOptions, toOptions).flatten();
|
88
|
+
newOptions = newOptions.sort(this._optionsSorter);
|
89
|
+
newOptions.each( function(elem) { toList.insert(elem) } );
|
90
|
+
},
|
91
|
+
/*
|
92
|
+
* To be used as a comparison function with Array.sort. Compares the
|
93
|
+
* the text of two Option elements and sorts them Alpha ASC.
|
94
|
+
*/
|
95
|
+
_optionsSorter: function(option1, option2) {
|
96
|
+
return option1.text > option2.text ? 1 : (option1.text < option2.text ? -1 : 0);
|
97
|
+
},
|
98
|
+
|
99
|
+
};
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'ucb_ldap'
|
2
|
+
|
3
|
+
class LdapSearch
|
4
|
+
SEARCH_TERMS = [
|
5
|
+
[:last_name_and_first_name, 'Last Name, First Name'],
|
6
|
+
[:last_name, 'Last Name'],
|
7
|
+
[:first_name, 'First Name'],
|
8
|
+
[:email, 'Email'],
|
9
|
+
[:phone, 'Phone'],
|
10
|
+
[:department, 'Department'],
|
11
|
+
[:ldap_uid, 'UID']
|
12
|
+
]
|
13
|
+
|
14
|
+
LDAP_ALIASES = {
|
15
|
+
:first_name => :givenname,
|
16
|
+
:last_name => :sn,
|
17
|
+
:email => :mail,
|
18
|
+
:phone => :telephonenumber,
|
19
|
+
:department => :berkeleyeduunitcalnetdeptname,
|
20
|
+
:ldap_uid => :uid,
|
21
|
+
}
|
22
|
+
|
23
|
+
def self.search_term_select_list
|
24
|
+
SEARCH_TERMS.collect { |item| [item[1], item[0]] }
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.search_arguments_blank?(search_term, search_value)
|
28
|
+
search_term.nil? || search_term.empty? || search_value.nil? || search_value.empty?
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.find(search_term, search_value)
|
32
|
+
return [] if search_arguments_blank?(search_term, search_value)
|
33
|
+
|
34
|
+
search_hash = {}
|
35
|
+
if search_term.to_sym == SEARCH_TERMS[0][0]
|
36
|
+
lname_value, fname_value = search_value.split(",").map { |v| v.strip }
|
37
|
+
lname, fname = search_term.split("_and_")
|
38
|
+
return [] if lname.nil? || fname.nil?
|
39
|
+
search_hash[LDAP_ALIASES[fname.to_sym]] = "#{fname_value}"
|
40
|
+
search_hash[LDAP_ALIASES[lname.to_sym]] = "#{lname_value}"
|
41
|
+
else
|
42
|
+
search_hash[LDAP_ALIASES[search_term.to_sym]] = "#{search_value}"
|
43
|
+
end
|
44
|
+
|
45
|
+
UCB::LDAP::Person.search(:filter => search_hash)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Role < ActiveRecord::Base
|
2
|
+
has_and_belongs_to_many(:users, :join_table => "user_roles", :order => 'last_name')
|
3
|
+
|
4
|
+
validates_presence_of :name
|
5
|
+
validates_uniqueness_of :name
|
6
|
+
|
7
|
+
|
8
|
+
def formatted_created_at()
|
9
|
+
created_at.strftime('%m-%d-%Y')
|
10
|
+
end
|
11
|
+
|
12
|
+
def formatted_updated_at()
|
13
|
+
updated_at.strftime('%m-%d-%Y')
|
14
|
+
end
|
15
|
+
|
16
|
+
def users_menu_list()
|
17
|
+
self.users.map { |u| [u.display_name, u.id] }
|
18
|
+
end
|
19
|
+
|
20
|
+
def non_users_menu_list
|
21
|
+
self.non_users.map { |u| [u.display_name, u.id] }
|
22
|
+
end
|
23
|
+
|
24
|
+
def non_users
|
25
|
+
sql = %(
|
26
|
+
SELECT users.* FROM users LEFT JOIN user_roles
|
27
|
+
ON (users.id = user_roles.user_id AND user_roles.role_id = #{id})
|
28
|
+
WHERE user_roles.role_id IS NULL
|
29
|
+
)
|
30
|
+
User.find_by_sql(sql)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
class User < ActiveRecord::Base
|
2
|
+
has_and_belongs_to_many :roles, :join_table => 'user_roles', :order => 'name'
|
3
|
+
|
4
|
+
validates_uniqueness_of :ldap_uid
|
5
|
+
validates_uniqueness_of :email, :unless => lambda { |user| user.email.blank? }
|
6
|
+
validates_presence_of :ldap_uid, :first_name, :last_name
|
7
|
+
|
8
|
+
def formatted_created_at()
|
9
|
+
created_at.strftime('%m-%d-%Y')
|
10
|
+
end
|
11
|
+
|
12
|
+
def current_user?(ldap_uid)
|
13
|
+
self.ldap_uid == ldap_uid
|
14
|
+
end
|
15
|
+
|
16
|
+
def full_name()
|
17
|
+
"#{first_name} #{last_name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def display_name()
|
21
|
+
"#{last_name}, #{first_name}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def sync_attributes_with_ldap!()
|
25
|
+
ldap_person = UCB::LDAP::Person.find_by_uid(self.ldap_uid)
|
26
|
+
raise UCB::LDAP::Person::RecordNotFound if ldap_person.nil?
|
27
|
+
self.update_attributes!(self.class.attributes_hash_for_ldap_person(ldap_person))
|
28
|
+
end
|
29
|
+
|
30
|
+
class << self
|
31
|
+
### Start Class Aliases ###
|
32
|
+
#
|
33
|
+
# These methods provide aliases for ActiveRecord's
|
34
|
+
# dynamic finders and can't be aliased with the
|
35
|
+
# usual: alias :new_method :old_method
|
36
|
+
#
|
37
|
+
def find_by_uid(ldap_uid)
|
38
|
+
find_by_ldap_uid(ldap_uid)
|
39
|
+
end
|
40
|
+
|
41
|
+
def new_from_uid(ldap_uid)
|
42
|
+
new_from_ldap_uid(ldap_uid)
|
43
|
+
end
|
44
|
+
### End Class Aliases ####
|
45
|
+
|
46
|
+
def find_or_create_by_ldap_uid!(ldap_uid)
|
47
|
+
user = find_or_create_by_ldap_uid(ldap_uid)
|
48
|
+
if user.new_record?
|
49
|
+
ldap_person = UCB::LDAP::Person.find_by_uid(ldap_uid)
|
50
|
+
raise UCB::LDAP::Person::RecordNotFound if ldap_person.nil?
|
51
|
+
user.attributes = attributes_hash_for_ldap_person(ldap_person)
|
52
|
+
user.save!
|
53
|
+
end
|
54
|
+
user
|
55
|
+
end
|
56
|
+
|
57
|
+
def new_from_ldap_uid(ldap_uid)
|
58
|
+
ldap_person = ldap_uid.nil? ? nil : UCB::LDAP::Person.find_by_uid(ldap_uid)
|
59
|
+
if ldap_person.nil?
|
60
|
+
self.new
|
61
|
+
else
|
62
|
+
user = self.new
|
63
|
+
user.attributes = attributes_hash_for_ldap_person(ldap_person)
|
64
|
+
user
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def attributes_hash_for_ldap_person(ldap_person)
|
69
|
+
{
|
70
|
+
:ldap_uid => ldap_person.uid,
|
71
|
+
:first_name => ldap_person.first_name,
|
72
|
+
:last_name => ldap_person.last_name,
|
73
|
+
:phone => ldap_person.phone,
|
74
|
+
:email => ldap_person.email,
|
75
|
+
:department => ldap_person.dept_name
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def find_in_ldap(search_params = {})
|
80
|
+
return [] if search_params.empty?
|
81
|
+
|
82
|
+
ldap_people = []
|
83
|
+
UCB::LDAP::Person.search(:filter => search_params).each do |person|
|
84
|
+
ldap_people << person
|
85
|
+
end
|
86
|
+
ldap_people
|
87
|
+
end
|
88
|
+
|
89
|
+
def sync_all_with_ldap!()
|
90
|
+
unfound = []
|
91
|
+
users = self.find(:all).each do |u|
|
92
|
+
begin
|
93
|
+
u.sync_attributes_with_ldap!
|
94
|
+
rescue UCB::LDAP::Person::RecordNotFound => e
|
95
|
+
unfound << u.uid
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
unless unfound.blank?
|
100
|
+
msg = "Sync failed for uids: #{unfound.join(',')}"
|
101
|
+
raise(UCB::LDAP::Person::RecordNotFound, msg)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
@@ -0,0 +1,347 @@
|
|
1
|
+
#container {
|
2
|
+
width: 100%;
|
3
|
+
background-color: #fff;
|
4
|
+
color: #333;
|
5
|
+
line-height: 160%;
|
6
|
+
vertical-align: top;
|
7
|
+
}
|
8
|
+
|
9
|
+
#main {
|
10
|
+
padding: 1.5em;
|
11
|
+
overflow: clip;
|
12
|
+
vertical-align: top;
|
13
|
+
}
|
14
|
+
|
15
|
+
#site_header {
|
16
|
+
color: #02305c;
|
17
|
+
font-weight: bold;
|
18
|
+
font-size: 1.8em;
|
19
|
+
padding: .5em;
|
20
|
+
background-color: #fff;
|
21
|
+
}
|
22
|
+
|
23
|
+
#site_header div {
|
24
|
+
font-size: .4em;
|
25
|
+
float: right;
|
26
|
+
}
|
27
|
+
|
28
|
+
#site_header div strong {
|
29
|
+
color: black;
|
30
|
+
font-style: oblique;
|
31
|
+
}
|
32
|
+
/* Start General Element Styles */
|
33
|
+
html {
|
34
|
+
padding: 0em;
|
35
|
+
}
|
36
|
+
|
37
|
+
body {
|
38
|
+
margin: 0em;
|
39
|
+
background-color: white;
|
40
|
+
}
|
41
|
+
|
42
|
+
a, a:visited, a:hover {
|
43
|
+
color: #0058c4;
|
44
|
+
text-decoration: underline;
|
45
|
+
}
|
46
|
+
|
47
|
+
/*p {
|
48
|
+
margin: 0px 1em;
|
49
|
+
line-height: 1.5em;
|
50
|
+
color: black;
|
51
|
+
}*/
|
52
|
+
|
53
|
+
h1 {
|
54
|
+
font-size: 150%;
|
55
|
+
color: black;
|
56
|
+
font-weight: bold;
|
57
|
+
}
|
58
|
+
|
59
|
+
h2 {
|
60
|
+
font-size: 120%;
|
61
|
+
color: black;
|
62
|
+
}
|
63
|
+
/* End General Element Styles */
|
64
|
+
|
65
|
+
.max_width {
|
66
|
+
width: 100%;
|
67
|
+
}
|
68
|
+
|
69
|
+
.mid_width {
|
70
|
+
width: 75%;
|
71
|
+
}
|
72
|
+
|
73
|
+
.min_width {
|
74
|
+
width: 40%;
|
75
|
+
}
|
76
|
+
|
77
|
+
.align_right {
|
78
|
+
text-align: right;
|
79
|
+
}
|
80
|
+
|
81
|
+
.align_left {
|
82
|
+
text-align: left;
|
83
|
+
}
|
84
|
+
|
85
|
+
.align_center {
|
86
|
+
text-align: center;
|
87
|
+
}
|
88
|
+
|
89
|
+
.red_text p {
|
90
|
+
text-align: center;
|
91
|
+
font-size: 100%;
|
92
|
+
color: red;
|
93
|
+
}
|
94
|
+
|
95
|
+
/* End General Element Styles */
|
96
|
+
|
97
|
+
|
98
|
+
.note {
|
99
|
+
color: red;
|
100
|
+
font-weight: bold;
|
101
|
+
}
|
102
|
+
|
103
|
+
.error {
|
104
|
+
margin-bottom: 2em;
|
105
|
+
background-color: #c40d0d;
|
106
|
+
text-align: center;
|
107
|
+
font-size: 110%;
|
108
|
+
padding: 1px;
|
109
|
+
border: 1px solid gray;
|
110
|
+
color: white;
|
111
|
+
}
|
112
|
+
|
113
|
+
.notice {
|
114
|
+
margin-bottom: 2em;
|
115
|
+
background-color: #dbffb4;
|
116
|
+
text-align: center;
|
117
|
+
font-family: arial;
|
118
|
+
padding: 1px;
|
119
|
+
border: 1px solid gray;
|
120
|
+
color: black;
|
121
|
+
}
|
122
|
+
|
123
|
+
#footer {
|
124
|
+
margin: 1em;
|
125
|
+
text-align: center;
|
126
|
+
margin: 1em;
|
127
|
+
}
|
128
|
+
|
129
|
+
div.button_widget {
|
130
|
+
margin: .2em 0em .4em 0em;
|
131
|
+
}
|
132
|
+
|
133
|
+
.button_widget form, .button_widget div {
|
134
|
+
display: inline;
|
135
|
+
}
|
136
|
+
|
137
|
+
div.new_record_widget a {
|
138
|
+
color: #fe7600;
|
139
|
+
font-weight: bold;
|
140
|
+
font-size: 14px;
|
141
|
+
}
|
142
|
+
|
143
|
+
div.button_widget a, div.button_widget {
|
144
|
+
font-size: 14px;
|
145
|
+
}
|
146
|
+
|
147
|
+
#logout_link {
|
148
|
+
color: #fe7600;
|
149
|
+
}
|
150
|
+
|
151
|
+
|
152
|
+
/********* tables *********/
|
153
|
+
|
154
|
+
input[readonly], textarea[readonly] {
|
155
|
+
border: 1px dotted #bcbcbc;
|
156
|
+
padding: 2px;
|
157
|
+
}
|
158
|
+
|
159
|
+
table {
|
160
|
+
vertical-align: top;
|
161
|
+
border: 1px solid black;
|
162
|
+
border-collapse: collapse;
|
163
|
+
margin: 0 0 1.5em 0;
|
164
|
+
}
|
165
|
+
|
166
|
+
table td {
|
167
|
+
border: 1px solid black;
|
168
|
+
padding: 0px 5px;
|
169
|
+
color: black;
|
170
|
+
}
|
171
|
+
|
172
|
+
table th {
|
173
|
+
border: 1px solid black;
|
174
|
+
color: black;
|
175
|
+
background-color: #ccc;
|
176
|
+
white-space: nowrap;
|
177
|
+
padding: 0px 5px;
|
178
|
+
text-align: left;
|
179
|
+
}
|
180
|
+
|
181
|
+
table.vertical th {
|
182
|
+
background-color: #eee;
|
183
|
+
white-space: nowrap;
|
184
|
+
text-align: right;
|
185
|
+
}
|
186
|
+
|
187
|
+
caption {
|
188
|
+
font-weight: bold;
|
189
|
+
color: white;
|
190
|
+
background-color: #26A;
|
191
|
+
border: 1px solid black;
|
192
|
+
text-align: center;
|
193
|
+
padding: 4px;
|
194
|
+
font-size: 110%;
|
195
|
+
}
|
196
|
+
|
197
|
+
table.horizontal th {
|
198
|
+
background-color: #fff;
|
199
|
+
text-align: left;
|
200
|
+
font-size: 90%;
|
201
|
+
}
|
202
|
+
|
203
|
+
table tbody.highlight tr:hover {
|
204
|
+
background-color: #ffd;
|
205
|
+
}
|
206
|
+
|
207
|
+
.blue {
|
208
|
+
padding: 2px 5px;
|
209
|
+
border: 1px solid black;
|
210
|
+
border-bottom: 0px;
|
211
|
+
color: white;
|
212
|
+
background-color: #58B;
|
213
|
+
font-size: 110%;
|
214
|
+
font-weight: bold;
|
215
|
+
text-align: left;
|
216
|
+
margin: 0px;
|
217
|
+
}
|
218
|
+
|
219
|
+
.empty_result_set {
|
220
|
+
font-weight: bold;
|
221
|
+
text-align: center;
|
222
|
+
border: 1px solid black;
|
223
|
+
}
|
224
|
+
|
225
|
+
/** tabbed navigation **/
|
226
|
+
|
227
|
+
#navbar_footer {
|
228
|
+
clear: both;
|
229
|
+
margin: 0;
|
230
|
+
padding: 0;
|
231
|
+
width: 100%;
|
232
|
+
/* sync these values, line-height is needed for IE */
|
233
|
+
height: 4px;
|
234
|
+
line-height: 4px;
|
235
|
+
border-bottom: 1px solid #9C9C9C;
|
236
|
+
background: #81BBF2;
|
237
|
+
}
|
238
|
+
|
239
|
+
#navbar ul {
|
240
|
+
clear: both;
|
241
|
+
display: block;
|
242
|
+
margin: 0;
|
243
|
+
background-color: gray;
|
244
|
+
font-size: 15px;
|
245
|
+
}
|
246
|
+
|
247
|
+
#navbar li {
|
248
|
+
float: left;
|
249
|
+
display: block;
|
250
|
+
margin: 0 2px;
|
251
|
+
padding: 0px 5px;
|
252
|
+
border: 1px solid #9C9C9C;
|
253
|
+
background-color: #ffffff;
|
254
|
+
border-bottom: none;
|
255
|
+
white-space: nowrap;
|
256
|
+
}
|
257
|
+
|
258
|
+
#navbar li a, #navbar li a:visited {
|
259
|
+
color: black;
|
260
|
+
text-decoration: none;
|
261
|
+
}
|
262
|
+
|
263
|
+
#navbar li.current a {
|
264
|
+
font-weight: bold;
|
265
|
+
}
|
266
|
+
|
267
|
+
#navbar li:hover {
|
268
|
+
background: #CCCCCC;
|
269
|
+
}
|
270
|
+
|
271
|
+
#navbar li.current, #navbar li.current:hover {
|
272
|
+
background-color: #81bbf2;
|
273
|
+
}
|
274
|
+
|
275
|
+
.ucb_rails_security_form label {
|
276
|
+
width: 8em;
|
277
|
+
float: left;
|
278
|
+
text-align: right;
|
279
|
+
margin-right: 0.5em;
|
280
|
+
display: block;
|
281
|
+
font-size: 1em;
|
282
|
+
padding-right: 2px;
|
283
|
+
font-weight: bold;
|
284
|
+
}
|
285
|
+
|
286
|
+
.ucb_rails_security_form input[type=text] {
|
287
|
+
font-size: .9em;
|
288
|
+
}
|
289
|
+
|
290
|
+
.ucb_rails_security_form select[multiple] {
|
291
|
+
font-size: .8em;
|
292
|
+
padding: .5em;
|
293
|
+
margin-top: 0px;
|
294
|
+
width: 350px;
|
295
|
+
}
|
296
|
+
|
297
|
+
|
298
|
+
.ucb_rails_security_form fieldset {
|
299
|
+
width: 65%;
|
300
|
+
overflow: visible;
|
301
|
+
border: 1px solid #999999;
|
302
|
+
}
|
303
|
+
|
304
|
+
.ucb_rails_security_form legend {
|
305
|
+
background-color: #efefef;
|
306
|
+
font-family: sans-serif;
|
307
|
+
padding: 0em .5em;
|
308
|
+
border: 1px solid black;
|
309
|
+
font-size: .8em;
|
310
|
+
font-weight: bold;
|
311
|
+
}
|
312
|
+
|
313
|
+
div.button_widget {
|
314
|
+
margin-left: 6em;
|
315
|
+
}
|
316
|
+
|
317
|
+
.fieldWithErrors {
|
318
|
+
padding: 2px;
|
319
|
+
background-color: red;
|
320
|
+
display: table;
|
321
|
+
}
|
322
|
+
|
323
|
+
|
324
|
+
|
325
|
+
table.doubleSelectList {
|
326
|
+
border: 0px solid white;
|
327
|
+
}
|
328
|
+
|
329
|
+
table.doubleSelectList td {
|
330
|
+
text-align: center;
|
331
|
+
vertical-align: top;
|
332
|
+
border: 0px solid white;
|
333
|
+
}
|
334
|
+
|
335
|
+
table.doubleSelectList td.buttons {
|
336
|
+
text-align: center;
|
337
|
+
vertical-align: middle;
|
338
|
+
color: gray;
|
339
|
+
border: 0px solid white;
|
340
|
+
}
|
341
|
+
|
342
|
+
.doubleSelectList select[multiple] {
|
343
|
+
font-size: .8em;
|
344
|
+
padding: .5em;
|
345
|
+
margin-top: 0px;
|
346
|
+
width: 350px;
|
347
|
+
}
|
data/generators/ucb_rails_security/templates/views/layouts/ucb_security/_main_navigation.html.erb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
<div id="navbar">
|
2
|
+
<ul>
|
3
|
+
<% users_class = params[:controller] =~ /users/ ? "class='current'" : "" %>
|
4
|
+
<% roles_class = params[:controller] =~ /roles/ ? "class='current'" : "" %>
|
5
|
+
<% help_class = params[:controller] =~ /help/ ? "class='current'" : "" %>
|
6
|
+
<li <%= users_class %>><%= link_to('Users', ucb_security_users_path()) %></li>
|
7
|
+
<li <%= roles_class %>><%= link_to('Roles', ucb_security_roles_path()) %></li>
|
8
|
+
</ul>
|
9
|
+
</div>
|
10
|
+
<div id="navbar_footer"><hr style="display:none;"></div>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
|
3
|
+
<head>
|
4
|
+
<title>UCB Rails Security - <%= @title %></title>
|
5
|
+
<%= stylesheet_link_tag 'ucb_security' %>
|
6
|
+
<%= javascript_include_tag :defaults, 'ucb_security' %>
|
7
|
+
</head>
|
8
|
+
|
9
|
+
<body>
|
10
|
+
<div id="site_header">
|
11
|
+
UCB Rails Security
|
12
|
+
</div>
|
13
|
+
|
14
|
+
<div id="container">
|
15
|
+
<%= render :partial => 'layouts/ucb_security/main_navigation' %>
|
16
|
+
|
17
|
+
<div id="main">
|
18
|
+
<div id="message"><%= display_message() %></div>
|
19
|
+
<h1><%= @title %></h1>
|
20
|
+
<%= yield %>
|
21
|
+
</div>
|
22
|
+
</div>
|
23
|
+
</body>
|
24
|
+
</html>
|