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