https://github.com/it-at-m/ad2image
easy avatars powered by AD / Exchange & Identicons
https://github.com/it-at-m/ad2image
active-directory exchange-server java spring-boot
Last synced: 4 months ago
JSON representation
easy avatars powered by AD / Exchange & Identicons
- Host: GitHub
- URL: https://github.com/it-at-m/ad2image
- Owner: it-at-m
- License: mit
- Created: 2022-12-23T13:47:17.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2026-03-04T11:33:47.000Z (4 months ago)
- Last Synced: 2026-03-04T13:50:16.411Z (4 months ago)
- Topics: active-directory, exchange-server, java, spring-boot
- Language: Java
- Homepage:
- Size: 340 KB
- Stars: 8
- Watchers: 2
- Forks: 3
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
[![Contributors][contributors-shield]][contributors-url]
[![Stargazers][stars-shield]][stars-url]
[![Issues][issues-shield]][issues-url]
[![MIT License][license-shield]][license-url]
[![GitHub Workflow Status][github-workflow-status]][github-workflow-status-url]
[![GitHub release (latest SemVer)][release-shield]][release-url]
# ad2image
**ad2image** provides an easy-to-use, minimalistic HTTP API to retrieve user photos from an Active Directory / Microsoft
Exchange environment. It also provides fallback photos
using [avatar-generator](https://gitlab.talanlabs.com/gabriel-allaigre/avatar-generator-parent) if a user has no photo
stored.
Behind the curtains, by default a 64x64 pixel thumbnail photo is retrieved from Active Directory (Attribute
`thumbnailPhoto`). Higher resolution photos can also be requested, those will be fetched by using
the [Exchange EWS REST API](https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-get-user-photos-by-using-ews-in-exchange#get-a-mailbox-user-photo-by-using-rest).
**ad2image** can be integrated in your Spring Boot application by using the provided starter
`ad2image-spring-boot-starter`.
If you want to deploy **ad2image** as a standalone application, you can use
the [provided container image](#running-as-a-container-standalone) or [Helm chart][helm-chart-github].
**ad2image** was initially created as **mucatar** internally at it@M. It is used by many of our in-house projects to
provide user photos for a richer user experience. For example, it can be very easily used as photo provider
for [Vuetify's Avatar component](https://vuetifyjs.com/en/components/avatars/).
## Built With
This project is built with technologies we use in our projects:
- Java
- Spring Boot
## Set up
```bash
mvn clean install
```
For development, an Active Directory / Exchange environment is not needed. It is mocked by an embedded LDAP server and
WireMock (for the EWS API).
## Documentation
OpenAPI v3 documentation is provided and can be retrieved via Swagger UI (`/swagger-ui/index.html`).
### Using the API
`GET /avatar?uid=john.doe[&m=identicon|404|fallbackIdenticon|...][&size=64]`
Possible modes (`m`):
- `404`: 404 Response, if the user has no photo stored in AD/Exchange
- `identicon`: renders an [Identicon](https://en.wikipedia.org/wiki/Identicon), if the user has no photo stored in
AD/Exchange
- `fallbackIdenticon`: identical to `identicon`, but also responds with an Identicon if the user itself does not exist
in AD/Exchange
- `generic`: renders an [generic placeholder icon](ad2image-spring-boot-starter/src/main/resources/account_64.png), if
the user has no photo stored in AD/Exchange
- `fallbackGeneric`: **default** - identical to `generic`, but also responds with an generic placeholder icon if the
user itself does not exist in AD/Exchange
- `genericDark`: renders a [generic placeholder icon with white foreground](ad2image-spring-boot-starter/src/main/resources/account_dark.png) (for dark mode applications), if
the user has no photo stored in AD/Exchange
- `fallbackGenericDark`: identical to `genericDark`, but also responds with a generic placeholder icon with white foreground if the
user itself does not exist in AD/Exchange
- `triangle`: renders
an [randomly generated Avatar based on triangles](https://raw.githubusercontent.com/gabrie-allaigre/avatar-generator/master/doc/triangle1.png),
if the user has no photo stored in AD/Exchange
- `fallbackTriangle`: identical to `triangle`, but also responds correspondingly if the user itself does not exist in
AD/Exchange
- `square`: renders
an [randomly generated Avatar based on squares](https://raw.githubusercontent.com/gabrie-allaigre/avatar-generator/master/doc/square1.png),
if the user has no photo stored in AD/Exchange
- `fallbackSquare`: identical to `square`, but also responds correspondingly if the user itself does not exist in
AD/Exchange
- `github`: renders
an [randomly generated Avatar based Github avatar style](https://raw.githubusercontent.com/gabrie-allaigre/avatar-generator/master/doc/github2.png),
if the user has no photo stored in AD/Exchange
- `fallbackGithub`: identical to `github`, but also responds correspondingly if the user itself does not exist in
AD/Exchange
- `initials`: renders a colored square avatar with the user's initials (first letter of given name + first letter of surname), derived from the user's AD `givenName` and `sn` attributes. The background color is deterministically derived from the user's uid. If no name is stored, a plain colored rectangle is rendered. Returns 404 if the user does not exist in AD.
The background colors in `initials` mode (implemented in [InitialsAvatarGenerator.java](ad2image-spring-boot-starter/src/main/java/de/muenchen/oss/ad2image/starter/core/InitialsAvatarGenerator.java)) are chosen using an HSL strategy (60% saturation and ~45% lightness) to provide sufficient contrast with the white initials text for accessibility.
Possible resolutions (`size`): between 1 and 2048 pixels
### Gravatar compatability API endpoint
ad2image provides an API endpoint that mimics the [Gravatar API](https://docs.gravatar.com/sdk/images/) but
internally resolves the user photos from your Active Directory / Exchange environment:
`GET /gravatar/?[d=identicon/404]&s=200`
When the Gravatar compatability endpoint is activated, ad2image retrieves all users from Active Directory on startup to
compute an in-memory lookup table that contains the SHA256-hashed mail addresses. ad2image also can periodically update
this lookup table during runtime.
See [Configuration](#configuration) for more details on how to configure this endpoint for your environment.
This endpoint also only supports a subset of the Gravatar API features:
- Default image (`d` query param): `identicon`, `404`, `mp` (mystery person), and `initials` are supported; other values fall back to the configured gravatar default mode
- Size: can be requested between 1 and 2048px
- Force Default (`f`): not supported, will be ignored
- Rating (`r`): not supported, will be ignored
### Running as a container (standalone)
You can use the provided official Docker
image [ghcr.io/it-at-m/ad2image](https://github.com/it-at-m/ad2image/pkgs/container/ad2image) to run **ad2image** as a
standalone application.
```sh
docker run -d -p 8080:8080 --name ad2image ghcr.io/it-at-m/ad2image:1.1.1
```
To connect to your Exchange/EWS environment, some environment variables must be set, see [Configuration](#configuration)
for a full list.
By default, ad2image uses a server-side cache (
see [default_ehcache.xml](ad2image-app/src/main/resources/default_ehcache.xml)). You can provide your own `ehcache.xml`
if you want to change the cache configuration (e.g. decrease the TTL).
1. Create your custom `ehcache.xml` and mount it as a volume for the container, for example with Docker `--mount`:
```
docker run --mount type=bind,source=/home/user/my-ehcache.xml,target=/cacheconfig/my-ehcache.xml,readonly [...]
```
2. Set the container environment variable `SPRING_CACHE_JCACHE_CONFIG` to point to the custom `ehcache.xml`, for
example:
```
SPRING_CACHE_JCACHE_CONFIG=file:/cacheconfig/my-ehcache.xml
```
### Deploying on Kubernetes using a Helm chart
If you want to deploy ad2image on a Kubernetes cluster, you can use the [provided Helm chart][helm-chart-github].
### Integrating in a existing Spring Boot application
ad2image can be integrated in a existing Spring Boot application by adding the `ad2image-spring-boot-starter`
dependency, e.g. for Maven:
```xml
de.muenchen.oss.ad2image
ad2image-spring-boot-starter
1.1.1
```
To configure ad2image, add the corresponding `de.muenchen.oss.ad2image.*` properties to your `application.properties`/
`application.yml`. For a full list of possible configuration properties see [Configuration](#configuration).
### Configuration
ad2image can be configured via Spring environment abstraction.
| Environment variable | System/Spring property | Description | Default value | Required |
| ----------------------------------------------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | -------- |
| `DE_MUENCHEN_OSS_AD2IMAGE_ENABLED` | `de.muenchen.oss.ad2image.enabled` | can be used to disable ad2image auto configuration (if integrated in your own application) | - | no |
| `DE_MUENCHEN_OSS_AD2IMAGE_DEFAULT_MODE` | `de.muenchen.oss.ad2image.default-mode` | Default mode (`m`) if user provides none. | `"M_FALLBACK_GENERIC"` (`fallbackGeneric`) | yes |
| `DE_MUENCHEN_OSS_AD2IMAGE_AD_URL` | `de.muenchen.oss.ad2image.ad.url` | Connection URL for AD server, for example 'ldaps://example.com:636'. | - | yes |
| `DE_MUENCHEN_OSS_AD2IMAGE_AD_USER_DN` | `de.muenchen.oss.ad2image.ad.user-dn` | Bind User-DN for AD authentication | - | yes |
| `DE_MUENCHEN_OSS_AD2IMAGE_AD_PASSWORD` | `de.muenchen.oss.ad2image.ad.password` | Password for AD authentication | - | yes |
| `DE_MUENCHEN_OSS_AD2IMAGE_AD_USER_SEARCH_BASE` | `de.muenchen.oss.ad2image.ad.user-search-base` | User Search Base for user lookup, for example 'OU=Users,DC=mycompany,DC=com'. | - | yes |
| `DE_MUENCHEN_OSS_AD2IMAGE_AD_USER_SEARCH_FILTER` | `de.muenchen.oss.ad2image.ad.user-search-filter` | User Search filter, `{uid}` will be replaced with the requested user uid. | `(&(objectClass=organizationalPerson)(cn={uid}))` | yes |
| `DE_MUENCHEN_OSS_AD2IMAGE_AD_SN_ATTRIBUTE` | `de.muenchen.oss.ad2image.ad.sn-attribute` | LDAP attribute name for the user's surname, used to build initials avatars. | `sn` | no |
| `DE_MUENCHEN_OSS_AD2IMAGE_AD_GIVEN_NAME_ATTRIBUTE` | `de.muenchen.oss.ad2image.ad.given-name-attribute` | LDAP attribute name for the user's given name, used to build initials avatars. | `givenName` | no |
| `DE_MUENCHEN_OSS_AD2IMAGE_EWS_EWS_SERVICE_URL` | `de.muenchen.oss.ad2image.ews.ews-service-url` | [EWS service URL](https://learn.microsoft.com/en-US/exchange/client-developer/exchange-web-services/how-to-set-the-ews-service-url-by-using-the-ews-managed-api), e.g. `https://example.com/ews/Exchange.asmx`. | - | yes |
| `DE_MUENCHEN_OSS_AD2IMAGE_EWS_USERNAME` | `de.muenchen.oss.ad2image.ews.username` | Username for EWS [Basic Authentication](https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/authentication-and-ews-in-exchange#basic-authentication). | - | yes |
| `DE_MUENCHEN_OSS_AD2IMAGE_EWS_PASSWORD` | `de.muenchen.oss.ad2image.ews.password` | Password for EWS [Basic Authentication](https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/authentication-and-ews-in-exchange#basic-authentication). | - | yes |
| `DE_MUENCHEN_OSS_AD2IMAGE_GRAVATAR_ENABLED` | `de.muenchen.oss.ad2image.gravatar.enabled` | Enables/disables the Gravatar compatability endpoint. | `false` | no |
| `DE_MUENCHEN_OSS_AD2IMAGE_GRAVATAR_HASH_CACHE_REFRESH_CRON` | `de.muenchen.oss.ad2image.gravatar.hash-cache-refresh-cron` | Spring "cron" expression for periodic refresh of the SHA256 email address hashes, '-' to disable. | `-` | no |
| `DE_MUENCHEN_OSS_AD2IMAGE_GRAVATAR_MAP_POPULATION_FILTER` | `de.muenchen.oss.ad2image.gravatar.map-population-filter` | LDAP search filter for users which should be included in generation of SHA256-hashed email addresses. | `(&(objectClass=organizationalPerson)(mail=*))` | no |
| `DE_MUENCHEN_OSS_AD2IMAGE_GRAVATAR_PAGE_SIZE` | `de.muenchen.oss.ad2image.gravatar.page-size` | page size for retrieval of users during map population. | `500` | no |
| `DE_MUENCHEN_OSS_AD2IMAGE_GRAVATAR_DEFAULT_MODE` | `de.muenchen.oss.ad2image.gravatar.default-mode` | Default mode for Gravatar API when the requested `d=` parameter is unsupported or missing. Independent from the main avatar API's default mode setting. | `M_FALLBACK_GENERIC` | no |
## Contributing
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any
contributions you make are **greatly appreciated**.
If you have a suggestion that would make this better, please open an issue with the tag "enhancement", fork the repo and
create a pull request. You can also simply open an issue with the tag "enhancement".
Don't forget to give the project a star! Thanks again!
1. Open an issue with the tag "enhancement"
2. Fork the Project
3. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
4. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
5. Push to the Branch (`git push origin feature/AmazingFeature`)
6. Open a Pull Request
We use [itm-java-codeformat](https://github.com/it-at-m/itm-java-codeformat), so please make sure to apply the correct
code format for your contributions.
## License
Distributed under the MIT License. See [LICENSE](LICENSE) file for more information.
## Contact
it@M - opensource@muenchen.de
[contributors-shield]: https://img.shields.io/github/contributors/it-at-m/ad2image.svg?style=for-the-badge
[contributors-url]: https://github.com/it-at-m/ad2image/graphs/contributors
[forks-shield]: https://img.shields.io/github/forks/it-at-m/ad2image.svg?style=for-the-badge
[forks-url]: https://github.com/it-at-m/ad2image/network/members
[stars-shield]: https://img.shields.io/github/stars/it-at-m/ad2image.svg?style=for-the-badge
[stars-url]: https://github.com/it-at-m/ad2image/stargazers
[issues-shield]: https://img.shields.io/github/issues/it-at-m/ad2image.svg?style=for-the-badge
[issues-url]: https://github.com/it-at-m/ad2image/issues
[license-shield]: https://img.shields.io/github/license/it-at-m/ad2image.svg?style=for-the-badge
[license-url]: https://github.com/it-at-m/ad2image/blob/main/LICENSE
[github-workflow-status]: https://img.shields.io/github/actions/workflow/status/it-at-m/ad2image/build.yaml?style=for-the-badge
[github-workflow-status-url]: https://github.com/it-at-m/ad2image/actions/workflows/build.yaml
[release-shield]: https://img.shields.io/github/v/release/it-at-m/ad2image?sort=semver&style=for-the-badge
[release-url]: https://github.com/it-at-m/ad2image/releases
[helm-chart-github]: https://artifacthub.io/packages/helm/it-at-m/ad2image