password_policy 0.1

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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in password_policy.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Craig Russell
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,111 @@
1
+ # Password Policy #
2
+
3
+ A password policy class for Ruby
4
+
5
+ **Author** Craig Russell [craig@craig-russell.co.uk](mailto:craig@craig-russell.co.uk)
6
+ **Version** 0.1
7
+
8
+ Password Policy is a library that makes it easy to implement a password format policy on your application. It includes functions to return password validation errors.
9
+ ## Download ##
10
+
11
+
12
+ ## Usage ##
13
+
14
+ ### Getting Started ###
15
+
16
+ Using Password Policy on your site is simple.
17
+
18
+ 1. Install the Gem
19
+
20
+ $ gem install password_policy
21
+
22
+ 2. Include the library
23
+
24
+ > require 'password_policy'
25
+
26
+ 2. Create the Password Policy object
27
+
28
+ > @policy = PasswordPolicy.new
29
+
30
+ 3. Define the policy rules
31
+
32
+ > @policy.min_length = 8;
33
+ > @policy.max_length = 64;
34
+
35
+ 4. Validate a password
36
+
37
+ puts "Password OK!" if @policy.validate 'passw0rd'
38
+
39
+
40
+ ## Advanced ##
41
+
42
+ ### Separate Policy Rules ###
43
+
44
+ You can define your policy rules separately as a Hash and pass this to the constructor, rather than defining rules on the object. Hash keys should be rule identifiers, values should be the correct type. This is useful if you want to define your policy rules is a separate configuration file.
45
+
46
+ @rules = {
47
+ :min_length => 8,
48
+ :max_length => 64
49
+ }
50
+ @policy = PasswordPolicy.new @rules
51
+
52
+ ### Password Validation Errors ###
53
+
54
+ After validating the password, any errors can be retrieved as an array of strings.
55
+
56
+ @policy.errors.each do |error|
57
+ puts error
58
+ end
59
+
60
+ ## Policy Rules ##
61
+
62
+ A Password Policy has several rules which can be configured, these are detailed below.
63
+
64
+ Policy rules have different types, a rule will ignore any attempt to set its value to an incorrect type. Please refer to the documentation below.
65
+
66
+ **IMPORTANT** It is possible to define conflicting rules in a policy, which would make it impossible to set a password.
67
+
68
+ @rules = {
69
+ :min_length => 20,
70
+ :max_length => 10
71
+ }
72
+
73
+ ### Minimum Length ###
74
+
75
+ The minimum length of a password
76
+
77
+ **Identifier** `min_length`
78
+
79
+ @policy.min_length = 10;
80
+
81
+ ### Maximum Length ###
82
+
83
+ The maximum length of a password
84
+
85
+ **Identifier** `max_length`
86
+
87
+ @policy.max_length = 64;
88
+
89
+ ### Minimum Lower-case Characters ###
90
+
91
+ The minimum number of lower-case characters allowed in a password
92
+
93
+ **Identifier** `min_lowercase_chars`
94
+
95
+ @policy.min_lowercase_chars = 1;
96
+
97
+ ### Minimum Uppercase Characters ###
98
+
99
+ The minimum number of uppercase characters allowed in a password
100
+
101
+ **Identifier** `min_uppercase_chars`
102
+
103
+ @policy.min_uppercase_chars = 1;
104
+
105
+ ### Minimun Numeric Characters ###
106
+
107
+ The minimum number of numeric characters allowed in a password
108
+
109
+ **Identifier** `min_numeric_chars`
110
+
111
+ @policy.min_numeric_chars = 1;
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ end
8
+
9
+ desc "Run tests"
10
+ task :default => :test
@@ -0,0 +1,82 @@
1
+ require_relative "password_policy/version"
2
+ require_relative "password_policy/rules"
3
+
4
+ class PasswordPolicy
5
+
6
+ # Constructor
7
+ #
8
+ # == Parameters:
9
+ # rules::
10
+ # A Hash of rule values defining the policy
11
+ #
12
+ # == Returns:
13
+ # A PasswordPolicy object
14
+ def initialize(rules = {})
15
+
16
+ # Initialize error message and rule data structures
17
+ @errors = []
18
+ @rules = {}
19
+
20
+ # Define rules
21
+ rule_definitions
22
+
23
+ # Define accessors for rule values
24
+ @rules.each do |id, rule|
25
+ define_singleton_method(id) { rule[:value] }
26
+ define_singleton_method("#{id}=") { |val| rule[:value] = val }
27
+ end
28
+
29
+ # Merge provided rules values with defaults
30
+ rules.each do |rule, val|
31
+ @rules[rule.to_sym][:value] = val
32
+ end
33
+ end
34
+
35
+ # Validate a password against the password policy
36
+ #
37
+ # == Parameters:
38
+ # password:
39
+ # A password String to be validated
40
+ #
41
+ # == Returns:
42
+ # True if the password is validated
43
+ # false otherwise
44
+ #
45
+ def validate(password)
46
+ # Reset errors
47
+ @errors = []
48
+ # Test password against rules
49
+ @rules.each_value do |rule|
50
+ @errors << vsub(rule[:error_msg], rule[:value]) unless rule[:test].call(password)
51
+ end
52
+ # Password validated if no errors
53
+ @errors.length == 0
54
+ end
55
+
56
+ # Get a list of failed validation errors
57
+ #
58
+ # == Returns:
59
+ # An Array of password error Strings
60
+ #
61
+ def errors
62
+ @errors
63
+ end
64
+
65
+ private
66
+
67
+ # Globally substitute #VAL# for val in string
68
+ #
69
+ # == Parameters:
70
+ # string:
71
+ # The host String
72
+ # val:
73
+ # The value to be substituted in
74
+ #
75
+ # == Returns:
76
+ # The host Sting with all instances of #VAL#
77
+ # replaced with val:
78
+ #
79
+ def vsub(string, val)
80
+ string.gsub('#VAL#', val.to_s)
81
+ end
82
+ end
@@ -0,0 +1,52 @@
1
+ class PasswordPolicy
2
+
3
+ def rule_definitions
4
+ # Rule definitions are stored in the Hash @rules
5
+ # Hash key describes rule and is used as the accessor
6
+ # :value Default value for rule (can be overridden in constructor)
7
+ # :error_msg Message returned if validation fails
8
+ # :test Proc returning true if password validates against rule
9
+
10
+
11
+ @rules[:min_length] = {
12
+ :value => 8,
13
+ :error_msg => 'Password must be more than #VAL# characters',
14
+ :test => proc do |password|
15
+ password.length >= @rules[:min_length][:value]
16
+ end
17
+ }
18
+
19
+ @rules[:max_length] = {
20
+ :value => 64,
21
+ :error_msg => 'Password must be less than #VAL# characters',
22
+ :test => proc do |password|
23
+ password.length <= @rules[:max_length][:value]
24
+ end
25
+ }
26
+
27
+ @rules[:min_lowercase_chars] = {
28
+ :value => 0,
29
+ :error_msg => 'Password must contain at least #VAL# lowercase characters',
30
+ :test => proc do |password|
31
+ password.scan(/[a-z]/).size >= @rules[:min_lowercase_chars][:value]
32
+ end
33
+ }
34
+
35
+ @rules[:min_uppercase_chars] = {
36
+ :value => 0,
37
+ :error_msg => 'Password must contain at least #VAL# uppercase characters',
38
+ :test => proc do |password|
39
+ password.scan(/[A-Z]/).size >= @rules[:min_uppercase_chars][:value]
40
+ end
41
+ }
42
+
43
+ @rules[:min_numeric_chars] = {
44
+ :value => 0,
45
+ :error_msg => 'Password must contain at least #VAL# numeric characters',
46
+ :test => proc do |password|
47
+ password.scan(/[0-9]/).size >= @rules[:min_numeric_chars][:value]
48
+ end
49
+ }
50
+
51
+ end
52
+ end
@@ -0,0 +1,3 @@
1
+ class PasswordPolicy
2
+ VERSION = "0.1"
3
+ end
@@ -0,0 +1,17 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/password_policy/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Craig Russell"]
6
+ gem.email = ["craig@craig-russell.co.uk"]
7
+ gem.description = %q{A simple password policy enforcer}
8
+ gem.summary = %q{Password Policy}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "password_policy"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = PasswordPolicy::VERSION
17
+ end
@@ -0,0 +1,25 @@
1
+ require 'test/unit'
2
+ require File.expand_path('../../lib/password_policy', __FILE__)
3
+
4
+ class PasswordPolicyTests < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @pp = PasswordPolicy.new
8
+ end
9
+
10
+ def test_password_policy_object
11
+ assert_not_nil PasswordPolicy
12
+ assert_equal PasswordPolicy, @pp.class
13
+ end
14
+
15
+ def test_error_message_method
16
+ assert @pp.respond_to? :errors
17
+ assert_equal Array, @pp.errors.class
18
+ assert_equal [], @pp.errors
19
+ end
20
+
21
+ def test_validation_method
22
+ assert @pp.respond_to? :validate
23
+ assert @pp.validate('').is_a?(TrueClass) || @pp.validate('').is_a?(FalseClass)
24
+ end
25
+ end
@@ -0,0 +1,105 @@
1
+ require 'test/unit'
2
+ require File.expand_path('../../lib/password_policy', __FILE__)
3
+
4
+ class PasswordPolicyRulesTests < Test::Unit::TestCase
5
+
6
+ def test_min_length_rule
7
+ assert pp1 = PasswordPolicy.new
8
+ assert pp2 = PasswordPolicy.new(:min_length => 6)
9
+
10
+ assert_respond_to pp1, :min_length
11
+ assert_respond_to pp1, :min_length=
12
+
13
+ assert_equal 8, pp1.min_length
14
+ assert_equal 6, pp2.min_length
15
+
16
+ assert_equal false, pp1.validate('x' * 7)
17
+ assert_equal true, pp1.validate('x' * 8)
18
+
19
+ assert pp1.min_length = 10
20
+ assert_equal 10, pp1.min_length
21
+
22
+ assert_equal false, pp1.validate('x' * 9)
23
+ assert_equal true, pp1.validate('x' * 10)
24
+ end
25
+
26
+ def test_max_length_rule
27
+ assert pp1 = PasswordPolicy.new
28
+ assert pp2 = PasswordPolicy.new(:max_length => 10)
29
+
30
+ assert_respond_to pp1, :max_length
31
+ assert_respond_to pp1, :max_length=
32
+
33
+ assert_equal 64, pp1.max_length
34
+ assert_equal 10, pp2.max_length
35
+
36
+ assert_equal false, pp1.validate('x' * 65)
37
+ assert_equal true, pp1.validate('x' * 64)
38
+
39
+ assert pp1.max_length = 32
40
+ assert_equal 32, pp1.max_length
41
+
42
+ assert_equal false, pp1.validate('x' * 33)
43
+ assert_equal true, pp1.validate('x' * 32)
44
+ end
45
+
46
+ def test_min_lowercase_chars_rule
47
+ assert pp1 = PasswordPolicy.new
48
+ assert pp2 = PasswordPolicy.new(:min_lowercase_chars => 1)
49
+
50
+ assert_respond_to pp1, :min_lowercase_chars
51
+ assert_respond_to pp1, :min_lowercase_chars=
52
+
53
+ assert_equal 0, pp1.min_lowercase_chars
54
+ assert_equal 1, pp2.min_lowercase_chars
55
+
56
+ assert_equal false, pp2.validate('ABCDEFGHI')
57
+ assert_equal true, pp2.validate('AaBCDEFGHI')
58
+
59
+ assert pp1.min_lowercase_chars = 3
60
+ assert_equal 3, pp1.min_lowercase_chars
61
+
62
+ assert_equal false, pp1.validate('AaBbCDEFGHI')
63
+ assert_equal true, pp1.validate('AaBbCcDEFGHI')
64
+ end
65
+
66
+ def test_min_uppercase_chars_rule
67
+ assert pp1 = PasswordPolicy.new
68
+ assert pp2 = PasswordPolicy.new(:min_uppercase_chars => 1)
69
+
70
+ assert_respond_to pp1, :min_uppercase_chars
71
+ assert_respond_to pp1, :min_uppercase_chars=
72
+
73
+ assert_equal 0, pp1.min_uppercase_chars
74
+ assert_equal 1, pp2.min_uppercase_chars
75
+
76
+ assert_equal false, pp2.validate('abcdefghi')
77
+ assert_equal true, pp2.validate('aAbcdefghi')
78
+
79
+ assert pp1.min_uppercase_chars = 3
80
+ assert_equal 3, pp1.min_uppercase_chars
81
+
82
+ assert_equal false, pp1.validate('aAbBcdefghi')
83
+ assert_equal true, pp1.validate('aAbBcCdefghi')
84
+ end
85
+
86
+ def test_min_numeric_chars_rule
87
+ assert pp1 = PasswordPolicy.new
88
+ assert pp2 = PasswordPolicy.new(:min_numeric_chars => 1)
89
+
90
+ assert_respond_to pp1, :min_numeric_chars
91
+ assert_respond_to pp1, :min_numeric_chars=
92
+
93
+ assert_equal 0, pp1.min_numeric_chars
94
+ assert_equal 1, pp2.min_numeric_chars
95
+
96
+ assert_equal false, pp2.validate('abcdefghi')
97
+ assert_equal true, pp2.validate('abcdefghi1')
98
+
99
+ assert pp1.min_numeric_chars = 3
100
+ assert_equal 3, pp1.min_numeric_chars
101
+
102
+ assert_equal false, pp1.validate('abcdefghi1')
103
+ assert_equal true, pp1.validate('abcdefghi123')
104
+ end
105
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: password_policy
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Craig Russell
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-13 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A simple password policy enforcer
15
+ email:
16
+ - craig@craig-russell.co.uk
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - .gitignore
22
+ - Gemfile
23
+ - LICENSE
24
+ - README.md
25
+ - Rakefile
26
+ - lib/password_policy.rb
27
+ - lib/password_policy/rules.rb
28
+ - lib/password_policy/version.rb
29
+ - password_policy.gemspec
30
+ - test/test_password_policy.rb
31
+ - test/test_rule_definitions.rb
32
+ homepage: ''
33
+ licenses: []
34
+ post_install_message:
35
+ rdoc_options: []
36
+ require_paths:
37
+ - lib
38
+ required_ruby_version: !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubyforge_project:
52
+ rubygems_version: 1.8.21
53
+ signing_key:
54
+ specification_version: 3
55
+ summary: Password Policy
56
+ test_files:
57
+ - test/test_password_policy.rb
58
+ - test/test_rule_definitions.rb