keycard 0.2.4 → 0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 289f06e8e7d3002eba8c6aa13bedf6be9fd2cd643f2923ce8cb5185aeaec6fda
4
- data.tar.gz: 885e1c86b158ff4778764ea0d2a5ee6bd18ff133e811af47032b42b7a56f0e24
3
+ metadata.gz: 3a653bd311fdb43e3c4f202e8761582c459ffa1c4e85a1e7309e337e8dd6e1f0
4
+ data.tar.gz: 846d43693d28a97cdd4a9fca88e0ee51c6a6289ac389122e078ccc9a8193a40f
5
5
  SHA512:
6
- metadata.gz: 1c510e8be9b90985c08d54c07489368b14911c28d595abe51748acea4ec9f2b5914a06c3425d97afc7e9eeae18c8a7a02b1ca8a3850bc0795f88fb897918b384
7
- data.tar.gz: d60d7e51da879687dd570c26382947a619f9978309de7cb797bde095e11043e71c28783e85847f22c12beff652b685db8b0dcdeb55b715197ea502fb0f6c7d4f
6
+ metadata.gz: 6b9185d2dc8a350988c52bfd56c3417840969d89167ee7824132ddc505630b99a4bbc757edd1ea8b644e67da856a3ca78fe88a927334d0ecd7cc16c606de423a
7
+ data.tar.gz: 343cab74ac29ded2ff832c19c141fd0d14dc6fdb7d0da3fb0ba7e32006ba29a0550445a1d42c204d15e569c2797c142a02769e8360cfa9ac8e72c375b2a0f9ad
data/.gitignore CHANGED
@@ -3,6 +3,8 @@
3
3
  /_yardoc/
4
4
  /coverage/
5
5
  /doc/
6
+ /docs/_build/
7
+ /docs/_yard/
6
8
  /pkg/
7
9
  /spec/reports/
8
10
  /tmp/
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  [![Build Status](https://travis-ci.org/mlibrary/keycard.svg?branch=master)](https://travis-ci.org/mlibrary/keycard?branch=master)
2
2
  [![Coverage Status](https://coveralls.io/repos/github/mlibrary/keycard/badge.svg?branch=master)](https://coveralls.io/github/mlibrary/keycard?branch=master)
3
+ [![Documentation Status](https://readthedocs.org/projects/keycard/badge/?version=latest)](https://keycard.readthedocs.io/en/latest/?badge=latest)
3
4
 
4
5
  # Keycard
5
6
 
data/bin/rake ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rake' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rake", "rake")
data/docs/Makefile ADDED
@@ -0,0 +1,24 @@
1
+ # Minimal makefile for Sphinx documentation
2
+ #
3
+
4
+ # You can set these variables from the command line.
5
+ SPHINXOPTS =
6
+ SPHINXBUILD = sphinx-build
7
+ SPHINXPROJ = Keycard
8
+ AUTOBUILD = sphinx-autobuild
9
+ SOURCEDIR = .
10
+ BUILDDIR = _build
11
+
12
+ # Put it first so that "make" without argument is like "make help".
13
+ help:
14
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
15
+
16
+ auto:
17
+ @$(AUTOBUILD) ${@:2} "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
18
+
19
+ .PHONY: auto help Makefile
20
+
21
+ # Catch-all target: route all unknown targets to Sphinx using the new
22
+ # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
23
+ %: Makefile
24
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
File without changes
File without changes
@@ -0,0 +1,210 @@
1
+ Identity and Authentication
2
+ ===========================
3
+
4
+ Users can be identified in any number of ways and carry with them
5
+ attributes that determine the entirety of "who they are". Typical needs
6
+ include identifying a person by username or email address, and building a
7
+ profile of attributes such as geographical region (as determined by IP address),
8
+ or University status (student, staff, etc.). The identifiers and attributes are
9
+ intrinsic to the user and do not, by themselves, grant any permissions within
10
+ an application. Likewise, these attributes cannot be granted within an
11
+ application, but only inspected.
12
+
13
+ This document gives an overview of authentication terminology and scenarios
14
+ from an application perspective. Not all of these concepts are strictly in the
15
+ domain of Keycard (for example, we mention some typical authorization rules as
16
+ they relate to different user types). This background is presented here to
17
+ establish the environment within which Keycard operates and functionality it
18
+ seeks to support. How to use Keycard in an application is documented elsewhere
19
+ (TODO: complete examples and link API).
20
+
21
+ Authentication Glossary
22
+ -----------------------
23
+
24
+ There are many overlapping concepts and terms regarding identity, privacy,
25
+ security, and technology. These definitions give building blocks for the
26
+ discrete combination scenarios that require (or support) different business
27
+ rules.
28
+
29
+ As far as classifying users, there are three dimensions to consider. A user may
30
+ have only one status in a given dimension:
31
+
32
+ * **Identification** -- Anonymous, Unnamed, Named
33
+ * **Affiliation** -- Unaffiliated, Affiliated
34
+ * **Account Status** -- Nonmember, Member
35
+
36
+ * **Anonymous** -- individually indistinguishable from other people except
37
+ circumstantially (e.g., visiting from the same IP address)
38
+ * **Identified** -- a person whose identity has been verified; importantly, the
39
+ identity may not be known to all parties
40
+ * **Unnamed** -- identified, but only opaquely; that is, the person (principal)
41
+ is not revealed to the application, though the specific affiliation is,
42
+ usually an organizational role or roles
43
+ * **Named** -- personally identified; that is, a resolvable identifier for the
44
+ person (principal) is revealed, possibly along with name information
45
+ * **Session** -- a period of usage that is considered to be conducted by the
46
+ same person
47
+ * **Principal** -- a person with an organizational account (but not necessarily
48
+ an application account)
49
+ * **Partner** -- an organization with some agreement with the application
50
+ providers, in order to authenticate its users and offer access on its behalf
51
+ * **Affiliate** -- a person with at least one affiliation relationship with a
52
+ partner; asserted by the organization (e.g., a university asserts that a
53
+ person is a faculty member)
54
+ * **Visitor** -- a person with no identification or affiliation whatsoever;
55
+ effectively unrecognized by any means
56
+ * **Guest** -- a person with some identification or affiliation; recognized, but
57
+ transient, that is, not holding an account of any sort
58
+ * **Member** -- a person with identification; recognized, holding an account;
59
+ Visitors and Guests are considered non-members
60
+
61
+ Not all combinations are sensible for determining business rules. For example,
62
+ membership requires some form of identification, so there can be no anonymous
63
+ members.
64
+
65
+ To aid consideration of the rules for an application, this table names all of
66
+ the unique combinations, which are further defined below. It does not imply
67
+ that all applications should have seven user types, but that each combination
68
+ has unique characteristics that may need to be handled differently. A given
69
+ application may exclude certain types or treat different types the same in many
70
+ ways. For example, an application may completely disregard identification for
71
+ Guests, treating them all the same.
72
+
73
+ .. csv-table::
74
+ :header: "", "Unaffiliated Nonmember", "Unaffiliated Member", "Affiliated Nonmember", "Affiliated Member"
75
+ :stub-columns: 1
76
+
77
+ "Anonymous", "Visitor (Public)", "--", "Unknown Guest", "--"
78
+ "Unnamed", "--", "--", "Unnamed Guest", "Private Member"
79
+ "Named", "--", "Local Account", "Named Guest", "Member"
80
+
81
+
82
+
83
+ Authentication Scenarios / User Types
84
+ -------------------------------------
85
+
86
+ Visitor
87
+ ~~~~~~~
88
+
89
+ A person with no recognized identification or affiliation whatsoever. The user
90
+ is effectively unauthenticated by any means.
91
+
92
+ Anyone who can connect to the application (at the very least by obscuring their
93
+ identity and any affiliation) may act as a visitor, so there should be no
94
+ restrictions that apply to other users that do not apply to visitors. Entry or
95
+ modification of data should be permitted only under scrutiny, where vandalism
96
+ is of no concern and appropriate auditing and moderation are in place.
97
+
98
+ A visitor may have a session to enhance user experience, but all session data
99
+ should be transient and discarded after an appropriate inactivity period, if
100
+ stored server-side.
101
+
102
+ Visitor (Public)
103
+ ................
104
+ All Visitors are anonymous and should be treated as "any public user". This
105
+ typically means that they have access to a limited set of resources and cannot
106
+ receive any personalization features.
107
+
108
+ Guest
109
+ ~~~~~
110
+
111
+ A person with some recognized identification or affiliation. The user is
112
+ authenticated, but transient – that is, not holding an account of any sort.
113
+ This type of user is typically permitted access to restricted materials based
114
+ on agreements between organizations.
115
+
116
+ There may be useful distinctions applied or features available for different
117
+ types of Guest. For example, the text may be personalized for a Named Guest, or
118
+ additional features may be provided to Unnamed Guests with the "faculty"
119
+ designation.
120
+
121
+ Unknown Guest
122
+ .............
123
+ A user connecting from a recognized affiliate network, but with no
124
+ identification. All that can be asserted is that the user has a generic
125
+ affiliation implying that the person can access organizational computing
126
+ resources. This may be by way of public computers, campus networking,
127
+ or VPN access, as examples.
128
+
129
+ Unnamed Guest
130
+ .............
131
+ A person with specified affiliation and a persistent identifier. The identifier
132
+ is opaque, but stable; that is, the same identifier presented over time implies
133
+ that the user is the same person. It is expressly not human-friendly and should
134
+ not be displayed.
135
+
136
+ Keycard calls this persistent ID the user_pid. Generally, the affiliate will
137
+ not present different identifiers for the same person, but that is outside of
138
+ the control and knowledge of the application. It should be assumed that
139
+ different IDs represent different people.
140
+
141
+ The affiliation may be multi-valued and is *scoped*, meaning that it applies
142
+ within a security domain. Common semantics assert that a person has roles like
143
+ member and staff, or member and student, scoped to the entire affiliate
144
+ organization. An example of one scoped affiliation would be
145
+ ``faculty@umich.edu``.
146
+
147
+ Named Guest
148
+ ...........
149
+ A person with specified affiliation and both persistent and enterprise
150
+ identifiers. The persistent identifier is as for Unnamed Guests. The enterprise
151
+ identifier is name-based, meaning that it based on some account name for the
152
+ person used within the affiliate organization. It is expressly personally
153
+ identifiable, and often human-friendly, meaning that other people may recognize
154
+ it and it would be suitable for display.
155
+
156
+ Keycard calls the enterprise ID the ``user_eid``. It is single-valued and
157
+ often, but not always, matches an email address for the person. Generally, this
158
+ ID is stable between sessions, but there is no guarantee that it will not be
159
+ reassigned at some point.
160
+
161
+ Member
162
+ ~~~~~~
163
+
164
+ A person with recognized identification and an account for application features
165
+ such as content ownership. The user is authenticated and persistent.
166
+
167
+ The reasons to maintain Members may vary between application. For example,
168
+ those with a narrower audience may prefer the semantics that anyone
169
+ individually authenticated becomes a Member automatically to simplify data
170
+ modeling and reporting. Those with very broad audiences may choose to have many
171
+ Guests and only a few Members to reduce the number of dormant or single-use
172
+ accounts.
173
+
174
+ Local Account
175
+ .............
176
+ A user (person or machine user) that is only known the application, not an
177
+ identity authority. The application must manage any authentication directly.
178
+ This may not even be an interactive account, but used as a means to record
179
+ ownership or action by the system consistently alongside human users, for
180
+ example.
181
+
182
+ Some applications may have a dedicated super user with a special login
183
+ procedure, where others may manage those tasks by designating human Members as
184
+ administrative users.
185
+
186
+ Private Member
187
+ ..............
188
+ A person with specified affiliation and a privacy-preserving, persistent
189
+ identifier. This Member is very similar to an Unnamed Guest, but has been given
190
+ an account for some application purpose. Some applications may choose to have
191
+ only Unnamed Guests or Private Members, not both types.
192
+
193
+ The authentication information does not include anything personally
194
+ identifiable, so the application must decide whether to ask the user to supply
195
+ items like a display name or email address, or to deal with the lack of
196
+ human-friendly information in another way. For example, an application that
197
+ only maintains a set of favorite items for the user may find no need to provide
198
+ meaningful display to that member others as to whose favorites they are. By
199
+ contrast, an application that tracks and attributes comments to a Member would
200
+ generally need some label for the commenter.
201
+
202
+ Member
203
+ ......
204
+ A person with specified affiliation and both persistent and enterprise
205
+ identifiers. This Member is similar to a Named Guest, but has been given an
206
+ account for some application purpose. This Member fits the classical definition
207
+ of "named user"; that is, account and display information is maintained, likely
208
+ in order to grant individual permissions and display name information to other
209
+ users.
210
+
data/docs/conf.py ADDED
@@ -0,0 +1,46 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import guzzle_sphinx_theme
4
+ from recommonmark.parser import CommonMarkParser
5
+
6
+ # -- General configuration ------------------------------------------------
7
+ project = u'Keycard'
8
+ copyright = u'2018, Regents of the University of Michigan'
9
+ author = u'Noah Botimer'
10
+ version = u'0.2.4'
11
+ release = u'0.2.4'
12
+
13
+
14
+ extensions = ['guzzle_sphinx_theme']
15
+ templates_path = ['_templates']
16
+ master_doc = 'index'
17
+
18
+ source_parsers = {
19
+ '.md': CommonMarkParser,
20
+ }
21
+ source_suffix = ['.rst', '.md']
22
+
23
+ language = None
24
+ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
25
+ pygments_style = 'sphinx'
26
+ todo_include_todos = False
27
+
28
+
29
+ # -- Options for HTML output ----------------------------------------------
30
+ html_theme_path = guzzle_sphinx_theme.html_theme_path()
31
+ html_theme = 'guzzle_sphinx_theme'
32
+ html_static_path = ['_static']
33
+
34
+ # Guzzle theme options (see theme.conf for more information)
35
+ html_theme_options = {
36
+ "project_nav_name": "Keycard",
37
+ }
38
+
39
+ html_sidebars = {
40
+ '**': [
41
+ 'logo-text.html',
42
+ 'globaltoc.html',
43
+ 'searchbox.html',
44
+ ]
45
+ }
46
+
data/docs/index.rst ADDED
@@ -0,0 +1,37 @@
1
+ .. title:: Keycard, authentication for Ruby applications
2
+
3
+ Keycard Documentation
4
+ =====================
5
+
6
+ Keycard is both a Ruby library and an abstract model for authentication and
7
+ directory information for users of an application.
8
+
9
+ Keycard is primarily concerned with establishing identity and supplemental
10
+ attributes of users. It provides a data model for user information and
11
+ conveniences for building applications that will be deployed with reverse
12
+ proxies and single sign-on systems. It is well-suited to enterprise deployments
13
+ where there are external login and directory systems.
14
+
15
+ Authorization needs are not covered by Keycard at all. See Checkpoint_ for a
16
+ library that can store grants based on the Keycard attributes and enforce
17
+ policies against them.
18
+
19
+ Table of Contents
20
+ -----------------
21
+
22
+ .. toctree::
23
+ :maxdepth: 2
24
+
25
+ authentication.rst
26
+ runtime_context.rst
27
+
28
+ .. _Checkpoint: https://github.com/mlibrary/checkpoint
29
+
30
+
31
+ Naming
32
+ ------
33
+ Keycard takes its name from physical keycards, where a person presents a card
34
+ to a reader. The card may hold any number of attributes, including personal
35
+ identification, staff classification, or clearance levels. The reader (or
36
+ attached system) is left to make any authorization decisions or present the
37
+ information to a person to do so.
@@ -0,0 +1,4 @@
1
+ sphinx>=1.6.5,<1.7.0
2
+ sphinx-autobuild>=0.7.1,<0.8.0
3
+ guzzle_sphinx_theme>=0.7.11,<0.8.0
4
+ recommonmark>=0.4.0,<0.5.0
@@ -0,0 +1,42 @@
1
+ Runtime Context
2
+ ===============
3
+
4
+ An application can be run in different environments and configurations for
5
+ different purposes like development, testing, staging, or public use. There are
6
+ many overlapping terms in use, so, for our purposes here, we use the term
7
+ *Runtime Context* to give labels to the scenarios where the infrastructure is
8
+ different, and in what ways.
9
+
10
+ Development Context
11
+ -------------------
12
+
13
+ This means that the application is running with direct access by the client,
14
+ generally from a workstation. There is no front-end server, so all
15
+ authentication must be managed by the application. The Rails environment is
16
+ generally set to ``development``.
17
+
18
+ A proxy managing single sign-on may be emulated either at the Rack or
19
+ application level if needed. Generally, there is some bit of UI or cookie/param
20
+ handling exposed only in development mode to influence how the requests appear
21
+ to the application, or there is a login form for local accounts.
22
+
23
+ Deployment Context
24
+ ------------------
25
+
26
+ This means that the application is deployed to dedicated infrastructure. There
27
+ is a front-end server (proxy) that may or may not manage single sign-on. The
28
+ Rails environment is generally set to ``production``.
29
+
30
+ A typical configuration is to have an Apache web server proxying all traffic,
31
+ with either a module for Cosign, CAS, or Shibboleth configured. There is often
32
+ a fixed path (e.g., ``/login``) that is intercepted to require SSO
33
+ authentication. If the user is authenticated, the request is forwarded on with
34
+ headers in place. If the user cannot authenticate, the app never receives the
35
+ login path request. For Shibboleth scenarios, there is a Service Provider that
36
+ is set up for the endpoint (application URL).
37
+
38
+ With Shibboleth, it is also possible to have the headers present on each
39
+ request when there is an active session with the Service Provider. Some special
40
+ care must be taken here that sessions are initiated and terminated properly and
41
+ when desired (usually on login and logout requests).
42
+
data/keycard.gemspec CHANGED
@@ -26,14 +26,14 @@ Gem::Specification.new do |spec|
26
26
 
27
27
  spec.add_dependency "sequel"
28
28
 
29
- spec.add_development_dependency "bundler", "~> 1.16"
30
- spec.add_development_dependency "coveralls", "~> 0.8"
29
+ spec.add_development_dependency "bundler"
30
+ spec.add_development_dependency "coveralls"
31
31
  spec.add_development_dependency "pry"
32
- spec.add_development_dependency "rake", "~> 12.0"
33
- spec.add_development_dependency "rspec", "~> 3.0"
34
- spec.add_development_dependency "rubocop", "~> 0.52"
35
- spec.add_development_dependency "rubocop-rails", "~> 1.1"
36
- spec.add_development_dependency "rubocop-rspec", "~> 1.16"
32
+ spec.add_development_dependency "rake"
33
+ spec.add_development_dependency "rspec"
34
+ spec.add_development_dependency "rubocop"
35
+ spec.add_development_dependency "rubocop-rails"
36
+ spec.add_development_dependency "rubocop-rspec"
37
37
  spec.add_development_dependency "sqlite3"
38
- spec.add_development_dependency "yard", "~> 0.9"
38
+ spec.add_development_dependency "yard"
39
39
  end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+ require "securerandom"
5
+
6
+ # A typical digest or api key, ready to be encrypted.
7
+ class Keycard::DigestKey
8
+ class HiddenKeyError < StandardError; end
9
+ HIDDEN_KEY = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX".freeze
10
+
11
+ # To simply mint a new key, call #new without any parameters.
12
+ # For wrapping existing, deserialized keys, pass the digest to the constructor.
13
+ # @param digest [String] The value of the hashed key
14
+ # @param key [String] Use this if you'd like to specify the unhashed key.
15
+ # If a digest is also provided, this parameter is ignored.
16
+ def initialize(digest = nil, key: nil)
17
+ if digest
18
+ @digest = digest
19
+ else
20
+ @key = key || SecureRandom.uuid
21
+ end
22
+ end
23
+
24
+ # A string representation of this key. For hidden keys, this returns an
25
+ # obfuscated value.
26
+ # @return [String]
27
+ def to_s
28
+ @key || HIDDEN_KEY
29
+ end
30
+
31
+ # The unhashed value of the key.
32
+ # @return [String]
33
+ # @raise [HiddenKeyError] This exception is raised if the unhashed key is
34
+ # not available.
35
+ def value
36
+ if @key
37
+ @key
38
+ else
39
+ raise HiddenKeyError, "Cannot display hashed/hidden keys"
40
+ end
41
+ end
42
+
43
+ # The result of hashing the key
44
+ # @return [String]
45
+ def digest
46
+ @digest ||= Digest::SHA256.hexdigest(@key)
47
+ end
48
+
49
+ def eql?(other)
50
+ digest == if other.is_a?(self.class)
51
+ other.digest
52
+ else
53
+ other.to_s
54
+ end
55
+ end
56
+ alias == eql?
57
+
58
+ end
59
+
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Keycard
4
- VERSION = "0.2.4"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/keycard.rb CHANGED
@@ -13,6 +13,7 @@ module Keycard
13
13
  end
14
14
  end
15
15
 
16
+ require "keycard/digest_key"
16
17
  require "keycard/db"
17
18
  require "keycard/railtie" if defined?(Rails)
18
19
  require "keycard/institution_finder"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: keycard
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Noah Botimer
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2018-07-20 00:00:00.000000000 Z
12
+ date: 2019-03-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sequel
@@ -29,30 +29,30 @@ dependencies:
29
29
  name: bundler
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - "~>"
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: '1.16'
34
+ version: '0'
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - "~>"
39
+ - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: '1.16'
41
+ version: '0'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: coveralls
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - "~>"
46
+ - - ">="
47
47
  - !ruby/object:Gem::Version
48
- version: '0.8'
48
+ version: '0'
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - "~>"
53
+ - - ">="
54
54
  - !ruby/object:Gem::Version
55
- version: '0.8'
55
+ version: '0'
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: pry
58
58
  requirement: !ruby/object:Gem::Requirement
@@ -71,72 +71,72 @@ dependencies:
71
71
  name: rake
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - "~>"
74
+ - - ">="
75
75
  - !ruby/object:Gem::Version
76
- version: '12.0'
76
+ version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
- - - "~>"
81
+ - - ">="
82
82
  - !ruby/object:Gem::Version
83
- version: '12.0'
83
+ version: '0'
84
84
  - !ruby/object:Gem::Dependency
85
85
  name: rspec
86
86
  requirement: !ruby/object:Gem::Requirement
87
87
  requirements:
88
- - - "~>"
88
+ - - ">="
89
89
  - !ruby/object:Gem::Version
90
- version: '3.0'
90
+ version: '0'
91
91
  type: :development
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
- - - "~>"
95
+ - - ">="
96
96
  - !ruby/object:Gem::Version
97
- version: '3.0'
97
+ version: '0'
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: rubocop
100
100
  requirement: !ruby/object:Gem::Requirement
101
101
  requirements:
102
- - - "~>"
102
+ - - ">="
103
103
  - !ruby/object:Gem::Version
104
- version: '0.52'
104
+ version: '0'
105
105
  type: :development
106
106
  prerelease: false
107
107
  version_requirements: !ruby/object:Gem::Requirement
108
108
  requirements:
109
- - - "~>"
109
+ - - ">="
110
110
  - !ruby/object:Gem::Version
111
- version: '0.52'
111
+ version: '0'
112
112
  - !ruby/object:Gem::Dependency
113
113
  name: rubocop-rails
114
114
  requirement: !ruby/object:Gem::Requirement
115
115
  requirements:
116
- - - "~>"
116
+ - - ">="
117
117
  - !ruby/object:Gem::Version
118
- version: '1.1'
118
+ version: '0'
119
119
  type: :development
120
120
  prerelease: false
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
122
  requirements:
123
- - - "~>"
123
+ - - ">="
124
124
  - !ruby/object:Gem::Version
125
- version: '1.1'
125
+ version: '0'
126
126
  - !ruby/object:Gem::Dependency
127
127
  name: rubocop-rspec
128
128
  requirement: !ruby/object:Gem::Requirement
129
129
  requirements:
130
- - - "~>"
130
+ - - ">="
131
131
  - !ruby/object:Gem::Version
132
- version: '1.16'
132
+ version: '0'
133
133
  type: :development
134
134
  prerelease: false
135
135
  version_requirements: !ruby/object:Gem::Requirement
136
136
  requirements:
137
- - - "~>"
137
+ - - ">="
138
138
  - !ruby/object:Gem::Version
139
- version: '1.16'
139
+ version: '0'
140
140
  - !ruby/object:Gem::Dependency
141
141
  name: sqlite3
142
142
  requirement: !ruby/object:Gem::Requirement
@@ -155,16 +155,16 @@ dependencies:
155
155
  name: yard
156
156
  requirement: !ruby/object:Gem::Requirement
157
157
  requirements:
158
- - - "~>"
158
+ - - ">="
159
159
  - !ruby/object:Gem::Version
160
- version: '0.9'
160
+ version: '0'
161
161
  type: :development
162
162
  prerelease: false
163
163
  version_requirements: !ruby/object:Gem::Requirement
164
164
  requirements:
165
- - - "~>"
165
+ - - ">="
166
166
  - !ruby/object:Gem::Version
167
- version: '0.9'
167
+ version: '0'
168
168
  description:
169
169
  email:
170
170
  - botimer@umich.edu
@@ -183,11 +183,21 @@ files:
183
183
  - README.md
184
184
  - Rakefile
185
185
  - bin/console
186
+ - bin/rake
186
187
  - bin/setup
187
188
  - db/migrations/1_create_tables.rb
189
+ - docs/Makefile
190
+ - docs/_static/.gitkeep
191
+ - docs/_templates/.gitkeep
192
+ - docs/authentication.rst
193
+ - docs/conf.py
194
+ - docs/index.rst
195
+ - docs/requirements.txt
196
+ - docs/runtime_context.rst
188
197
  - keycard.gemspec
189
198
  - lib/keycard.rb
190
199
  - lib/keycard/db.rb
200
+ - lib/keycard/digest_key.rb
191
201
  - lib/keycard/institution_finder.rb
192
202
  - lib/keycard/railtie.rb
193
203
  - lib/keycard/request.rb