sip_digest_auth 0.0.2
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 +15 -0
- data/.gitignore +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +7 -0
- data/lib/sip_digest_auth.rb +38 -0
- data/lib/sip_digest_auth/session.rb +35 -0
- data/lib/sip_digest_auth/util.rb +18 -0
- data/lib/sip_digest_auth/version.rb +3 -0
- data/sip_digest_auth.gemspec +26 -0
- data/test/sip_digest_auth/session_spec.rb +74 -0
- data/test/sip_digest_auth/util_spec.rb +30 -0
- data/test/sip_digest_auth_spec.rb +30 -0
- data/test/spec_helper.rb +2 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZTY0YjU1NTExNzI0ZTA2NjBmZDFkZjI3NmRmZjYyOTQ1MjY0NWUxNw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZTMzNDY4MjIxYzhmYjZlZTA2MzY2YjcyMzM3NmQ2ZjgxOTkzNDVlMw==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
NjU0YjljMjUyYjFmNTk0OWJkODY5YjNiMjc0MTViMzIzOGM1MWFkOGZjOTVm
|
10
|
+
MDYzNDA4NjY3MjI5NzJhM2ZhNWQ3MTYzYWVlNWU0YzBhMzAxOTViMTY1NmJh
|
11
|
+
ZTIzM2M5NTE1NzNmNmQ4NzNkOGNlNTQ5MWM5NDYwMWQ2YmVmM2Y=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZDIwOTNhODdhYTFiZGY2MTlkYjhjNjVhYWU2Y2Q0MGU3MTdjMTgzYzhlZGM2
|
14
|
+
Y2JiYmI3MzAxMTQwZTMwYWJmMWE3YmFjZjM5YjE3MWIxM2JkNzc4MjhjZGVj
|
15
|
+
MGJlZTE4OTZkMGMwZjVkNWJkNTRlNTVmODdjNDAyOGFhYjIwOGQ=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Daniel Jabbour
|
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,29 @@
|
|
1
|
+
# SipDigestAuth
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'sip_digest_auth'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install sip_digest_auth
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'sip_digest_auth/util'
|
2
|
+
require 'sip_digest_auth/session'
|
3
|
+
require 'sip_digest_auth/version'
|
4
|
+
|
5
|
+
module SipDigestAuth
|
6
|
+
extend self
|
7
|
+
|
8
|
+
def challenge(session)
|
9
|
+
header_name = session.proxy ? 'proxy-authenticate' : 'www-authenticate'
|
10
|
+
|
11
|
+
header_values = [
|
12
|
+
"Digest",
|
13
|
+
"realm: #{q(session.realm)}",
|
14
|
+
"qop: #{q(session.qop)}",
|
15
|
+
"algorithm: #{q(session.algorithm)}",
|
16
|
+
"nonce: #{q(session.nonce)}",
|
17
|
+
"opaque: #{q(session.opaque)}"
|
18
|
+
]
|
19
|
+
|
20
|
+
[header_name, header_values.join(', ')]
|
21
|
+
end
|
22
|
+
|
23
|
+
# Credentials are optional if the session is established. When specified, it is a hash containing
|
24
|
+
# either :user & :password OR the key :hash. Required on the first call to cache h1 in session.
|
25
|
+
def authenticate_request(session, request, credentials=nil)
|
26
|
+
#TODO: Implement
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def q(str)
|
32
|
+
if str && str[0] != '"'
|
33
|
+
str = "\"#{str}\""
|
34
|
+
end
|
35
|
+
str
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'hashie/dash'
|
2
|
+
|
3
|
+
module SipDigestAuth
|
4
|
+
class Session < ::Hashie::Dash
|
5
|
+
# Realm *must* be set, and is the only required field when creating a session for the first time
|
6
|
+
property :realm, required: true
|
7
|
+
|
8
|
+
# The nonce should stay the same for a single session, and will be generated if not provided on
|
9
|
+
# initialization. Subsequent requests within the same session should ensure nonce is set
|
10
|
+
property :nonce, default: Util.generate_nonce
|
11
|
+
|
12
|
+
# Opaque doesn't seem to be mandated and I'm a little confused as to why it's necessary with a
|
13
|
+
# nonce. Rfc2617 specifies: "A string of data, specified by the server, which should be returned
|
14
|
+
# by the client unchanged in the Authorization header of subsequent requests with URIs in the
|
15
|
+
# same protection space." In this case, I'm going to leave it up to the caller to specify it.
|
16
|
+
property :opaque, default: ''
|
17
|
+
|
18
|
+
# The ha1 is generated during authentication. HA1 = MD5(username:realm:password)
|
19
|
+
property :ha1
|
20
|
+
|
21
|
+
# When true, assume a proxy of some kind to an upstream SIP provider. This has subtle effects on
|
22
|
+
# how authentication takes place (for example, changing the name of the challenge headers)
|
23
|
+
property :proxy, default: false
|
24
|
+
|
25
|
+
# These are internal and probably not going to change, but it's possible to build more support
|
26
|
+
# into the library later, and they really belong in the session:
|
27
|
+
property :qop, default: 'auth,auth-int'
|
28
|
+
property :algorithm, default: 'md5'
|
29
|
+
property :nc, default: 0
|
30
|
+
|
31
|
+
def increment_nc!
|
32
|
+
self.nc = self.nc + 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module SipDigestAuth
|
4
|
+
# Utility functions for our library
|
5
|
+
module Util
|
6
|
+
extend self
|
7
|
+
|
8
|
+
# args is an array of crap
|
9
|
+
def create_digest(*args)
|
10
|
+
::Digest::MD5.hexdigest(args.join(":"))
|
11
|
+
end
|
12
|
+
|
13
|
+
def generate_nonce(secret_key = rand.to_s, time = Time.now)
|
14
|
+
t = time.to_i
|
15
|
+
create_digest(t, secret_key)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sip_digest_auth/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "sip_digest_auth"
|
8
|
+
spec.version = SipDigestAuth::VERSION
|
9
|
+
spec.authors = ["Daniel Jabbour"]
|
10
|
+
spec.email = ["sayhi@amoe.ba"]
|
11
|
+
spec.description = "Implementation of SIP Digest Authentication as specified in RFC3261"
|
12
|
+
spec.summary = "This gem is to be used with a SIP server to implement Digest Authentication, like HTTP authentication (specified in RFC2617)"
|
13
|
+
spec.homepage = "http://github.com/AmoebaLabs/sip_digest_auth"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "hashie"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.2.0"
|
26
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SipDigestAuth::Session do
|
4
|
+
before do
|
5
|
+
@session = SipDigestAuth::Session.new(realm: "test")
|
6
|
+
end
|
7
|
+
|
8
|
+
it "lets you pass all arguments on initializer" do
|
9
|
+
session = SipDigestAuth::Session.new({
|
10
|
+
realm: 'test',
|
11
|
+
nonce: 'test',
|
12
|
+
opaque: 'test',
|
13
|
+
ha1: 'test',
|
14
|
+
proxy: true
|
15
|
+
})
|
16
|
+
|
17
|
+
%w(realm nonce opaque ha1).each do |field|
|
18
|
+
session.send(field).must_equal 'test'
|
19
|
+
end
|
20
|
+
session.proxy.must_equal true
|
21
|
+
end
|
22
|
+
|
23
|
+
it "requires a realm" do
|
24
|
+
proc {
|
25
|
+
session = SipDigestAuth::Session.new
|
26
|
+
}.must_raise ArgumentError
|
27
|
+
end
|
28
|
+
|
29
|
+
it "has a nonce by default" do
|
30
|
+
@session.nonce.wont_be_empty
|
31
|
+
end
|
32
|
+
|
33
|
+
it "has a blank opaque by default" do
|
34
|
+
@session.opaque.must_be_empty
|
35
|
+
end
|
36
|
+
|
37
|
+
it "has no default ha1" do
|
38
|
+
@session.ha1.must_be_nil
|
39
|
+
end
|
40
|
+
|
41
|
+
it "lets you set a ha1" do
|
42
|
+
@session.ha1 = "test"
|
43
|
+
@session.ha1.must_equal "test"
|
44
|
+
end
|
45
|
+
|
46
|
+
it "defaults to no proxy mode" do
|
47
|
+
@session.proxy.must_equal false
|
48
|
+
end
|
49
|
+
|
50
|
+
it "lets you set the proxy" do
|
51
|
+
@session.proxy = true
|
52
|
+
@session.proxy.must_equal true
|
53
|
+
end
|
54
|
+
|
55
|
+
it "deafults qop properly" do
|
56
|
+
@session.qop.must_equal 'auth,auth-int'
|
57
|
+
end
|
58
|
+
|
59
|
+
it "defaults algorithm property" do
|
60
|
+
@session.algorithm.must_equal 'md5'
|
61
|
+
end
|
62
|
+
|
63
|
+
it "has a nc of 0 by default" do
|
64
|
+
@session.nc.must_equal 0
|
65
|
+
end
|
66
|
+
|
67
|
+
it "can increment nc" do
|
68
|
+
nc = @session.nc
|
69
|
+
@session.increment_nc!
|
70
|
+
@session.nc.must_equal nc+1
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
describe SipDigestAuth::Util do
|
6
|
+
describe "#create_digest" do
|
7
|
+
it "can make a digest with arguments" do
|
8
|
+
args = ['1', '2']
|
9
|
+
SipDigestAuth::Util.create_digest(*args).must_equal ::Digest::MD5.hexdigest(args.join(":"))
|
10
|
+
end
|
11
|
+
|
12
|
+
it "can make a digest with an array" do
|
13
|
+
args = ['1', '2']
|
14
|
+
SipDigestAuth::Util.create_digest(args).must_equal ::Digest::MD5.hexdigest(args.join(":"))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#generate_nonce" do
|
19
|
+
it "generates a 32 character string" do
|
20
|
+
SipDigestAuth::Util.generate_nonce.length.must_equal 32
|
21
|
+
end
|
22
|
+
|
23
|
+
it "lets you specify the secret_key and time" do
|
24
|
+
time = Time.now
|
25
|
+
nonce = SipDigestAuth::Util.generate_nonce("secret", time)
|
26
|
+
nonce.must_equal SipDigestAuth::Util.create_digest(time.to_i, "secret")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SipDigestAuth do
|
4
|
+
describe "#challenge" do
|
5
|
+
before do
|
6
|
+
@session = SipDigestAuth::Session.new(realm: 'test', qop: 'test', algorithm: 'test', nonce: 'test', opaque: '')
|
7
|
+
end
|
8
|
+
|
9
|
+
it "returns proxy-authenticate when session.proxy" do
|
10
|
+
@session.proxy = true
|
11
|
+
SipDigestAuth.challenge(@session)[0].must_equal 'proxy-authenticate'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "returns www-authenticate when not session.proxy" do
|
15
|
+
@session.proxy = false
|
16
|
+
SipDigestAuth.challenge(@session)[0].must_equal 'www-authenticate'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "contains the accurate session values in its return header" do
|
20
|
+
SipDigestAuth.challenge(@session)[1].must_equal [
|
21
|
+
'Digest',
|
22
|
+
"realm: \"#{@session.realm}\"",
|
23
|
+
"qop: \"#{@session.qop}\"",
|
24
|
+
"algorithm: \"#{@session.algorithm}\"",
|
25
|
+
"nonce: \"#{@session.nonce}\"",
|
26
|
+
"opaque: \"#{@session.opaque}\""
|
27
|
+
].join(', ')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/test/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sip_digest_auth
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Jabbour
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: hashie
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 5.2.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 5.2.0
|
69
|
+
description: Implementation of SIP Digest Authentication as specified in RFC3261
|
70
|
+
email:
|
71
|
+
- sayhi@amoe.ba
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lib/sip_digest_auth.rb
|
82
|
+
- lib/sip_digest_auth/session.rb
|
83
|
+
- lib/sip_digest_auth/util.rb
|
84
|
+
- lib/sip_digest_auth/version.rb
|
85
|
+
- sip_digest_auth.gemspec
|
86
|
+
- test/sip_digest_auth/session_spec.rb
|
87
|
+
- test/sip_digest_auth/util_spec.rb
|
88
|
+
- test/sip_digest_auth_spec.rb
|
89
|
+
- test/spec_helper.rb
|
90
|
+
homepage: http://github.com/AmoebaLabs/sip_digest_auth
|
91
|
+
licenses:
|
92
|
+
- MIT
|
93
|
+
metadata: {}
|
94
|
+
post_install_message:
|
95
|
+
rdoc_options: []
|
96
|
+
require_paths:
|
97
|
+
- lib
|
98
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ! '>='
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: '0'
|
108
|
+
requirements: []
|
109
|
+
rubyforge_project:
|
110
|
+
rubygems_version: 2.2.1
|
111
|
+
signing_key:
|
112
|
+
specification_version: 4
|
113
|
+
summary: This gem is to be used with a SIP server to implement Digest Authentication,
|
114
|
+
like HTTP authentication (specified in RFC2617)
|
115
|
+
test_files:
|
116
|
+
- test/sip_digest_auth/session_spec.rb
|
117
|
+
- test/sip_digest_auth/util_spec.rb
|
118
|
+
- test/sip_digest_auth_spec.rb
|
119
|
+
- test/spec_helper.rb
|