44
55package cloud .katta .protocols .hub ;
66
7- import ch .cyberduck .core .Credentials ;
8- import ch .cyberduck .core .CredentialsConfigurator ;
9- import ch .cyberduck .core .DisabledCancelCallback ;
10- import ch .cyberduck .core .DisabledHostKeyCallback ;
11- import ch .cyberduck .core .DisabledLoginCallback ;
12- import ch .cyberduck .core .Host ;
13- import ch .cyberduck .core .HostUrlProvider ;
14- import ch .cyberduck .core .PasswordCallback ;
15- import ch .cyberduck .core .Path ;
16- import ch .cyberduck .core .PathAttributes ;
17- import ch .cyberduck .core .Protocol ;
18- import ch .cyberduck .core .ProtocolFactory ;
19- import ch .cyberduck .core .Session ;
20- import ch .cyberduck .core .SessionFactory ;
7+ import ch .cyberduck .core .*;
218import ch .cyberduck .core .cryptomator .ContentWriter ;
229import ch .cyberduck .core .cryptomator .UVFVault ;
2310import ch .cyberduck .core .exception .BackgroundException ;
11+ import ch .cyberduck .core .exception .ConnectionCanceledException ;
2412import ch .cyberduck .core .exception .InteroperabilityException ;
2513import ch .cyberduck .core .features .AttributesFinder ;
2614import ch .cyberduck .core .features .Directory ;
2715import ch .cyberduck .core .features .Write ;
2816import ch .cyberduck .core .preferences .PreferencesFactory ;
17+ import ch .cyberduck .core .preferences .ProxyPreferencesReader ;
2918import ch .cyberduck .core .proxy .ProxyFactory ;
3019import ch .cyberduck .core .s3 .S3Session ;
3120import ch .cyberduck .core .ssl .X509KeyManager ;
3423import ch .cyberduck .core .vault .VaultCredentials ;
3524import ch .cyberduck .core .vault .VaultUnlockCancelException ;
3625
37- import org .apache .http .HttpStatus ;
3826import org .apache .logging .log4j .LogManager ;
3927import org .apache .logging .log4j .Logger ;
4028import org .joda .time .DateTime ;
4533import java .util .UUID ;
4634
4735import cloud .katta .client .ApiException ;
48- import cloud .katta .client .api .UsersResourceApi ;
4936import cloud .katta .client .api .VaultResourceApi ;
5037import cloud .katta .client .model .UserDto ;
5138import cloud .katta .client .model .VaultDto ;
52- import cloud .katta .crypto .DeviceKeys ;
5339import cloud .katta .crypto .UserKeys ;
5440import cloud .katta .crypto .uvf .UvfMetadataPayload ;
5541import cloud .katta .crypto .uvf .UvfMetadataPayloadPasswordCallback ;
5642import cloud .katta .crypto .uvf .VaultMetadataJWEAutomaticAccessGrantDto ;
5743import cloud .katta .crypto .uvf .VaultMetadataJWEBackendDto ;
5844import cloud .katta .protocols .hub .exceptions .HubExceptionMappingService ;
59- import cloud .katta .workflows .DeviceKeysServiceImpl ;
60- import cloud .katta .workflows .UserKeysServiceImpl ;
61- import cloud .katta .workflows .VaultServiceImpl ;
62- import cloud .katta .workflows .exceptions .AccessException ;
63- import cloud .katta .workflows .exceptions .SecurityFailure ;
45+ import cloud .katta .protocols .s3 .S3AssumeRoleProtocol ;
6446import com .fasterxml .jackson .core .JsonProcessingException ;
6547import com .nimbusds .jose .JOSEException ;
6648
@@ -73,28 +55,76 @@ public class HubUVFVault extends UVFVault {
7355 private static final Logger log = LogManager .getLogger (HubUVFVault .class );
7456
7557 private final UUID vaultId ;
58+ private final UvfMetadataPayload vaultMetadata ;
7659
7760 /**
7861 * Storage connection only available after loading vault
7962 */
80- private Session <?> storage ;
63+ private final Session <?> storage ;
64+
8165 private final Path home ;
82- private final Credentials credentials ;
66+
67+ public HubUVFVault (final HubSession hub , final Path bucket , final HubStorageLocationService .StorageLocation location ) throws ConnectionCanceledException {
68+ this (hub , UUID .fromString (new UUIDRandomStringService ().random ()), bucket , location );
69+ }
70+
71+ /**
72+ * Constructor for factory creating new vault
73+ *
74+ * @param bucket Bucket
75+ */
76+ public HubUVFVault (final HubSession hub , final UUID vaultId , final Path bucket , final HubStorageLocationService .StorageLocation location ) throws ConnectionCanceledException {
77+ this (hub , vaultId , bucket ,
78+ UvfMetadataPayload .create ()
79+ .withStorage (new VaultMetadataJWEBackendDto ()
80+ .provider (location .getProfile ())
81+ .defaultPath (bucket .getAbsolute ())
82+ .region (location .getRegion ())
83+ .nickname (null != bucket .attributes ().getDisplayname () ? bucket .attributes ().getDisplayname () : "Vault" ))
84+ .withAutomaticAccessGrant (new VaultMetadataJWEAutomaticAccessGrantDto ()
85+ .enabled (true )
86+ .maxWotDepth (null )));
87+ }
8388
8489 /**
8590 * Open from existing metadata
8691 *
87- * @param vaultId Vault ID Used to lookup profile
88- * @param bucket Bucket name
89- * @param credentials Storage access credentials
92+ * @param vaultId Vault ID Used to lookup profile
9093 */
91- public HubUVFVault (final UUID vaultId , final Path bucket , final Credentials credentials ) {
94+ public HubUVFVault (final HubSession hub , final UUID vaultId , final UvfMetadataPayload vaultMetadata ) throws ConnectionCanceledException {
95+ this (hub , vaultId , new Path (vaultMetadata .storage ().getDefaultPath (), EnumSet .of (Path .Type .directory , Path .Type .volume ),
96+ new PathAttributes ().setDisplayname (vaultMetadata .storage ().getNickname ())), vaultMetadata );
97+ }
98+
99+ public HubUVFVault (final HubSession hub , final UUID vaultId , final Path bucket , final UvfMetadataPayload vaultMetadata ) throws ConnectionCanceledException {
92100 super (bucket );
93101 this .vaultId = vaultId ;
102+ this .vaultMetadata = vaultMetadata ;
94103 this .home = bucket ;
95- this .credentials = credentials ;
104+
105+ final VaultMetadataJWEBackendDto vaultStorageMetadata = vaultMetadata .storage ();
106+ final Protocol profile = ProtocolFactory .get ().forName (vaultStorageMetadata .getProvider ());
107+ log .debug ("Loaded profile {} for UVF metadata {}" , profile , vaultMetadata );
108+ final Credentials credentials =
109+ hub .getFeature (CredentialsConfigurator .class ).reload ().configure (hub .getHost ());
110+ log .debug ("Copy credentials {}" , credentials );
111+ if (vaultStorageMetadata .getUsername () != null ) {
112+ credentials .setUsername (vaultStorageMetadata .getUsername ());
113+ }
114+ if (vaultStorageMetadata .getPassword () != null ) {
115+ credentials .setPassword (vaultStorageMetadata .getPassword ());
116+ }
117+ final Host storageProvider = new Host (profile , credentials );
118+ storageProvider .setProperty (OAUTH_TOKENEXCHANGE_VAULT , vaultId .toString ());
119+ storageProvider .setRegion (vaultStorageMetadata .getRegion ());
120+ log .debug ("Configured {} for vault {}" , storageProvider , this );
121+ this .storage = SessionFactory .create (storageProvider , hub .getFeature (X509TrustManager .class ), hub .getFeature (X509KeyManager .class ));
96122 }
97123
124+ /**
125+ *
126+ * @return Storage provider configuration
127+ */
98128 public Session <?> getStorage () {
99129 return storage ;
100130 }
@@ -126,32 +156,21 @@ public synchronized void close() {
126156 @ Override
127157 public Path create (final Session <?> session , final String region , final VaultCredentials noop ) throws BackgroundException {
128158 try {
129- final HubStorageLocationService .StorageLocation location = HubStorageLocationService .StorageLocation .fromIdentifier (region );
130- final String storageProfileId = location .getProfile ();
131- final UvfMetadataPayload metadataPayload = UvfMetadataPayload .create ()
132- .withStorage (new VaultMetadataJWEBackendDto ()
133- .provider (storageProfileId )
134- .defaultPath (home .getAbsolute ())
135- .region (location .getRegion ())
136- .nickname (null != home .attributes ().getDisplayname () ? home .attributes ().getDisplayname () : "Vault" ))
137- .withAutomaticAccessGrant (new VaultMetadataJWEAutomaticAccessGrantDto ()
138- .enabled (true )
139- .maxWotDepth (null ));
140- log .debug ("Created metadata JWE {}" , metadataPayload );
159+ final HubSession hub = HubSession .coerce (session );
160+ log .debug ("Created metadata JWE {}" , vaultMetadata );
141161 final UvfMetadataPayload .UniversalVaultFormatJWKS jwks = UvfMetadataPayload .createKeys ();
142162 final VaultDto vaultDto = new VaultDto ()
143163 .id (vaultId )
144- .name (metadataPayload .storage ().getNickname ())
164+ .name (vaultMetadata .storage ().getNickname ())
145165 .description (null )
146166 .archived (false )
147167 .creationTime (DateTime .now ())
148- .uvfMetadataFile (metadataPayload .encrypt (
168+ .uvfMetadataFile (vaultMetadata .encrypt (
149169 String .format ("%s/api" , new HostUrlProvider (false , true ).get (session .getHost ())),
150170 vaultId ,
151171 jwks .toJWKSet ()
152172 ))
153173 .uvfKeySet (jwks .serializePublicRecoverykey ());
154- final HubSession hub = (HubSession ) session ;
155174 // Create vault in Hub
156175 final VaultResourceApi vaultResourceApi = new VaultResourceApi (hub .getClient ());
157176 log .debug ("Create vault {}" , vaultDto );
@@ -165,20 +184,19 @@ public Path create(final Session<?> session, final String region, final VaultCre
165184 vaultResourceApi .apiVaultsVaultIdAccessTokensPost (vaultDto .getId (),
166185 Collections .singletonMap (userDto .getId (), jwks .toOwnerAccessToken ().encryptForUser (userKeys .ecdhKeyPair ().getPublic ())));
167186 // Upload vault template to storage
168- final Protocol profile = ProtocolFactory .get ().forName (storageProfileId );
169- log .debug ("Loaded profile {} for vault {}" , profile , this );
170- final Host bookmark = new Host (profile , credentials );
171- bookmark .setProperty (OAUTH_TOKENEXCHANGE_VAULT , vaultId .toString ());
172- bookmark .setRegion (location .getRegion ());
173- bookmark .setDefaultPath (home .getAbsolute ());
174- log .debug ("Configured {} for vault {}" , bookmark , this );
175- storage = SessionFactory .create (bookmark , session .getFeature (X509TrustManager .class ), session .getFeature (X509KeyManager .class ));
176187 log .debug ("Connect to {}" , storage );
188+ final Host configuration = storage .getHost ();
189+ // No token exchange with Katta Server
190+ configuration .setProperty (S3AssumeRoleProtocol .OAUTH_TOKENEXCHANGE , null );
191+ // Assume role with policy attached to create vault
192+ configuration .setProperty (S3AssumeRoleProtocol .S3_ASSUMEROLE_ROLEARN_WEBIDENTITY ,
193+ new ProxyPreferencesReader (storage .getHost ()).getProperty (S3AssumeRoleProtocol .S3_ASSUMEROLE_ROLEARN_CREATE_BUCKET ));
194+ // No role chaining when creating vault
195+ configuration .setProperty (S3AssumeRoleProtocol .S3_ASSUMEROLE_ROLEARN_TAG , null );
177196 storage .open (ProxyFactory .get (), new DisabledHostKeyCallback (), new DisabledLoginCallback (), new DisabledCancelCallback ());
178- storage .login (new DisabledLoginCallback (), new DisabledCancelCallback ());
179- log .debug ("Upload vault template to {}" , storage );
180197 final Path vault ;
181198 if (false ) {
199+ log .debug ("Upload vault template to {}" , storage );
182200 return super .create (storage ,
183201 HubStorageLocationService .StorageLocation .fromIdentifier (region ).getRegion (), noop );
184202 }
@@ -188,7 +206,7 @@ public Path create(final Session<?> session, final String region, final VaultCre
188206 final TransferStatus status = (new TransferStatus ()).setRegion (HubStorageLocationService .StorageLocation .fromIdentifier (region ).getRegion ());
189207 vault = directory .mkdir (storage ._getFeature (Write .class ), home , status );
190208
191- final String hashedRootDirId = metadataPayload .computeRootDirIdHash ();
209+ final String hashedRootDirId = vaultMetadata .computeRootDirIdHash ();
192210 final Path dataDir = new Path (vault , "d" , EnumSet .of (Path .Type .directory ));
193211 final Path firstLevel = new Path (dataDir , hashedRootDirId .substring (0 , 2 ), EnumSet .of (Path .Type .directory ));
194212 final Path secondLevel = new Path (firstLevel , hashedRootDirId .substring (2 ), EnumSet .of (Path .Type .directory ));
@@ -202,11 +220,11 @@ public Path create(final Session<?> session, final String region, final VaultCre
202220 EnumSet .of (Path .Type .file , Path .Type .vault )), vaultDto .getUvfMetadataFile ().getBytes (StandardCharsets .US_ASCII ));
203221 // dir.uvf
204222 new ContentWriter (storage ).write (new Path (secondLevel , "dir.uvf" , EnumSet .of (Path .Type .file )),
205- metadataPayload .computeRootDirUvf ());
223+ vaultMetadata .computeRootDirUvf ());
206224 }
207225 return vault ;
208226 }
209- catch (JOSEException | JsonProcessingException | AccessException | SecurityFailure e ) {
227+ catch (JOSEException | JsonProcessingException e ) {
210228 throw new InteroperabilityException (e .getMessage (), e );
211229 }
212230 catch (ApiException e ) {
@@ -223,35 +241,9 @@ public Path create(final Session<?> session, final String region, final VaultCre
223241 @ Override
224242 public HubUVFVault load (final Session <?> session , final PasswordCallback prompt ) throws BackgroundException {
225243 try {
226- final HubSession hub = HubSession .coerce (session );
227- // Find storage configuration in vault metadata
228- final VaultServiceImpl vaultService = new VaultServiceImpl (hub );
229- final UvfMetadataPayload vaultMetadata = vaultService .getVaultMetadataJWE (vaultId , hub .getUserKeys ());
230- final Protocol profile = ProtocolFactory .get ().forName (vaultMetadata .storage ().getProvider ());
231- log .debug ("Loaded profile {} for vault {}" , profile , this );
232- final Credentials credentials =
233- session .getFeature (CredentialsConfigurator .class ).reload ().configure (session .getHost ());
234- log .debug ("Copy credentials {}" , credentials );
235- final VaultMetadataJWEBackendDto vaultStorageMetadata = vaultMetadata .storage ();
236- if (vaultStorageMetadata .getUsername () != null ) {
237- credentials .setUsername (vaultStorageMetadata .getUsername ());
238- }
239- if (vaultStorageMetadata .getPassword () != null ) {
240- credentials .setPassword (vaultStorageMetadata .getPassword ());
241- }
242- final Host bookmark = new Host (profile , credentials );
243- log .debug ("Configure bookmark for vault {}" , vaultStorageMetadata );
244- bookmark .setNickname (vaultStorageMetadata .getNickname ());
245- bookmark .setDefaultPath (vaultStorageMetadata .getDefaultPath ());
246- bookmark .setProperty (OAUTH_TOKENEXCHANGE_VAULT , vaultId .toString ());
247- // region as chosen by user upon vault creation (STS) or as retrieved from bucket (permanent)
248- bookmark .setRegion (vaultStorageMetadata .getRegion ());
249- log .debug ("Configured {} for vault {}" , bookmark , this );
250- storage = SessionFactory .create (bookmark , session .getFeature (X509TrustManager .class ), session .getFeature (X509KeyManager .class ));
251244 log .debug ("Connect to {}" , storage );
252245 try {
253246 storage .open (ProxyFactory .get (), new DisabledHostKeyCallback (), new DisabledLoginCallback (), new DisabledCancelCallback ());
254- storage .login (new DisabledLoginCallback (), new DisabledCancelCallback ());
255247 }
256248 catch (BackgroundException e ) {
257249 log .warn ("Skip loading vault with failure {} connecting to storage" , e .toString ());
@@ -265,13 +257,7 @@ public HubUVFVault load(final Session<?> session, final PasswordCallback prompt)
265257 super .load (storage , new UvfMetadataPayloadPasswordCallback (vaultMetadata .toJSON ()));
266258 return this ;
267259 }
268- catch (ApiException e ) {
269- if (HttpStatus .SC_FORBIDDEN == e .getCode ()) {
270- throw new VaultUnlockCancelException (this , e );
271- }
272- throw new HubExceptionMappingService ().map (e );
273- }
274- catch (JsonProcessingException | SecurityFailure | AccessException e ) {
260+ catch (JsonProcessingException e ) {
275261 throw new InteroperabilityException (e .getMessage (), e );
276262 }
277263 }
@@ -280,8 +266,8 @@ public HubUVFVault load(final Session<?> session, final PasswordCallback prompt)
280266 public String toString () {
281267 final StringBuilder sb = new StringBuilder ("HubUVFVault{" );
282268 sb .append ("vaultId=" ).append (vaultId );
269+ sb .append (", vaultMetadata=" ).append (vaultMetadata );
283270 sb .append (", home=" ).append (home );
284- sb .append (", credentials=" ).append (credentials );
285271 sb .append ('}' );
286272 return sb .toString ();
287273 }
0 commit comments