rots 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
|
8
|
+
[![Version](https://img.shields.io/gem/v/rots.svg)](https://rubygems.org/gems/rots)
|
9
|
+
[![Downloads Today](https://img.shields.io/gem/rd/rots.svg)](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"
|