global_session 3.2.10 → 3.3.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.
@@ -0,0 +1,3 @@
1
+ module GlobalSession
2
+ VERSION = '3.3.0'
3
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: global_session
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.10
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Spataro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-30 00:00:00.000000000 Z
11
+ date: 2016-12-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -42,22 +42,22 @@ dependencies:
42
42
  name: right_support
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "<"
46
- - !ruby/object:Gem::Version
47
- version: '4.0'
48
45
  - - ">="
49
46
  - !ruby/object:Gem::Version
50
- version: 2.8.2
47
+ version: 2.14.1
48
+ - - "<"
49
+ - !ruby/object:Gem::Version
50
+ version: '3.0'
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
- - - "<"
56
- - !ruby/object:Gem::Version
57
- version: '4.0'
58
55
  - - ">="
59
56
  - !ruby/object:Gem::Version
60
- version: 2.8.2
57
+ version: 2.14.1
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: simple_uuid
63
63
  requirement: !ruby/object:Gem::Requirement
@@ -72,82 +72,13 @@ dependencies:
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
74
  version: 0.2.0
75
- - !ruby/object:Gem::Dependency
76
- name: ruby-debug
77
- requirement: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
80
- - !ruby/object:Gem::Version
81
- version: '0.10'
82
- type: :development
83
- prerelease: false
84
- version_requirements: !ruby/object:Gem::Requirement
85
- requirements:
86
- - - "~>"
87
- - !ruby/object:Gem::Version
88
- version: '0.10'
89
- - !ruby/object:Gem::Dependency
90
- name: pry
91
- requirement: !ruby/object:Gem::Requirement
92
- requirements:
93
- - - "~>"
94
- - !ruby/object:Gem::Version
95
- version: '0.10'
96
- type: :development
97
- prerelease: false
98
- version_requirements: !ruby/object:Gem::Requirement
99
- requirements:
100
- - - "~>"
101
- - !ruby/object:Gem::Version
102
- version: '0.10'
103
- - !ruby/object:Gem::Dependency
104
- name: pry-byebug
105
- requirement: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - "~>"
108
- - !ruby/object:Gem::Version
109
- version: '2.0'
110
- type: :development
111
- prerelease: false
112
- version_requirements: !ruby/object:Gem::Requirement
113
- requirements:
114
- - - "~>"
115
- - !ruby/object:Gem::Version
116
- version: '2.0'
117
- - !ruby/object:Gem::Dependency
118
- name: jeweler
119
- requirement: !ruby/object:Gem::Requirement
120
- requirements:
121
- - - "~>"
122
- - !ruby/object:Gem::Version
123
- version: '1.8'
124
- type: :development
125
- prerelease: false
126
- version_requirements: !ruby/object:Gem::Requirement
127
- requirements:
128
- - - "~>"
129
- - !ruby/object:Gem::Version
130
- version: '1.8'
131
- description: This Rack middleware allows several web apps in an authentication domain
132
- to share session state, facilitating single sign-on in a distributed web app. It
133
- only provides session sharing and does not concern itself with authentication or
134
- replication of the user database.
135
- email: support@rightscale.com
75
+ description: A toolkit of useful, reusable foundation code created by RightScale.
76
+ email: rubygems@rightscale.com
136
77
  executables: []
137
78
  extensions: []
138
- extra_rdoc_files:
139
- - LICENSE
140
- - README.rdoc
79
+ extra_rdoc_files: []
141
80
  files:
142
- - ".ruby-version"
143
- - ".travis.yml"
144
- - CHANGELOG.md
145
- - LICENSE
146
- - README.rdoc
147
- - Rakefile
148
- - VERSION
149
81
  - global_session.gemspec
150
- - init.rb
151
82
  - lib/global_session.rb
152
83
  - lib/global_session/configuration.rb
153
84
  - lib/global_session/directory.rb
@@ -162,13 +93,9 @@ files:
162
93
  - lib/global_session/session/v1.rb
163
94
  - lib/global_session/session/v2.rb
164
95
  - lib/global_session/session/v3.rb
165
- - rails/init.rb
166
- - rails_generators/global_session/USAGE
167
- - rails_generators/global_session/global_session_generator.rb
168
- - rails_generators/global_session/templates/global_session.yml.erb
169
- - rails_generators/global_session_authority/USAGE
170
- - rails_generators/global_session_authority/global_session_authority_generator.rb
171
- homepage: https://github.com/rightscale/global_session
96
+ - lib/global_session/session/v4.rb
97
+ - lib/global_session/version.rb
98
+ homepage: https://github.com/rightscale/right_support
172
99
  licenses:
173
100
  - MIT
174
101
  metadata: {}
@@ -180,7 +107,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
180
107
  requirements:
181
108
  - - "~>"
182
109
  - !ruby/object:Gem::Version
183
- version: '2.0'
110
+ version: '2.1'
184
111
  required_rubygems_version: !ruby/object:Gem::Requirement
185
112
  requirements:
186
113
  - - ">="
@@ -191,5 +118,5 @@ rubyforge_project:
191
118
  rubygems_version: 2.2.3
192
119
  signing_key:
193
120
  specification_version: 4
194
- summary: Secure single-domain session sharing plugin for Rack and Rails.
121
+ summary: Reusable foundation code.
195
122
  test_files: []
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 2.1.6
data/.travis.yml DELETED
@@ -1,11 +0,0 @@
1
- language: ruby
2
- cache: bundler
3
- rvm:
4
- - 1.8.7
5
- - 2.1.8
6
- before_install:
7
- - sudo apt-get -qq update
8
- - sudo apt-get install -y libgmp3-dev
9
- script:
10
- - bundle exec rake ci:spec
11
- bundler_args: --without development
data/CHANGELOG.md DELETED
@@ -1,94 +0,0 @@
1
- 3.2.1 (2015-07-10)
2
- ---------------
3
-
4
- Fixed a bug with automatic cookie renewal; cookies were not being renewed unless
5
- the `authority` directive was present in the configuration.
6
-
7
- 3.2.0 (2015-07-08)
8
- ------------------
9
-
10
- If cookie domain is omitted from configuration, the Rack middleware will
11
- guess a suitable domain by looking at the HTTP Host header (or `X-Forwarded-Host`
12
- if it is present, i.e. the request has passed through a load balancer). The
13
- heuristic for HTTP-host-to-cookie-domain is:
14
-
15
- * Numeric IPv4: `127.0.0.1` -> _no_ domain
16
- * 1-component: `localhost` -> _no_ domain
17
- * 2-component: `example.com` -> `example.com`
18
- * N-component: `foo.test.example.com` -> `test.example.com`
19
-
20
- This doesn't handle country-code TLDs (`.co.uk`) so you'll still need to specify
21
- the cookie domain for Web sites under a ccTLD.
22
-
23
- The Rack middleware will guess whether to add the `secure` flag to cookies
24
- based on `rack.url_scheme` (or `X-Forwarded-Proto` if it is present).
25
-
26
- 3.1 (2015-01-27)
27
- ----------------
28
-
29
- Split Directory class into Directory & Keystore, retaining some backward-compatibility shims
30
- inside Directory. In v4, these shims will be removed and all key management concerns will be
31
- handled by Keystore; the Directory class will be limited to session creation, renewal, and
32
- validity checking.
33
-
34
- The `trust` and `authority` configuration elements have been deprecated, as ha
35
- the ability to pass a keystore directory to `Directory.new`. Instead, the
36
- configuration should contain a `keystore` that tells the gem where to find its
37
- public and private keys; every public key is implicitly trusted, and if some
38
- private key is found, the app is an authority (otherwise it's not an authority
39
- and sessions are read-only). Example new configuration:
40
-
41
- keystore:
42
- public:
43
- - config/authorities
44
- - config/other_dir_with_keys_i_should_trust
45
- private: /etc/my_private.key
46
-
47
- As with any other Global Session configuration, this stanza can appear under
48
- `common` or under an enivronment-specific section (`staging`, `production`, etc).
49
-
50
- Finally, you can pass a private key location in the environment variable named
51
- `GLOBAL_SESSION_PRIVATE_KEY` instead of including that information in the
52
- configuration.
53
-
54
- 3.0 (2013-10-03)
55
- ----------------
56
-
57
- The format of the global session cookie has been reinvented again! It once again uses JSON
58
- (because msgpack was not widely supported in other languages/OSes) but retains the compact
59
- array encoding introduced in v2.
60
-
61
- The cryptographic signature scheme has been changed for better compatibility; we now use
62
- PKCS1 v1.5 sign and verify operations instead of "raw" RSA. v2 and v1 sessions are fully
63
- supported for read/write, but any session created with the v3 gem will use the v3 crypto
64
- scheme.
65
-
66
- 2.0 (2012-11-06)
67
- ----------------
68
-
69
- The format of the global session cookie has been reinvented; it now uses msgpack and delegates
70
- all crypto to RightSupport::Crypto::SignedHash. Together with a few other optimizations, the
71
- size of the cookie has shrunk by about 30%.
72
-
73
- The gem remains capable of reading and writing V1 format cookies, but all new cookies are created
74
- with the V2 format.
75
-
76
- The "integrated" feature is no longer supported for the Rails integration layer; global session
77
- attributes must always be accessed separately from local session attributes, through the
78
- #global_session reader method that is mixed into ActionController::Base.
79
-
80
- 1.0 (2011-01-01)
81
- ----------------
82
-
83
- General Availability release. Mostly interface-compatible with 0.9.
84
-
85
- 0.9 (2010-12-07)
86
- ----------------
87
-
88
- Rack middleware implementation is feature-complete and has major spec coverage. Rails integration
89
- is untested and may contain bugs.
90
-
91
- 0.9.0 (2010-12-22)
92
- ----------------
93
-
94
- Initial commit ported from 'rack' branch of old has_global_session project
data/LICENSE DELETED
@@ -1,20 +0,0 @@
1
- Copyright (c) 2009-2015 RightScale, Inc.
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- 'Software'), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc DELETED
@@ -1,298 +0,0 @@
1
- Copyright (c) 2009-2015 RightScale, Inc. <support@rightscale.com>; see LICENSE for more details.
2
-
3
- = Preamble
4
-
5
- <b>WARNING:</b> This RubyGem was authored in 2010 when Rails 2.1 was state of
6
- the art. Its Rails integration has not been kept up to date over time; it is
7
- untested with Rails 3, 4 and 5, and its generators are broken with Rails above
8
- 2.3.5.
9
-
10
- We continue to support the Rack middleware and other components of this gem,
11
- and recommend using it as a plain old Rack middleware in your Rails apps.
12
- Instructions for doing so are provided in this README.
13
-
14
- = Introduction
15
-
16
- GlobalSession enables multiple heterogeneous Web applications to share
17
- session state in a cryptographically secure way, facilitating single sign-on
18
- and enabling easier development of distributed applications that make use of
19
- architectural strategies such as sharding or separation of concerns.
20
-
21
- In other words: it glues your Web apps together by letting them share session state.
22
- This is done by putting the session itself into a cookie and adding some crypto to
23
- protect against tampering.
24
-
25
- Maintained by
26
- - [RightScale Engineering](https://github.com/rightscale)
27
-
28
- Merge to master whitelist
29
- - @tony-spataro-rs
30
-
31
- == What Is It Not?
32
-
33
- This gem does not provide a complete solution for identity management. In
34
- particular, it does not provide any of the following:
35
-
36
- * <b>federation</b> -- aka cross-domain single sign-on -- use SAML for that.
37
-
38
- * <b>authentication</b> -- the application must authenticate the user.
39
-
40
- * <b>authorization</b> -- the application is responsible for using the contents
41
- of the global session to make authorization decisions.
42
-
43
- * <b>secrecy</b> -- global session attributes can be signed but never encrypted.
44
- Protect against third-party snooping using SSL. Group secrecy is expensive;
45
- if you don't want your users to see their session state, put it in a database,
46
- or in an encrypted local session cookie.
47
-
48
- * <b>replication</b> -- the session authorities must have some way to
49
- share information about the database of users in order to authenticate
50
- them and place identifying information into the global session.
51
-
52
- * <b>single sign-out</b> -- the authorities must have some way to broadcast a
53
- notification when sessions are invalidated; they can override the default
54
- Directory implementation to do realtime revocation checking.
55
-
56
- = Examples
57
-
58
- == Make a YML configuration file
59
-
60
- The config file format is designed to be self-documenting. The most important
61
- data are: what data can be in your global session (`attributes`), what
62
- directory contains your `.pub` files with authorities' public keys (`keystore.public`),
63
- and the locatio nof `.key` private key file, if any, used by this app (`keystore.private`).
64
-
65
- You can omit `keystore.private` if the app should be able to read, but not
66
- write, global sessions.
67
-
68
- If you have asymmetrical trust (e.g. dev trusts production but not vice-versa),
69
- you can include an optional `trust` list. By default, every public key file is
70
- trusted.
71
-
72
- common:
73
- attributes:
74
- signed:
75
- - user
76
- insecure:
77
- - favorite_color
78
- cookie:
79
- name: global_session
80
- keystore:
81
- public: config/authorities
82
- renew: 30
83
- timeout: 60
84
- development:
85
- keystore:
86
- private: config/authorities/dev
87
- production:
88
- trust:
89
- - prod
90
- keystore:
91
- private: config/authorities/prod
92
-
93
- == Make a new keypair for a GlobalSession authority
94
-
95
- Decide on a name for your authority. The name is a short string that identifies
96
- a pair of key files on disk (one public, one private) which will be used to
97
- sign and verify sessions. If you have mutual trust between every app in your
98
- architecture, then you only need one authority and your domain name, e.g.
99
- `example-com`, is a fine choice of name. If you want partition trust within your
100
- architecture, then authorities could be named after environments
101
- (`staging`, `production`), regions (`us`, `eu`) or even specific apps
102
- (`frontend`, `api`) depending on where you draw the trust boundaries.
103
-
104
- Figure out where key files live in your application. This is whatever value
105
- you set in the `keystore: public: ...` directive in the configuration.
106
-
107
- If you have complete, mutual trust between all components of your architecture,
108
- then something based on your organization's domain name (e.g. `example-com`)
109
- is a fine choice.
110
-
111
- Open irb or your console of choice and require the `global_session` gem.
112
-
113
- # default is RSA cryptosystem with 1024-bit keys.
114
- keypair = GlobalSession::Keystore.create_keypair(:RSA, 1024)
115
- public_pem = keypair.public_key.to_pem
116
- private_pem = keypair.to_pem
117
-
118
- # write keys to disk
119
- File.open('config/authorities/example-com.pub', 'w') { |f| f.write public_pem }
120
- File.open('config/authorities/example-com.key', 'w') { |f| f.write private_pem }
121
-
122
- == Integration with Rails
123
-
124
- Install the GlobalSession middleware in your application startup. Open
125
- `environment.rb` or `application.rb` (depending on your Rails version) and
126
- add a new file to `config/initializers` to configure and install the
127
- middleware:
128
-
129
- configuration = GlobalSession::Configuration.new('config/global_session.yml', Rails.env)
130
- directory = GlobalSession::Directory.new(configuration)
131
-
132
- == Integration with Rack
133
-
134
- Install the GlobalSession middleware into your Rack stack; pass a config and a directory
135
- object to its initializer. For instance, in config.ru:
136
-
137
- configuration = GlobalSession::Configuration.new('path/to/config.yml', RACK_ENV)
138
- directory = GlobalSession::Directory.new(configuration)
139
- use ::GlobalSession::Rack::Middleware, configuration, directory
140
-
141
- Application.config.middleware.insert_before(Application.config.session_store, ::Rack::Cookies)
142
- Application.config.middleware.insert_before(Application.config.session_store, ::Rack::GlobalSession, configuration, directory)
143
-
144
- Note that the GlobalSession middleware depends on `Rack::Cookies`; be sure
145
- to install them both, and in the proper order.
146
-
147
- = Global Session Contents
148
-
149
- Global session state is stored as a cookie in the user's browser and/or sent
150
- with every request as an HTTP Authorization header. If your app uses the
151
- Authorization header, then it's responsible for communicating new or changed
152
- header values to clients out-of-band (i.e. as part of an OAuth refresh-token
153
- operation). If your app uses the cookie, GlobalSession will take care of
154
- updating the cookie whenever session values change.
155
-
156
- Data-wise, the session is a JSON dictionary containing the following stuff:
157
- * session metadata (UUID, created at, expires at, signing authority)
158
- * signed session attributes (e.g. the authenticated user ID)
159
- * insecure session attributes (e.g. the last-visited URL)
160
- * a cryptographic signature of the metadata and signed attributes
161
-
162
- The global session is unserialized and its signature is verified whenever
163
- Rack receives a request. The cookie's value is updated whenever attributes
164
- change. As an optimization, the signature is only recomputed when the metadata
165
- or signed attributes have changed; insecure attributes can change "for free."
166
-
167
- Because the security properties of attributes can vary, GlobalSession
168
- requires all _possible_ attributes to be declared up-front in the config
169
- file. The 'attributes' section of the config file defines the _schema_
170
- for the global session: which attributes can be used, which can be trusted
171
- to make authorization decisions (because they are signed), and which are
172
- insecure and act only as "hints" about the session.
173
-
174
- Since the session is serialized as JSON, only a limited range of object
175
- types can be stored in it: nil, strings, numbers, lists, hashes, booleans
176
- and other Ruby primitives.
177
-
178
- = Detailed Information
179
-
180
- == Global Session Domain
181
-
182
- We refer to collection of _all_ Web application instances capable of using the
183
- global session as the "domain." The global session domain may consist of any
184
- number of distinct nodes, possibly hidden behind load balancers or proxies.
185
- The nodes within the domain may all be running the same Rails application,
186
- or they may be running different codebases that represent different parts of
187
- a distributed application. (They may also be using app frameworks other than
188
- Rails.)
189
-
190
- The only constraint imposed by GlobalSession is that all nodes within the
191
- domain must have end-user-facing URLs within the same second-level DNS domain.
192
- This is due to limitations imposed by the HTTP cookie mechanism: for privacy
193
- reasons, cookies will only be sent to nodes within the same domain as the
194
- node that first created them.
195
-
196
- For example, in my GlobalSession configuration file I might specify that my
197
- cookie's domain is "example.com". My app nodes at app1.example.com and
198
- app2.example.com would be part of the global session domain, but my business
199
- partner's application at app3.partner.com could not participate.
200
-
201
- If your app uses an Authorization header instead of cookies, the domain-name
202
- constraint does not apply!
203
-
204
- == Authorities and Relying Parties
205
-
206
- A node that can create or update the global session is said to be an "authority"
207
- (because it's trusted by other parties to make assertions about global session
208
- state). An application that can read the global session is said to be a "relying
209
- party." In practice, every application is a relying party, but not all of them
210
- need to be authorities.
211
-
212
- There is an RSA key pair associated with each authority. The authority's
213
- public key is distribued to all relying parties, but the private key must
214
- remain a secret to that authority (which may consist of many individual
215
- nodes).
216
-
217
- This system allows for significant flexibility when configuring a distributed
218
- app's global session. There must be at least one authority, but for many apps
219
- one authority (plus an arbitrary number of relying parties, which do not need
220
- a key pair) will be sufficient.
221
-
222
- In general, two systems should be part of the same authority if there is no
223
- trust boundary between them -- that is to say, trust between the two systems
224
- is unlimited in both directions.
225
-
226
- Here are some reasons you might consider dividing your systems into different
227
- authorities:
228
- * beta/staging system vs. production system
229
- * system hosted by a third party vs. system hosted internally
230
- * e-commerce app vs. storefront app vs. admin app
231
-
232
- == The Keystore
233
-
234
- The Directory is a Ruby object that provides lookups of public and private
235
- keys. Given an authority name (as found in a session cookie), the Directory
236
- can find the corresponding RSA public key.
237
-
238
- If the local system is an authority itself, #private_key_name will
239
- return the authority name and #private_key will return an RSA private key
240
- suitable for signing session attributes.
241
-
242
- The Keystore implementation included with GlobalSession uses the filesystem
243
- as the backing store for its key pairs. Its #initialize method accepts a
244
- filesystem path that will be searched for files containing PEM-encoded public
245
- and private keys (the same format used by OpenSSH). This simple Directory
246
- implementation relies on the following conventions:
247
- * Public keys have a *.pub extension.
248
- * Private keys have a *.key extension.
249
- * If a node is an authority, then one (and *only* one) *.key file should exist.
250
- * The local node's authority name is inferred from the name of the private key
251
- file.
252
-
253
- When used with a Rails app, GlobalSession expects to find its keystore in
254
- config/authorities. You can use the global_session generator to create new key
255
- pairs. Remember never to check a *.key file into a public repository!! (*.pub
256
- files can be checked into source control and distributed freely.)
257
-
258
- If you wish all of the systems to stop trusting an authority, simply delete
259
- its public key from config/authorities and re-deploy your app.
260
-
261
- The keystore needs to be told where to find its keys. This is accomplished by
262
- setting some configuration attributes like so:
263
-
264
- keystore:
265
- public:
266
- - config/authorities
267
- - config/more_authorities
268
- private: config/authorities/my_private.key
269
-
270
- The filename of keys is relevant; after stripping the *.pub or *.key extension,
271
- the remainder of the file's basename is taken to be the authority name. For
272
- instance, "production.pub" is the public key of the authority named "production"
273
- and "development.key" is the private key of the authority named "development."
274
-
275
- == The Directory
276
-
277
- The Directory is a Ruby object that performs session management operations,
278
- including:
279
- * Checking whether sessions have become invalid (e.g. after sign-out)
280
- * Creating new sessions
281
- * Unserializing existing sessions
282
- * Renewing sessions if they will expire
283
- * Updating session signatures
284
-
285
- In GlobalSession v3, Directory also presents methods for key management, but
286
- these are all delegated to the Keystore class. In v4, the concerns of Directory
287
- and Keystore will be fully separated.
288
-
289
- === Implementing Your Own Directory Provider
290
-
291
- To replace or enhance the built-in Directory, simply create a new class that
292
- extends Directory and put the class somewhere in your app (the lib directory
293
- is a good choice). In the GlobalSession configuration file, specify the
294
- class name of the directory under the 'common' section, like so:
295
-
296
- common:
297
- directory:
298
- class: MyCoolDirectory