Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make encrypting secrets with symmetric-encryption optional #25

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,6 @@ build_config: &build_config
- ./vendor/bundle
key: v1-dependencies-{{ checksum "devise_2fa.gemspec" }}-{{ checksum "Appraisals" }}

- run:
name: Setup Symmetric Encryption Config
command: |
cd spec/dummy/
symmetric-encryption -g

- run:
name: Run Tests
command: |
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Changed
- *Possibly Breaking*: Remove assumption of using symmetric-encryption gem and replace with optional instructions for how to encrypt secrets. For existing applications, you'll likely need to add `gem 'symmetric-encryption'` to your Gemfile if it's not already there.

## [0.4.1] - 2019-10-31
### Changed
Expand Down
44 changes: 40 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
Devise TwoFactor implements two-factor authentication for Devise, using an rfc6238 compatible Time-Based One-Time Password Algorithm.
* Uses [rotp](https://github.com/mdp/rotp) for the generation and verification of codes.
* Uses [RQRCode](https://github.com/whomwah/rqrcode) to generate QR Code PNGs.
* Uses [SymmetricEncryption](https://github.com/rocketjob/symmetric-encryption) to encrypt secrets and recovery codes.

It currently has the following features:

Expand All @@ -22,8 +21,6 @@ Compatible token devices are:

## Installation

Setup the symmetric-encryption gem by following the steps on the (configuration page)[http://rocketjob.github.io/symmetric-encryption/configuration.html]

Add this line to your application's Gemfile:

gem 'devise'
Expand Down Expand Up @@ -103,7 +100,46 @@ The install generator adds some options to the end of your Devise config file (c
* `config.otp_trust_persistence` - The user is allowed to set his browser as "trusted", no more OTP challenges will be asked for that browser, for a limited time. (default: `1.month`, set to false to disable setting the browser as trusted)
* `config.otp_issuer` - The name of the token issuer, to be added to the provisioning url. Display will vary based on token application. (defaults to the Rails application class)

### Development
## Encrypting Secrets

It's best practice to encrypt the secrets stored in the database for authentication and recovery so they can't be exploted should your database be breached. You can use a gem like [SymmetricEncryption](https://github.com/rocketjob/symmetric-encryption) to seamlessly handle the encryption.

The following instructions assume you're starting from scratch and don't have any existing two-factor authentication data.

Add this line to your application's Gemfile:

gem 'symmetric-encryption'

And then execute:

$ bundle

Or install it yourself as:

$ gem install symmetric-encryption

Next, setup the symmetric-encryption gem by following the steps on the (configuration page)[http://rocketjob.github.io/symmetric-encryption/configuration.html]

Finally, modify your model to specify which attributes to encrypt. For Rails 5+, add the following to your model:

attribute :otp_auth_secret, :encrypted
attribute :otp_recovery_secret, :encrypted

For Rails 3/4, add the following to your model:

attr_encrypted :otp_auth_secret
attr_encrypted :otp_recovery_secret
validates :otp_auth_secret, symmetric_encryption: true
validates :otp_recovery_secret, symmetric_encryption: true

And rename the `otp_auth_secret` and `otp_recovery_secret` columns in your database to `encrypted_otp_auth_secret` and `encrypted_otp_recovery_secret`, respectively.

For Mongoid, replace your `otp_auth_secret` and `otp_recovery_secret` fields with the following:

field :encrypted_otp_auth_secret, type: String, encrypted: true
field :encrypted_otp_recovery_secret, type: String, encrypted: true

## Development

Set up the gem for development with `bin/setup`.

Expand Down
1 change: 0 additions & 1 deletion devise_2fa.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ Gem::Specification.new do |gem|
gem.add_runtime_dependency 'devise', '~> 4.6'
gem.add_runtime_dependency 'rotp', '~> 5.1'
gem.add_runtime_dependency 'rqrcode', '~> 0.10.1'
gem.add_runtime_dependency 'symmetric-encryption', '~> 4.3.0'

gem.add_development_dependency 'appraisal'
gem.add_development_dependency 'capybara'
Expand Down
29 changes: 0 additions & 29 deletions lib/generators/active_record/devise_two_factor_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,6 @@ class DeviseTwoFactorGenerator < ActiveRecord::Generators::Base
def copy_devise_migration
migration_template 'migration.rb', "db/migrate/devise_two_factor_add_to_#{table_name}.rb"
end

def inject_field_types
class_path = if namespaced?
class_name.to_s.split("::")
else
[class_name]
end

inject_into_class(model_path, class_path.last, content) if model_exists?
end

def content
<<RUBY
attr_encrypted :otp_auth_secret
attr_encrypted :otp_recovery_secret
validates :otp_auth_secret, symmetric_encryption: true
validates :otp_recovery_secret, symmetric_encryption: true
RUBY
end

private

def model_exists?
File.exist?(File.join(destination_root, model_path))
end

def model_path
@model_path ||= File.join("app", "models", "#{file_path}.rb")
end
end
end
end
4 changes: 2 additions & 2 deletions lib/generators/mongoid/devise_two_factor_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ def inject_field_types
def migration_data
<<RUBY
# Devise TwoFactor
field :encrypted_otp_auth_secret, type: String, encrypted: true
field :encrypted_otp_recovery_secret, type: String, encrypted: true
field :otp_auth_secret, type: String
field :otp_recovery_secret, type: String
field :otp_enabled, type: Boolean, default: false
field :otp_mandatory, type: Boolean, default: false
field :otp_enabled_on, type: DateTime
Expand Down
6 changes: 2 additions & 4 deletions spec/dummy/app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# frozen_string_literal: true

require 'symmetric_encryption'

if defined?(ActiveRecord)
class User < ApplicationRecord
devise :two_factorable, :database_authenticatable, :registerable,
Expand All @@ -11,8 +9,8 @@ class User < ApplicationRecord
require 'mongoid'
class User
include Mongoid::Document
field :encrypted_otp_auth_secret, type: String, encrypted: true
field :encrypted_otp_recovery_secret, type: String, encrypted: true
field :otp_auth_secret, type: String
field :otp_recovery_secret, type: String
field :otp_enabled, type: Boolean, default: false
field :otp_mandatory, type: Boolean, default: false
field :otp_enabled_on, type: DateTime
Expand Down