oversip-mod-callsign 0.1.0

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,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NThlYWM3NmQxYWFhNWQ0ODQ2ZmIxZjQ1ODJjOTYwMmExYjIyNjQ3MA==
5
+ data.tar.gz: !binary |-
6
+ M2NkMTVkNjg1OGI1ODM4NDUzZjM2ZmEzOTIzZWFmZTBlYWU3MDU4Zg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ ODIwMGUwNGJkODU1NmIxOTkxMDE5M2NhMTk3ZjYwZGYyN2EwMTVkMjE4NTBl
10
+ MjY2M2U1MjE1MmY5NjZlZGRkMmJlYmJlODM3NGRiZmIzZTY4NTllOTE4Nzc0
11
+ YWE2NTc5MjMzOGYwNzFlNzhhMzRlOTY4ZjQyNDBiOTUwYTQyMjI=
12
+ data.tar.gz: !binary |-
13
+ MjIzNTlhYWMyNzk4NDIzYTVjMWY0NGYxZTJmZWZkYjI0ZjJkMzAxYzQzZWI3
14
+ ZWJlY2U1OTQwYzA3NjA5ZTNmNjU5M2I4ZTgxMzAzZjIxOTgzYzIwMTJiYzMw
15
+ ODZmNGQ3YzQyNjY1YjZlOTE0NDU5YzVmMWM2MDQwMjJkMGEzODI=
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Bandwidth.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ oversip-mod-callsign
2
+ ==========================
3
+
4
+ `oversip-mod-callsign` facilitates authentication and assertion of users that provide a Callsign credential.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'oversip-mod-callsign'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install oversip-mod-callsign
21
+
22
+ ## Usage
23
+ At the top of your `server.rb` file:
24
+
25
+ ```ruby
26
+ require 'oversip-mod-callsign'
27
+ ```
28
+
29
+ ## API
@@ -0,0 +1,65 @@
1
+ require 'em-http-request'
2
+ require 'fiber'
3
+ require 'json'
4
+
5
+ require 'oversip-mod-callsign/token'
6
+ require 'oversip-mod-callsign/token_cache'
7
+ require 'oversip-mod-callsign/client'
8
+
9
+ module OverSIP
10
+ module Modules
11
+ module Callsign
12
+ extend ::OverSIP::Logger
13
+
14
+ @log_id = "Callsign Module"
15
+
16
+ class << self
17
+ def config
18
+ @config ||= {}
19
+ end
20
+
21
+ def configure properties
22
+ %w[
23
+ callsign_client_id callsign_client_secret authorized_callsign_tenants authorized_callsign_scopes
24
+ ].each do |property|
25
+ config[property] = properties[property] || raise(OverSIP::ConfigurationError.new("Missing required Callsign configuration property: #{property}"))
26
+ end
27
+
28
+ @token_cache = TokenCache.new config['callsign_token_ttl']
29
+ @client = Client.new config['callsign_client_id'], config['callsign_client_secret']
30
+ end
31
+
32
+ def token_cache
33
+ @token_cache
34
+ end
35
+
36
+ def assert_callsign_identity(request)
37
+ x_callsign_token = request.header_top 'X-Callsign-Token'
38
+ token = token_cache.get(x_callsign_token) || @client.describe_token(x_callsign_token)
39
+
40
+ return false unless token && authorized_token?(token)
41
+
42
+ sip_identity = token.identity.identifier
43
+
44
+ log_system_debug "user asserted, adding P-Asserted-Identity '#{sip_identity}' for '#{request.log_id}'" if $oversip_debug
45
+ request.set_header 'P-Asserted-Identity', '<' << sip_identity << '>'
46
+
47
+ true
48
+ end
49
+
50
+ def authorized_token?(token)
51
+ token_client_id = token.client_id
52
+ token_scopes = token.scope.split(' ')
53
+
54
+ # (unauthorized) token is not associated with an authorized tenant
55
+ return false unless config['authorized_callsign_tenants'].include? token_client_id
56
+
57
+ # (unauthorized) token was not issued an authorized scope
58
+ return false unless (config['authorized_callsign_scopes'] & token_scopes).size > 0
59
+
60
+ true
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,56 @@
1
+ require 'eventmachine'
2
+ require 'fiber'
3
+ require 'em-http-request'
4
+ require 'base64'
5
+
6
+ require 'oversip-mod-callsign/token'
7
+
8
+ module OverSIP
9
+ module Modules
10
+ module Callsign
11
+ class Client
12
+ def describe_token(access_token)
13
+ url = [
14
+ @base_url,
15
+ 'tokens',
16
+ access_token
17
+ ].join('/')
18
+
19
+ request = if ::Fiber.current != OverSIP.root_fiber
20
+ send_request :get, url
21
+ else
22
+ ::Fiber.new do
23
+ send_request :get, url
24
+ end.resume
25
+ end
26
+
27
+ status = request.response_header.status
28
+ if status == 200
29
+ Token.from_json request.response
30
+ else
31
+ log_info request.response
32
+ nil
33
+ end
34
+ end
35
+
36
+ def initialize client_id, client_secret
37
+ @base_url = 'https://callsign.bwincubator.com/v1'
38
+ @client_id = client_id
39
+ @client_secret = client_secret
40
+ end
41
+
42
+ private
43
+
44
+ def send_request(method, url)
45
+ fiber = Fiber.current
46
+ credentials = Base64.strict_encode64 [@client_id, @client_secret].join(':')
47
+ http = EventMachine::HttpRequest.new(url).__send__ method.to_sym, :head => { 'Authorization' => ['Basic', credentials].join(' ') }
48
+ http.callback { fiber.resume(http) }
49
+ http.errback { fiber.resume(http) }
50
+
51
+ Fiber.yield
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,21 @@
1
+ module OverSIP
2
+ module Modules
3
+ module Callsign
4
+ class Identity
5
+ attr_accessor :identifier
6
+ attr_accessor :type
7
+
8
+ def initialize(identifier, type)
9
+ @identifier = identifier
10
+ @type = type
11
+ end
12
+
13
+ def self.parse(input)
14
+ result, identifier, type = /^(.*):(\w+)$/.match(input).to_a.flatten
15
+ raise("Unable to parse identity: #{input}") if result.nil?
16
+ Identity.new identifier, type
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,38 @@
1
+ require 'json'
2
+
3
+ require 'oversip-mod-callsign/identity'
4
+
5
+ module OverSIP
6
+ module Modules
7
+ module Callsign
8
+ class Token
9
+ attr_accessor :access_token
10
+ attr_accessor :client_id
11
+ attr_accessor :identity
12
+ attr_accessor :scope
13
+ attr_accessor :revision
14
+ attr_accessor :expires_in
15
+ attr_accessor :token_type
16
+
17
+ def scopes
18
+ @scopes ||= @scope.split ' '
19
+ end
20
+
21
+ def initialize(access_token, client_id, identity, scope, revision, expires_in, token_type)
22
+ @access_token = access_token
23
+ @client_id = client_id
24
+ @identity = Identity.parse identity
25
+ @scope = scope
26
+ @revision = revision
27
+ @expires_in = expires_in
28
+ @token_type = token_type
29
+ end
30
+
31
+ def self.from_json(json_string)
32
+ json = JSON.parse(json_string)
33
+ Token.new json['access_token'], json['client_id'], json['identity'], json['scope'], json['revision'], json['expires_in'], json['token_type']
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,23 @@
1
+ require 'eventmachine'
2
+
3
+ module OverSIP
4
+ module Modules
5
+ module Callsign
6
+ class TokenCache
7
+ def get(token)
8
+ @cache[token]
9
+ end
10
+
11
+ def set(token, data)
12
+ @cache[token] = data
13
+ EventMachine.add_timer(@token_ttl) { @cache.delete(token) }
14
+ end
15
+
16
+ def initialize(token_ttl=10)
17
+ @cache = {}
18
+ @token_ttl = token_ttl
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ module OverSIP
2
+ module Modules
3
+ module Callsign
4
+ VERSION = '0.1.0'
5
+ end
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oversip-mod-callsign
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tyler Cross
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 3.0.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.0
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: oversip
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.3.7
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.3.7
55
+ - !ruby/object:Gem::Dependency
56
+ name: em-http-request
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.1.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.1.2
69
+ description:
70
+ email:
71
+ - tcross@bandwidth.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - LICENSE
77
+ - README.md
78
+ - lib/oversip-mod-callsign.rb
79
+ - lib/oversip-mod-callsign/client.rb
80
+ - lib/oversip-mod-callsign/identity.rb
81
+ - lib/oversip-mod-callsign/token.rb
82
+ - lib/oversip-mod-callsign/token_cache.rb
83
+ - lib/oversip-mod-callsign/version.rb
84
+ homepage: https://github.com/inetCatapult/oversip-mod-callsign.
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: 1.9.3
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.4.3
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Callsign user assertion for OverSIP
108
+ test_files: []