Skip to content

Commit bc3cb9f

Browse files
Merge pull request #139 from BioImageTools/issue-82-aws-profile
Support named AWS profiles for s3:// locations
2 parents 69b32fc + adcc4c5 commit bc3cb9f

33 files changed

Lines changed: 1489 additions & 494 deletions

File tree

‎CLAUDE.md‎

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,23 @@ and half-working link support is worse for users than a clear "not supported". R
135135
non-`java.net` schemes (e.g. falling back to `LocationService.resolve` when `new URL(p)` throws); links then get `s3:`
136136
for free, with no change here.
137137

138+
**Named AWS profiles** (issue #82) are how private buckets and non-AWS endpoints are reached: credentials stay in
139+
`~/.aws/*` (no key fields in any dialog, nothing secret in `PrefService`), and the user only picks a profile *name* in
140+
`S3Settings` — a dialog of its own, since most users never need it and it means nothing on Fiji-Stable, but stored in
141+
`OmeZarrOpeningSettings` next to the backend, so each open reads one settings object. The name travels as a
142+
constructor argument of the backend (`OmeZarrBackend.createBackend( awsProfile )`), so callers only need
143+
`PyramidBackend`. A setter on `AbstractPyramidBackend` forced callers onto the abstract class, and a setter on the
144+
interface would have to throw for every backend that cannot read `s3:` (PR #139 review). Both backends build a fresh
145+
`S3Client` per open, so a changed profile applies to the next open without a restart.
146+
`AwsProfiles` (in `ome-zarr-imglib2`) parses the two files itself rather than using the SDK's `ProfileFile`: the dialog
147+
lists the profiles, and it must not link AWS classes on Fiji-Stable. Do not "simplify" it back to the SDK parser; keep
148+
it agreeing with it instead (the SDK skips profile names outside `[A-Za-z0-9-/.%@_:+]` and merges `region` from both
149+
files). A chosen profile that has since vanished from the files makes `AbstractPyramidBackend.read` throw
150+
`AwsProfileNotFoundException`, which `OmeZarr` reports — left to the SDK, it would silently fall back to anonymous
151+
access on AWS. The remaining SDK wiring (`defaultProfileName` for region and `endpoint_url`, a profile-named credentials
152+
chain with anonymous fallback) is duplicated in `S3StoreFactory` and `N5PyramidBackend.configureS3`, because no module
153+
both backends share may depend on the AWS SDK.
154+
138155
An installation without the AWS SDK on the classpath (Fiji-Stable) only notices when the first `s3:` URI is opened —
139156
see `S3StoreFactory` under `ome-zarr-zarrjava` for the lazy-loading rule and the `S3SupportUnavailableException` it
140157
throws so the user gets a "get Fiji-Latest" message instead of a linkage stack trace.
@@ -158,10 +175,12 @@ override with their library's display name (`"N5"`, `"zarr-java"`) for user-faci
158175
implements `read` as a template method – try the multiscales group, fall back to a single array (parent multiscales
159176
group first, then the array's own `dimension_names`) – and leaves three `protected abstract` hooks for the
160177
reader-specific steps: `readMultiscale`, `tryReadLevelFromParent` and `tryReadArrayNodeOnly` (the two `try*` hooks
161-
return `null` for "not applicable, try the next"). `read` and `readSingleArray` are `final`, so the order is fixed for
162-
every backend. Both `PyramidContents` and the per-level `CachedCellImg`s, transforms, calibration and optional OMERO
163-
metadata it holds are immutable. Each backend also exposes a static `readPyramid(URI)` convenience entry point for
164-
outside API users — not named `read`, because Java forbids a static method hiding an inherited instance method.
178+
return `null` for "not applicable, try the next"; the last one throws `NotAMultiscaleImageException` when there is no
179+
array at all, so a missing location is never reported as unknown axes). `read` and `readSingleArray` are `final`, so
180+
the order is fixed for every backend. Both `PyramidContents` and the per-level `CachedCellImg`s, transforms, calibration
181+
and optional OMERO metadata it holds are immutable. Each backend also exposes a static `readPyramid(URI)` convenience
182+
entry point for outside API users — not named `read`, because Java forbids a static method hiding an inherited instance
183+
method.
165184

166185
**A too-old reader library is reported, not thrown at the console.** A Fiji-Stable installation whose N5 stack predates
167186
this plugin fails inside the backend with a `NoClassDefFoundError` (e.g. on `OmeNgffMetadataParser`), which is useless
@@ -274,8 +293,8 @@ with `Namespace 'ome.zarr' is not allowed`. So going back to Central means switc
274293
`releaseProfiles`; an org-owned namespace (`io.github.bioimagetools`, or `org.bioimagetools` if the domain is ever
275294
registered) would be the alternative. Java package names stay `ome.zarr.*` through all of this.
276295

277-
- **`ome-zarr-imglib2`** – package `ome.zarr.imglib2` (+`.metadata`, `.exceptions`); backend-agnostic core. No Fiji or
278-
backend dependency.
296+
- **`ome-zarr-imglib2`** – package `ome.zarr.imglib2` (+`.metadata`, `.exceptions`, `.s3`, `.util`); backend-agnostic
297+
core. No Fiji or backend dependency.
279298
- **`ome-zarr-n5`** – `ome.zarr.n5` (`N5PyramidBackend`, N5-universe, OME-NGFF v0.3–v0.5); depends on imglib2 +
280299
external N5-universe (codecs `n5-zarr`/`n5-blosc`/zstd arrive transitively via `n5-universe`).
281300
- **`ome-zarr-zarrjava`** – `ome.zarr.zarrjava` (`ZarrJavaPyramidBackend`, Zarr v2/v3); depends on imglib2 +
@@ -313,9 +332,9 @@ registered) would be the alternative. Java package names stay `ome.zarr.*` throu
313332
Swing dialogs in `.dialog`, the six built-in `OmeZarrOpener`s in `.open.openers`. The SciJava commands sit in three
314333
sibling packages under `.plugin.command`, one per menu location: `.fileimport` for the two `File > Import` entries
315334
plus their shared `FileImportHelper` (package-private, so its tests live there too), `.tools` for the
316-
`Plugins > OME-Zarr` entries, and `.settings` for `OpeningBehaviorSettings` and `UserScriptSettings`. Commands are
317-
discovered through the `@Plugin` annotation index, not by package, so moving one between these packages does not
318-
touch its menu path – but `PrefService` keys off **both** the package and the simple class name
335+
`Plugins > OME-Zarr` entries, and `.settings` for `OpeningBehaviorSettings`, `S3Settings` and `UserScriptSettings`.
336+
Commands are discovered through the `@Plugin` annotation index, not by package, so moving one between these
337+
packages does not touch its menu path – but `PrefService` keys off **both** the package and the simple class name
319338
(`DefaultPrefService.prefs(Class)` is `userNodeForPackage( c ).node( c.getSimpleName() )`), so *moving or renaming* a
320339
class used as a preference key (as `ScriptUtils` uses `UserScriptSettings`) resets that stored setting. Renaming
321340
`ZarrOpeningSettings` to `OmeZarrOpeningSettings` in 0.9 did exactly that, deliberately: opener, preferred width and

‎README.md‎

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
- [Open via menu (local folders)](#open-via-menu-local-folders)
1717
- [Open as `Dataset` (scripting)](#open-as-dataset-scripting)
1818
- [FIJI links (`fiji://`)](#fiji-links-fiji)
19+
- [AWS profiles (private buckets, non-AWS S3 endpoints)](#aws-profiles-private-buckets-non-aws-s3-endpoints)
1920
- [Opening Behavior Settings](#opening-behavior-settings)
2021
- [Default opening behavior](#default-opening-behavior)
2122
- [Selection dialog (Ask me every time)](#selection-dialog-ask-me-every-time)
@@ -57,9 +58,10 @@ Drop a local OME-Zarr folder or an OME-Zarr URI onto Fiji. What happens next is
5758
* Supports local paths, http(s) URLs, and `s3://` URIs
5859
* Public (anonymous) S3 buckets work out of the box, e.g.
5960
`s3://janelia-cosem-datasets/jrc_mus-choroid-plexus-3/jrc_mus-choroid-plexus-3.zarr/recon-1/em/fibsem-uint8`.
60-
* Private buckets use your ambient AWS credentials (environment variables, `~/.aws/credentials`,
61-
instance profile, etc.); if those are absent, access falls back to anonymous.
62-
* The AWS region defaults to `us-east-1`.
61+
* Private buckets, S3 storage outside amazonaws.com and multiple accounts: choose a
62+
[named AWS profile](#aws-profiles-private-buckets-non-aws-s3-endpoints); region, endpoint and keys then come from it.
63+
* Without a chosen profile, your ambient AWS credentials are used (environment variables, `~/.aws/credentials`,
64+
instance profile, etc.), falling back to anonymous access; the region is then always `us-east-1`.
6365
* Three entry points:
6466
* Paste with `CTRL` / `CMD` / `SHIFT` + `V` (requires FIJI latest)
6567
* Paste via menu: Plugins -> OME-Zarr -> Paste OME-Zarr URI
@@ -121,6 +123,31 @@ work, check the *Enable web links* setting in `Edit -> Options -> Desktop...`:
121123
See [doc/fiji-links-demo.html](https://htmlpreview.github.io/?https://raw.githubusercontent.com/BioImageTools/ome-zarr-fiji-java/main/doc/fiji-links-demo.html)
122124
for a page with clickable examples of each form.
123125

126+
### AWS profiles (private buckets, non-AWS S3 endpoints)
127+
128+
Credentials are expected to live in the standard AWS files. Define a profile like this:
129+
130+
```
131+
# ~/.aws/config
132+
[profile my_profile]
133+
endpoint_url = https://s3.example.org
134+
region = us-east-1
135+
136+
# ~/.aws/credentials
137+
[my_profile]
138+
aws_access_key_id = ...
139+
aws_secret_access_key = ...
140+
```
141+
142+
Then choose `my_profile` as *AWS profile for s3:// locations* in `Plugins > OME-Zarr > Settings > S3 Settings`. The
143+
list shows every profile defined in these two files.
144+
The next pasted `s3://` URI uses its `endpoint_url`, `region` and keys without needing a restart of Fiji.
145+
A profile without `region` uses `us-east-1`.
146+
A profile without keys falls back to anonymous access.
147+
*No profile* uses the profile named by the `AWS_PROFILE` environment variable at Fiji start (e.g.
148+
`AWS_PROFILE=my_profile ./fiji`), else the `default` profile, always with region `us-east-1`. Choose `default` in the
149+
list to use its own `region`.
150+
124151
## Opening Behavior Settings
125152

126153
`Plugins -> OME-Zarr -> Settings -> Opening Behavior Settings` sets three things, kept across Fiji sessions: the

‎doc/DEVELOPERS.md‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ graph TD
3939

4040
`ome-zarr-imglib2`, `ome-zarr-n5` and `ome-zarr-zarrjava` are plain Java — **no Fiji, so headless use works**.
4141

42-
| Module | Packages | Purpose | Depends on |
43-
|---------------------|-------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|
44-
| `ome-zarr-imglib2` | `ome.zarr.imglib2` `.metadata` `.exceptions` | Backend-agnostic core: data model, OME-NGFF metadata, Zarr detection. No Fiji, no backend library. | imglib2, imglib2-cache, imglib2-realtransform, gson |
45-
| `ome-zarr-n5` | `ome.zarr.n5` | N5-universe backed reader, OME-Zarr v0.3 – v0.5. | `ome-zarr-imglib2`, the N5 stack |
46-
| `ome-zarr-zarrjava` | `ome.zarr.zarrjava` | zarr-java backed reader (the default), Zarr v2/v3 i.e. OME-Zarr v0.4 + v0.5. The only backend that reads `.ozx` archives. | `ome-zarr-imglib2`, `dev.zarr:zarr-java` |
47-
| `ome-zarr-fiji` | `ome.zarr.fiji` `.read` `.open` `.plugins` `.util` | Opens a pyramid in ImageJ or BigDataViewer, tracks the active window, and defines the `OmeZarrOpener` extension point. No dialogs, no backend dependency — pick one at runtime. | `ome-zarr-imglib2`, bigdataviewer-core, spim_data, imagej-common, ij, scijava-common |
48-
| `ome-zarr-fiji-ui` | `ome.zarr.fijiui` `.open` `.plugin` `.dialog` `.util` | The shipped plugin: `IOPlugin`, clipboard, Swing dialogs, SciJava commands, persisted settings, the six built-in openers. | the four above, scijava-common, script-editor, n5-viewer_fiji |
42+
| Module | Packages | Purpose | Depends on |
43+
|---------------------|------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|
44+
| `ome-zarr-imglib2` | `ome.zarr.imglib2` `.metadata` `.exceptions` `.s3` `.util` | Backend-agnostic core: data model, OME-NGFF metadata, Zarr detection. No Fiji, no backend library. | imglib2, imglib2-cache, imglib2-realtransform, gson |
45+
| `ome-zarr-n5` | `ome.zarr.n5` | N5-universe backed reader, OME-Zarr v0.3 – v0.5. | `ome-zarr-imglib2`, the N5 stack |
46+
| `ome-zarr-zarrjava` | `ome.zarr.zarrjava` | zarr-java backed reader (the default), Zarr v2/v3 i.e. OME-Zarr v0.4 + v0.5. The only backend that reads `.ozx` archives. | `ome-zarr-imglib2`, `dev.zarr:zarr-java` |
47+
| `ome-zarr-fiji` | `ome.zarr.fiji` `.read` `.open` `.plugins` `.util` | Opens a pyramid in ImageJ or BigDataViewer, tracks the active window, and defines the `OmeZarrOpener` extension point. No dialogs, no backend dependency — pick one at runtime. | `ome-zarr-imglib2`, bigdataviewer-core, spim_data, imagej-common, ij, scijava-common |
48+
| `ome-zarr-fiji-ui` | `ome.zarr.fijiui` `.open` `.plugin` `.dialog` `.util` | The shipped plugin: `IOPlugin`, clipboard, Swing dialogs, SciJava commands, persisted settings, the six built-in openers. | the four above, scijava-common, script-editor, n5-viewer_fiji |
4949

5050
Pick the smallest one you need:
5151

‎ome-zarr-fiji-ui/src/main/java/ome/zarr/fijiui/open/OmeZarrOpenActions.java‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,15 +189,16 @@ public OmeZarrOpenActions( final OmeZarr omeZarr )
189189
}
190190

191191
/**
192-
* Reader for {@code inputUri} using the backend and preferred width from
193-
* {@code settings}, or the defaults when no settings are given.
192+
* Reader for {@code inputUri} using the backend, AWS profile and preferred
193+
* width from {@code settings}, or the defaults when no settings are given.
194194
*/
195195
private static OmeZarr omeZarrFor( final URI inputUri, final Context context,
196196
final OmeZarrOpeningSettings settings, final Consumer< String > errorHandler )
197197
{
198198
final OmeZarrBackend backend = settings == null ? OmeZarrOpeningSettings.DEFAULT_BACKEND : settings.getBackend();
199+
final String awsProfile = settings == null ? null : settings.getAwsProfile();
199200
final Integer preferredMaxWidth = settings == null ? null : settings.getPreferredMaxWidth();
200-
return new OmeZarr( inputUri, context, backend.createBackend(), preferredMaxWidth, errorHandler );
201+
return new OmeZarr( inputUri, context, backend.createBackend( awsProfile ), preferredMaxWidth, errorHandler );
201202
}
202203

203204
private String uriFormattedForN5Dialog( final URI uri )

‎ome-zarr-fiji-ui/src/main/java/ome/zarr/fijiui/open/PasteToOpenAction.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import org.scijava.Context;
3535

3636
import ome.zarr.fijiui.util.ClipboardUtils;
37-
import ome.zarr.imglib2.ZarrUtils;
37+
import ome.zarr.imglib2.util.ZarrUtils;
3838

3939
/**
4040
* Opening orchestration for the "paste an OME-Zarr location and open it" flow,

‎ome-zarr-fiji-ui/src/main/java/ome/zarr/fijiui/open/options/OmeZarrBackend.java‎

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
* %%
77
* Redistribution and use in source and binary forms, with or without
88
* modification, are permitted provided that the following conditions are met:
9-
*
9+
*
1010
* 1. Redistributions of source code must retain the above copyright notice,
1111
* this list of conditions and the following disclaimer.
1212
* 2. Redistributions in binary form must reproduce the above copyright notice,
1313
* this list of conditions and the following disclaimer in the documentation
1414
* and/or other materials provided with the distribution.
15-
*
15+
*
1616
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1717
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1818
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -78,20 +78,32 @@ public String getDescription()
7878
}
7979

8080
/**
81-
* Creates a fresh {@link PyramidBackend} for the backend library this constant
82-
* represents.
81+
* Creates a fresh backend for the backend library this constant represents,
82+
* reading {@code s3:} URIs with the AWS SDK default profile.
8383
*
8484
* @return a new backend instance, never {@code null}
8585
*/
8686
public PyramidBackend createBackend()
87+
{
88+
return createBackend( null );
89+
}
90+
91+
/**
92+
* Creates a fresh backend for the backend library this constant represents.
93+
*
94+
* @param awsProfile the AWS profile for {@code s3:} URIs, or {@code null} for
95+
* the AWS SDK default
96+
* @return a new backend instance, never {@code null}
97+
*/
98+
public PyramidBackend createBackend( final String awsProfile )
8799
{
88100
switch ( this )
89101
{
90102
case ZARR_JAVA:
91-
return new ZarrJavaPyramidBackend();
103+
return new ZarrJavaPyramidBackend( awsProfile );
92104
case N5:
93105
default:
94-
return new N5PyramidBackend();
106+
return new N5PyramidBackend( awsProfile );
95107
}
96108
}
97109
}

0 commit comments

Comments
 (0)