Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
R
RPServer
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Josh Ji
RPServer
Commits
2b24d6ec
Commit
2b24d6ec
authored
Nov 21, 2022
by
Josh Ji
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
implement the asking flow to IDP
parent
1d32e5f2
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
151 additions
and
13 deletions
+151
-13
pom.xml
pom.xml
+5
-0
src/main/java/com/example/rpserver/controller/MakeCredential.java
.../java/com/example/rpserver/controller/MakeCredential.java
+84
-10
src/main/resources/static/js/webauthn.js
src/main/resources/static/js/webauthn.js
+3
-2
src/test/java/com/example/rpserver/RpServerApplicationTests.java
...t/java/com/example/rpserver/RpServerApplicationTests.java
+59
-1
No files found.
pom.xml
View file @
2b24d6ec
...
@@ -57,6 +57,11 @@
...
@@ -57,6 +57,11 @@
<artifactId>
webauthn4j-core
</artifactId>
<artifactId>
webauthn4j-core
</artifactId>
<version>
0.20.5.RELEASE
</version>
<version>
0.20.5.RELEASE
</version>
</dependency>
</dependency>
<dependency>
<groupId>
co.nstant.in
</groupId>
<artifactId>
cbor
</artifactId>
<version>
0.8
</version>
</dependency>
</dependencies>
</dependencies>
<build>
<build>
...
...
src/main/java/com/example/rpserver/controller/MakeCredential.java
View file @
2b24d6ec
package
com.example.rpserver.controller
;
package
com.example.rpserver.controller
;
import
co.nstant.in.cbor.CborDecoder
;
import
co.nstant.in.cbor.CborException
;
import
co.nstant.in.cbor.model.Array
;
import
co.nstant.in.cbor.model.ByteString
;
import
co.nstant.in.cbor.model.DataItem
;
import
co.nstant.in.cbor.model.UnicodeString
;
import
com.example.rpserver.model.Credential
;
import
com.example.rpserver.model.Credential
;
import
com.example.rpserver.model.FidoUser
;
import
com.example.rpserver.model.FidoUser
;
import
com.example.rpserver.model.Response
;
import
com.example.rpserver.model.Response
;
...
@@ -18,13 +24,16 @@ import com.webauthn4j.validator.attestation.trustworthiness.self.NullSelfAttesta
...
@@ -18,13 +24,16 @@ import com.webauthn4j.validator.attestation.trustworthiness.self.NullSelfAttesta
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.bind.annotation.*
;
import
org.springframework.web.client.RestTemplate
;
import
java.net.http.HttpResponse
;
import
java.security.SecureRandom
;
import
java.security.SecureRandom
;
import
java.util.Date
;
import
java.util.Date
;
import
java.util.HashMap
;
import
java.util.LinkedList
;
import
java.util.LinkedList
;
import
java.util.List
;
@RestController
@RestController
public
class
MakeCredential
{
public
class
MakeCredential
{
...
@@ -39,10 +48,14 @@ public class MakeCredential {
...
@@ -39,10 +48,14 @@ public class MakeCredential {
@ResponseBody
@ResponseBody
@PostMapping
(
"/BeginMakeCredential"
)
@PostMapping
(
"/BeginMakeCredential"
)
public
ResponseEntity
<
PublicKeyCredentialCreationOptions
>
beginMakeCredential
(
@RequestParam
(
"username"
)
String
username
,
public
ResponseEntity
<
PublicKeyCredentialCreationOptions
>
beginMakeCredential
(
@RequestParam
(
"advanced"
)
String
advanced
,
@RequestParam
(
"conveyance"
)
String
conveyance
,
@RequestParam
(
"advancedOptions"
)
String
advancedOptions
,
@RequestParam
(
"attachment"
)
String
attachment
,
@RequestHeader
(
HttpHeaders
.
HOST
)
String
host
){
@RequestParam
(
"username"
)
String
username
)
{
byte
[]
userIdBytes
=
new
byte
[
32
];
byte
[]
userIdBytes
=
new
byte
[
32
];
secureRandom
.
nextBytes
(
userIdBytes
);
secureRandom
.
nextBytes
(
userIdBytes
);
PublicKeyCredentialUserEntity
userEntity
=
new
PublicKeyCredentialUserEntity
(
userIdBytes
,
username
,
username
);
PublicKeyCredentialUserEntity
userEntity
=
new
PublicKeyCredentialUserEntity
(
userIdBytes
,
username
,
username
);
...
@@ -51,7 +64,22 @@ public class MakeCredential {
...
@@ -51,7 +64,22 @@ public class MakeCredential {
LinkedList
<
PublicKeyCredentialParameters
>
parameters
=
new
LinkedList
<>();
LinkedList
<
PublicKeyCredentialParameters
>
parameters
=
new
LinkedList
<>();
parameters
.
add
(
new
PublicKeyCredentialParameters
(
PublicKeyCredentialType
.
PUBLIC_KEY
,
COSEAlgorithmIdentifier
.
RS256
));
parameters
.
add
(
new
PublicKeyCredentialParameters
(
PublicKeyCredentialType
.
PUBLIC_KEY
,
COSEAlgorithmIdentifier
.
RS256
));
parameters
.
add
(
new
PublicKeyCredentialParameters
(
PublicKeyCredentialType
.
PUBLIC_KEY
,
COSEAlgorithmIdentifier
.
ES256
));
parameters
.
add
(
new
PublicKeyCredentialParameters
(
PublicKeyCredentialType
.
PUBLIC_KEY
,
COSEAlgorithmIdentifier
.
ES256
));
PublicKeyCredentialCreationOptions
options
=
new
PublicKeyCredentialCreationOptions
(
rp
,
userEntity
,
challenge
,
parameters
);
PublicKeyCredentialCreationOptions
options
=
new
PublicKeyCredentialCreationOptions
(
rp
,
userEntity
,
challenge
,
parameters
,
null
,
null
,
new
AuthenticatorSelectionCriteria
(
attachment
.
equals
(
"cross-platform"
)?
AuthenticatorAttachment
.
CROSS_PLATFORM
:
AuthenticatorAttachment
.
PLATFORM
,
null
,
null
,
null
),
conveyance
.
equals
(
"direct"
)?
AttestationConveyancePreference
.
DIRECT
:
AttestationConveyancePreference
.
NONE
,
null
);
logger
.
debug
(
"PublicKeyCredentialCreationOptions : {}"
,
options
);
FidoUser
fidoUser
=
new
FidoUser
(
userIdBytes
,
challenge
.
toString
(),
username
);
FidoUser
fidoUser
=
new
FidoUser
(
userIdBytes
,
challenge
.
toString
(),
username
);
userRepository
.
save
(
fidoUser
);
userRepository
.
save
(
fidoUser
);
...
@@ -71,16 +99,21 @@ public class MakeCredential {
...
@@ -71,16 +99,21 @@ public class MakeCredential {
rawId
=
Base64Util
.
decode
(
rawId
);
rawId
=
Base64Util
.
decode
(
rawId
);
// logger
// logger
logger
.
info
(
"clientDataJson : {}"
,
new
String
(
clientDataJSONBytes
));
logger
.
debug
(
"clientDataJson : {}"
,
new
String
(
clientDataJSONBytes
));
logger
.
info
(
"attestationObject hex String : {}"
,
HexUtil
.
encodeToString
(
attestationObjectBytes
));
logger
.
debug
(
"attestationObject hex String : {}"
,
HexUtil
.
encodeToString
(
attestationObjectBytes
));
logger
.
info
(
"rawId hex String : {}"
,
HexUtil
.
encodeToString
(
rawId
));
logger
.
debug
(
"rawId hex String : {}"
,
HexUtil
.
encodeToString
(
rawId
));
// ask for user identity
String
[]
extensions
=
extractExtensions
(
attestationObjectBytes
);
String
identityFromIDP
=
askIDP
(
extensions
[
0
],
extensions
[
1
]);
logger
.
debug
(
"identityFromIDP : {}"
,
identityFromIDP
);
RegistrationRequest
registrationRequest
=
new
RegistrationRequest
(
attestationObjectBytes
,
clientDataJSONBytes
);
RegistrationRequest
registrationRequest
=
new
RegistrationRequest
(
attestationObjectBytes
,
clientDataJSONBytes
);
LinkedList
<
AttestationStatementValidator
>
attestationStatementValidators
=
new
LinkedList
<>();
LinkedList
<
AttestationStatementValidator
>
attestationStatementValidators
=
new
LinkedList
<>();
WebAuthnManager
webAuthnManager
=
new
WebAuthnManager
(
attestationStatementValidators
,
new
NullCertPathTrustworthinessValidator
(),
new
NullSelfAttestationTrustworthinessValidator
());
WebAuthnManager
webAuthnManager
=
new
WebAuthnManager
(
attestationStatementValidators
,
new
NullCertPathTrustworthinessValidator
(),
new
NullSelfAttestationTrustworthinessValidator
());
RegistrationData
registrationData
=
webAuthnManager
.
parse
(
registrationRequest
);
RegistrationData
registrationData
=
webAuthnManager
.
parse
(
registrationRequest
);
logger
.
info
(
"registrationData {}"
,
registrationData
);
logger
.
debug
(
"registrationData {}"
,
registrationData
);
FidoUser
user
=
userRepository
.
findByChallenge
(
registrationData
.
getCollectedClientData
().
getChallenge
().
toString
());
FidoUser
user
=
userRepository
.
findByChallenge
(
registrationData
.
getCollectedClientData
().
getChallenge
().
toString
());
...
@@ -94,4 +127,45 @@ public class MakeCredential {
...
@@ -94,4 +127,45 @@ public class MakeCredential {
return
ResponseEntity
.
ok
().
body
(
new
Response
(
true
,
"Successfully created credential"
));
return
ResponseEntity
.
ok
().
body
(
new
Response
(
true
,
"Successfully created credential"
));
}
}
private
String
[]
extractExtensions
(
byte
[]
attestationObjectBytes
){
String
hmac
=
""
;
String
Cx
=
""
;
try
{
co
.
nstant
.
in
.
cbor
.
model
.
Map
attestationObjectCbor
=
(
co
.
nstant
.
in
.
cbor
.
model
.
Map
)
CborDecoder
.
decode
(
attestationObjectBytes
).
get
(
0
);
for
(
DataItem
key
:
attestationObjectCbor
.
getKeys
())
logger
.
debug
(
"first layer keys : {} : "
,
key
);
co
.
nstant
.
in
.
cbor
.
model
.
Map
attestationStatement
=
(
co
.
nstant
.
in
.
cbor
.
model
.
Map
)
attestationObjectCbor
.
get
(
new
UnicodeString
(
"attStmt"
));
for
(
DataItem
key
:
attestationStatement
.
getKeys
())
logger
.
debug
(
"keys under attStmt node : {}"
,
key
);
List
<
DataItem
>
extensions
=
((
Array
)
attestationStatement
.
get
(
new
UnicodeString
(
"extensions"
))).
getDataItems
();
for
(
DataItem
item
:
extensions
)
logger
.
debug
(
"extensions : {}"
,
item
);
byte
[][]
extensionSendsOut
=
new
byte
[
2
][];
extensionSendsOut
[
0
]
=
((
ByteString
)
extensions
.
get
(
0
)).
getBytes
();
extensionSendsOut
[
1
]
=
((
ByteString
)
extensions
.
get
(
1
)).
getBytes
();
hmac
=
HexUtil
.
encodeToString
(
extensionSendsOut
[
0
]);
// param 1 : hmac
Cx
=
HexUtil
.
encodeToString
(
extensionSendsOut
[
1
]);
// param 2 : Cx
}
catch
(
CborException
e
)
{
e
.
printStackTrace
();
}
return
new
String
[]{
hmac
,
Cx
};
}
private
String
askIDP
(
String
hmac
,
String
Cx
){
RestTemplate
restTemplate
=
new
RestTemplate
();
String
uri
=
"http://localhost:8086/api/idp/askIdentity"
;
HashMap
<
String
,
String
>
map
=
new
HashMap
<>();
String
base64hmac
=
Base64Util
.
encodeToString
(
HexUtil
.
decode
(
hmac
));
String
base64Cx
=
Base64Util
.
encodeToString
(
HexUtil
.
decode
(
Cx
));
map
.
put
(
"HMAC"
,
base64hmac
);
map
.
put
(
"Cx"
,
base64Cx
);
return
restTemplate
.
postForObject
(
uri
,
map
,
String
.
class
);
}
}
}
src/main/resources/static/js/webauthn.js
View file @
2b24d6ec
...
@@ -304,8 +304,9 @@ function makeCredential(advancedOptions) {
...
@@ -304,8 +304,9 @@ function makeCredential(advancedOptions) {
let
username
=
document
.
querySelector
(
'
#username
'
).
value
;
let
username
=
document
.
querySelector
(
'
#username
'
).
value
;
return
_fetch
(
'
/BeginMakeCredential
'
,
{
return
_fetch
(
'
/BeginMakeCredential
'
,
{
advanced
:
true
,
// advancedOptions: JSON.stringify(advancedOptions),
advancedOptions
:
JSON
.
stringify
(
advancedOptions
),
conveyance
:
advancedOptions
.
attestationConveyancePreference
,
attachment
:
advancedOptions
.
authenticatorAttachment
,
// Tyler -----------------
// Tyler -----------------
username
:
username
username
:
username
})
})
...
...
src/test/java/com/example/rpserver/RpServerApplicationTests.java
View file @
2b24d6ec
package
com.example.rpserver
;
package
com.example.rpserver
;
import
co.nstant.in.cbor.CborDecoder
;
import
co.nstant.in.cbor.CborException
;
import
co.nstant.in.cbor.model.Array
;
import
co.nstant.in.cbor.model.ByteString
;
import
co.nstant.in.cbor.model.DataItem
;
import
co.nstant.in.cbor.model.UnicodeString
;
import
com.webauthn4j.util.Base64Util
;
import
com.webauthn4j.util.HexUtil
;
import
org.junit.jupiter.api.Test
;
import
org.junit.jupiter.api.Test
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.http.HttpEntity
;
import
org.springframework.web.client.RestTemplate
;
import
java.util.HashMap
;
import
java.util.List
;
@SpringBootTest
@SpringBootTest
class
RpServerApplicationTests
{
class
RpServerApplicationTests
{
Logger
logger
=
LoggerFactory
.
getLogger
(
RpServerApplicationTests
.
class
);
@Test
@Test
void
contextLoads
()
{
void
contextLoads
()
throws
CborException
{
String
hexString
=
"A363666D74667061636B65646761747453746D74A463616C67266373696758483046022100AAE24FC859C63F9443E1E0CEE91A70544B43BB4392FF10559462E75F75B4B5B0022100DD473DDA4DB18F1E17303FE8693A0AAF252A55ABAA1B14BD748F89769BED4A2663783563815901403082013C3081E4A003020102020A47901280001155957352300A06082A8648CE3D0403023017311530130603550403130C476E756262792050696C6F74301E170D3132303831343138323933325A170D3133303831343138323933325A3031312F302D0603550403132650696C6F74476E756262792D302E342E312D34373930313238303030313135353935373335323059301306072A8648CE3D020106082A8648CE3D030107034200048D617E65C9508E64BCC5673AC82A6799DA3C1446682C258C463FFFDF58DFD2FA3E6C378B53D795C4A4DFFB4199EDD7862F23ABAF0203B4B8911BA0569994E101300A06082A8648CE3D0403020347003044022060CDB6061E9C22262D1AAC1D96D8C70829B2366531DDA268832CB836BCD30DFA0220631B1459F09E6330055722C8D89B7F48883B9089B88D60D1D9795902B30410DF6A657874656E73696F6E738258201FA3CD730BC2E3630D22DB8C9B4A6A4B30C65FE269E023A995E18A2265BB508F504D3A97BCBBA5F38B0E4640C38F09B3F7686175746844617461589449960DE5880E8C687434170F6476605B8FE4AEB9A28632C7995CF3BA831D976345000000007465737461616775696470726C61625F0010C78C7AA8AE8EDB531B01C82C63B8EE3FA5010203262001215820B8A7649E3322C6B22F8E6F06D02CF93E48A27580ED64E19F4056BD92849122C9225820726B2E1FFB54D8BA5A790D398EED09478D62351FA8CC0AFACCA78B394A0D7B51"
;
// hmac=1FA3CD730BC2E3630D22DB8C9B4A6A4B30C65FE269E023A995E18A2265BB508F
// Cx=4D3A97BCBBA5F38B0E4640C38F09B3F7
byte
[]
hexBytes
=
HexUtil
.
decode
(
hexString
);
co
.
nstant
.
in
.
cbor
.
model
.
Map
attestationObjectCbor
=
(
co
.
nstant
.
in
.
cbor
.
model
.
Map
)
CborDecoder
.
decode
(
hexBytes
).
get
(
0
);
for
(
DataItem
key
:
attestationObjectCbor
.
getKeys
())
logger
.
info
(
"first layer keys : {} : "
,
key
);
co
.
nstant
.
in
.
cbor
.
model
.
Map
attestationStatement
=
(
co
.
nstant
.
in
.
cbor
.
model
.
Map
)
attestationObjectCbor
.
get
(
new
UnicodeString
(
"attStmt"
));
for
(
DataItem
key
:
attestationStatement
.
getKeys
())
logger
.
info
(
"keys under attStmt node : {}"
,
key
);
List
<
DataItem
>
extensions
=
((
Array
)
attestationStatement
.
get
(
new
UnicodeString
(
"extensions"
))).
getDataItems
();
for
(
DataItem
item
:
extensions
)
logger
.
info
(
"extensions : {}"
,
item
);
byte
[][]
extensionSendsOut
=
new
byte
[
2
][];
extensionSendsOut
[
0
]
=
((
ByteString
)
extensions
.
get
(
0
)).
getBytes
();
extensionSendsOut
[
1
]
=
((
ByteString
)
extensions
.
get
(
1
)).
getBytes
();
String
hmac
=
HexUtil
.
encodeToString
(
extensionSendsOut
[
0
]);
// param 1 : hmac
String
Cx
=
HexUtil
.
encodeToString
(
extensionSendsOut
[
1
]);
// param 2 : Cx
logger
.
info
(
"p1 : {}"
,
hmac
);
logger
.
info
(
"p2 : {}"
,
Cx
);
logger
.
info
(
"result from IDP : {}"
,
askIDP
(
hmac
,
Cx
));
}
private
String
askIDP
(
String
hmac
,
String
Cx
){
RestTemplate
restTemplate
=
new
RestTemplate
();
String
uri
=
"http://localhost:8086/api/idp/askIdentity"
;
HashMap
<
String
,
String
>
map
=
new
HashMap
<>();
String
base64hmac
=
Base64Util
.
encodeToString
(
HexUtil
.
decode
(
hmac
));
String
base64Cx
=
Base64Util
.
encodeToString
(
HexUtil
.
decode
(
Cx
));
map
.
put
(
"HMAC"
,
base64hmac
);
map
.
put
(
"Cx"
,
base64Cx
);
return
restTemplate
.
postForObject
(
uri
,
map
,
String
.
class
);
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment