Class: DRbService

Inherits:
Object
  • Object
show all
Includes:
Logging, DRbUndumped
Defined in:
lib/drbservice.rb,
lib/drbservice/utils.rb

Overview

A base class for DRb-based services. Concrete subclasses must define the service API by declaring public methods. By default, any public methods are hidden until the client authenticates. You can optionally declare a subset of its API that is # accessible before authentication by wrapping them in an 'unguarded' block. # See DRbService::unguarded for more details.

Defined Under Namespace

Modules: ANSIColorUtilities, LDAPAuthentication, Logging, PasswordAuthentication Classes: ColorLogFormatter, HtmlLogFormatter, LogFormatter

Constant Summary collapse

VERSION =

Library version

'1.0.4'
REVISION =

Version-control revision

%$Revision: 59c8e5acd8bb $
DEFAULT_IP =

The default IP address to listen on

'127.0.0.1'
DEFAULT_PORT =

The default port to listen on

4848
DEFAULT_CERTNAME =

The default path to the service cert, relative to the current directory

'service-cert.pem'
DEFAULT_KEYNAME =

The default path to the service key, relative to the current directory

'service-key.pem'
DEFAULT_CONFIG =

The default values for the drbservice config hash

{
  :ip       => DEFAULT_IP,
  :port     => DEFAULT_PORT,
  :certfile => DEFAULT_CERTNAME,
  :keyfile  => DEFAULT_KEYNAME,
}

Constants included from Logging

Logging::LEVEL

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Logging

included, #initialize_copy, #log, #log_debug

Constructor Details

#initialize(config = {}) ⇒ DRbService

Create a new instance of the service. Raises a ScriptError if DRbService is instantiated directly.

Raises:

  • (ScriptError)


146
147
148
149
150
151
# File 'lib/drbservice.rb', line 146

def initialize( config={} )
  raise ScriptError,
    "can't instantiate #{self.class} directly: please subclass it instead" if
    self.class == DRbService
  @authenticated = false
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(sym, *args) ⇒ Object (protected)

Handle calls to guarded methods by requiring the authentication flag be set if there is a password set.



194
195
196
197
198
199
200
201
202
203
# File 'lib/drbservice.rb', line 194

def method_missing( sym, *args )
  return super unless body = self.class.real_methods[ sym ]

  if self.authorized?
    return body.clone.bind( self ).call( *args )
  else
    self.log.error "Guarded method %p called without authentication!" % [ sym ]
    raise SecurityError, "not authenticated"
  end
end

Class Attribute Details

.real_methodsObject (readonly)

Returns the value of attribute real_methods.



45
46
47
# File 'lib/drbservice.rb', line 45

def real_methods
  @real_methods
end

.unguarded_modeObject

The unguarded mode flag -- instance methods defined while this flag is set will not be hidden



135
136
137
# File 'lib/drbservice.rb', line 135

def unguarded_mode
  @unguarded_mode
end

Class Method Details

.inherited(subclass) ⇒ Object

Inheritance callback: Add a per-class 'unguarded mode' flag to subclasses.



105
106
107
108
109
# File 'lib/drbservice.rb', line 105

def self::inherited( subclass )
  self.log.debug "Setting @unguarded_mode in %p" % [ subclass ]
  subclass.instance_variable_set( :@unguarded_mode, false )
  super
end

.method_added(meth) ⇒ Object

Method-addition callback: Obscure the method meth unless unguarded mode is enabled.



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/drbservice.rb', line 86

def self::method_added( meth )
  super

  unless self == ::DRbService || meth.to_sym == :initialize
    if !self.public_instance_methods.collect( &:to_sym ).include?( meth )
      DRbService.log.debug "Not obsuring %p#%s: not a public method" % [ self, meth ]
    elsif self.unguarded_mode
      DRbService.log.debug "Not obscuring %p#%s: unguarded mode." % [ self, meth ]
    else
      DRbService.log.debug "Obscuring %p#%s." % [ self, meth ]
      @real_methods ||= {}
      @real_methods[ meth.to_sym ] = self.instance_method( meth )
      remove_method( meth )
    end
  end
end

.start(config = {}) ⇒ Object

Start the DRbService, using the ip, port, and cert information from the given config hash.

[:ip] the ip to bind to [:port] the port to listen on [:certfile] the name of the server's SSL certificate file [:keyfile] the name of the server's SSL key file



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/drbservice.rb', line 61

def self::start( config={} )
  config = DEFAULT_CONFIG.merge( config )

  frontobj = self.new( config )
  uri = "drbssl://%s:%d" % config.values_at( :ip, :port )

  cert = OpenSSL::X509::Certificate.new( File.read(config[:certfile]) )
  key  = OpenSSL::PKey::RSA.new( File.read(config[:keyfile]) )

  config = {
    :safe_level     => 1,
    :verbose        => true,
        :SSLCertificate => cert,
        :SSLPrivateKey  => key,
  }

  DRbService.log.info "Starting %p as a DRbService at %s" % [ self, uri ]
  server = DRb::DRbServer.new( uri, frontobj, config )
  DRbService.log.debug "  started. Joining the DRb thread."
  $0 = "%s %s" % [ self.name, uri ]
  server.thread.join
end

.unguardedObject

Declare some service methods that can be called without authentication in the provided block.



114
115
116
117
118
119
# File 'lib/drbservice.rb', line 114

def self::unguarded
  self.unguarded_mode = true
  yield
ensure
  self.unguarded_mode = false
end

.version_string(include_buildnum = false) ⇒ Object

Return the library's version string



123
124
125
126
127
# File 'lib/drbservice.rb', line 123

def self::version_string( include_buildnum=false )
  vstring = "%s %s" % [ self.name, VERSION ]
  vstring << " (build %s)" % [ REVISION[/.*: ([[:xdigit:]]+)/, 1] || '0' ] if include_buildnum
  return vstring
end

Instance Method Details

#authenticate(*args) ⇒ Object

Default authentication implementation -- always fails. You'll need to include one of the authentication modules or provide your own #authenticate method in your subclass.

Raises:

  • (SecurityError)


182
183
184
185
# File 'lib/drbservice.rb', line 182

def authenticate( *args )
  self.log.error "authentication failure (fallback method)"
  raise SecurityError, "authentication failure"
end

#authenticated?Boolean

Returns true if the client has successfully authenticated.

Returns:

  • (Boolean)


165
166
167
# File 'lib/drbservice.rb', line 165

def authenticated?
  return @authenticated ? true : false
end

#authorized?Boolean

Returns true if the client has successfully authenticated and is authorized to use the service. By default, authentication is sufficient for authorization; to specify otherwise, override this method in your service's subclass or include an auth mixin that provides one.

Returns:

  • (Boolean)


174
175
176
# File 'lib/drbservice.rb', line 174

def authorized?
  return self.authenticated?
end

#inspectObject

Return a human-readable representation of the object.



159
160
161
# File 'lib/drbservice.rb', line 159

def inspect
  return "#<%s:0x%0x>" % [ self.class, self.__id__ * 2 ]
end