digestive 0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 21d6d553eb8692cd4ba1c1153ab5c1709f4fbe90
4
+ data.tar.gz: 0d94f3e0c745428fe9291976f9c9a77cd3fb5e61
5
+ SHA512:
6
+ metadata.gz: c2ba4d48fa6c6cf74c1e674f219122d2a657a056bd8fbac485a25cc8bcf59e469477c0cfa3993a493f328610def044c377d760f1c23efcfdb67da8c975907929
7
+ data.tar.gz: c158552c5e55affc3fa23096031857642ac1c014c69bc56e5327f611abd3fcc8d6c8ae29130abdd33ae7fc152314dc525bc86b2be548096734cd8acf095a6980
data/.gitignore ADDED
@@ -0,0 +1,18 @@
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
18
+ memory
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in digestive.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,7 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ guard :minitest do
4
+ watch(%r|^spec/(.+)_spec\.rb$|)
5
+ watch(%r|^lib/(.+)\.rb$|) { |m| "spec/#{m[1]}_spec.rb" }
6
+ watch(%r|^spec/spec_helper.rb$|)
7
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Robert Dallas Gray
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.
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # Digestive
2
+
3
+ A super-simple microframework to implement Digest Authentication for
4
+ Rails apps.
5
+
6
+ NB USE AT YOUR OWN RISK!
7
+
8
+ ```ruby
9
+ include Digestive::Auth
10
+ # simple simon
11
+ before_filter :authenticate
12
+
13
+ # authenticate with an authorization strategy
14
+ def authenticate_as_admin
15
+ authenticate { |user| user.is_admin? }
16
+ end
17
+
18
+ # on successful authentication, user stored in instance var
19
+ # of including class
20
+ @current_user.is_a?(User)
21
+ ```
22
+
23
+ ## Installation
24
+
25
+ $ gem install digestive
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.pattern = 'spec/**/*_spec.rb'
8
+ end
data/digestive.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'digestive/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'digestive'
8
+ spec.version = Digestive::VERSION
9
+ spec.authors = ['Robert Dallas Gray']
10
+ spec.email = ['mail@robertdallasgray.com']
11
+ spec.description = %q{Simple digest auth with roles}
12
+ spec.summary = %q{Simple digest auth with roles}
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.test_files = spec.files.grep(/^spec\//)
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_development_dependency 'bundler', '~> 1.3'
21
+ spec.add_development_dependency 'rake'
22
+ spec.add_development_dependency 'm', '~> 1.3.1'
23
+ spec.add_development_dependency 'guard', '>= 1.8'
24
+ spec.add_development_dependency 'guard-minitest'
25
+ spec.add_development_dependency 'activerecord', '~> 3'
26
+ spec.add_development_dependency 'sqlite3'
27
+ spec.add_development_dependency 'mocha'
28
+ end
@@ -0,0 +1,57 @@
1
+ # encoding: UTF-8
2
+
3
+ module Digestive
4
+ module Auth
5
+ # Handles authentication of a credentialed object, using a given provider.
6
+ # The credentialed object will normally be a user, and the provider
7
+ # `ActionController::HttpAuthentication::Digest::ControllerMethods`.
8
+ # @!attribute [r] user
9
+ # @return [Object]
10
+ # The currently-authenticated user, or nil
11
+ class Service
12
+
13
+ attr_reader :user
14
+
15
+ # Create a new Digest::Auth::Service.
16
+ # @param [Object] credentialed
17
+ # An object responding to constant DIGEST_REALM and
18
+ # method find_by_username. See {Digestive::User}.
19
+ # @param [Object] provider
20
+ # An object responding to methods
21
+ # `authenticate_with_http_digest` and
22
+ # `request_http_digest_authentication`.
23
+ # Defaults to nil; if not given, {Digestive::Auth::Service}
24
+ # will expect the methods to be mixed-in, which
25
+ # in the context of Rails, they should be.
26
+ def initialize(credentialed, provider=nil)
27
+ @credentialed = credentialed
28
+ @provider = provider || self
29
+ end
30
+
31
+ # Authenticate, optionally with an authorization strategy.
32
+ # If authentication can't be verified, prompt for credentials.
33
+ # @param [Block] strategy
34
+ # Block accepting one argument (an object returned by
35
+ # @credentialed.find_by_username) and returning a boolean.
36
+ def authenticate(&strategy)
37
+ unless authenticated?(strategy)
38
+ realm = @credentialed::DIGEST_REALM
39
+ @provider.request_http_digest_authentication(realm)
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def authenticated?(strategy=nil)
46
+ realm = @credentialed::DIGEST_REALM
47
+ strategy ||= ->(user) { true }
48
+ user = nil
49
+ @provider.authenticate_with_http_digest(realm) do |username|
50
+ user = @credentialed.find_by_username(username)
51
+ user.nil? ? nil : user.password
52
+ end
53
+ @user = user if strategy.call(user)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative 'auth/service'
4
+
5
+ module Digestive
6
+ module Auth
7
+ # Convenience method to require authentication.
8
+ # If successful, will set the @current_user
9
+ # instance variable of the including object to the
10
+ # authenticated user.
11
+ # @param [Hash] options
12
+ # @option options [Object] credentialed
13
+ # An object responding to constant DIGEST_REALM and
14
+ # method find_by_username.
15
+ # See {Digestive::User}, to which the option defaults.
16
+ # @option options [Object] provider
17
+ # An object responding to methods
18
+ # `authenticate_with_http_digest` and
19
+ # `request_http_digest_authentication`.
20
+ # Defaults to nil; if not given, {Digestive::Auth::Service}
21
+ # will expect the methods to be mixed-in, which
22
+ # in the context of Rails, they should be.
23
+ # @param [Block] strategy
24
+ # A block, accepting a single argument, intended
25
+ # to be the authenticating user, which will
26
+ # return true or false to indicate authorization.
27
+ # @return [Object]
28
+ # The authenticated user, or nil if authentication fails.
29
+ def authenticate(options={}, &strategy)
30
+ credentialed = options[:credentialed] || ::User
31
+ provider = options[:provider]
32
+ service = Service.new(credentialed, provider)
33
+ service.authenticate(&strategy)
34
+ @current_user = service.user
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'digest/md5'
4
+
5
+ module Digestive
6
+ module Credentials
7
+ # Encrypt a given password for comparison with a password
8
+ # given during the authentication process, per
9
+ # {http://tools.ietf.org/html/rfc2069 RFC2069}.
10
+ # @param [String] username
11
+ # User's username
12
+ # @param [String] realm
13
+ # Realm to which the user is authenticating
14
+ # @param [String] password
15
+ # User's password
16
+ # @return [String]
17
+ # A string encrypted per RFC2069
18
+ def encrypt_password(username, realm, password)
19
+ a1 = [username, realm, password].join(':')
20
+ ::Digest::MD5.hexdigest(a1).to_s
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative 'credentials'
4
+
5
+ module Digestive
6
+ # A simple User class which will function with Digestive.
7
+ class User < ::ActiveRecord::Base
8
+ include Credentials
9
+
10
+ # The realm to which the user will authenticate
11
+ DIGEST_REALM = 'user@example.com'
12
+
13
+ validates :username, presence: true, uniqueness: true
14
+ validates :password, presence: true
15
+
16
+ attr_accessible :username, :password
17
+
18
+ before_save :digest_encrypt_password
19
+
20
+ # The JSON representation of a User conceals the password
21
+ def as_json(options={})
22
+ hash = super(options)
23
+ hash['user']['password'] = ''
24
+ hash
25
+ end
26
+
27
+ private
28
+
29
+ # User's password is encrypted before save
30
+ def digest_encrypt_password
31
+ if password_changed? || username_changed?
32
+ self.password = encrypt_password(username, DIGEST_REALM, password)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ module Digestive
2
+ VERSION = "0.0.1"
3
+ end
data/lib/digestive.rb ADDED
@@ -0,0 +1,9 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'digestive/version'
4
+ require 'digestive/user'
5
+ require 'digestive/auth'
6
+ require 'digestive/credentials'
7
+
8
+ module Digestive
9
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative '../../spec_helper'
4
+ require_relative '../../../lib/digestive/auth/service'
5
+
6
+ describe Digestive::Auth::Service do
7
+
8
+ class Provider
9
+ def self.request_http_digest_authentication(realm, message=nil)
10
+ end
11
+ def self.authenticate_with_http_digest(realm, &procedure)
12
+ procedure.call('test')
13
+ end
14
+ end
15
+
16
+ before do
17
+ @service = Digestive::Auth::Service.new(User, Provider)
18
+ end
19
+
20
+ it 'should prompt for authentication if a user is not authenticated' do
21
+ Provider.expects(:request_http_digest_authentication)
22
+ .with(User::DIGEST_REALM)
23
+ @service.stubs(:authenticated?).returns(false)
24
+ @service.authenticate
25
+ end
26
+
27
+ it 'should authenticate a user with http digest' do
28
+ Provider.expects(:authenticate_with_http_digest).with(User::DIGEST_REALM)
29
+ @service.authenticate
30
+ end
31
+
32
+ it 'should return the user if authenticated' do
33
+ @service.authenticate
34
+ @service.user.must_be_instance_of User
35
+ end
36
+
37
+ it 'should use a strategy to authorize a user' do
38
+ @service.authenticate { |u| false }
39
+ @service.user.must_equal nil
40
+ @service.authenticate { |u| true }
41
+ @service.user.must_be_instance_of User
42
+ end
43
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative '../spec_helper'
4
+ require_relative '../../lib/digestive/auth'
5
+ require_relative '../../lib/digestive/user'
6
+
7
+ describe Digestive::Auth do
8
+
9
+ class Authenticatable
10
+ include Digestive::Auth
11
+ attr_reader :current_user
12
+ end
13
+
14
+ before do
15
+ @authenticatable = Authenticatable.new
16
+ end
17
+
18
+ it 'should provide a convenience method' do
19
+ service = Digestive::Auth::Service.new(::User)
20
+ Digestive::Auth::Service.expects(:new).with(::User, nil)
21
+ .returns(service)
22
+ service.expects(:authenticate)
23
+ @authenticatable.authenticate
24
+ end
25
+
26
+ it 'should set the authenticated user' do
27
+ service = Digestive::Auth::Service.new(::User)
28
+ Digestive::Auth::Service.expects(:new).returns(service)
29
+ service.expects(:authenticate)
30
+ service.expects(:user).returns(::User.new)
31
+ @authenticatable.authenticate
32
+ @authenticatable.current_user.must_be_instance_of ::User
33
+ end
34
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative '../spec_helper'
4
+ require_relative '../../lib/digestive/credentials'
5
+
6
+ describe Digestive do
7
+
8
+ class Encryptable
9
+ include Digestive::Credentials
10
+ end
11
+
12
+ before do
13
+ @encryptable = Encryptable.new
14
+ end
15
+
16
+ it 'should encrypt a password for a set of credentials' do
17
+ username = 'test_username'
18
+ realm = 'test_realm'
19
+ password = 'test_password'
20
+ encrypted_password = @encryptable.encrypt_password(username, realm, password)
21
+ a1 = [username, realm, password].join(':')
22
+ sample_password = Digest::MD5.hexdigest(a1).to_s
23
+ encrypted_password.must_equal sample_password
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: UTF-8
2
+
3
+ require_relative '../spec_helper'
4
+ require_relative '../../lib/digestive/user'
5
+
6
+ describe Digestive::User do
7
+
8
+ before do
9
+ @user_attrs = { name: 'Rich', username: 'tea', password: 'hobnob' }
10
+ @user = Digestive::User.new(@user_attrs)
11
+ end
12
+
13
+ it 'should conceal the password in json' do
14
+ json = @user.to_json
15
+ json.wont_match @user_attrs[:password]
16
+ end
17
+
18
+ it 'should digest-encrypt the password on save' do
19
+ a1 = [@user.username, Digestive::User::DIGEST_REALM, @user.password].join(':')
20
+ encrypted_password = Digest::MD5.hexdigest(a1).to_s
21
+ @user.save
22
+ @user.password.must_equal encrypted_password
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: UTF-8
2
+
3
+ gem 'activerecord'
4
+
5
+ require 'active_record'
6
+ require 'minitest/autorun'
7
+ require 'mocha/setup'
8
+
9
+ class User
10
+ DIGEST_REALM = 'test'
11
+ def self.find_by_username(username)
12
+ self.new
13
+ end
14
+ def password
15
+ 'test'
16
+ end
17
+ end
18
+
19
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: 'memory')
20
+
21
+ ActiveRecord::Schema.define do
22
+ self.verbose = false
23
+
24
+ create_table :users, force: true do |t|
25
+ t.string :username
26
+ t.string :password
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,180 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: digestive
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Robert Dallas Gray
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-07-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: m
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 1.3.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.3.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '1.8'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '1.8'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: activerecord
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '3'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '3'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: mocha
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: Simple digest auth with roles
126
+ email:
127
+ - mail@robertdallasgray.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - .gitignore
133
+ - Gemfile
134
+ - Guardfile
135
+ - LICENSE.txt
136
+ - README.md
137
+ - Rakefile
138
+ - digestive.gemspec
139
+ - lib/digestive.rb
140
+ - lib/digestive/auth.rb
141
+ - lib/digestive/auth/service.rb
142
+ - lib/digestive/credentials.rb
143
+ - lib/digestive/user.rb
144
+ - lib/digestive/version.rb
145
+ - spec/digestive/auth/service_spec.rb
146
+ - spec/digestive/auth_spec.rb
147
+ - spec/digestive/credentials_spec.rb
148
+ - spec/digestive/user_spec.rb
149
+ - spec/spec_helper.rb
150
+ homepage: ''
151
+ licenses:
152
+ - MIT
153
+ metadata: {}
154
+ post_install_message:
155
+ rdoc_options: []
156
+ require_paths:
157
+ - lib
158
+ required_ruby_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - '>='
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - '>='
166
+ - !ruby/object:Gem::Version
167
+ version: '0'
168
+ requirements: []
169
+ rubyforge_project:
170
+ rubygems_version: 2.0.2
171
+ signing_key:
172
+ specification_version: 4
173
+ summary: Simple digest auth with roles
174
+ test_files:
175
+ - spec/digestive/auth/service_spec.rb
176
+ - spec/digestive/auth_spec.rb
177
+ - spec/digestive/credentials_spec.rb
178
+ - spec/digestive/user_spec.rb
179
+ - spec/spec_helper.rb
180
+ has_rdoc: