@multiplatform.one/wallet 7.7.2
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.
- package/README.md +8 -0
- package/dist/cjs/SiweKeycloakProvider.cjs +273 -0
- package/dist/cjs/SiweKeycloakProvider.native.js +309 -0
- package/dist/cjs/SiweKeycloakProvider.native.js.map +1 -0
- package/dist/cjs/base64.cjs +51 -0
- package/dist/cjs/base64.native.js +55 -0
- package/dist/cjs/base64.native.js.map +1 -0
- package/dist/cjs/base64.spec.cjs +57 -0
- package/dist/cjs/base64.spec.native.js +79 -0
- package/dist/cjs/base64.spec.native.js.map +1 -0
- package/dist/cjs/context.cjs +29 -0
- package/dist/cjs/context.native.js +32 -0
- package/dist/cjs/context.native.js.map +1 -0
- package/dist/cjs/hooks/context.cjs +29 -0
- package/dist/cjs/hooks/context.native.js +32 -0
- package/dist/cjs/hooks/context.native.js.map +1 -0
- package/dist/cjs/hooks/index.cjs +20 -0
- package/dist/cjs/hooks/index.native.js +23 -0
- package/dist/cjs/hooks/index.native.js.map +1 -0
- package/dist/cjs/hooks/useSiweKeycloak.cjs +61 -0
- package/dist/cjs/hooks/useSiweKeycloak.native.js +64 -0
- package/dist/cjs/hooks/useSiweKeycloak.native.js.map +1 -0
- package/dist/cjs/index.cjs +133 -0
- package/dist/cjs/index.native.js +189 -0
- package/dist/cjs/index.native.js.map +1 -0
- package/dist/cjs/render.cjs +78 -0
- package/dist/cjs/render.native.js +82 -0
- package/dist/cjs/render.native.js.map +1 -0
- package/dist/cjs/siwe.cjs +76 -0
- package/dist/cjs/siwe.native.js +94 -0
- package/dist/cjs/siwe.native.js.map +1 -0
- package/dist/cjs/types.cjs +18 -0
- package/dist/cjs/types.native.js +21 -0
- package/dist/cjs/types.native.js.map +1 -0
- package/dist/cjs/util.cjs +53 -0
- package/dist/cjs/util.native.js +56 -0
- package/dist/cjs/util.native.js.map +1 -0
- package/dist/cjs/util.spec.cjs +53 -0
- package/dist/cjs/util.spec.native.js +62 -0
- package/dist/cjs/util.spec.native.js.map +1 -0
- package/dist/esm/SiweKeycloakProvider.mjs +237 -0
- package/dist/esm/SiweKeycloakProvider.mjs.map +1 -0
- package/dist/esm/SiweKeycloakProvider.native.js +270 -0
- package/dist/esm/SiweKeycloakProvider.native.js.map +1 -0
- package/dist/esm/base64.mjs +26 -0
- package/dist/esm/base64.mjs.map +1 -0
- package/dist/esm/base64.native.js +27 -0
- package/dist/esm/base64.native.js.map +1 -0
- package/dist/esm/base64.spec.mjs +58 -0
- package/dist/esm/base64.spec.mjs.map +1 -0
- package/dist/esm/base64.spec.native.js +77 -0
- package/dist/esm/base64.spec.native.js.map +1 -0
- package/dist/esm/context.mjs +4 -0
- package/dist/esm/context.mjs.map +1 -0
- package/dist/esm/context.native.js +4 -0
- package/dist/esm/context.native.js.map +1 -0
- package/dist/esm/hooks/context.mjs +4 -0
- package/dist/esm/hooks/context.mjs.map +1 -0
- package/dist/esm/hooks/context.native.js +4 -0
- package/dist/esm/hooks/context.native.js.map +1 -0
- package/dist/esm/hooks/index.mjs +2 -0
- package/dist/esm/hooks/index.mjs.map +1 -0
- package/dist/esm/hooks/index.native.js +2 -0
- package/dist/esm/hooks/index.native.js.map +1 -0
- package/dist/esm/hooks/useSiweKeycloak.mjs +36 -0
- package/dist/esm/hooks/useSiweKeycloak.mjs.map +1 -0
- package/dist/esm/hooks/useSiweKeycloak.native.js +36 -0
- package/dist/esm/hooks/useSiweKeycloak.native.js.map +1 -0
- package/dist/esm/index.mjs +107 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/index.native.js +160 -0
- package/dist/esm/index.native.js.map +1 -0
- package/dist/esm/render.mjs +42 -0
- package/dist/esm/render.mjs.map +1 -0
- package/dist/esm/render.native.js +43 -0
- package/dist/esm/render.native.js.map +1 -0
- package/dist/esm/siwe.mjs +51 -0
- package/dist/esm/siwe.mjs.map +1 -0
- package/dist/esm/siwe.native.js +66 -0
- package/dist/esm/siwe.native.js.map +1 -0
- package/dist/esm/types.mjs +2 -0
- package/dist/esm/types.mjs.map +1 -0
- package/dist/esm/types.native.js +2 -0
- package/dist/esm/types.native.js.map +1 -0
- package/dist/esm/util.mjs +27 -0
- package/dist/esm/util.mjs.map +1 -0
- package/dist/esm/util.native.js +27 -0
- package/dist/esm/util.native.js.map +1 -0
- package/dist/esm/util.spec.mjs +54 -0
- package/dist/esm/util.spec.mjs.map +1 -0
- package/dist/esm/util.spec.native.js +60 -0
- package/dist/esm/util.spec.native.js.map +1 -0
- package/package.json +81 -0
- package/src/SiweKeycloakProvider.tsx +297 -0
- package/src/base64.spec.ts +65 -0
- package/src/base64.ts +26 -0
- package/src/context.ts +10 -0
- package/src/hooks/context.ts +10 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useSiweKeycloak.ts +23 -0
- package/src/index.ts +127 -0
- package/src/main/java/com/bitspur/keycloak/siwe/Errors.java +21 -0
- package/src/main/java/com/bitspur/keycloak/siwe/LiteAuthenticationService.java +167 -0
- package/src/main/java/com/bitspur/keycloak/siwe/SiweCredentials.java +36 -0
- package/src/main/java/com/bitspur/keycloak/siwe/SiweSession.java +36 -0
- package/src/main/java/com/bitspur/keycloak/siwe/SiweUtil.java +599 -0
- package/src/main/java/com/bitspur/keycloak/siwe/Token.java +85 -0
- package/src/main/java/com/bitspur/keycloak/siwe/authenticators/browser/SiweBrowserAuthenticator.java +109 -0
- package/src/main/java/com/bitspur/keycloak/siwe/authenticators/browser/SiweBrowserAuthenticatorFactory.java +93 -0
- package/src/main/java/com/bitspur/keycloak/siwe/authenticators/directgrant/SiweDirectGrantAuthenticator.java +153 -0
- package/src/main/java/com/bitspur/keycloak/siwe/authenticators/directgrant/SiweDirectGrantAuthenticatorFactory.java +93 -0
- package/src/main/java/com/bitspur/keycloak/siwe/jpa/nonce/SiweNonce.java +95 -0
- package/src/main/java/com/bitspur/keycloak/siwe/jpa/nonce/SiweNonceJpaEntityProvider.java +82 -0
- package/src/main/java/com/bitspur/keycloak/siwe/jpa/nonce/SiweNonceJpaEntityProviderFactory.java +46 -0
- package/src/main/java/com/bitspur/keycloak/siwe/jpa/wallet/SiweWalletAddress.java +103 -0
- package/src/main/java/com/bitspur/keycloak/siwe/jpa/wallet/SiweWalletJpaEntityProvider.java +43 -0
- package/src/main/java/com/bitspur/keycloak/siwe/jpa/wallet/SiweWalletJpaEntityProviderFactory.java +46 -0
- package/src/main/java/com/bitspur/keycloak/siwe/protocol/SiweWalletProtocolMapper.java +85 -0
- package/src/main/java/com/bitspur/keycloak/siwe/resource/SiweResource.java +210 -0
- package/src/main/java/com/bitspur/keycloak/siwe/resource/SiweResourceProvider.java +34 -0
- package/src/main/java/com/bitspur/keycloak/siwe/resource/SiweResourceProviderFactory.java +46 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siu/SiuCredentials.java +52 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siu/SiuMessage.java +362 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siu/SiuParseException.java +23 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siu/SiuUtil.java +547 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siu/authenticators/browser/SiuBrowserAuthenticator.java +112 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siu/authenticators/browser/SiuBrowserAuthenticatorFactory.java +96 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siu/authenticators/directgrant/SiuDirectGrantAuthenticator.java +169 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siu/authenticators/directgrant/SiuDirectGrantAuthenticatorFactory.java +96 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siu/resource/SiuResource.java +244 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siu/resource/SiuResourceProvider.java +34 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siu/resource/SiuResourceProviderFactory.java +48 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siws/SiwsCredentials.java +52 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siws/SiwsMessage.java +362 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siws/SiwsParseException.java +23 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siws/SiwsUtil.java +564 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siws/authenticators/browser/SiwsBrowserAuthenticator.java +112 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siws/authenticators/browser/SiwsBrowserAuthenticatorFactory.java +96 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siws/authenticators/directgrant/SiwsDirectGrantAuthenticator.java +169 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siws/authenticators/directgrant/SiwsDirectGrantAuthenticatorFactory.java +96 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siws/resource/SiwsResource.java +244 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siws/resource/SiwsResourceProvider.java +34 -0
- package/src/main/java/com/bitspur/keycloak/siwe/siws/resource/SiwsResourceProviderFactory.java +48 -0
- package/src/main/resources/META-INF/keycloak-themes.json +8 -0
- package/src/main/resources/META-INF/services/org.keycloak.authentication.AuthenticatorFactory +6 -0
- package/src/main/resources/META-INF/services/org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory +2 -0
- package/src/main/resources/META-INF/services/org.keycloak.protocol.ProtocolMapper +1 -0
- package/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory +3 -0
- package/src/main/resources/META-INF/siwe-nonce-changelog.xml +29 -0
- package/src/main/resources/META-INF/siwe-wallet-changelog.xml +46 -0
- package/src/render.tsx +47 -0
- package/src/siwe.tsx +57 -0
- package/src/types.ts +6 -0
- package/src/util.spec.ts +72 -0
- package/src/util.ts +28 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File: /src/main/java/com/bitspur/keycloak/siwe/jpa/wallet/SiweWalletAddress.java
|
|
3
|
+
* Project: siwe-keycloak
|
|
4
|
+
* File Created: 13-03-2024
|
|
5
|
+
* Author: Clay Risser
|
|
6
|
+
* -----
|
|
7
|
+
* BitSpur (c) Copyright 2022 - 2024
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
package com.bitspur.keycloak.siwe.jpa.wallet;
|
|
11
|
+
|
|
12
|
+
import java.time.LocalDateTime;
|
|
13
|
+
|
|
14
|
+
import jakarta.persistence.Column;
|
|
15
|
+
import jakarta.persistence.Entity;
|
|
16
|
+
import jakarta.persistence.GeneratedValue;
|
|
17
|
+
import jakarta.persistence.GenerationType;
|
|
18
|
+
import jakarta.persistence.Id;
|
|
19
|
+
import jakarta.persistence.NamedQueries;
|
|
20
|
+
import jakarta.persistence.NamedQuery;
|
|
21
|
+
import jakarta.persistence.Table;
|
|
22
|
+
|
|
23
|
+
import org.hibernate.annotations.CreationTimestamp;
|
|
24
|
+
import org.hibernate.annotations.UpdateTimestamp;
|
|
25
|
+
|
|
26
|
+
@Entity
|
|
27
|
+
@Table(name = "SIWE_WALLET_ADDRESS")
|
|
28
|
+
@NamedQueries({
|
|
29
|
+
@NamedQuery(name = "findByAddress", query = "from SiweWalletAddress where address = :address"),
|
|
30
|
+
@NamedQuery(name = "findByUserId", query = "from SiweWalletAddress where userId = :userId"),
|
|
31
|
+
@NamedQuery(name = "findByRealmAddress", query = "from SiweWalletAddress where realmId = :realmId and address = :address"),
|
|
32
|
+
@NamedQuery(name = "findByRealmAddressType", query = "from SiweWalletAddress where realmId = :realmId and address = :address and addressType = :addressType")
|
|
33
|
+
})
|
|
34
|
+
public class SiweWalletAddress {
|
|
35
|
+
@Id
|
|
36
|
+
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
|
37
|
+
@Column(name = "ID", nullable = false)
|
|
38
|
+
private Long id;
|
|
39
|
+
|
|
40
|
+
@Column(name = "ADDRESS", nullable = false)
|
|
41
|
+
private String address;
|
|
42
|
+
|
|
43
|
+
@Column(name = "ADDRESS_TYPE", nullable = false)
|
|
44
|
+
private String addressType;
|
|
45
|
+
|
|
46
|
+
@Column(name = "USER_ID", nullable = false)
|
|
47
|
+
private String userId;
|
|
48
|
+
|
|
49
|
+
@Column(name = "REALM_ID", nullable = false)
|
|
50
|
+
private String realmId;
|
|
51
|
+
|
|
52
|
+
@CreationTimestamp
|
|
53
|
+
@Column(name = "CREATED_AT", nullable = false, updatable = false)
|
|
54
|
+
private LocalDateTime createdAt;
|
|
55
|
+
|
|
56
|
+
@UpdateTimestamp
|
|
57
|
+
@Column(name = "UPDATED_AT", nullable = false)
|
|
58
|
+
private LocalDateTime updatedAt;
|
|
59
|
+
|
|
60
|
+
public Long getId() {
|
|
61
|
+
return this.id;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public String getAddress() {
|
|
65
|
+
return this.address;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public String getAddressType() {
|
|
69
|
+
return this.addressType;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public String getUserId() {
|
|
73
|
+
return this.userId;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public String getRealmId() {
|
|
77
|
+
return this.realmId;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public LocalDateTime getCreatedAt() {
|
|
81
|
+
return this.createdAt;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public LocalDateTime getUpdatedAt() {
|
|
85
|
+
return this.updatedAt;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public void setAddress(String address) {
|
|
89
|
+
this.address = address;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public void setAddressType(String addressType) {
|
|
93
|
+
this.addressType = addressType;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public void setUserId(String userId) {
|
|
97
|
+
this.userId = userId;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public void setRealmId(String realmId) {
|
|
101
|
+
this.realmId = realmId;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File: /src/main/java/com/bitspur/keycloak/siwe/jpa/wallet/SiweWalletJpaEntityProvider.java
|
|
3
|
+
* Project: siwe-keycloak
|
|
4
|
+
* File Created: 13-03-2024
|
|
5
|
+
* Author: Clay Risser
|
|
6
|
+
* -----
|
|
7
|
+
* BitSpur (c) Copyright 2022 - 2024
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
package com.bitspur.keycloak.siwe.jpa.wallet;
|
|
11
|
+
|
|
12
|
+
import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider;
|
|
13
|
+
import org.keycloak.models.KeycloakSession;
|
|
14
|
+
|
|
15
|
+
import java.util.Collections;
|
|
16
|
+
import java.util.List;
|
|
17
|
+
|
|
18
|
+
public class SiweWalletJpaEntityProvider implements JpaEntityProvider {
|
|
19
|
+
KeycloakSession session;
|
|
20
|
+
|
|
21
|
+
SiweWalletJpaEntityProvider(KeycloakSession session) {
|
|
22
|
+
this.session = session;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Override
|
|
26
|
+
public List<Class<?>> getEntities() {
|
|
27
|
+
return Collections.<Class<?>>singletonList(SiweWalletAddress.class);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Override
|
|
31
|
+
public String getChangelogLocation() {
|
|
32
|
+
return "META-INF/siwe-wallet-changelog.xml";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@Override
|
|
36
|
+
public void close() {
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Override
|
|
40
|
+
public String getFactoryId() {
|
|
41
|
+
return SiweWalletJpaEntityProviderFactory.ID;
|
|
42
|
+
}
|
|
43
|
+
}
|
package/src/main/java/com/bitspur/keycloak/siwe/jpa/wallet/SiweWalletJpaEntityProviderFactory.java
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File: /src/main/java/com/bitspur/keycloak/siwe/jpa/wallet/SiweWalletJpaEntityProviderFactory.java
|
|
3
|
+
* Project: siwe-keycloak
|
|
4
|
+
* File Created: 20-01-2025 07:52:54
|
|
5
|
+
* Author: Clay Risser
|
|
6
|
+
* -----
|
|
7
|
+
* Last Modified: 20-01-2025 08:04:48
|
|
8
|
+
* Modified By: Clay Risser
|
|
9
|
+
* -----
|
|
10
|
+
* BitSpur (c) Copyright 2022 - 2025
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
package com.bitspur.keycloak.siwe.jpa.wallet;
|
|
14
|
+
|
|
15
|
+
import org.keycloak.Config.Scope;
|
|
16
|
+
import org.keycloak.connections.jpa.entityprovider.JpaEntityProvider;
|
|
17
|
+
import org.keycloak.connections.jpa.entityprovider.JpaEntityProviderFactory;
|
|
18
|
+
import org.keycloak.models.KeycloakSession;
|
|
19
|
+
import org.keycloak.models.KeycloakSessionFactory;
|
|
20
|
+
|
|
21
|
+
public class SiweWalletJpaEntityProviderFactory implements JpaEntityProviderFactory {
|
|
22
|
+
|
|
23
|
+
protected static final String ID = "siwe-wallet-entity-provider";
|
|
24
|
+
|
|
25
|
+
@Override
|
|
26
|
+
public JpaEntityProvider create(KeycloakSession session) {
|
|
27
|
+
return new SiweWalletJpaEntityProvider(session);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Override
|
|
31
|
+
public String getId() {
|
|
32
|
+
return ID;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@Override
|
|
36
|
+
public void init(Scope config) {
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@Override
|
|
40
|
+
public void postInit(KeycloakSessionFactory factory) {
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@Override
|
|
44
|
+
public void close() {
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File: /src/main/java/com/bitspur/keycloak/siwe/protocol/SiweWalletProtocolMapper.java
|
|
3
|
+
* Project: siwe-keycloak
|
|
4
|
+
* File Created: 20-01-2025 16:31:23
|
|
5
|
+
* Author: Clay Risser
|
|
6
|
+
* -----
|
|
7
|
+
* Last Modified: 20-01-2025 16:47:30
|
|
8
|
+
* Modified By: Clay Risser
|
|
9
|
+
* -----
|
|
10
|
+
* BitSpur (c) Copyright 2022 - 2025
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
package com.bitspur.keycloak.siwe.protocol;
|
|
14
|
+
|
|
15
|
+
import com.bitspur.keycloak.siwe.SiweUtil;
|
|
16
|
+
|
|
17
|
+
import org.keycloak.models.ClientSessionContext;
|
|
18
|
+
import org.keycloak.models.KeycloakSession;
|
|
19
|
+
import org.keycloak.models.ProtocolMapperModel;
|
|
20
|
+
import org.keycloak.models.UserSessionModel;
|
|
21
|
+
import org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper;
|
|
22
|
+
import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
|
|
23
|
+
import org.keycloak.protocol.oidc.mappers.OIDCIDTokenMapper;
|
|
24
|
+
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
|
|
25
|
+
import org.keycloak.protocol.oidc.mappers.UserInfoTokenMapper;
|
|
26
|
+
import org.keycloak.provider.ProviderConfigProperty;
|
|
27
|
+
import org.keycloak.representations.IDToken;
|
|
28
|
+
|
|
29
|
+
import java.util.ArrayList;
|
|
30
|
+
import java.util.List;
|
|
31
|
+
|
|
32
|
+
public class SiweWalletProtocolMapper extends AbstractOIDCProtocolMapper
|
|
33
|
+
implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
|
|
34
|
+
|
|
35
|
+
public static final String PROVIDER_ID = "siwe-wallet-mapper";
|
|
36
|
+
public static final String CLAIM_NAME = "wallets";
|
|
37
|
+
|
|
38
|
+
private static final List<ProviderConfigProperty> configProperties = new ArrayList<>();
|
|
39
|
+
|
|
40
|
+
static {
|
|
41
|
+
ProviderConfigProperty property = new ProviderConfigProperty();
|
|
42
|
+
property.setName(CLAIM_NAME);
|
|
43
|
+
property.setLabel("Wallet Addresses Claim Name");
|
|
44
|
+
property.setType(ProviderConfigProperty.STRING_TYPE);
|
|
45
|
+
property.setDefaultValue(CLAIM_NAME);
|
|
46
|
+
property.setHelpText("Name of the claim to add to the token");
|
|
47
|
+
configProperties.add(property);
|
|
48
|
+
OIDCAttributeMapperHelper.addIncludeInTokensConfig(configProperties, SiweWalletProtocolMapper.class);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@Override
|
|
52
|
+
public String getDisplayCategory() {
|
|
53
|
+
return "Token mapper";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@Override
|
|
57
|
+
public String getDisplayType() {
|
|
58
|
+
return "SIWE Wallet Addresses";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@Override
|
|
62
|
+
public String getHelpText() {
|
|
63
|
+
return "Adds wallet addresses to the token in a structured format";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@Override
|
|
67
|
+
public List<ProviderConfigProperty> getConfigProperties() {
|
|
68
|
+
return configProperties;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@Override
|
|
72
|
+
public String getId() {
|
|
73
|
+
return PROVIDER_ID;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
@Override
|
|
77
|
+
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession,
|
|
78
|
+
KeycloakSession keycloakSession, ClientSessionContext clientSessionCtx) {
|
|
79
|
+
String claimName = mappingModel.getConfig().get(CLAIM_NAME);
|
|
80
|
+
if (claimName == null) {
|
|
81
|
+
claimName = CLAIM_NAME;
|
|
82
|
+
}
|
|
83
|
+
SiweUtil.addWalletsToToken(keycloakSession, userSession.getUser(), token.getOtherClaims());
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File: /src/main/java/com/bitspur/keycloak/siwe/resource/SiweResource.java
|
|
3
|
+
* Project: siwe-keycloak
|
|
4
|
+
* File Created: 04-11-2024 22:05:52
|
|
5
|
+
* Author: Clay Risser
|
|
6
|
+
* -----
|
|
7
|
+
* Last Modified: 24-01-2026 00:40:00
|
|
8
|
+
* Modified By: Clay Risser
|
|
9
|
+
* -----
|
|
10
|
+
* BitSpur (c) Copyright 2022 - 2026
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
package com.bitspur.keycloak.siwe.resource;
|
|
14
|
+
|
|
15
|
+
import jakarta.json.Json;
|
|
16
|
+
import jakarta.json.JsonObject;
|
|
17
|
+
import jakarta.ws.rs.GET;
|
|
18
|
+
import jakarta.ws.rs.OPTIONS;
|
|
19
|
+
import jakarta.ws.rs.POST;
|
|
20
|
+
import jakarta.ws.rs.Path;
|
|
21
|
+
import jakarta.ws.rs.Produces;
|
|
22
|
+
import jakarta.ws.rs.core.MediaType;
|
|
23
|
+
import jakarta.ws.rs.core.Response;
|
|
24
|
+
|
|
25
|
+
import org.jboss.logging.Logger;
|
|
26
|
+
import org.keycloak.models.KeycloakSession;
|
|
27
|
+
import org.keycloak.models.UserModel;
|
|
28
|
+
import org.keycloak.services.managers.AuthenticationManager.AuthResult;
|
|
29
|
+
|
|
30
|
+
import com.bitspur.keycloak.siwe.SiweUtil;
|
|
31
|
+
import com.bitspur.keycloak.siwe.LiteAuthenticationService;
|
|
32
|
+
import com.bitspur.keycloak.siwe.SiweSession;
|
|
33
|
+
import com.bitspur.keycloak.siwe.SiweCredentials;
|
|
34
|
+
|
|
35
|
+
import java.io.StringReader;
|
|
36
|
+
import java.util.Base64;
|
|
37
|
+
|
|
38
|
+
public class SiweResource {
|
|
39
|
+
private static final Logger logger = Logger.getLogger(SiweResource.class);
|
|
40
|
+
private final KeycloakSession session;
|
|
41
|
+
private LiteAuthenticationService liteAuthenticationService;
|
|
42
|
+
|
|
43
|
+
public SiweResource(KeycloakSession session) {
|
|
44
|
+
this.session = session;
|
|
45
|
+
this.liteAuthenticationService = new LiteAuthenticationService(this.session);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@OPTIONS
|
|
49
|
+
@Path("nonce")
|
|
50
|
+
public Response optionsNonce() {
|
|
51
|
+
return createCorsPreflightResponse();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@OPTIONS
|
|
55
|
+
@Path("session")
|
|
56
|
+
public Response optionsSession() {
|
|
57
|
+
return createCorsPreflightResponse();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@OPTIONS
|
|
61
|
+
@Path("register")
|
|
62
|
+
public Response optionsRegister() {
|
|
63
|
+
return createCorsPreflightResponse();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@OPTIONS
|
|
67
|
+
@Path("unregister")
|
|
68
|
+
public Response optionsUnregister() {
|
|
69
|
+
return createCorsPreflightResponse();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@GET
|
|
73
|
+
@Path("nonce")
|
|
74
|
+
@Produces({ MediaType.TEXT_PLAIN })
|
|
75
|
+
public Response getNonce() {
|
|
76
|
+
SiweSession siweSession = SiweUtil.generateSiweSession(this.session);
|
|
77
|
+
// cannot use Cookie and NewCookie because it does not support SameSite=None
|
|
78
|
+
String cookieString = String.format("%s=%s; Path=/; Secure; HttpOnly; SameSite=None",
|
|
79
|
+
SiweUtil.KEYCLOAK_SESSION_SIWE, siweSession.getKey());
|
|
80
|
+
return addCorsHeaders(Response.ok(siweSession.getNonce(), MediaType.TEXT_PLAIN)
|
|
81
|
+
.header("Set-Cookie", cookieString))
|
|
82
|
+
.build();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@GET
|
|
86
|
+
@Path("session")
|
|
87
|
+
@Produces({ MediaType.APPLICATION_JSON })
|
|
88
|
+
public Response getSession() {
|
|
89
|
+
UserModel user = this.getCurrentUser();
|
|
90
|
+
if (user == null) {
|
|
91
|
+
return this.createErrorResponse(new Exception("No user"), Response.Status.UNAUTHORIZED);
|
|
92
|
+
}
|
|
93
|
+
JsonObject json = Json.createObjectBuilder()
|
|
94
|
+
.add("address", user.getUsername())
|
|
95
|
+
.add("chainId", "1").build();
|
|
96
|
+
return this.createResponse(json.toString(), Response.Status.OK);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private Response createErrorResponse(Exception e, Response.Status status) {
|
|
100
|
+
JsonObject json = Json.createObjectBuilder().add("message", e.getMessage()).build();
|
|
101
|
+
return this.createResponse(json.toString(), status);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private Response createResponse(String body, Response.Status status) {
|
|
105
|
+
return this.createResponse(body, status, MediaType.APPLICATION_JSON);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private Response createResponse(String body, Response.Status status, String type) {
|
|
109
|
+
return addCorsHeaders(Response.ok(body, type).status(status)).build();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private Response.ResponseBuilder addCorsHeaders(Response.ResponseBuilder builder) {
|
|
113
|
+
return builder
|
|
114
|
+
.header("Access-Control-Allow-Origin", "*")
|
|
115
|
+
.header("Access-Control-Allow-Credentials", "true")
|
|
116
|
+
.header("Access-Control-Allow-Headers", "Authorization, Content-Type")
|
|
117
|
+
.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
|
|
118
|
+
.header("Access-Control-Expose-Headers", "Authorization");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private Response createCorsPreflightResponse() {
|
|
122
|
+
return addCorsHeaders(Response.ok()).build();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@POST
|
|
126
|
+
@Path("register")
|
|
127
|
+
@Produces(MediaType.APPLICATION_JSON)
|
|
128
|
+
public Response register(String body) {
|
|
129
|
+
UserModel user = this.getCurrentUser();
|
|
130
|
+
if (user == null) {
|
|
131
|
+
return this.createErrorResponse(new Exception("no user"), Response.Status.UNAUTHORIZED);
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
logger.info("Register request body: " + body);
|
|
135
|
+
JsonObject jsonBody = Json.createReader(new StringReader(body)).readObject();
|
|
136
|
+
String message = jsonBody.getString("message");
|
|
137
|
+
String signature = jsonBody.getString("signature");
|
|
138
|
+
logger.info("Parsed message: " + message);
|
|
139
|
+
logger.info("Parsed signature: " + signature);
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
SiweCredentials siweCredentials = new SiweCredentials(signature,
|
|
143
|
+
Base64.getEncoder().encodeToString(message.getBytes()));
|
|
144
|
+
logger.info("Successfully created SiweCredentials");
|
|
145
|
+
logger.info("Parsed SIWE message details:");
|
|
146
|
+
logger.info("- Domain: " + siweCredentials.message.getDomain());
|
|
147
|
+
logger.info("- Address: " + siweCredentials.message.getAddress());
|
|
148
|
+
logger.info("- URI: " + siweCredentials.message.getUri());
|
|
149
|
+
logger.info("- Version: " + siweCredentials.message.getVersion());
|
|
150
|
+
logger.info("- Chain ID: " + siweCredentials.message.getChainId());
|
|
151
|
+
logger.info("- Nonce: " + siweCredentials.message.getNonce());
|
|
152
|
+
logger.info("- Issued At: " + siweCredentials.message.getIssuedAt());
|
|
153
|
+
|
|
154
|
+
String address = siweCredentials.message.getAddress();
|
|
155
|
+
UserModel existingUser = SiweUtil.findUserByWalletAddress(session, address);
|
|
156
|
+
if (existingUser != null) {
|
|
157
|
+
return this.createErrorResponse(new Exception("wallet already registered"), Response.Status.CONFLICT);
|
|
158
|
+
}
|
|
159
|
+
JsonObject result = Json.createObjectBuilder()
|
|
160
|
+
.add("registered", SiweUtil.addWalletAddress(session, user, address))
|
|
161
|
+
.build();
|
|
162
|
+
return this.createResponse(result.toString(), Response.Status.OK);
|
|
163
|
+
} catch (Exception e) {
|
|
164
|
+
logger.error("SIWE message parsing failed:", e);
|
|
165
|
+
return this.createErrorResponse(new Exception("invalid siwe message: " + e.getMessage()),
|
|
166
|
+
Response.Status.BAD_REQUEST);
|
|
167
|
+
}
|
|
168
|
+
} catch (Exception e) {
|
|
169
|
+
logger.error("Request processing failed:", e);
|
|
170
|
+
return this.createErrorResponse(e, Response.Status.BAD_REQUEST);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
@POST
|
|
175
|
+
@Path("unregister")
|
|
176
|
+
@Produces(MediaType.APPLICATION_JSON)
|
|
177
|
+
public Response unregister(String body) {
|
|
178
|
+
UserModel user = this.getCurrentUser();
|
|
179
|
+
if (user == null) {
|
|
180
|
+
return this.createErrorResponse(new Exception("no user"), Response.Status.UNAUTHORIZED);
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
JsonObject bodyJson = Json.createReader(new StringReader(body)).readObject();
|
|
184
|
+
String address = bodyJson.getString("address");
|
|
185
|
+
if (address == null || address.isEmpty()) {
|
|
186
|
+
return this.createErrorResponse(new Exception("no address provided"), Response.Status.BAD_REQUEST);
|
|
187
|
+
}
|
|
188
|
+
UserModel existingUser = SiweUtil.findUserByWalletAddress(session, address);
|
|
189
|
+
if (existingUser == null || !existingUser.getId().equals(user.getId())) {
|
|
190
|
+
return this.createErrorResponse(new Exception("wallet not found"), Response.Status.NOT_FOUND);
|
|
191
|
+
}
|
|
192
|
+
JsonObject result = Json.createObjectBuilder()
|
|
193
|
+
.add("unregistered", SiweUtil.removeWalletAddress(session, address))
|
|
194
|
+
.build();
|
|
195
|
+
return this.createResponse(result.toString(), Response.Status.OK);
|
|
196
|
+
} catch (Exception e) {
|
|
197
|
+
return this.createErrorResponse(e, Response.Status.BAD_REQUEST);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private UserModel getCurrentUser() {
|
|
202
|
+
AuthResult authResult = this.liteAuthenticationService.resolveAuthentication(
|
|
203
|
+
this.session.getContext().getRequestHeaders(),
|
|
204
|
+
this.session.getContext().getConnection());
|
|
205
|
+
if (authResult == null) {
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
return authResult.getUser();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File: /src/main/java/com/bitspur/keycloak/siwe/resource/SiweResourceProvider.java
|
|
3
|
+
* Project: authenticators
|
|
4
|
+
* File Created: 08-04-2023 11:27:18
|
|
5
|
+
* Author: Clay Risser
|
|
6
|
+
* -----
|
|
7
|
+
* Last Modified: 10-08-2023 16:34:52
|
|
8
|
+
* Modified By: Clay Risser
|
|
9
|
+
* -----
|
|
10
|
+
* BitSpur (c) Copyright 2022 - 2023
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
package com.bitspur.keycloak.siwe.resource;
|
|
14
|
+
|
|
15
|
+
import org.keycloak.models.KeycloakSession;
|
|
16
|
+
import org.keycloak.services.resource.RealmResourceProvider;
|
|
17
|
+
|
|
18
|
+
public class SiweResourceProvider implements RealmResourceProvider {
|
|
19
|
+
|
|
20
|
+
private final KeycloakSession session;
|
|
21
|
+
|
|
22
|
+
public SiweResourceProvider(KeycloakSession session) {
|
|
23
|
+
this.session = session;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@Override
|
|
27
|
+
public Object getResource() {
|
|
28
|
+
return new SiweResource(this.session);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@Override
|
|
32
|
+
public void close() {
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File: /src/main/java/com/bitspur/keycloak/siwe/resource/SiweResourceProviderFactory.java
|
|
3
|
+
* Project: authenticators
|
|
4
|
+
* File Created: 08-04-2023 11:25:27
|
|
5
|
+
* Author: Clay Risser
|
|
6
|
+
* -----
|
|
7
|
+
* Last Modified: 10-08-2023 16:34:52
|
|
8
|
+
* Modified By: Clay Risser
|
|
9
|
+
* -----
|
|
10
|
+
* BitSpur (c) Copyright 2022 - 2023
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
package com.bitspur.keycloak.siwe.resource;
|
|
14
|
+
|
|
15
|
+
import org.keycloak.models.KeycloakSession;
|
|
16
|
+
import org.keycloak.models.KeycloakSessionFactory;
|
|
17
|
+
import org.keycloak.services.resource.RealmResourceProvider;
|
|
18
|
+
import org.keycloak.services.resource.RealmResourceProviderFactory;
|
|
19
|
+
import static org.keycloak.Config.Scope;
|
|
20
|
+
|
|
21
|
+
public class SiweResourceProviderFactory implements RealmResourceProviderFactory {
|
|
22
|
+
public static final String ID = "siwe";
|
|
23
|
+
|
|
24
|
+
@Override
|
|
25
|
+
public RealmResourceProvider create(KeycloakSession session) {
|
|
26
|
+
return new SiweResourceProvider(session);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@Override
|
|
30
|
+
public void init(Scope scope) {
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@Override
|
|
34
|
+
public void postInit(KeycloakSessionFactory keycloakSessionFactory) {
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@Override
|
|
39
|
+
public void close() {
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@Override
|
|
43
|
+
public String getId() {
|
|
44
|
+
return ID;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File: /src/main/java/com/bitspur/keycloak/siwe/siu/SiuCredentials.java
|
|
3
|
+
* Project: siwe-keycloak
|
|
4
|
+
* File Created: 24-01-2026
|
|
5
|
+
* Author: Clay Risser
|
|
6
|
+
* -----
|
|
7
|
+
* BitSpur (c) Copyright 2022 - 2026
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
package com.bitspur.keycloak.siwe.siu;
|
|
11
|
+
|
|
12
|
+
import com.bitspur.keycloak.siwe.Errors.SiweKeycloakException;
|
|
13
|
+
import java.util.Base64;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Holds SIU credentials: the parsed message and the signature.
|
|
17
|
+
*
|
|
18
|
+
* The signature is a Base64-encoded ed25519 signature.
|
|
19
|
+
* The message is a Base64-encoded SIU message string.
|
|
20
|
+
*/
|
|
21
|
+
public class SiuCredentials {
|
|
22
|
+
private static final Base64.Decoder decoder = Base64.getDecoder();
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The parsed SIU message.
|
|
26
|
+
*/
|
|
27
|
+
public SiuMessage message;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The Base64-encoded ed25519 signature.
|
|
31
|
+
*/
|
|
32
|
+
public String signature;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Creates new SIU credentials.
|
|
36
|
+
*
|
|
37
|
+
* @param username The signature (Base64 encoded)
|
|
38
|
+
* @param password The SIU message (Base64 encoded)
|
|
39
|
+
* @throws SiweKeycloakException If the message cannot be parsed
|
|
40
|
+
*/
|
|
41
|
+
public SiuCredentials(String username, String password) throws SiweKeycloakException {
|
|
42
|
+
this.signature = username;
|
|
43
|
+
try {
|
|
44
|
+
String decodedMessage = new String(decoder.decode(password));
|
|
45
|
+
this.message = new SiuMessage.Parser().parse(decodedMessage);
|
|
46
|
+
} catch (SiuParseException e) {
|
|
47
|
+
throw new SiweKeycloakException(e.getMessage());
|
|
48
|
+
} catch (IllegalArgumentException e) {
|
|
49
|
+
throw new SiweKeycloakException("Invalid Base64 encoding for SIU message");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|