rots 1.0.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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +3 -0
- data/AUTHORS +4 -0
- data/CHANGELOG.md +22 -0
- data/CONTRIBUTING.md +55 -0
- data/LICENSE.txt +21 -0
- data/README.md +255 -0
- data/SECURITY.md +14 -0
- data/exe/rots +98 -0
- data/lib/rots/identity_page_app.rb +37 -0
- data/lib/rots/mocks/client_app.rb +53 -0
- data/lib/rots/mocks/mock_fetcher.rb +34 -0
- data/lib/rots/mocks/rots_server.rb +49 -0
- data/lib/rots/mocks.rb +8 -0
- data/lib/rots/server_app.rb +167 -0
- data/lib/rots/test/rack_test_helpers.rb +21 -0
- data/lib/rots/test/request_helper.rb +78 -0
- data/lib/rots/test.rb +2 -0
- data/lib/rots/version.rb +5 -0
- data/lib/rots.rb +27 -0
- data.tar.gz.sig +5 -0
- metadata +481 -0
- metadata.gz.sig +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 172f3bd6eee16ac007608e427e6dac75ddab29657cdb701c6bce562a1959f66d
|
4
|
+
data.tar.gz: 386ee12b9e29481d6c7a3c063e730510bf2e5718d89b3aedf3211d37fefd4ea9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e2610b68941ba6da18d9e1b189aa4341bbb17b37d38e18912c0ea5ee121e42f1cc1cd96eb9338170db8af09cedb90aabe4bdd63064432cc3117b1be9e3c50586
|
7
|
+
data.tar.gz: 65f012defce46b5ebad95bc43bc7820a7843b10de6cc7e167c26d65aae679d3789b6b7b5170492ce16feb0f216f9623fb58bb19a6c57a11c9576915f45f1d6f7
|
checksums.yaml.gz.sig
ADDED
data/AUTHORS
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Changelog
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
Since version 3.0.0, the format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
|
+
|
7
|
+
## [Unreleased]
|
8
|
+
### Added
|
9
|
+
### Changed
|
10
|
+
### Fixed
|
11
|
+
### Removed
|
12
|
+
|
13
|
+
## 1.0.0 - 2024-09-24
|
14
|
+
COVERAGE: 96.33% -- 236/245 lines in 11 files
|
15
|
+
BRANCH COVERAGE: 77.78% -- 35/45 branches in 11 files
|
16
|
+
37.84% documented
|
17
|
+
### Fixed
|
18
|
+
- More tests & switch to RSpec
|
19
|
+
- Modernized code (require_relative)
|
20
|
+
- Refactored
|
21
|
+
- GitHub Actions for CI
|
22
|
+
- Upgraded to ruby-openid2 v3.1.0
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
## Contributing
|
2
|
+
|
3
|
+
Bug reports and pull requests are welcome on GitHub at [https://github.com/oauth-xx/rots][🚎src-main]
|
4
|
+
. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to
|
5
|
+
the [code of conduct][🤝conduct].
|
6
|
+
|
7
|
+
To submit a patch, please fork the project and create a patch with tests.
|
8
|
+
Once you're happy with it send a pull request.
|
9
|
+
|
10
|
+
## Release
|
11
|
+
|
12
|
+
### One-time, Per-developer, Setup
|
13
|
+
|
14
|
+
**IMPORTANT**: Your public key for signing gems will need to be picked up by the line in the
|
15
|
+
`gemspec` defining the `spec.cert_chain` (check the relevant ENV variables there),
|
16
|
+
in order to sign the new release.
|
17
|
+
See: [RubyGems Security Guide][🔒️rubygems-security-guide]
|
18
|
+
|
19
|
+
### To release a new version:
|
20
|
+
|
21
|
+
1. Run `bin/setup && bin/rake` as a tests, coverage, & linting sanity check
|
22
|
+
2. Update the version number in `version.rb`
|
23
|
+
3. Run `bin/setup && bin/rake` again as a secondary check, and to update `Gemfile.lock`
|
24
|
+
4. Run `git commit -am "🔖 Prepare release v<VERSION>"` to commit the changes
|
25
|
+
5. Run `git push` to trigger the final CI pipeline before release, & merge PRs
|
26
|
+
- NOTE: Remember to [check the build][🧪build]!
|
27
|
+
6. Run `export GIT_TRUNK_BRANCH_NAME="$(git remote show origin | grep 'HEAD branch' | cut -d ' ' -f5)" && echo $GIT_TRUNK_BRANCH_NAME`
|
28
|
+
7. Run `git checkout $GIT_TRUNK_BRANCH_NAME`
|
29
|
+
8. Run `git pull origin $GIT_TRUNK_BRANCH_NAME` to ensure you will release the latest trunk code
|
30
|
+
9. Set `SOURCE_DATE_EPOCH` so `rake build` and `rake release` use same timestamp, and generate same checksums
|
31
|
+
- Run `export SOURCE_DATE_EPOCH=$EPOCHSECONDS && echo $SOURCE_DATE_EPOCH`
|
32
|
+
- If the echo above has no output, then it didn't work.
|
33
|
+
- Note that you'll need the `zsh/datetime` module, if running `zsh`.
|
34
|
+
- In `bash` you can use `date +%s` instead, i.e. `export SOURCE_DATE_EPOCH=$(date +%s) && echo $SOURCE_DATE_EPOCH`
|
35
|
+
10. Run `bundle exec rake build`
|
36
|
+
11. Run `bin/checksums` (more [context][🔒️rubygems-checksums-pr]) to create SHA-256 and SHA-512 checksums
|
37
|
+
- Checksums will be committed automatically by the script, but not pushed
|
38
|
+
12. Run `bundle exec rake release` which will create a git tag for the version,
|
39
|
+
push git commits and tags, and push the `.gem` file to [rubygems.org][💎rubygems]
|
40
|
+
|
41
|
+
## Contributors
|
42
|
+
|
43
|
+
[![Contributors][🖐contributors-img]][🖐contributors]
|
44
|
+
|
45
|
+
Made with [contributors-img][🖐contrib-rocks].
|
46
|
+
|
47
|
+
[🧪build]: https://github.com/oauth-xx/rots/actions
|
48
|
+
[🤝conduct]: https://github.com/oauth-xx/rots/blob/main/CODE_OF_CONDUCT.md
|
49
|
+
[🖐contrib-rocks]: https://contrib.rocks
|
50
|
+
[🖐contributors]: https://github.com/oauth-xx/rots/graphs/contributors
|
51
|
+
[🖐contributors-img]: https://contrib.rocks/image?repo=oauth-xx/rots
|
52
|
+
[💎rubygems]: https://rubygems.org
|
53
|
+
[🔒️rubygems-security-guide]: https://guides.rubygems.org/security/#building-gems
|
54
|
+
[🔒️rubygems-checksums-pr]: https://github.com/rubygems/guides/pull/325
|
55
|
+
[🚎src-main]: https://github.com/oauth-xx/rots
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009 - 2011, 2013 - 2014, 2017 Roman Gonzalez <romanandreg@gmail.com>
|
4
|
+
Copyright (c) 2024 Peter H. Boling, http://railsbling.com
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
of this software and associated documentation files (the "Software"), to
|
8
|
+
deal in the Software without restriction, including without limitation the
|
9
|
+
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
10
|
+
sell copies of the Software, and to permit persons to whom the Software is
|
11
|
+
furnished to do so, subject to the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
14
|
+
all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
19
|
+
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
20
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
21
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,255 @@
|
|
1
|
+
# ROTS - Ruby OpenID Test Server
|
2
|
+
|
3
|
+
<div id="badges">
|
4
|
+
|
5
|
+
<div align="center">
|
6
|
+
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
8
|
+
[](https://rubygems.org/gems/rots)
|
9
|
+
[](https://github.com/oauth-xx/rots)
|
10
|
+
[![CodeCov][🖇codecov-img♻️]][🖇codecov]
|
11
|
+
[![CI Supported Build][🚎s-wfi]][🚎s-wf]
|
12
|
+
[![CI Unsupported Build][🚎us-wfi]][🚎us-wf]
|
13
|
+
[![CI Style Build][🚎st-wfi]][🚎st-wf]
|
14
|
+
[![CI Coverage Build][🚎cov-wfi]][🚎cov-wf]
|
15
|
+
[![CI Heads Build][🚎hd-wfi]][🚎hd-wf]
|
16
|
+
[![CI Ancient Build][🚎an-wfi]][🚎an-wf]
|
17
|
+
|
18
|
+
[🖇codecov-img♻️]: https://codecov.io/gh/oauth-xx/rots/graph/badge.svg?token=qycnWzl6qM
|
19
|
+
[🖇codecov]: https://codecov.io/gh/oauth-xx/rots
|
20
|
+
[🚎s-wf]: https://github.com/oauth-xx/rots/actions/workflows/supported.yml
|
21
|
+
[🚎s-wfi]: https://github.com/oauth-xx/rots/actions/workflows/supported.yml/badge.svg
|
22
|
+
[🚎us-wf]: https://github.com/oauth-xx/rots/actions/workflows/unsupported.yml
|
23
|
+
[🚎us-wfi]: https://github.com/oauth-xx/rots/actions/workflows/unsupported.yml/badge.svg
|
24
|
+
[🚎st-wf]: https://github.com/oauth-xx/rots/actions/workflows/style.yml
|
25
|
+
[🚎st-wfi]: https://github.com/oauth-xx/rots/actions/workflows/style.yml/badge.svg
|
26
|
+
[🚎cov-wf]: https://github.com/oauth-xx/rots/actions/workflows/coverage.yml
|
27
|
+
[🚎cov-wfi]: https://github.com/oauth-xx/rots/actions/workflows/coverage.yml/badge.svg
|
28
|
+
[🚎hd-wf]: https://github.com/oauth-xx/rots/actions/workflows/heads.yml
|
29
|
+
[🚎hd-wfi]: https://github.com/oauth-xx/rots/actions/workflows/heads.yml/badge.svg
|
30
|
+
[🚎an-wf]: https://github.com/oauth-xx/rots/actions/workflows/ancient.yml
|
31
|
+
[🚎an-wfi]: https://github.com/oauth-xx/rots/actions/workflows/ancient.yml/badge.svg
|
32
|
+
|
33
|
+
</div>
|
34
|
+
|
35
|
+
-----
|
36
|
+
|
37
|
+
<div align="center">
|
38
|
+
|
39
|
+
[![Liberapay Patrons][⛳liberapay-img]][⛳liberapay]
|
40
|
+
[![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor]
|
41
|
+
[![Polar Shield][🖇polar-img]][🖇polar]
|
42
|
+
[![Donate to my FLOSS or refugee efforts at ko-fi.com][🖇kofi-img]][🖇kofi]
|
43
|
+
[![Donate to my FLOSS or refugee efforts using Patreon][🖇patreon-img]][🖇patreon]
|
44
|
+
|
45
|
+
[⛳liberapay-img]: https://img.shields.io/liberapay/patrons/pboling.svg?logo=liberapay
|
46
|
+
[⛳liberapay]: https://liberapay.com/pboling/donate
|
47
|
+
[🖇sponsor-img]: https://img.shields.io/badge/Sponsor_Me!-pboling.svg?style=social&logo=github
|
48
|
+
[🖇sponsor]: https://github.com/sponsors/pboling
|
49
|
+
[🖇polar-img]: https://polar.sh/embed/seeks-funding-shield.svg?org=pboling
|
50
|
+
[🖇polar]: https://polar.sh/pboling
|
51
|
+
[🖇kofi-img]: https://img.shields.io/badge/buy%20me%20coffee-donate-yellow.svg
|
52
|
+
[🖇kofi]: https://ko-fi.com/O5O86SNP4
|
53
|
+
[🖇patreon-img]: https://img.shields.io/badge/patreon-donate-yellow.svg
|
54
|
+
[🖇patreon]: https://patreon.com/galtzo
|
55
|
+
|
56
|
+
<span class="badge-buymealatte">
|
57
|
+
<a href="https://www.buymeacoffee.com/pboling"><img src="https://img.buymeacoffee.com/button-api/?text=Buy me a latte&emoji=&slug=pboling&button_colour=FFDD00&font_colour=000000&font_family=Cookie&outline_colour=000000&coffee_colour=ffffff" /></a>
|
58
|
+
</span>
|
59
|
+
|
60
|
+
</div>
|
61
|
+
</div>
|
62
|
+
|
63
|
+
Ruby OpenID Test Server (ROTS) is a dummy OpenID server that makes consumer tests dead easy.
|
64
|
+
|
65
|
+
ROTS is a minimal implementation of an OpenID server, developed on top of the Rack middleware, this
|
66
|
+
server provides an easy to use interface to make testing OpenID consumers really easy.
|
67
|
+
|
68
|
+
## No more mocks
|
69
|
+
|
70
|
+
Have you always wanted to test the authentication of an OpenID consumer implementation, but find your self
|
71
|
+
in a point where is to hard to mock? A lot of people have been there.
|
72
|
+
|
73
|
+
With ROTS, you only need to specify an identity url provided by the dummy server, passing with it a flag
|
74
|
+
saying that you want the authentication to be successful. It handles SREG extensions as well.
|
75
|
+
|
76
|
+
### Or do use mocks, maybe?
|
77
|
+
|
78
|
+
You can also require a library of mocks and request helpers which might be useful in your tests (perhaps in your `spec_helper.rb`):
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
require "rots/mocks"
|
82
|
+
require "rots/test"
|
83
|
+
|
84
|
+
OpenID.fetcher = Rots::Mocks::Fetcher.new(Rots::Mocks::RotsServer.new)
|
85
|
+
|
86
|
+
RSpec.configure do |config|
|
87
|
+
config.include(Rots::Test::RackTestHelpers)
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
Helpers are written with minitest syntax,
|
92
|
+
but RSpec supports that, so it should work in both RSpec and MiniTest,
|
93
|
+
and you don't need to switch your other tests to use minitest syntax.
|
94
|
+
Use them interchangeably, as needed.
|
95
|
+
```ruby
|
96
|
+
RSpec.configure do |config|
|
97
|
+
config.expect_with(:rspec, :minitest)
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
101
|
+
And in another file (see `spec/rots/mocks/integration_spec.rb` for more):
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
RSpec.describe("openid") do
|
105
|
+
subject(:app) { Rots::Mocks::ClientApp.new(**options) }
|
106
|
+
|
107
|
+
let(:options) { {identifier: "#{Rots::Mocks::RotsServer::SERVER_URL}/john.doe?openid.success=true"} }
|
108
|
+
|
109
|
+
it "with_get" do
|
110
|
+
mock_openid_request(app, "/", method: "GET")
|
111
|
+
follow_openid_redirect!(app)
|
112
|
+
|
113
|
+
assert_equal 200, @response.status
|
114
|
+
assert_equal "GET", @response.headers["X-Method"]
|
115
|
+
assert_equal "/", @response.headers["X-Path"]
|
116
|
+
assert_equal "success", @response.body
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
### Note about the deprecation of stdlib gems `logger`, `rexml`, `stringio`, `net-http`, and `uri`
|
122
|
+
|
123
|
+
They will not be direct dependencies until the situation with bundler is resolved.
|
124
|
+
You will need to add them directly to downstream tools.
|
125
|
+
|
126
|
+
See [this discussion](https://github.com/rubygems/rubygems/issues/7178#issuecomment-2372558363) for more information.
|
127
|
+
|
128
|
+
## How does it work?
|
129
|
+
|
130
|
+
When you install the ROTS gem, a binary called rots is provided for starting the server (for more
|
131
|
+
info about what options you have when executing this file, check the -h option).
|
132
|
+
|
133
|
+
By default, rots will have a test user called "John Doe", with an OpenID identity "john.doe".
|
134
|
+
If you want to use your own test user name, you can specify a config file to rots. The
|
135
|
+
default configuration file looks like this:
|
136
|
+
|
137
|
+
### Default configuration file
|
138
|
+
```yaml
|
139
|
+
identity: john.doe
|
140
|
+
sreg:
|
141
|
+
nickname: jdoe
|
142
|
+
fullname: John Doe
|
143
|
+
email: jhon@doe.com
|
144
|
+
dob: 1985-09-21
|
145
|
+
gender: M
|
146
|
+
```
|
147
|
+
|
148
|
+
You can specify a new config file using the option `--config`.
|
149
|
+
|
150
|
+
## Getting Started
|
151
|
+
|
152
|
+
The best way to get started, is running the rots server, and then starting to execute your OpenID consumer tests/specs. You just have to specify the identity url of your test user, if you want the OpenID response be successful just add the openid.success=true flag to the user identity url. If you don't specify the flag it
|
153
|
+
will return a cancel response instead.
|
154
|
+
|
155
|
+
Example:
|
156
|
+
```ruby
|
157
|
+
it "should authenticate with OpenID" do
|
158
|
+
post("/consumer_openid_login", "identity_url" => "http://localhost:1132/john.doe?openid.success=true")
|
159
|
+
end
|
160
|
+
```
|
161
|
+
|
162
|
+
## 🤝 Contributing
|
163
|
+
|
164
|
+
See [CONTRIBUTING.md][🤝contributing]
|
165
|
+
|
166
|
+
[🤝contributing]: CONTRIBUTING.md
|
167
|
+
|
168
|
+
### Code Coverage
|
169
|
+
|
170
|
+
If you need some ideas of where to help, you could work on adding more code coverage.
|
171
|
+
|
172
|
+
[![Coverage Graph][🔑codecov-g]][🖇codecov]
|
173
|
+
|
174
|
+
[🔑codecov-g]: https://codecov.io/gh/oauth-xx/rots/graphs/tree.svg?token=qycnWzl6qM
|
175
|
+
|
176
|
+
## 🌈 Contributors
|
177
|
+
|
178
|
+
[![Contributors][🖐contributors-img]][🖐contributors]
|
179
|
+
|
180
|
+
Made with [contributors-img][🖐contrib-rocks].
|
181
|
+
|
182
|
+
[🖐contrib-rocks]: https://contrib.rocks
|
183
|
+
[🖐contributors]: https://github.com/oauth-xx/rots/graphs/contributors
|
184
|
+
[🖐contributors-img]: https://contrib.rocks/image?repo=oauth-xx/rots
|
185
|
+
|
186
|
+
## Star History
|
187
|
+
|
188
|
+
<a href="https://star-history.com/#oauth-xx/rots&Date">
|
189
|
+
<picture>
|
190
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=oauth-xx/rots&type=Date&theme=dark" />
|
191
|
+
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=oauth-xx/rots&type=Date" />
|
192
|
+
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=oauth-xx/rots&type=Date" />
|
193
|
+
</picture>
|
194
|
+
</a>
|
195
|
+
|
196
|
+
## 🪇 Code of Conduct
|
197
|
+
|
198
|
+
Everyone interacting in this project's codebases, issue trackers,
|
199
|
+
chat rooms and mailing lists is expected to follow the [code of conduct][🪇conduct].
|
200
|
+
|
201
|
+
[🪇conduct]: CODE_OF_CONDUCT.md
|
202
|
+
|
203
|
+
## 📌 Versioning
|
204
|
+
|
205
|
+
This Library adheres to [Semantic Versioning 2.0.0][📌semver].
|
206
|
+
Violations of this scheme should be reported as bugs.
|
207
|
+
Specifically, if a minor or patch version is released that breaks backward compatibility,
|
208
|
+
a new version should be immediately released that restores compatibility.
|
209
|
+
Breaking changes to the public API will only be introduced with new major versions.
|
210
|
+
|
211
|
+
To get a better understanding of how SemVer is intended to work over a project's lifetime,
|
212
|
+
read this article from the creator of SemVer:
|
213
|
+
|
214
|
+
- ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
|
215
|
+
|
216
|
+
As a result of this policy, you can (and should) specify a dependency on these libraries using
|
217
|
+
the [Pessimistic Version Constraint][📌pvc] with two digits of precision.
|
218
|
+
|
219
|
+
For example:
|
220
|
+
|
221
|
+
```ruby
|
222
|
+
spec.add_dependency("rots", "~> 1.0")
|
223
|
+
```
|
224
|
+
|
225
|
+
See [CHANGELOG.md][📌changelog] for list of releases.
|
226
|
+
|
227
|
+
[comment]: <> ( 📌 VERSIONING LINKS )
|
228
|
+
|
229
|
+
[📌pvc]: http://guides.rubygems.org/patterns/#pessimistic-version-constraint
|
230
|
+
[📌semver]: http://semver.org/
|
231
|
+
[📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
|
232
|
+
[📌changelog]: CHANGELOG.md
|
233
|
+
|
234
|
+
## 📄 License
|
235
|
+
|
236
|
+
The gem is available as open source under the terms of
|
237
|
+
the [MIT License][📄license] [![License: MIT][📄license-img]][📄license-ref].
|
238
|
+
See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright-notice-explainer].
|
239
|
+
|
240
|
+
[comment]: <> ( 📄 LEGAL LINKS )
|
241
|
+
|
242
|
+
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
243
|
+
[📄license]: LICENSE.txt
|
244
|
+
[📄license-ref]: https://opensource.org/licenses/MIT
|
245
|
+
[📄license-img]: https://img.shields.io/badge/License-MIT-green.svg
|
246
|
+
|
247
|
+
### © Copyright
|
248
|
+
|
249
|
+
* Copyright (c) 2013 - 2014, 2016 - 2020, 2023 - 2024 [Peter H. Boling][peterboling] of [Rails Bling][railsbling]
|
250
|
+
|
251
|
+
[railsbling]: http://www.railsbling.com
|
252
|
+
[peterboling]: http://www.peterboling.com
|
253
|
+
[bundle-group-pattern]: https://gist.github.com/pboling/4564780
|
254
|
+
[documentation]: http://rdoc.info/github/oauth-xx/rots/frames
|
255
|
+
[homepage]: https://github.com/oauth-xx/rots
|
data/SECURITY.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Security Policy
|
2
|
+
|
3
|
+
## Supported Versions
|
4
|
+
|
5
|
+
| Version | Supported |
|
6
|
+
|---------|-----------|
|
7
|
+
| 1.x | ✅ |
|
8
|
+
| 0.x | ❌ |
|
9
|
+
|
10
|
+
## Reporting a Vulnerability
|
11
|
+
|
12
|
+
Peter Boling is the primary maintainer of this gem. Please find a way
|
13
|
+
to [contact him directly](https://railsbling.com/contact) to report the issue. Include as much relevant information as
|
14
|
+
possible.
|
data/exe/rots
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require "rots"
|
5
|
+
|
6
|
+
server_options = {
|
7
|
+
debugger: false,
|
8
|
+
port: 1123,
|
9
|
+
verbose: true,
|
10
|
+
storage: File.join(".", "tmp", "rots"),
|
11
|
+
config: <<~DEFAULT_CONFIG,
|
12
|
+
# Default configuration file
|
13
|
+
identity: john.doe
|
14
|
+
sreg:
|
15
|
+
nickname: jdoe
|
16
|
+
fullname: John Doe
|
17
|
+
email: jhon@doe.com
|
18
|
+
dob: 1985-09-21
|
19
|
+
gender: M
|
20
|
+
|
21
|
+
DEFAULT_CONFIG
|
22
|
+
}
|
23
|
+
|
24
|
+
opts = OptionParser.new do |opts|
|
25
|
+
opts.banner = "Usage: rots [options]"
|
26
|
+
|
27
|
+
opts.separator("")
|
28
|
+
opts.separator("Options:")
|
29
|
+
|
30
|
+
opts.on(
|
31
|
+
"-p",
|
32
|
+
"--port PORT",
|
33
|
+
"use PORT (default: 1123)",
|
34
|
+
) do |port|
|
35
|
+
server_options[:port] = port
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on(
|
39
|
+
"-s",
|
40
|
+
"--storage PATH",
|
41
|
+
"use PATH as the OpenID Server storage path (default: ./tmp/rots)",
|
42
|
+
) do |storage_path|
|
43
|
+
server_options[:storage] = storage_path
|
44
|
+
end
|
45
|
+
|
46
|
+
opts.on(
|
47
|
+
"-c",
|
48
|
+
"--config FILE.yaml",
|
49
|
+
"server configuration YAML file",
|
50
|
+
) do |config_path|
|
51
|
+
abort("\x1B[31mConfiguration file #{config_path} not found\x1B[0m") unless File.exist?(config_path)
|
52
|
+
server_options[:config] = File.new(config_path)
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on(
|
56
|
+
"-s",
|
57
|
+
"--silent",
|
58
|
+
"If specified, the server will be in silent mode",
|
59
|
+
) do
|
60
|
+
server_options[:verbose] = false
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on("-d", "--debugger") do
|
64
|
+
server_options[:debugger] = true
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.separator("")
|
68
|
+
opts.separator("Common options:")
|
69
|
+
|
70
|
+
opts.on_tail("-h", "--help", "Show this help message") do
|
71
|
+
puts opts
|
72
|
+
exit
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
opts.parse!(ARGV)
|
77
|
+
|
78
|
+
config = YAML.load(server_options[:config], permitted_classes: [Date])
|
79
|
+
|
80
|
+
require "ruby-debug" if server_options[:debugger]
|
81
|
+
|
82
|
+
server = Rack::Builder.new do
|
83
|
+
use(Rack::Lint)
|
84
|
+
if server_options[:verbose]
|
85
|
+
use(Rack::CommonLogger, $stdout)
|
86
|
+
use(Rack::ShowExceptions)
|
87
|
+
end
|
88
|
+
map("/%s" % config["identity"]) do
|
89
|
+
run(Rots::IdentityPageApp.new(config, server_options))
|
90
|
+
end
|
91
|
+
map("/server") do
|
92
|
+
run(Rots::ServerApp.new(config, server_options))
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
puts "\x1B[32mRunning Ruby OpenID Test Server (ROTS) on port #{server_options[:port]}\x1B[0m" if server_options[:verbose]
|
97
|
+
|
98
|
+
Rackup::Server.start(app: server, Port: server_options[:port])
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# external libraries
|
2
|
+
require "rack/request"
|
3
|
+
require "rack/response"
|
4
|
+
require "rack/utils"
|
5
|
+
require "openid"
|
6
|
+
|
7
|
+
class Rots::IdentityPageApp
|
8
|
+
def initialize(config, server_options)
|
9
|
+
@server_options = server_options
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(env)
|
14
|
+
@request = Rack::Request.new(env)
|
15
|
+
Rack::Response.new do |response|
|
16
|
+
response.write(<<~HERE)
|
17
|
+
<html>
|
18
|
+
<head>
|
19
|
+
<link rel="openid2.provider" href="#{op_endpoint}" />
|
20
|
+
<link rel="openid.server" href="#{op_endpoint}" />
|
21
|
+
</head>
|
22
|
+
<body>
|
23
|
+
<h1>This is #{@config["identity"]} identity page</h1>
|
24
|
+
</body>
|
25
|
+
</html>
|
26
|
+
HERE
|
27
|
+
end.finish
|
28
|
+
end
|
29
|
+
|
30
|
+
def op_endpoint
|
31
|
+
"http://%s:%d/server/%s" % [
|
32
|
+
@request.host,
|
33
|
+
@request.port,
|
34
|
+
(@request.params["openid.success"] ? "?openid.success=true" : ""),
|
35
|
+
]
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "rack/openid" # rack-openid2
|
2
|
+
require "rack/session"
|
3
|
+
|
4
|
+
module Rots
|
5
|
+
module Mocks
|
6
|
+
class ClientApp
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
attr_reader :app, :options
|
10
|
+
|
11
|
+
def_delegator :@app, :call
|
12
|
+
|
13
|
+
def initialize(**options)
|
14
|
+
@options = options.dup
|
15
|
+
|
16
|
+
@options[:identifier] ||= "#{Rots::Mocks::RotsServer::SERVER_URL}/john.doe?openid.success=true"
|
17
|
+
|
18
|
+
@app = Rack::Session::Pool.new(Rack::OpenID.new(rack_app))
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def rack_app
|
24
|
+
# block passed to new is evaluated with instance_eval,
|
25
|
+
# which searches `binding` for local variables,
|
26
|
+
# while `self` is searched for instance variables and methods.
|
27
|
+
# A local pointer in `binding` to @options makes it accessible.
|
28
|
+
options = @options
|
29
|
+
lambda { |env|
|
30
|
+
if (resp = env[Rack::OpenID::RESPONSE])
|
31
|
+
headers = {
|
32
|
+
"X-Path" => env["PATH_INFO"],
|
33
|
+
"X-Method" => env["REQUEST_METHOD"],
|
34
|
+
"X-Query-String" => env["QUERY_STRING"],
|
35
|
+
}
|
36
|
+
if resp.status == :success
|
37
|
+
[200, headers, [resp.status.to_s]]
|
38
|
+
elsif resp.status == :setup_needed
|
39
|
+
headers["Location"] = Rots::Mocks::RotsServer::SERVER_URL # TODO update Rots to properly send user_setup_url. This should come from resp.
|
40
|
+
[307, headers, [resp.status.to_s]]
|
41
|
+
else
|
42
|
+
[400, headers, [resp.status.to_s]]
|
43
|
+
end
|
44
|
+
elsif env["MOCK_HTTP_BASIC_AUTH"]
|
45
|
+
[401, {Rack::OpenID::AUTHENTICATE_HEADER => 'Realm="Example"'}, []]
|
46
|
+
else
|
47
|
+
[401, {Rack::OpenID::AUTHENTICATE_HEADER => Rack::OpenID.build_header(options)}, []]
|
48
|
+
end
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "openid" # ruby-openid2
|
2
|
+
require "rack/utils"
|
3
|
+
require "net/http" # stdlib in Ruby < 3, gem after
|
4
|
+
require "net/protocol"
|
5
|
+
|
6
|
+
module Rots
|
7
|
+
module Mocks
|
8
|
+
class Fetcher
|
9
|
+
def initialize(app)
|
10
|
+
@app = app
|
11
|
+
end
|
12
|
+
|
13
|
+
def fetch(url, body = nil, headers = nil, limit = nil)
|
14
|
+
opts = (headers || {}).dup
|
15
|
+
opts[:input] = body
|
16
|
+
opts[:method] = "POST" if body
|
17
|
+
env = Rack::MockRequest.env_for(url, opts)
|
18
|
+
|
19
|
+
status, headers, body = @app.call(env)
|
20
|
+
|
21
|
+
buf = []
|
22
|
+
buf << "HTTP/1.1 #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}"
|
23
|
+
headers.each { |header, value| buf << "#{header}: #{value}" }
|
24
|
+
buf << ""
|
25
|
+
body.each { |part| buf << part }
|
26
|
+
|
27
|
+
io = Net::BufferedIO.new(StringIO.new(buf.join("\n")))
|
28
|
+
res = Net::HTTPResponse.read_new(io)
|
29
|
+
res.reading_body(io, true) {}
|
30
|
+
OpenID::HTTPResponse._from_net_response(res, url)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Rots
|
2
|
+
module Mocks
|
3
|
+
class RotsServer
|
4
|
+
extend Forwardable
|
5
|
+
SERVER_URL = "http://localhost:9292"
|
6
|
+
DEFAULT_CONFIG = {
|
7
|
+
"identity" => "john.doe",
|
8
|
+
"sreg" => {
|
9
|
+
"nickname" => "jdoe",
|
10
|
+
"fullname" => "John Doe",
|
11
|
+
"email" => "jhon@doe.com",
|
12
|
+
"dob" => Date.parse("1985-09-21"),
|
13
|
+
"gender" => "M",
|
14
|
+
}.freeze,
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
attr_reader :app, :config
|
18
|
+
|
19
|
+
def_delegator :@app, :call
|
20
|
+
|
21
|
+
# @param config [Hash, nil] - the configuration of the app's authorizable identity
|
22
|
+
def initialize(config = nil)
|
23
|
+
@config ||= DEFAULT_CONFIG
|
24
|
+
raise ArgumentError, "config must be a Hash" unless self.config.is_a?(Hash)
|
25
|
+
|
26
|
+
@app = rack_app
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def rack_app
|
32
|
+
# block passed to new is evaluated with instance_eval,
|
33
|
+
# which searches `binding` for local variables,
|
34
|
+
# while `self` is searched for instance variables and methods.
|
35
|
+
# A local pointer in `binding` to @config makes it accessible.
|
36
|
+
config = @config
|
37
|
+
Rack::Builder.new do
|
38
|
+
map("/%s" % config["identity"]) do
|
39
|
+
run(Rots::IdentityPageApp.new(config, {}))
|
40
|
+
end
|
41
|
+
|
42
|
+
map("/server") do
|
43
|
+
run(Rots::ServerApp.new(config, storage: Dir.tmpdir))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/rots/mocks.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
# Not in the runtime dependencies.
|
2
|
+
# If you use the mocks, you need to add `rack-openid2` to your Gemfile.
|
3
|
+
require "rack/openid" # rack-openid2
|
4
|
+
|
5
|
+
# this gem's test support files:
|
6
|
+
require_relative "mocks/mock_fetcher"
|
7
|
+
require_relative "mocks/rots_server"
|
8
|
+
require_relative "mocks/client_app"
|