nemid 0.1.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
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +70 -0
- data/LICENSE.txt +21 -0
- data/README.md +174 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/nemid.rb +12 -0
- data/lib/nemid/authentication.rb +7 -0
- data/lib/nemid/authentication/params.rb +52 -0
- data/lib/nemid/authentication/response.rb +93 -0
- data/lib/nemid/crypto.rb +53 -0
- data/lib/nemid/errors.rb +17 -0
- data/lib/nemid/errors/app.rb +49 -0
- data/lib/nemid/errors/auth.rb +180 -0
- data/lib/nemid/errors/can.rb +97 -0
- data/lib/nemid/errors/capp.rb +105 -0
- data/lib/nemid/errors/lib.rb +19 -0
- data/lib/nemid/errors/lock.rb +48 -0
- data/lib/nemid/errors/oces.rb +85 -0
- data/lib/nemid/errors/srv.rb +72 -0
- data/lib/nemid/errors/validation.rb +31 -0
- data/lib/nemid/ocsp.rb +81 -0
- data/lib/nemid/ocsp/errors.rb +29 -0
- data/lib/nemid/pid_cpr.rb +68 -0
- data/lib/nemid/version.rb +3 -0
- data/lib/nemid/xmldsig.rb +35 -0
- data/lib/nemid/xmldsig/document.rb +75 -0
- data/nemid.gemspec +32 -0
- metadata +139 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
module NemID
|
2
|
+
module Errors
|
3
|
+
class CAPPError < ResponseError
|
4
|
+
def initialize(msg='')
|
5
|
+
super(msg)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class CAPP001Error < CAPPError
|
10
|
+
def initialize
|
11
|
+
@da = "Nøgleappen kunne ikke blive indskrevet på grund af krænkelse af app'ens begrænsede identites type."
|
12
|
+
@en = "The code app could not be enrolled due to violation of the app's restricted identity type."
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class CAPP002Error < CAPPError
|
18
|
+
def initialize
|
19
|
+
@da = "Din nøgleapp kunne ikke blive indskrevet på grund af krænkelse af suspensionsreglerne."
|
20
|
+
@en = "Your code app could not be enrolled due to violation of the suspension rules."
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class CAPP003Error < CAPPError
|
26
|
+
def initialize
|
27
|
+
@da = "Din nøgleapp kunne ikke blive indskrevet på grund af, at dens app id ikke er i en aktiv status."
|
28
|
+
@en = "Your code app could not be enrolled due to its app id is not in status active."
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class CAPP004Error < CAPPError
|
34
|
+
def initialize
|
35
|
+
@da = "Din nøgleapp er suspenderet eller spærret. Prøv at opdatere din nøgleapp."
|
36
|
+
@en = "Your code app is suspended or revoked. Please try and update your code app."
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class CAPP006Error < CAPPError
|
42
|
+
def initialize
|
43
|
+
@da = "Din nøgleapp kunne ikke blive aktiveret, da den ikke kunne blive fundet for brugeren der loggede ind."
|
44
|
+
@en = "Your code app could not be activated as it could not be found for the user who logged in."
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class CAPP007Error < CAPPError
|
50
|
+
def initialize
|
51
|
+
@da = "Din nøgleapp kunne ikke blive aktiveret, da den ikke har den korrekte status (VALIDATIONS_MISSING)."
|
52
|
+
@en = "Your code app could not be activated as it did not have the correct status (VALIDATION_MISSING)."
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class CAPP008Error < CAPPError
|
58
|
+
def initialize
|
59
|
+
@da = "Din nøgleapp kunne ikke blive aktiveret, da venteperioden ikke er uløbet."
|
60
|
+
@en = "Your code app could not be activated as the waiting period has not expired."
|
61
|
+
super
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class CAPP009Error < CAPPError
|
66
|
+
def initialize
|
67
|
+
@da = "Din nøgleapp kunne ikke blive aktiveret, da venteperioden ikke er uløbet."
|
68
|
+
@en = "Your code app could not be activated as the waiting period has not expired."
|
69
|
+
super
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class CAPP010Error < CAPPError
|
74
|
+
def initialize
|
75
|
+
@da = "Nulstilling af din nøgeleapps pin kunne ikke blive fuldført, da din nøgleapp ikke er i en aktiv status."
|
76
|
+
@en = "The reset of your code app pin could not be done as the code app is not in status active."
|
77
|
+
super
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class CAPP011Error < CAPPError
|
82
|
+
def initialize
|
83
|
+
@da = "Valideringen af admin action challenge fejlede."
|
84
|
+
@en = "The validation of the admin action challenge failed."
|
85
|
+
super
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class CAPP012Error < CAPPError
|
90
|
+
def initialize
|
91
|
+
@da = "Din nøgleapp kunne ikke blive indskrefvet, da dens app id ikke eksisterer."
|
92
|
+
@en = "Your code app could not be enrolled as the code app id does not exist."
|
93
|
+
super
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class CAPP013Error < CAPPError
|
98
|
+
def initialize
|
99
|
+
@da = "Din nøgleapp kunne ikke blive indskrevet på grund af forkert software fingeraftryk eller manglende whitelist af software fingeraftryk."
|
100
|
+
@en = "Your code app could not be enrolled due to incorrect software fingerprint or missing whitelist of software fingerprint"
|
101
|
+
super
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module NemID
|
2
|
+
module Errors
|
3
|
+
class LIBError < ResponseError
|
4
|
+
def initialize(msg='')
|
5
|
+
super(msg)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class LIB002Error < LIBError
|
10
|
+
def initialize
|
11
|
+
@da = "Der er opstået en teknisk fejl på grund af netværksproblemer. Forsøg igen. " \
|
12
|
+
"Kontakt support, hvis problemet fortsætter."
|
13
|
+
@en = "A technical error has occurred due to network issues. Please try again. " \
|
14
|
+
"Contact support if the problem persists"
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module NemID
|
2
|
+
module Errors
|
3
|
+
class LOCKError < ResponseError
|
4
|
+
DA_SUPPORT_URL = '[https://www.nemid.nu/dk-da/support/faa_hjaelp_til_nemid/kontakt/]'
|
5
|
+
EN_SUPPORT_URL = '[https://www.nemid.nu/dk-en/support/contact/]'
|
6
|
+
|
7
|
+
def initialize(msg='')
|
8
|
+
super(msg)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class LOCK001Error < LOCKError
|
13
|
+
def initialize
|
14
|
+
@da = "Du har angivet forkert bruger-id eller adgangskode for mange gange. " \
|
15
|
+
"NemID er nu spærret i 8 timer, hvorefter du kan forsøge igen Har du " \
|
16
|
+
"glemt din adgangskode kan du finde hjælp her #{DA_SUPPORT_URL}. "
|
17
|
+
@en = "You have used the wrong user ID or password too many times. " \
|
18
|
+
"Your NemID is now blocked for 8 hours after which you can try again. " \
|
19
|
+
"If you have forgotten your password you can find support here " \
|
20
|
+
"#{EN_SUPPORT_URL}"
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class LOCK002Error < LOCKError
|
26
|
+
def initialize
|
27
|
+
@da = "Du har angivet en forkert adgangskode for mange gange. " \
|
28
|
+
"Dit NemID er spærret. Kontakt NemID support for at få adgang til dit " \
|
29
|
+
"NemID igen. #{DA_SUPPORT_URL}"
|
30
|
+
@en = "You have used a wrong password too many times. Your NemID is " \
|
31
|
+
"blocked and cannot be used. To get help with this problem, Please contact " \
|
32
|
+
"NemID support. #{EN_SUPPORT_URL}"
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class LOCK003Error < LOCKError
|
38
|
+
def initialize
|
39
|
+
@da = "Du har angivet forkert NemID nøgle for mange gange. " \
|
40
|
+
"Dit NemID er spærret. Kontakt NemID support for at få adgang til dit " \
|
41
|
+
"NemID igen.#{DA_SUPPORT_URL}"
|
42
|
+
@en = "You have entered a wrong NemID key too many times. Your NemID is " \
|
43
|
+
"blocked and cannot be used. Please contact NemID support. #{EN_SUPPORT_URL}"
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module NemID
|
2
|
+
module Errors
|
3
|
+
class OCESError < ResponseError
|
4
|
+
def initialize(msg='')
|
5
|
+
super(msg)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class OCES001Error < OCESError
|
10
|
+
def initialize
|
11
|
+
@da = "Du har kun NemID til netbank. Ønsker du at bruge NemID til andre " \
|
12
|
+
"hjemmesider, skal du tilknytte en offentlig digital signatur til dit NemID. " \
|
13
|
+
"[https://service.nemid.nu/dk-da/bestil_nemid/bestil_offentlig_digital_signatur_til_dit_nemid/]."
|
14
|
+
@en = "You only have NemID for online banking. If you wish to use NemID for " \
|
15
|
+
"other public or private services, you must affiliate a public digital " \
|
16
|
+
"signature to your NemID " \
|
17
|
+
"[https://service.nemid.nu/dk-da/bestil_nemid/bestil_offentlig_digital_signatur_til_dit_nemid/]"
|
18
|
+
super
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class OCES002Error < OCESError
|
23
|
+
def initialize
|
24
|
+
@da = "Ønsker du at bruge NemID til andet end netbank, skal du først " \
|
25
|
+
"tilknytte en offentlig digital signatur. Det kan du gøre ved at lave en " \
|
26
|
+
"almindelig NemID bestilling. " \
|
27
|
+
"Bestil NemID [https://service.nemid.nu/dk-da/bestil_nemid/]."
|
28
|
+
@en = "If you wish to use NemID for other services than online banking, " \
|
29
|
+
"you have to affiliate a public digital signature to your NemID. " \
|
30
|
+
"You can do this by starting the regular NemID order flow, which will " \
|
31
|
+
"then order the needed public digital signature. " \
|
32
|
+
"Request NemID [https://service.nemid.nu/dk-da/bestil_nemid/]"
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class OCES003Error < OCESError
|
38
|
+
def initialize
|
39
|
+
@da = "Der er ikke tilknyttet en offentlig digital signatur til " \
|
40
|
+
"det NemID du har forsøgt at logge på med. Hvis du tidligere har logget " \
|
41
|
+
"ind hos os med NemID, kan fejlen skyldes, at du har flere NemID, og har " \
|
42
|
+
"brugt et andet end normalt."
|
43
|
+
@en = "You have attempted to log on using a NemID with no public " \
|
44
|
+
"digital signature. If you previously have logged on to our service " \
|
45
|
+
"using your NemID, the error can be due to having more than one NemID and " \
|
46
|
+
"having used a different NemID than normally."
|
47
|
+
super
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class OCES004Error < OCESError
|
52
|
+
def initialize
|
53
|
+
@da = "Du kan kun bruge dette NemID til netbank."
|
54
|
+
@en = "You can only use this NemID for your online banking service."
|
55
|
+
super
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class OCES005Error < OCESError
|
60
|
+
def initialize(msg="The service provider is advised to perform a reload of " \
|
61
|
+
"the client so the user can try again. Also, if the problem persists, refer to Support.")
|
62
|
+
@da = "Udstedelsen af din offentlige digitale signatur mislykkedes. " \
|
63
|
+
"Forsøg venligst igen. Hvis problemet fortsætter, kontakt NemID support " \
|
64
|
+
"[https://www.nemid.nu/dk-da/support/faa_hjaelp_til_nemid/kontakt/]"
|
65
|
+
@en = "Issuing your public digital signature failed. Please try again. " \
|
66
|
+
"If the problem persists contact NemID support " \
|
67
|
+
"[https://www.nemid.nu/dk-en/support/contact/]"
|
68
|
+
super
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class OCES006Error < OCESError
|
73
|
+
def initialize
|
74
|
+
@da = "Du har ikke en aktiv offentlig digital signatur tilknyttet " \
|
75
|
+
"NemID i øjeblikket. Ved bestilling af NemID vil du blive tilbudt at knytte " \
|
76
|
+
"en signatur til dit nuværende NemID. Bestil NemID [https://service.nemid.nu/dk-da/bestil_nemid/]."
|
77
|
+
@en = "You currently don’t have an active public digital signature " \
|
78
|
+
"(OCES certificate) affiliated with your NemID. To get this, start the regular " \
|
79
|
+
"NemID order flow after which you will be asked to affiliate a public " \
|
80
|
+
"digital signature with your current NemID. Request NemID [https://service.nemid.nu/dk-da/bestil_nemid/]"
|
81
|
+
super
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module NemID
|
2
|
+
module Errors
|
3
|
+
class SRVError < ResponseError
|
4
|
+
def initialize(msg='')
|
5
|
+
@da = "Der er opstået en teknisk fejl. Forsøg igen. " \
|
6
|
+
"Kontakt support, hvis problemet fortsætter."
|
7
|
+
@en = "A technical error has occurred. Please try again. " \
|
8
|
+
"Contact support if the problem persists. "
|
9
|
+
super(msg)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class SRV001Error < SRVError; end
|
14
|
+
|
15
|
+
class SRV002Error < SRVError; end
|
16
|
+
|
17
|
+
class SRV003Error < SRVError; end
|
18
|
+
|
19
|
+
class SRV004Error < SRVError
|
20
|
+
def initialize
|
21
|
+
super
|
22
|
+
@da = "Der er opstået en teknisk fejl. Kontakt NemID support " \
|
23
|
+
"[https://www.nemid.nu/dk-da/support/faa_hjaelp_til_nemid/kontakt/]."
|
24
|
+
@en = "A technical error has occurred. Please contact NemID support. " \
|
25
|
+
"[https://www.nemid.nu/dk-en/support/contact/]"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class SRV005Error < SRVError; end
|
30
|
+
|
31
|
+
class SRV006Error < SRVError
|
32
|
+
def initialize
|
33
|
+
super
|
34
|
+
@da = "Tidsgrænse er overskredet. Forsøg venligst igen."
|
35
|
+
@en = "Time limit exceeded. Please try again."
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class SRV007Error < SRVError
|
40
|
+
def initialize
|
41
|
+
super
|
42
|
+
@da = "Opdater venligst til nyeste version af appen."
|
43
|
+
@en = "Please update to the most recent version of the app."
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class SRV008Error < SRVError
|
48
|
+
def initialize(msg='Fix the integration issue.')
|
49
|
+
super
|
50
|
+
@da = "Der er opstået en teknisk fejl. Kontakt support."
|
51
|
+
@en = "A technical error has occurred. Contact support."
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class SRV010Error < SRVError
|
56
|
+
def initialize(msg="There could be a problem with the enrollment of the " \
|
57
|
+
"Service Provider’s VOCES certificate or its validity. Contact NemID for support.")
|
58
|
+
super
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class SRV011Error < SRVError
|
63
|
+
def initialize(msg="Fix the integration issue. The value specified in the " \
|
64
|
+
"TRANSACTION_CONTEXT parameter to the JS Client was longer than the " \
|
65
|
+
"allowed 100 characters.")
|
66
|
+
super
|
67
|
+
@da = "Der er opstået en teknisk fejl. Kontakt support."
|
68
|
+
@en = "A technical error has occurred. Contact support."
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module NemID
|
2
|
+
module Errors
|
3
|
+
class ResponseValidationError < ResponseError ; end
|
4
|
+
|
5
|
+
class InvalidSignature < ResponseValidationError
|
6
|
+
def initialize(
|
7
|
+
msg = "Invalid signature in the XML Document. Data might be altered."
|
8
|
+
)
|
9
|
+
super(msg)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class InvalidCertificateChain < ResponseValidationError
|
14
|
+
def initialize(msg = "Invalid certificate chain.")
|
15
|
+
super(msg)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class UserCertificateExpired < ResponseValidationError
|
20
|
+
def initialize(msg = "User certificate has expired.")
|
21
|
+
super(msg)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class UserCertificateRevoked < ResponseValidationError
|
26
|
+
def initialize(msg = "User certificate has been revoked by CA.")
|
27
|
+
super(msg)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/nemid/ocsp.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require_relative 'ocsp/errors'
|
2
|
+
require 'net/http'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module NemID
|
6
|
+
module OCSP
|
7
|
+
def self.request subject:, issuer:, ca:
|
8
|
+
digest = OpenSSL::Digest::SHA1.new
|
9
|
+
certificate_id = OpenSSL::OCSP::CertificateId.new(subject, issuer, digest)
|
10
|
+
|
11
|
+
request = OpenSSL::OCSP::Request.new
|
12
|
+
request.add_certid(certificate_id)
|
13
|
+
request.add_nonce
|
14
|
+
|
15
|
+
ocsp_uris = subject.ocsp_uris
|
16
|
+
ocsp_uri = URI ocsp_uris[0]
|
17
|
+
|
18
|
+
http_response = Net::HTTP.start ocsp_uri.hostname do |http|
|
19
|
+
http.post ocsp_uri.path, request.to_der,
|
20
|
+
'content-type' => 'application/ocsp-request'
|
21
|
+
end
|
22
|
+
|
23
|
+
response = OpenSSL::OCSP::Response.new http_response.body
|
24
|
+
response_basic = response.basic
|
25
|
+
|
26
|
+
response_has_valid_signature?(response_basic, subject, issuer, ca)
|
27
|
+
|
28
|
+
single_response = response_basic.find_response(certificate_id)
|
29
|
+
|
30
|
+
response_has_status_and_is_valid?(single_response)
|
31
|
+
|
32
|
+
raise NonceError if request.check_nonce(response_basic) == 0
|
33
|
+
|
34
|
+
return cert_status(single_response)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# Returns +true+ if the certificate has been revoked or its unknown,
|
40
|
+
# +false+ otherwise.
|
41
|
+
def self.cert_status(single_response)
|
42
|
+
case single_response.cert_status
|
43
|
+
when OpenSSL::OCSP::V_CERTSTATUS_GOOD
|
44
|
+
return false
|
45
|
+
when OpenSSL::OCSP::V_CERTSTATUS_REVOKED
|
46
|
+
return true
|
47
|
+
when OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
|
48
|
+
return true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.check_validity(single_response)
|
53
|
+
unless single_response.check_validity
|
54
|
+
raise InvalidUpdateError
|
55
|
+
end
|
56
|
+
|
57
|
+
return true
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.response_has_status_and_is_valid?(single_response)
|
61
|
+
unless single_response
|
62
|
+
raise NoStatusError
|
63
|
+
end
|
64
|
+
|
65
|
+
return check_validity(single_response)
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.response_has_valid_signature?(response_basic, subject, issuer, ca)
|
69
|
+
store = OpenSSL::X509::Store.new
|
70
|
+
store.add_cert(subject)
|
71
|
+
store.add_cert(issuer)
|
72
|
+
store.add_cert(ca)
|
73
|
+
|
74
|
+
unless response_basic.verify [], store then
|
75
|
+
raise InvalidSignatureError
|
76
|
+
end
|
77
|
+
|
78
|
+
return true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|