google_sign_in 0.1.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +12 -0
  3. data/.travis.yml +18 -0
  4. data/Gemfile.lock +130 -10
  5. data/README.md +114 -47
  6. data/Rakefile +31 -1
  7. data/SECURITY.md +15 -0
  8. data/app/controllers/google_sign_in/authorizations_controller.rb +17 -0
  9. data/app/controllers/google_sign_in/base_controller.rb +15 -0
  10. data/app/controllers/google_sign_in/callbacks_controller.rb +27 -0
  11. data/app/helpers/google_sign_in/button_helper.rb +7 -0
  12. data/bin/rails +16 -0
  13. data/config/routes.rb +4 -0
  14. data/google_sign_in.gemspec +9 -6
  15. data/lib/google_sign_in.rb +9 -1
  16. data/lib/google_sign_in/engine.rb +28 -0
  17. data/lib/google_sign_in/identity.rb +10 -21
  18. data/lib/google_sign_in/redirect_protector.rb +25 -0
  19. data/test/certificate.pem +19 -0
  20. data/test/controllers/authorizations_controller_test.rb +26 -0
  21. data/test/controllers/callbacks_controller_test.rb +36 -0
  22. data/test/dummy/.ruby-version +1 -0
  23. data/test/dummy/Rakefile +6 -0
  24. data/test/dummy/app/assets/config/manifest.js +3 -0
  25. data/test/dummy/app/assets/images/.keep +0 -0
  26. data/test/dummy/app/assets/javascripts/application.js +15 -0
  27. data/test/dummy/app/assets/javascripts/cable.js +13 -0
  28. data/test/dummy/app/assets/javascripts/channels/.keep +0 -0
  29. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  30. data/test/dummy/app/channels/application_cable/channel.rb +4 -0
  31. data/test/dummy/app/channels/application_cable/connection.rb +4 -0
  32. data/test/dummy/app/controllers/application_controller.rb +2 -0
  33. data/test/dummy/app/controllers/concerns/.keep +0 -0
  34. data/test/dummy/app/helpers/application_helper.rb +2 -0
  35. data/test/dummy/app/jobs/application_job.rb +2 -0
  36. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  37. data/test/dummy/app/models/application_record.rb +3 -0
  38. data/test/dummy/app/models/concerns/.keep +0 -0
  39. data/test/dummy/app/views/layouts/application.html.erb +15 -0
  40. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  41. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  42. data/test/dummy/bin/bundle +3 -0
  43. data/test/dummy/bin/rails +4 -0
  44. data/test/dummy/bin/rake +4 -0
  45. data/test/dummy/bin/setup +36 -0
  46. data/test/dummy/bin/update +31 -0
  47. data/test/dummy/bin/yarn +11 -0
  48. data/test/dummy/config.ru +5 -0
  49. data/test/dummy/config/application.rb +20 -0
  50. data/test/dummy/config/boot.rb +5 -0
  51. data/test/dummy/config/cable.yml +10 -0
  52. data/test/dummy/config/database.yml +25 -0
  53. data/test/dummy/config/environment.rb +5 -0
  54. data/test/dummy/config/environments/development.rb +32 -0
  55. data/test/dummy/config/environments/production.rb +57 -0
  56. data/test/dummy/config/environments/test.rb +33 -0
  57. data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
  58. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  59. data/test/dummy/config/initializers/content_security_policy.rb +25 -0
  60. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  61. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  62. data/test/dummy/config/initializers/google_sign_in.rb +4 -0
  63. data/test/dummy/config/initializers/inflections.rb +16 -0
  64. data/test/dummy/config/initializers/mime_types.rb +4 -0
  65. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  66. data/test/dummy/config/locales/en.yml +33 -0
  67. data/test/dummy/config/puma.rb +34 -0
  68. data/test/dummy/config/routes.rb +2 -0
  69. data/test/dummy/config/spring.rb +6 -0
  70. data/test/dummy/config/storage.yml +34 -0
  71. data/test/dummy/lib/assets/.keep +0 -0
  72. data/test/dummy/log/.keep +0 -0
  73. data/test/dummy/package.json +5 -0
  74. data/test/dummy/public/404.html +67 -0
  75. data/test/dummy/public/422.html +67 -0
  76. data/test/dummy/public/500.html +66 -0
  77. data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
  78. data/test/dummy/public/apple-touch-icon.png +0 -0
  79. data/test/dummy/public/favicon.ico +0 -0
  80. data/test/helpers/button_helper_test.rb +36 -0
  81. data/test/key.pem +27 -0
  82. data/test/models/identity_test.rb +76 -0
  83. data/test/models/redirect_protector_test.rb +34 -0
  84. data/test/test_helper.rb +27 -3
  85. metadata +200 -10
  86. data/lib/google_sign_in/helper.rb +0 -76
  87. data/lib/google_sign_in/railtie.rb +0 -12
  88. data/test/identity_test.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97c5ef43841bbc4901283ef218bd5bafcd321fbca2cbe51b991dce9c3943a656
4
- data.tar.gz: f644ef5388eda41ae7181c68c53ce10843f8b862946305075023d3c79a91c0cd
3
+ metadata.gz: 557cffa6305ceb683fbba3ea3564c57fa8cf11d0669efe32b424c1ea87cc8958
4
+ data.tar.gz: 3b71e313292efb16cae4ed263fd17618b0873e0e52f7c07a75a5ffb941506b3c
5
5
  SHA512:
6
- metadata.gz: 7a8116d55e09e785113aa8591a2ea3827f45bbe566413b323f3d8712a43dc84a7e21f1c0987c06b4ef5199a5ebf569d9237674ac949011e63aaad527bf725c2a
7
- data.tar.gz: e4e034189b5e8307d5454a2a59a7e5c50e8ebf33813163f9eb241e9f9e4ede44e3f31364cf912a4e2992f156df4ac99de75a401a7ed8112cfbce4d7b89157215
6
+ metadata.gz: 8ef94bd31647bcf663272796d8eba7567c8482c420532329c7bd3f2a8ace1b765638676dd70d6fa81162359fe660dfe26d3050b8f54b3cf4b35e76e224b5bdf5
7
+ data.tar.gz: aa72a39e77567372213df2173ba802cacf1bcb3fc91517ed660c251a96faf0d33baeeaaf84e653e63d91e84abca5b616ce58aeec086bb799fe67a8439bdf26b5
@@ -0,0 +1,12 @@
1
+ .bundle/
2
+ .byebug_history
3
+ log/*.log
4
+ pkg/
5
+
6
+ test/dummy/db/*.sqlite3
7
+ test/dummy/db/*.sqlite3-journal
8
+ test/dummy/log/*.log
9
+ test/dummy/node_modules/
10
+ test/dummy/yarn-error.log
11
+ test/dummy/storage/
12
+ test/dummy/tmp/
@@ -0,0 +1,18 @@
1
+ language: ruby
2
+ sudo: false
3
+ cache: bundler
4
+
5
+ # Bundler/RubyGems incompat on Ruby 2.5.0
6
+ before_install: gem install bundler
7
+
8
+ rvm:
9
+ - 2.2
10
+ - 2.3
11
+ - 2.4
12
+ - 2.5
13
+ - ruby-head
14
+
15
+ matrix:
16
+ allow_failures:
17
+ - rvm: ruby-head
18
+ fast_finish: true
@@ -1,29 +1,147 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- google_sign_in (0.1.2)
5
- activesupport (>= 5.1)
4
+ google_sign_in (1.0.0)
6
5
  google-id-token (>= 1.4.0)
6
+ oauth2 (>= 1.4.0)
7
+ rails (>= 5.2.0)
7
8
 
8
9
  GEM
9
10
  remote: https://rubygems.org/
10
11
  specs:
11
- activesupport (5.1.3)
12
+ actioncable (5.2.1)
13
+ actionpack (= 5.2.1)
14
+ nio4r (~> 2.0)
15
+ websocket-driver (>= 0.6.1)
16
+ actionmailer (5.2.1)
17
+ actionpack (= 5.2.1)
18
+ actionview (= 5.2.1)
19
+ activejob (= 5.2.1)
20
+ mail (~> 2.5, >= 2.5.4)
21
+ rails-dom-testing (~> 2.0)
22
+ actionpack (5.2.1)
23
+ actionview (= 5.2.1)
24
+ activesupport (= 5.2.1)
25
+ rack (~> 2.0)
26
+ rack-test (>= 0.6.3)
27
+ rails-dom-testing (~> 2.0)
28
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
29
+ actionview (5.2.1)
30
+ activesupport (= 5.2.1)
31
+ builder (~> 3.1)
32
+ erubi (~> 1.4)
33
+ rails-dom-testing (~> 2.0)
34
+ rails-html-sanitizer (~> 1.0, >= 1.0.3)
35
+ activejob (5.2.1)
36
+ activesupport (= 5.2.1)
37
+ globalid (>= 0.3.6)
38
+ activemodel (5.2.1)
39
+ activesupport (= 5.2.1)
40
+ activerecord (5.2.1)
41
+ activemodel (= 5.2.1)
42
+ activesupport (= 5.2.1)
43
+ arel (>= 9.0)
44
+ activestorage (5.2.1)
45
+ actionpack (= 5.2.1)
46
+ activerecord (= 5.2.1)
47
+ marcel (~> 0.3.1)
48
+ activesupport (5.2.1)
12
49
  concurrent-ruby (~> 1.0, >= 1.0.2)
13
- i18n (~> 0.7)
50
+ i18n (>= 0.7, < 2)
14
51
  minitest (~> 5.1)
15
52
  tzinfo (~> 1.1)
53
+ addressable (2.5.2)
54
+ public_suffix (>= 2.0.2, < 4.0)
55
+ arel (9.0.0)
56
+ builder (3.2.3)
16
57
  byebug (9.1.0)
17
58
  concurrent-ruby (1.0.5)
18
- google-id-token (1.4.0)
59
+ crack (0.4.3)
60
+ safe_yaml (~> 1.0.0)
61
+ crass (1.0.4)
62
+ erubi (1.7.1)
63
+ faraday (0.12.2)
64
+ multipart-post (>= 1.2, < 3)
65
+ globalid (0.4.1)
66
+ activesupport (>= 4.2.0)
67
+ google-id-token (1.4.2)
19
68
  jwt (>= 1)
20
- i18n (0.8.6)
21
- jwt (2.0.0)
22
- minitest (5.10.3)
69
+ hashdiff (0.3.7)
70
+ i18n (1.1.0)
71
+ concurrent-ruby (~> 1.0)
72
+ jwt (1.5.6)
73
+ loofah (2.2.2)
74
+ crass (~> 1.0.2)
75
+ nokogiri (>= 1.5.9)
76
+ mail (2.7.0)
77
+ mini_mime (>= 0.1.1)
78
+ marcel (0.3.2)
79
+ mimemagic (~> 0.3.2)
80
+ method_source (0.9.0)
81
+ mimemagic (0.3.2)
82
+ mini_mime (1.0.1)
83
+ mini_portile2 (2.3.0)
84
+ minitest (5.11.3)
85
+ multi_json (1.13.1)
86
+ multi_xml (0.6.0)
87
+ multipart-post (2.0.0)
88
+ nio4r (2.3.1)
89
+ nokogiri (1.8.4)
90
+ mini_portile2 (~> 2.3.0)
91
+ oauth2 (1.4.0)
92
+ faraday (>= 0.8, < 0.13)
93
+ jwt (~> 1.0)
94
+ multi_json (~> 1.3)
95
+ multi_xml (~> 0.5)
96
+ rack (>= 1.2, < 3)
97
+ public_suffix (3.0.3)
98
+ rack (2.0.5)
99
+ rack-test (1.1.0)
100
+ rack (>= 1.0, < 3)
101
+ rails (5.2.1)
102
+ actioncable (= 5.2.1)
103
+ actionmailer (= 5.2.1)
104
+ actionpack (= 5.2.1)
105
+ actionview (= 5.2.1)
106
+ activejob (= 5.2.1)
107
+ activemodel (= 5.2.1)
108
+ activerecord (= 5.2.1)
109
+ activestorage (= 5.2.1)
110
+ activesupport (= 5.2.1)
111
+ bundler (>= 1.3.0)
112
+ railties (= 5.2.1)
113
+ sprockets-rails (>= 2.0.0)
114
+ rails-dom-testing (2.0.3)
115
+ activesupport (>= 4.2.0)
116
+ nokogiri (>= 1.6)
117
+ rails-html-sanitizer (1.0.4)
118
+ loofah (~> 2.2, >= 2.2.2)
119
+ railties (5.2.1)
120
+ actionpack (= 5.2.1)
121
+ activesupport (= 5.2.1)
122
+ method_source
123
+ rake (>= 0.8.7)
124
+ thor (>= 0.19.0, < 2.0)
23
125
  rake (12.0.0)
126
+ safe_yaml (1.0.4)
127
+ sprockets (3.7.2)
128
+ concurrent-ruby (~> 1.0)
129
+ rack (> 1, < 3)
130
+ sprockets-rails (3.2.1)
131
+ actionpack (>= 4.0)
132
+ activesupport (>= 4.0)
133
+ sprockets (>= 3.0.0)
134
+ thor (0.20.0)
24
135
  thread_safe (0.3.6)
25
- tzinfo (1.2.3)
136
+ tzinfo (1.2.5)
26
137
  thread_safe (~> 0.1)
138
+ webmock (3.4.2)
139
+ addressable (>= 2.3.6)
140
+ crack (>= 0.3.2)
141
+ hashdiff
142
+ websocket-driver (0.7.0)
143
+ websocket-extensions (>= 0.1.0)
144
+ websocket-extensions (0.1.3)
27
145
 
28
146
  PLATFORMS
29
147
  ruby
@@ -32,7 +150,9 @@ DEPENDENCIES
32
150
  bundler (~> 1.15)
33
151
  byebug
34
152
  google_sign_in!
153
+ jwt
35
154
  rake
155
+ webmock
36
156
 
37
157
  BUNDLED WITH
38
- 1.15.4
158
+ 1.16.4
data/README.md CHANGED
@@ -1,85 +1,152 @@
1
1
  # Google Sign-In for Rails
2
2
 
3
- Google Sign-In provides an easy and secure way to let users signin into and up for your service,
4
- without adding yet-another per-app email/password combination. Integrating it into your Rails app
5
- should be drop-in easy. This gem makes it so.
3
+ This gem allows you to add Google sign-in to your Rails app. You can let users sign up for and sign in to your service
4
+ with their Google accounts.
6
5
 
7
- The only configuration needed is setting the Google client id for your application. [Google has a
8
- tutorial on how to setup a client id](https://developers.google.com/identity/sign-in/web/server-side-flow#step_1_create_a_client_id_and_client_secret).
9
6
 
10
- Once you have your client id, create a `config/initializers/google_sign_in_client_id.rb` file with this:
11
- `GoogleSignIn::Identity.client_id = <THAT CLIENT ID YOU GOT FROM GOOGLE>`
7
+ ## Installation
12
8
 
13
- Now you can use the sign-in integration on your signup or signin screen.
9
+ Add `google_sign_in` to your Rails app’s Gemfile and run `bundle install`:
14
10
 
15
- ## Example
11
+ ```ruby
12
+ gem 'google_sign_in'
13
+ ```
14
+
15
+ Google Sign-In for Rails requires Rails 5.2 or newer.
16
+
17
+
18
+ ## Configuration
19
+
20
+ First, set up an OAuth 2.0 Client ID in the Google API Console:
21
+
22
+ 1. Go to the [API Console](https://console.developers.google.com/apis/credentials).
23
+
24
+ 2. In the projects menu at the top of the page, ensure the correct project is selected or create a new one.
25
+
26
+ 3. In the left-side navigation menu, choose APIs & Services → Credentials.
27
+
28
+ 4. Click the button labeled “Create credentials.” In the menu that appears, choose to create an **OAuth client ID**.
29
+
30
+ 5. When prompted to select an application type, select **Web application**.
16
31
 
17
- Here's the most basic example:
32
+ 6. Enter your application’s name.
33
+
34
+ 7. This gem adds a single OAuth callback to your app at `/google_sign_in/callback`. Under **Authorized redirect URIs**,
35
+ add that callback for your application’s domain: for example, `https://example.com/google_sign_in/callback`.
36
+
37
+ To use Google sign-in in development, you’ll need to add another redirect URI for your local environment, like
38
+ `http://localhost:3000/google_sign_in/callback`. For security reasons, we recommend using a separate
39
+ client ID for local development. Repeat these instructions to set up a new client ID for development.
40
+
41
+ 8. Click the button labeled “Create.” You’ll be presented with a client ID and client secret. Save these.
42
+
43
+ With your client ID set up, configure your Rails application to use it. Run `bin/rails credentials:edit` to edit your
44
+ app’s [encrypted credentials](https://guides.rubyonrails.org/security.html#custom-credentials) and add the following:
45
+
46
+ ```yaml
47
+ google_sign_in:
48
+ client_id: [Your client ID here]
49
+ client_secret: [Your client secret here]
50
+ ```
51
+
52
+ You’re all set to use Google sign-in now. The gem automatically uses the client ID and client secret in your credentials.
53
+
54
+ Alternatively, you can provide the client ID and client secret using ENV variables. Add a new initializer that sets
55
+ `config.google_sign_in.client_id` and `config.google_sign_in.client_secret`:
18
56
 
19
57
  ```ruby
20
- # app/views/layouts/application.html.erb
21
- <html>
22
- <head>
23
- <% # Required for google_sign_in to add the Google JS assets and meta tags! %>
24
- <%= yield :head %>
25
- </head>
26
- <body>
27
- <%= yield %>
28
- </body>
29
- </html>
30
-
31
- # app/views/sessions/new.html.erb
32
- <%= google_sign_in(url: session_path) do %>
33
- # You can replace this with whatever design you please for the button.
34
- # You should follow Google's brand guidelines for Google Sign-In, though:
35
- # https://developers.google.com/identity/branding-guidelines
36
- <%= button_tag("Signin with Google") %>
58
+ # config/initializers/google_sign_in.rb
59
+ Rails.application.configure do
60
+ config.google_sign_in.client_id = ENV['google_sign_in_client_id']
61
+ config.google_sign_in.client_secret = ENV['google_sign_in_client_secret']
62
+ end
63
+ ```
64
+
65
+ **⚠️ Important:** Take care to protect your client secret from disclosure to third parties.
66
+
67
+
68
+ ## Usage
69
+
70
+ This gem provides a `google_sign_in_button` helper. It generates a button which initiates Google sign-in:
71
+
72
+ ```erb
73
+ <%= google_sign_in_button 'Sign in with my Google account', proceed_to: create_login_url %>
74
+
75
+ <%= google_sign_in_button image_tag('google_logo.png', alt: 'Google'), proceed_to: create_login_url %>
76
+
77
+ <%= google_sign_in_button proceed_to: create_login_url do %>
78
+ Sign in with my <%= image_tag('google_logo.png', alt: 'Google') %> account
37
79
  <% end %>
38
80
  ```
39
81
 
40
- The `url` option is the URL that the hidden form will be submitted against along with the Google ID Token
41
- that's set after the user has picked the account and authenticated in the pop-up window Google provides.
82
+ The `proceed_to` argument is required. After authenticating with Google, the gem redirects to `proceed_to`, providing
83
+ a Google ID token in `flash[:google_sign_in_token]`. Your application decides what to do with it:
42
84
 
43
- You can then use that in a sessions controller like so:
85
+ ```ruby
86
+ # config/routes.rb
87
+ Rails.application.routes.draw do
88
+ # ...
89
+ get 'login', to: 'logins#new'
90
+ get 'login/create', to: 'logins#create', as: :create_login
91
+ end
92
+ ```
44
93
 
45
94
  ```ruby
46
- class SessionsController < ApplicationController
95
+ # app/controllers/logins_controller.rb
96
+ class LoginsController < ApplicationController
47
97
  def new
48
98
  end
49
99
 
50
100
  def create
51
- if user = authenticate_via_google
101
+ if user = authenticate_with_google
52
102
  cookies.signed[:user_id] = user.id
53
103
  redirect_to user
54
104
  else
55
- redirect_to new_session_url, alert: "authentication_failed"
105
+ redirect_to new_session_url, alert: 'authentication_failed'
56
106
  end
57
107
  end
58
108
 
59
109
  private
60
- def authenticate_via_google
61
- if params[:google_id_token].present?
62
- User.find_by google_id: GoogleSignIn::Identity.new(params[:google_id_token]).user_id
110
+ def authenticate_with_google
111
+ if flash[:google_sign_in_token].present?
112
+ User.find_by google_id: GoogleSignIn::Identity.new(flash[:google_sign_in_token]).user_id
63
113
  end
64
114
  end
65
115
  end
66
116
  ```
67
117
 
68
- (This example assumes that a user has already signed up for your service using Google Sign-In and that
69
- you're storing the Google user id in the `User#google_id` attribute).
118
+ (The above example assumes the user has already signed up for your service and that you’re storing their Google user ID
119
+ in the `User#google_id` attribute.)
70
120
 
71
- That's it! You can checkout the `GoogleSignIn::Identity` class for the thin wrapping it provides around
72
- the decoding of the Google ID Token using the google-id-token library. Interrogating this identity object
73
- for profile details is particularly helpful when you use Google for signup, as you can get the name, email
74
- address, avatar url, and locale through it.
121
+ For security reasons, the `proceed_to` URL you provide to `google_sign_in_button` is required to reside on the same
122
+ origin as your application. This means it must have the same protocol, host, and port as the page where
123
+ `google_sign_in_button` is used. We enforce this before redirecting to the `proceed_to` URL to guard against
124
+ [open redirects](https://www.owasp.org/index.php/Unvalidated_Redirects_and_Forwards_Cheat_Sheet).
75
125
 
76
- ## Compatibility with Turbolinks
126
+ The `GoogleSignIn::Identity` class decodes and verifies the integrity of a Google ID token. It exposes the profile
127
+ information contained in the token via the following instance methods:
128
+
129
+ * `name`
130
+
131
+ * `email_address`
132
+
133
+ * `user_id`: A value that uniquely identifies a single Google user. Use this, not `email_address`, to associate a
134
+ Google user with an application user. A Google user’s email address may change, but their `user_id` will remain constant.
135
+
136
+ * `email_verified?`
137
+
138
+ * `avatar_url`
139
+
140
+ * `locale`
141
+
142
+
143
+ ## Security
144
+
145
+ For information on our security response procedure, see [SECURITY.md](SECURITY.md).
77
146
 
78
- Google's JavaScript doesn't play nice with Turbolinks. We've routed around the damage by adding a [Turbolinks
79
- meta tag](https://github.com/turbolinks/turbolinks/blob/master/README.md#ensuring-specific-pages-trigger-a-full-reload)
80
- on whatever page `google_sign_in` is called to always do a full reload for that page. Note that this
81
- auto-compatibility feature requires Turbolinks 5.1+.
82
147
 
83
148
  ## License
84
149
 
85
150
  Google Sign-In for Rails is released under the [MIT License](https://opensource.org/licenses/MIT).
151
+
152
+ Google is a registered trademark of Google LLC. This project is not operated by or in any way affiliated with Google LLC.
data/Rakefile CHANGED
@@ -4,7 +4,37 @@ require "rake/testtask"
4
4
 
5
5
  Rake::TestTask.new do |test|
6
6
  test.libs << "test"
7
- test.test_files = FileList["test/*_test.rb"]
7
+ test.test_files = FileList["test/**/*_test.rb"]
8
+ test.warning = false
8
9
  end
9
10
 
10
11
  task default: :test
12
+
13
+ desc "Generates an X509 certificate for decoding test ID tokens"
14
+ task "test:certificate:generate" do
15
+ require "openssl"
16
+ require "active_support"
17
+ require "active_support/core_ext/integer/time"
18
+
19
+ key = OpenSSL::PKey::RSA.new(File.read(File.expand_path("test/key.pem", __dir__)))
20
+
21
+ certificate = OpenSSL::X509::Certificate.new
22
+ certificate.subject = certificate.issuer = OpenSSL::X509::Name.parse("/CN=google-sign-in-for-rails.example.com")
23
+ certificate.not_before = Time.now
24
+ certificate.not_after = 5.years.from_now
25
+ certificate.public_key = key.public_key
26
+ certificate.serial = 0
27
+ certificate.version = 1
28
+
29
+ extension_factory = OpenSSL::X509::ExtensionFactory.new
30
+ extension_factory.subject_certificate = certificate
31
+ extension_factory.issuer_certificate = certificate
32
+ certificate.extensions = [
33
+ extension_factory.create_extension("basicConstraints", "CA:FALSE", true),
34
+ extension_factory.create_extension("keyUsage", "digitalSignature", true),
35
+ extension_factory.create_extension("extendedKeyUsage", "clientAuth", true)
36
+ ]
37
+
38
+ certificate.sign(key, OpenSSL::Digest::SHA1.new)
39
+ File.write(File.expand_path("test/certificate.pem", __dir__), certificate.to_pem)
40
+ end