Class: Msf::WebServices::JsonRpcApp
- Inherits:
-
Sinatra::Base
- Object
- Sinatra::Base
- Msf::WebServices::JsonRpcApp
- Defined in:
- lib/msf/core/web_services/json_rpc_app.rb
Defined Under Namespace
Classes: BootError
Constant Summary collapse
- MIN_API_TOKEN_LENGTH =
Shortest static API token accepted from the environment.
16- REMEDY =
Appended to every BootError so the operator knows both ways out.
'Set MSF_WS_JSON_RPC_API_TOKEN to a token of at least ' \ "#{MIN_API_TOKEN_LENGTH} characters, which needs no database, " \ "or run 'msfdb init' and create a user to authenticate with database API tokens.".freeze
- REMEDY_TOKEN_ONLY =
Appended when only the static token route is available.
'Set MSF_WS_JSON_RPC_API_TOKEN to a token of at least ' \ "#{MIN_API_TOKEN_LENGTH} characters.".freeze
- REMEDY_NO_USER_TOKEN =
Appended when the database holds users but none of them have an API token. Creating a user does not issue one - report_user leaves persistence_token unset - so this is a reachable state rather than a theoretical one.
"Issue one with 'POST /api/v1/auth/generate-token' on the data service, " \ 'or set MSF_WS_JSON_RPC_API_TOKEN to a token of at least ' \ "#{MIN_API_TOKEN_LENGTH} characters instead.".freeze
Class Method Summary collapse
-
.blank_token?(token) ⇒ Boolean
True if the token is missing or contains no usable characters.
-
.boot! ⇒ Object
Initialise auth and DB state once at startup.
- .setup_default_middleware(builder) ⇒ Object
Class Method Details
.blank_token?(token) ⇒ Boolean
Returns true if the token is missing or contains no usable characters.
145 146 147 |
# File 'lib/msf/core/web_services/json_rpc_app.rb', line 145 def self.blank_token?(token) !token.is_a?(String) || token.strip.empty? end |
.boot! ⇒ Object
Initialise auth and DB state once at startup. Called from the warmup block in msf-json-rpc.ru, after the framework is ready but before the socket is bound and connections are accepted.
A database is not required, but authentication is. It is resolved from either:
1. a static token supplied via MSF_WS_JSON_RPC_API_TOKEN
2. API tokens belonging to users in the database, when it is reachable
If neither is available the service refuses to start, rather than accepting unauthenticated requests.
Only option 2 needs a database to authenticate against. Which option is in use says nothing about whether a database is connected: the framework connects regardless of the token, so db.* works alongside a static token whenever a database is configured.
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/msf/core/web_services/json_rpc_app.rb', line 84 def self.boot! # Build the framework up front so that connecting to the database, and any failure # doing so, happens here rather than on the first request to reach the service. settings.framework token = settings.api_token unless blank_token?(token) if token.length < MIN_API_TOKEN_LENGTH raise BootError, 'JSON-RPC server cannot start: MSF_WS_JSON_RPC_API_TOKEN must be at least ' \ "#{MIN_API_TOKEN_LENGTH} characters." end return end # A blank token would otherwise authenticate any request presenting an equally # blank token, so discard it and fall back to database authentication. settings.api_token = nil # User accounts of a remote data service live on that service, not locally, so its # API tokens cannot be validated here. The local database that Active Record requires # alongside it holds a different set of users, and authenticating against those would # grant access on credentials the operator never issued for this service. unless settings.data_service_url.nil? || settings.data_service_url.empty? raise BootError, 'JSON-RPC server cannot start: no API token is configured and API tokens cannot ' \ "be validated against the remote data service #{settings.data_service_url}. " \ "#{REMEDY_TOKEN_ONLY}" end db = settings.framework.db unless db.active raise BootError, 'JSON-RPC server cannot start: no API token is configured and the database is ' \ "not available. #{REMEDY}" end begin users = db.users({}) # A nil list means no data service is registered at all, which is indistinguishable # here from an empty users table and reported the same way. tokens = users.nil? ? [] : users.map(&:persistence_token) rescue StandardError => e raise BootError, 'JSON-RPC server cannot start: no API token is configured and the database ' \ "could not be queried (#{e.class}: #{e.}). #{REMEDY}" end if tokens.empty? raise BootError, 'JSON-RPC server cannot start: no API token is configured and the database ' \ "holds no users. #{REMEDY}" end # Existing users are not enough: this application only authenticates persistence_token, # so a database of password-only accounts would start a service that 401s every request. if tokens.all? { |user_token| blank_token?(user_token) } raise BootError, 'JSON-RPC server cannot start: no API token is configured and no user in the ' \ "database has an API token to authenticate with. #{REMEDY_NO_USER_TOKEN}" end settings.db_manager = db end |
.setup_default_middleware(builder) ⇒ Object
190 191 192 193 194 195 |
# File 'lib/msf/core/web_services/json_rpc_app.rb', line 190 def self.setup_default_middleware(builder) super # Insertion at pos 1 needed to immediately follow Sinatra::ExtendedBase # proc block identical to one used in 'use' method lib/rack/builder:86 builder.instance_variable_get(:@use).insert(1, proc { |app| JsonRpcExceptionHandling::RackMiddleware.new(app) }) end |