desviar 0.0.15 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,20 +2,31 @@
2
2
 
3
3
  This is a Ruby-based app server built on Sinatra to create
4
4
  preauthorized time-limited, random URIs used in devops deployment
5
- scripts or in web applications such as confirmation emails.
5
+ scripts or in web applications such as confirmation emails. Your
6
+ scenario is that you have a database, repository or webserver
7
+ (possibly behind a firewall) that needs to stay both hidden and
8
+ secure, but you need to provide a means for a script to invoke an API
9
+ call or for a remote user to click a direct link to fetch a specific
10
+ item from its hidden source without presenting credentials.
6
11
 
7
12
  It operates similarly to TinyURL or the Amazon S3 temporary-URI
8
- feature: provide the tool with the URI to an existing secure resource,
9
- specify a number of seconds you want to authorize references to it,
10
- and you'll get back a temporary URI good for that amount of time.
11
-
12
- You can set it up on a DMZ network or in the cloud behind an
13
+ feature: provide the tool with the URI and credentials to an existing
14
+ secure resource, specify a number of seconds you want to authorize
15
+ references to it, and you'll get back a temporary URI good for that
16
+ amount of time. An analogy is the inexpensive key-card issued by a
17
+ hotel's desk clerk: to access secure content in the room, you first
18
+ need to present your credit-card credentials; your room key is all you
19
+ need thereafter, at least until the key expires. The hotel remains
20
+ secure even if you keep the key after checkout.
21
+
22
+ You can set up desviar on a DMZ network or in the cloud behind an
13
23
  iptables/nginx configuration to provide whatever ACL restrictions you
14
24
  want, and you can reference any source URI (not just those stored on
15
- S3).
25
+ S3 or an equivalent service).
16
26
 
17
- Secure content is cached in memory (sqlite3) by default; for
18
- troubleshooting, you can store content in a file.
27
+ Secure content is encrypted and cached in memory (sqlite3) by default;
28
+ for troubleshooting, you can store content in a file and/or turn off
29
+ encryption.
19
30
 
20
31
  #### Installation ####
21
32
 
@@ -27,7 +38,7 @@ Clone this repo and perform the following:
27
38
  git clone https://github.com/instantlinux/desviar.git
28
39
  cd desviar
29
40
  cp config/config.rb.example config/config.rb
30
- sudo apt-get install -y make libsqlite3-dev ruby-dev
41
+ sudo apt-get install -y make g++ libsqlite3-dev ruby-dev
31
42
  # package names above may differ if not using Ubuntu
32
43
  sudo gem install bundler
33
44
  sudo bundle install
@@ -35,9 +46,9 @@ Clone this repo and perform the following:
35
46
  rackup -p 4567
36
47
 
37
48
  ##### From rubygems.org #####
38
- Invoke the following:
49
+ [![Gem Version](https://badge.fury.io/rb/desviar.png)](http://badge.fury.io/rb/desviar) Invoke the following:
39
50
 
40
- sudo apt-get install -y make libsqlite3-dev ruby-dev
51
+ sudo apt-get install -y make g++ libsqlite3-dev ruby-dev
41
52
  sudo gem install desviar
42
53
  wget https://raw.github.com/instantlinux/desviar/master/config.ru
43
54
  wget https://raw.github.com/instantlinux/desviar/master/config/config.rb.example
@@ -47,7 +58,7 @@ Invoke the following:
47
58
 
48
59
  #### Usage ####
49
60
 
50
- Default credential of [app](http://localhost:4567) is user _desviar_, pw _password_.
61
+ In your browser, the [app](http://localhost:4567)'s default credential upon installation is user _desviar_, pw _password_.
51
62
 
52
63
  Commands:
53
64
  * /create - generate a new pre-authenticated URI
@@ -56,19 +67,14 @@ Commands:
56
67
  * /link/nnn - retrieve details
57
68
  * /config - set runtime configuration
58
69
 
59
- For scripting, the list, link and config commands can be modified with a _/json_ suffix (e.g. _/config/json_) to generate json instead of html output.
60
-
61
- Here's an example of creating a new link via _curl_:
62
-
63
- curl --digest --user desviar:password http://localhost:4567/create \
64
- --data "redir_uri=http://localhost/test&expiration=1800&captcha=1&notes=testing"
70
+ For scripting, the list, link and config commands can be modified with a _/json_ suffix (e.g. _/config/json_) to generate json instead of html output. Script examples for Ruby and bash are provided in the [examples directory](https://github.com/instantlinux/desviar/tree/master/examples).
65
71
 
66
72
  Security notes:
67
73
  Consider moving the default database location from /dev/shm/desviar, and set its permissions to 0600. You can modify config.ru to direct log output to a different file.
68
74
 
69
75
  #### Features implemented ####
70
76
 
71
- - [x] HTTP digest authentication for user interface
77
+ - [x] HTTP digest authentication for client API and user interface
72
78
  - [ ] Parse htpasswd files to support multiple credentials
73
79
  - [x] Bypass authentication for generated URIs
74
80
  - [x] Basic HTTP authentication for remote URIs
@@ -38,6 +38,7 @@ Gem::Specification.new do |spec|
38
38
  spec.add_dependency "dm-timestamps", ">= 1.2"
39
39
  spec.add_dependency "dm-validations", ">= 1.2"
40
40
  spec.add_dependency "multi_json", ">= 1.7"
41
+ spec.add_dependency "net-http-digest_auth", ">= 1.4"
41
42
  spec.add_dependency "rack-recaptcha", ">= 0.6"
42
43
  spec.add_dependency "rack-test", ">= 0.6"
43
44
  spec.add_dependency "sinatra", ">= 1.4"
@@ -0,0 +1,44 @@
1
+ #!/bin/bash
2
+ # API examples - Desviar::Client
3
+ #
4
+ # Created 1 Aug 2013
5
+ #
6
+ # Copyright 2013 Richard Braun
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+
14
+ # Usage:
15
+ # Start the server first (rackup -p 4567)
16
+ # Adjust credentials below if you've modified the server
17
+ # Invoke this program ./bash-client.sh
18
+
19
+ echo "========= Desviar::Client config =========="
20
+ curl --digest --user desviar:password -q http://localhost:4567/config/json
21
+ echo
22
+ echo "========= Desviar::Client create =========="
23
+ # In this example, create an item valid for 5 seconds and another valid for
24
+ # 10 minutes to demonstrate cleanup after 6 seconds. The notes field is
25
+ # an arbitrary payload which can be used for whatever tracking purposes
26
+ # your application requires.
27
+ id=`curl -q --digest --user desviar:password http://localhost:4567/create \
28
+ --data "redir_uri=https://rubygems.org/gems/desviar&expiration=5&captcha=1&notes=tracking-item" \
29
+ --location |grep ID:|egrep -o [0-9]+`
30
+ curl --digest --user desviar:password -q http://localhost:4567/link/json/$id
31
+ echo
32
+ id=`curl -q --digest --user desviar:password http://localhost:4567/create \
33
+ --data "redir_uri=https://rubygems.org/gems/desviar&expiration=600&notes=item%202" \
34
+ --location |grep ID:|egrep -o [0-9]+`
35
+ curl --digest --user desviar:password -q http://localhost:4567/link/json/$id
36
+ echo
37
+ echo "========= Desviar::Client list ============"
38
+ curl --digest --user desviar:password -q http://localhost:4567/list/json
39
+ echo
40
+ echo "========= Desviar::Client clean ============"
41
+ sleep 6
42
+ curl --digest --user desviar:password -q http://localhost:4567/clean
43
+ curl --digest --user desviar:password -q http://localhost:4567/list/json
44
+ echo
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env ruby
2
+ # API examples - Desviar::Client
3
+ #
4
+ # Created 1 Aug 2013
5
+ #
6
+ # Copyright 2013 Richard Braun
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+
14
+ # Usage:
15
+ # Start the server first (rackup -p 4567)
16
+ # Adjust credentials below if you've modified the server
17
+ # Invoke this program ./ruby-client.rb
18
+
19
+ require 'desviar/client'
20
+ require 'pp'
21
+
22
+ obj = Desviar::Client.new 'desviar', 'password'
23
+ puts "Starting Desviar::Client for server #{obj.server_uri} as user #{obj.user_name}"
24
+
25
+ puts "========= Desviar::Client config =========="
26
+ puts "dbencrypt is #{obj.config_item 'dbencrypt'}"
27
+ puts "debug is #{obj.config_item :debug}"
28
+ puts "Full config hash is:"
29
+ pp obj.config
30
+
31
+ puts "========= Desviar::Client create =========="
32
+ # Can specify option names using symbols/strings; values must be strings
33
+
34
+ # The notes field is an arbitrary payload which can be used for
35
+ # whatever tracking purposes your application requires.
36
+
37
+ # Example 1: create an item valid for 5 seconds to demonstrate
38
+ # cleanup after 6 seconds. Fetch will invoke captcha (get credentials
39
+ # from Google for a "real" test)
40
+ link = obj.create "https://rubygems.org/gems/desviar", 5, {
41
+ :captcha => 1.to_s,
42
+ "notes" => "tracking-item" }
43
+ puts link['temp_uri'].inspect
44
+ puts obj.fetch link['temp_uri']
45
+
46
+ # Example 2: same as #1 except without captcha
47
+ link = obj.create "https://rubygems.org/gems/desviar", 5, {
48
+ "notes" => "tracking example 2" }
49
+ puts link['temp_uri'].inspect
50
+ puts obj.fetch link['temp_uri']
51
+
52
+ # Example 3: valid for 10 minutes
53
+ pp obj.create "https://rubygems.org/gems/desviar", 600, {
54
+ "notes" => "example 3" }
55
+
56
+ puts "========= Desviar::Client list ============"
57
+ pp obj.list
58
+ begin
59
+ pp obj.list_item 999
60
+ rescue ArgumentError
61
+ puts "Handling expected error for item 999"
62
+ end
63
+
64
+ puts "========= Desviar::Client clean ============"
65
+ sleep 6
66
+ obj.clean
67
+ pp obj.list
@@ -3,7 +3,8 @@ require 'webrick/httpauth/htpasswd'
3
3
  module Desviar::Auth
4
4
 
5
5
  def self.htpasswd
6
- @htpasswd ||= Htpasswd.new(git.path_to("htpasswd"))
6
+ # @htpasswd ||= Htpasswd.new(git.path_to("htpasswd"))
7
+ @htpasswd ||= Htpasswd.new('.htpasswd')
7
8
  end
8
9
 
9
10
  def self.authentication
@@ -26,7 +27,8 @@ module Desviar::Auth
26
27
  end
27
28
  end
28
29
 
29
- def self.unauthorized!(realm = Desviar::info)
30
+ # def self.unauthorized!(realm = Desviar::info)
31
+ def self.unauthorized!(realm = 'desviar-realm')
30
32
  headers "WWW-Authenticate" => %(Basic realm="#{realm}")
31
33
  throw :halt, [ 401, "Authorization Required" ]
32
34
  end
@@ -75,8 +75,17 @@ module Desviar
75
75
  http.use_ssl = params[:redir_uri].index('https') == 0
76
76
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
77
77
  req = Net::HTTP::Get.new(object.request_uri)
78
- req.basic_auth params[:remoteuser], params[:remotepw] if params[:remoteuser] != ''
79
- response = http.request(req)
78
+ if params[:remoteuser] != ''
79
+ req.basic_auth params[:remoteuser], params[:remotepw]
80
+ end
81
+ begin
82
+ response = http.request(req)
83
+ rescue Errno::ECONNREFUSED
84
+ error 401
85
+ end
86
+ if response.code.to_i != 200
87
+ error response.code.to_i
88
+ end
80
89
  if !$config[:dbencrypt]
81
90
  @desviar[:content] = response.body[0, $config[:contentmax]]
82
91
  else
@@ -204,6 +213,7 @@ module Desviar
204
213
  def self.new(*)
205
214
  # TODO: htpasswd parsing
206
215
  # Desviar::Auth::authenticate!
216
+ # @auth.call()
207
217
  app = Rack::Auth::Digest::MD5.new(super) do |username|
208
218
  {$config[:adminuser] => $config[:adminpw]}[username]
209
219
  end
@@ -212,6 +222,22 @@ module Desviar
212
222
  app
213
223
  end
214
224
 
225
+ =begin
226
+ class Mytest
227
+ def initialize(app)
228
+ # Desviar::Public::log "Initializing auth from .htpasswd"
229
+ @obj = Rack::Auth::Basic.new(app) do |username, password|
230
+ unless File.exist?('../config/.htpasswd')
231
+ raise PasswordFileNotFound.new("#{file} is not found. Please create it with htpasswd")
232
+ end
233
+ htpasswd = WEBrick::HTTPAuth::Htpasswd.new(file)
234
+ crypted = htpasswd.get_passwd(nil, user, false)
235
+ crypted == pass.crypt(crypted) if crypted
236
+ end
237
+ end
238
+ end
239
+ =end
240
+
215
241
  end
216
242
 
217
243
  #############################################
@@ -0,0 +1,134 @@
1
+ # Client functions for Desviar main object
2
+ #
3
+ # Copyright 2013 Richard Braun
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ require 'json'
12
+ require 'uri'
13
+ require 'net/http'
14
+ require 'net/http/digest_auth'
15
+
16
+ module Desviar
17
+ class Client
18
+ ##
19
+ # Client functions for Desviar main object
20
+
21
+ # Create new client
22
+ def initialize(user_name, private_key, server_uri = 'http://localhost:4567')
23
+ @server_uri = server_uri
24
+ @user_name = user_name
25
+ @private_key = private_key
26
+ end
27
+
28
+ # Return server's URI
29
+ def server_uri()
30
+ @server_uri
31
+ end
32
+
33
+ # Return username
34
+ def user_name()
35
+ @user_name
36
+ end
37
+
38
+ # Fetch configuration (as a hash)
39
+ def config
40
+ JSON.parse get("config/json")
41
+ end
42
+
43
+ # Fetch a single configuration item
44
+ def config_item(item)
45
+ cfg = JSON.parse get("config/json")
46
+ raise ArgumentError, "Invalid item #{item}" if !cfg.has_key?(item.to_s)
47
+ cfg[item.to_s]
48
+ end
49
+
50
+ # Fetch list of stored redirects
51
+ def list
52
+ JSON.parse get("list/json")
53
+ end
54
+
55
+ # Fetch meta information about a particular redirect
56
+ def list_item(id)
57
+ JSON.parse get("link/json/#{id}")
58
+ end
59
+
60
+ # Clean out expired entries
61
+ def clean
62
+ get("clean")
63
+ end
64
+
65
+ # Create a new redirect
66
+ def create(uri, expiration = 900, opts = {})
67
+ opts[:captcha_button] = "Proceed" if !opts.has_key?(:captcha_button) && !opts.has_key?("captcha_button")
68
+ newlink = post("create", { :redir_uri => uri, :expiration => expiration.to_s }.merge(opts))
69
+ JSON.parse get("link/json/#{newlink.split('/').last}")
70
+ end
71
+
72
+ # Fetch content
73
+ def fetch(temp_uri)
74
+ get("desviar/#{temp_uri}", false)
75
+ end
76
+
77
+ private
78
+
79
+ # Internal function: raw, digest-authenticated HTTP get from server
80
+ def get(path, need_auth = true)
81
+ uri = URI.parse "#{@server_uri}/#{path}"
82
+ uri.user = @user_name
83
+ uri.password = @private_key
84
+
85
+ http = Net::HTTP.new uri.host, uri.port
86
+ http.use_ssl = @server_uri.index('https') == 0
87
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
88
+ req = Net::HTTP::Get.new uri.request_uri
89
+ response = http.request req
90
+ if need_auth
91
+ auth = Net::HTTP::DigestAuth.new.auth_header(
92
+ uri, response['www-authenticate'], 'GET')
93
+ req = Net::HTTP::Get.new uri.request_uri
94
+ req.add_field 'Authorization', auth
95
+ response = http.request req
96
+ end
97
+ case response.code.to_i
98
+ when 200
99
+ response.body
100
+ when 301..302
101
+ response.response['Location']
102
+ else
103
+ raise ArgumentError, "#{path} return status #{response.code}"
104
+ end
105
+ end
106
+
107
+ # Internal function: HTTP post
108
+ def post(path, params)
109
+ uri = URI.parse "#{@server_uri}/#{path}"
110
+ uri.user = @user_name
111
+ uri.password = @private_key
112
+
113
+ http = Net::HTTP.new uri.host, uri.port
114
+ http.use_ssl = @server_uri.index('https') == 0
115
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
116
+ req = Net::HTTP::Get.new uri.request_uri
117
+ response = http.request req
118
+ auth = Net::HTTP::DigestAuth.new.auth_header(
119
+ uri, response['www-authenticate'], 'POST')
120
+ req = Net::HTTP::Post.new uri.request_uri
121
+ req.add_field 'Authorization', auth
122
+ req.set_form_data params
123
+ response = http.request req
124
+ case response.code.to_i
125
+ when 200
126
+ response.body
127
+ when 303
128
+ response.response['Location']
129
+ else
130
+ raise ArgumentError, "#{path} return status #{response.code}"
131
+ end
132
+ end
133
+ end
134
+ end
@@ -10,6 +10,9 @@
10
10
 
11
11
  module Desviar
12
12
  module Model
13
+ ##
14
+ # Data model for Desviar main object
15
+
13
16
  class Main
14
17
  include DataMapper::Resource
15
18
 
Binary file
@@ -1,7 +1,7 @@
1
1
  module Desviar
2
- VERSION = "0.0.15"
3
- RELEASE = "2013-07-30"
4
- TIMESTAMP = "2013-07-29 08:27:33 -07:00"
2
+ VERSION = "0.0.16"
3
+ RELEASE = "2013-08-03"
4
+ TIMESTAMP = "2013-08-03 09:12:27 -07:00"
5
5
 
6
6
  def self.info
7
7
  "#{name} v#{VERSION} (#{RELEASE})"
@@ -1,13 +1,14 @@
1
1
  <div class="desviar">
2
2
  <a href="/desviar/<%= @desviar.temp_uri[0, @desviar.temp_uri.length - $config[:urisuffix].length] %>">
3
- https:<%= settings.bind %>:<%= settings.port %>/desviar/<%= @desviar.temp_uri[0, @desviar.temp_uri.length - $config[:urisuffix].length] %></a><br><hr>
3
+ http://<%= settings.bind %>:<%= settings.port %>/desviar/<%= @desviar.temp_uri[0, @desviar.temp_uri.length - $config[:urisuffix].length] %></a><br><hr>
4
4
  <h2><a href="<%= @desviar.redir_uri %>"><%= @desviar.redir_uri %></a></h2>
5
5
  <div class="sbody" id="box">
6
6
  <%= @desviar.formatted_notes %>
7
7
  </div>
8
8
  <div class="sdate">
9
- Created <%= @desviar.created_at.strftime("%D at %T %Z") %> <%= ENV['REMOTE_USER'] %><br>
10
- Expires <%= @desviar.expires_at.strftime("%D at %T %Z") %>
9
+ Created <%= @desviar.created_at.strftime("%D at %T %Z") %><br>
10
+ Expires <%= @desviar.expires_at.strftime("%D at %T %Z") %><br>
11
+ ID: <%= @desviar.id %>
11
12
  <%= @desviar.captcha ? "<br>CAPTCHA is required" : "" %>
12
13
  </div>
13
14
  <hr>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: desviar
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.15
4
+ version: 0.0.16
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-30 00:00:00.000000000 Z
12
+ date: 2013-08-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: dm-core
@@ -107,6 +107,22 @@ dependencies:
107
107
  - - ! '>='
108
108
  - !ruby/object:Gem::Version
109
109
  version: '1.7'
110
+ - !ruby/object:Gem::Dependency
111
+ name: net-http-digest_auth
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '1.4'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '1.4'
110
126
  - !ruby/object:Gem::Dependency
111
127
  name: rack-recaptcha
112
128
  requirement: !ruby/object:Gem::Requirement
@@ -222,9 +238,12 @@ files:
222
238
  - config.ru
223
239
  - config/config.rb.example
224
240
  - desviar.gemspec
241
+ - examples/bash-client.sh
242
+ - examples/ruby-client.rb
225
243
  - lib/auth.rb
226
244
  - lib/authorization.rb
227
245
  - lib/desviar.rb
246
+ - lib/desviar/client.rb
228
247
  - lib/encrypt.rb
229
248
  - lib/model.rb
230
249
  - lib/public/favicon.ico
@@ -239,7 +258,7 @@ files:
239
258
  homepage: http://github.com/instantlinux/desviar
240
259
  licenses: []
241
260
  post_install_message: ! "------------------------------------------------------------------------------\nDesviar
242
- v0.0.15\n\nTo configure, download from:\n https://raw.github.com/instantlinux/desviar/master/config/config.rb.example\ninto
261
+ v0.0.16\n\nTo configure, download from:\n https://raw.github.com/instantlinux/desviar/master/config/config.rb.example\ninto
243
262
  a new file config.rb and export DESVIAR_CONFIG=<path>/config.rb.\n\nThanks for using
244
263
  Desviar.\n------------------------------------------------------------------------------\n"
245
264
  rdoc_options: []