I am pretty new to docker. I have a spring-boot application that connects to postgres database (running in a container). I want to dockerize my spring-boot application and be able to connect it to the postgres database container.
What works:
Running the application without using docker works just fine: java -jar product-manager-0.0.1-SNAPSHOT.jar
What doesn't work:
Dockerizing and Running the application with Docker gives me an exception.
Note that I am not using docker-compose here.
My app Dockerfile:
FROM openjdk:11
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
Steps I've taken to run the app:
Run and start up the postgres database in a container using these commands:
docker run --rm --name lil-postgres -e POSTGRES_PASSWORD=password -d -v $HOME/srv/postgres:/var/lib/postgresql/data -p 5432:5432 postgres
postgres -D /usr/local/var/postgres
I've built the app's image:
docker build -t ensa/product-manager .
This is the result from running the latest command:
Sending build context to Docker daemon 38.01MB
Step 1/4 : FROM openjdk:11
---> 612d4d483eee
Step 2/4 : ARG JAR_FILE=target/*.jar
---> Running in 1b8674e959ca
Removing intermediate container 1b8674e959ca
---> d2c2b90680de
Step 3/4 : COPY ${JAR_FILE} app.jar
---> 01295beecd1b
Step 4/4 : ENTRYPOINT ["java","-jar","/app.jar"]
---> Running in 31230e7ff323
Removing intermediate container 31230e7ff323
---> c4487683e7b1
Successfully built c4487683e7b1
Successfully tagged ensa/product-manager:latest
Finally, I've created a running container using:
docker run --net="host" -it ensa/product-manager
The third step resulted in an exception:
org.postgresql.util.PSQLException: FATAL: password authentication failed for user "hamzabelmellouki"
at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:520) ~[postgresql-42.2.8.jar!/:42.2.8]
at org.postgresql.core.v3.ConnectionFactoryImpl.tryConnect(ConnectionFactoryImpl.java:141) ~[postgresql-42.2.8.jar!/:42.2.8]
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:192) ~[postgresql-42.2.8.jar!/:42.2.8]
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:49) ~[postgresql-42.2.8.jar!/:42.2.8]
at org.postgresql.jdbc.PgConnection.<init>(PgConnection.java:195) ~[postgresql-42.2.8.jar!/:42.2.8]
at org.postgresql.Driver.makeConnection(Driver.java:458) ~[postgresql-42.2.8.jar!/:42.2.8]
at org.postgresql.Driver.connect(Driver.java:260) ~[postgresql-42.2.8.jar!/:42.2.8]
at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:138) ~[HikariCP-3.4.1.jar!/:na]
at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:353) ~[HikariCP-3.4.1.jar!/:na]
at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:201) ~[HikariCP-3.4.1.jar!/:na]
at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:473) ~[HikariCP-3.4.1.jar!/:na]
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:562) ~[HikariCP-3.4.1.jar!/:na]
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:115) ~[HikariCP-3.4.1.jar!/:na]
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112) ~[HikariCP-3.4.1.jar!/:na]
at org.springframework.jdbc.datasource.DataSourceUtils.fetchConnection(DataSourceUtils.java:158) ~[spring-jdbc-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:116) ~[spring-jdbc-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:79) ~[spring-jdbc-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:324) ~[spring-jdbc-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.boot.jdbc.EmbeddedDatabaseConnection.isEmbedded(EmbeddedDatabaseConnection.java:120) ~[spring-boot-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.boot.autoconfigure.orm.jpa.HibernateDefaultDdlAutoProvider.getDefaultDdlAuto(HibernateDefaultDdlAutoProvider.java:42) ~[spring-boot-autoconfigure-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration.lambda$getVendorProperties$1(HibernateJpaConfiguration.java:130) ~[spring-boot-autoconfigure-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings.getDdlAuto(HibernateSettings.java:41) ~[spring-boot-autoconfigure-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties.determineDdlAuto(HibernateProperties.java:136) ~[spring-boot-autoconfigure-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties.getAdditionalProperties(HibernateProperties.java:102) ~[spring-boot-autoconfigure-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties.determineHibernateProperties(HibernateProperties.java:94) ~[spring-boot-autoconfigure-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration.getVendorProperties(HibernateJpaConfiguration.java:132) ~[spring-boot-autoconfigure-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.entityManagerFactory(JpaBaseConfiguration.java:133) ~[spring-boot-autoconfigure-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:640) ~[spring-beans-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:625) ~[spring-beans-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1108) ~[spring-context-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868) ~[spring-context-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.1.RELEASE.jar!/:5.2.1.RELEASE]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) ~[spring-boot-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) ~[spring-boot-2.2.1.RELEASE.jar!/:2.2.1.RELEASE]
at com.ensa.productmanager.ProductManagerApplication.main(ProductManagerApplication.java:10) ~[classes!/:0.0.1-SNAPSHOT]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) ~[app.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) ~[app.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:51) ~[app.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52) ~[app.jar:0.0.1-SNAPSHOT]
I've spent the whole day debugging and reading threads about this error. But I couldn't find a clue. Any help will be much appreciated.
UPDATE
I've run docker inspect on the Postgres container:
[
{
"Id": "426744f8c0a90b504c4d7c22242929f4b7f833e3ff4ddb9a112139d18ffd7c10",
"Created": "2020-01-16T19:14:14.7290504Z",
"Path": "docker-entrypoint.sh",
"Args": [
"postgres"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 8057,
"ExitCode": 0,
"Error": "",
"StartedAt": "2020-01-16T19:14:15.5451891Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:e2d75d1c1264a777df31dcbd4fd452b238134eb27854c2a173fdbfaa47ce9b87",
"ResolvConfPath": "/var/lib/docker/containers/426744f8c0a90b504c4d7c22242929f4b7f833e3ff4ddb9a112139d18ffd7c10/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/426744f8c0a90b504c4d7c22242929f4b7f833e3ff4ddb9a112139d18ffd7c10/hostname",
"HostsPath": "/var/lib/docker/containers/426744f8c0a90b504c4d7c22242929f4b7f833e3ff4ddb9a112139d18ffd7c10/hosts",
"LogPath": "/var/lib/docker/containers/426744f8c0a90b504c4d7c22242929f4b7f833e3ff4ddb9a112139d18ffd7c10/426744f8c0a90b504c4d7c22242929f4b7f833e3ff4ddb9a112139d18ffd7c10-json.log",
"Name": "/lil-postgres",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": [
"/Users/hamzabelmellouki/srv/postgres:/var/lib/postgresql/data"
],
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {
"5432/tcp": [
{
"HostIp": "",
"HostPort": "5432"
}
]
},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": true,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Capabilities": null,
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/baabe07f985a61979a3752f7e3c43116b980c45682d27c660b2867a6af3da28b-init/diff:/var/lib/docker/overlay2/ac6700580b74ace6c2f4eb9c274ef405124afb8019948c51516b496ed62eae8d/diff:/var/lib/docker/overlay2/35c484f8059617661ae54f749d0b938e7d81bc2089dd81ef81952aed6079c30b/diff:/var/lib/docker/overlay2/1649505946cf497fd95a5b7a118150a09315767464671f93459e3324f8e5ac42/diff:/var/lib/docker/overlay2/69a4818765c800f405e11c7755e184e4fd0837b68b4664821cf9c80daa7b629b/diff:/var/lib/docker/overlay2/177d3596510c3fdb235ec84728b8b6baf23a406dca3e9a3bfb45e98b48fe2395/diff:/var/lib/docker/overlay2/07d15f6f98f43ff88e6bdf9e361fadaaa46f83121278b5dbddac372cb95d99b8/diff:/var/lib/docker/overlay2/5e10c2001ef13459900f124ae825c210e2e001b0aa2f8b5e1e7c8c5c27d9e403/diff:/var/lib/docker/overlay2/b1e7828ebe991a7401746f581fd640bca3ae74f3a9820fd15e0fb2c666a08754/diff:/var/lib/docker/overlay2/e1b274467493537d29e25cce71acf9c3020d8a2e25080c75aa0fca10a5c05789/diff:/var/lib/docker/overlay2/11141fed542b6c519ec7621e0c4f341d2b2822a7c2885980216a2ef27609ffe0/diff:/var/lib/docker/overlay2/c3e4e9634bfe6a9e4b26f3d2d5751b2fa01aae0e8e1679a800accd94179d527d/diff:/var/lib/docker/overlay2/e7da8a834521c827046a2dc64f6f39afa6fded7f1af3241c75c592756d3053d6/diff:/var/lib/docker/overlay2/91d22f9b7d3aa1fae5cabcfe245a18c7dc6ac372696c73be70b65f7c8b42f1f4/diff:/var/lib/docker/overlay2/1a2021467ef42428eda11a9aef133e4b7ee9364266255abe5a0f2df4a9ff2584/diff",
"MergedDir": "/var/lib/docker/overlay2/baabe07f985a61979a3752f7e3c43116b980c45682d27c660b2867a6af3da28b/merged",
"UpperDir": "/var/lib/docker/overlay2/baabe07f985a61979a3752f7e3c43116b980c45682d27c660b2867a6af3da28b/diff",
"WorkDir": "/var/lib/docker/overlay2/baabe07f985a61979a3752f7e3c43116b980c45682d27c660b2867a6af3da28b/work"
},
"Name": "overlay2"
},
"Mounts": [
{
"Type": "bind",
"Source": "/Users/hamzabelmellouki/srv/postgres",
"Destination": "/var/lib/postgresql/data",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
"Config": {
"Hostname": "426744f8c0a9",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"5432/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"POSTGRES_USER=hamzabelmellouki",
"POSTGRES_PASSWORD=password",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/lib/postgresql/11/bin",
"GOSU_VERSION=1.11",
"LANG=en_US.utf8",
"PG_MAJOR=11",
"PG_VERSION=11.5-1.pgdg90+1",
"PGDATA=/var/lib/postgresql/data"
],
"Cmd": [
"postgres"
],
"Image": "postgres",
"Volumes": {
"/var/lib/postgresql/data": {}
},
"WorkingDir": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "2649b309ebde1f690927a1081497c9dc05dc249642b429f25d930243eb81e08f",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"5432/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "5432"
}
]
},
"SandboxKey": "/var/run/docker/netns/2649b309ebde",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "f01f60128018d8634f26a0c683ee6865e20361548b3a49007804dc913bfc4292",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "045d48c0f1d22cb7c319d6e850f6e9985a08e6d08884a79e823dbd0ac6c8a1b9",
"EndpointID": "f01f60128018d8634f26a0c683ee6865e20361548b3a49007804dc913bfc4292",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]
maybe,you can use docker-compose to defining and running multi-container docker applications(postgres+spring-boot) and you use a YAML file to configure your application's services.
So,You must create new volumes with different path to insert new data with new schema and configuration,because if you use volumes that already used before so you will find the problems like password authentication failed for user “hamzabelmellouki”
or the user(role) “hamzabelmellouki” does not existe or the database "database's name" does not existe because they have other user rhat created before .
#####docker-compose.yml#####
version: '3'
services:
db:
image: postgres
container_name: lil-postgres
ports:
- "5432:5432"
restart: unless-stopped
volumes:
- "./postgres/data:/var/lib/postgresql/data"
environment:
POSTGRES_USER: hamzabelmellouki
POSTGRES_PASSWORD: password
POSTGRES_DB: hamzabelmellouki
networks:
- product-net
product:
image: ensa/product-manager
restart: unless-stopped
ports:
- "8080:8080"
depends_on:
- db
networks:
- product-net
networks:
product-net:
driver: bridge
volumes:
db:
driver: local
Try below:
While running Postgres container, you have not provided any username , it should be something like:
docker run --rm --net="host" --name lil-postgres -e POSTGRES_USER=hamzabelmellouki -e POSTGRES_PASSWORD=password -d -v $HOME/srv/postgres:/var/lib/postgresql/data -p 5432:5432 postgres:9.6
by default Postgres container will run in bridge network (default docker network) and in your app, you've provided --net="host"
So maybe due to that, they are not able to communicate.
Provide the same network while running both
You can check it by below command
docker inspect container_name (or container_id)
Its nothing related, still, I've updated the docker image tag(Postgres:9.6), as it's always good to use a particular tag name, instead of default one (latest tag).
Try changing localhost by the ip adresse 172.17.0.2 in the application.properties spring.datasource.url=jdbc:postgresql://172.17.0.2:5432/testdb
I've been looking all over and I can't seem to find anywhere that MS has this information documented. (This includes the MS documentation on MAPI message classes. This Super User answer elucidates what seems to be all of the standard Message Classes that are possible, but I haven't been able to find a list of the possible metadata that are associated with the Message Classes.
Does anyone know where I can find the metadata for each of the Message Classes as well as a possible brief (or detailed!) description of what the column means? Some of them are pretty obvious ("ReceivedDate", Start, etc.) but others are less obvious.
I've munged around with PowerShell and managed to find the following:
Schedule Meeting Request:
"Application",
"Class",
"Session",
"Parent",
"Actions",
"Attachments",
"BillingInformation",
"Body",
"Categories",
"Companies ",
"ConversationIndex",
"ConversationTopic",
"CreationTime",
"EntryID",
"FormDescription",
"GetInspector",
"Importance",
"LastModificationTime",
"MAPIOBJECT",
"MessageClass",
"Mileage",
"NoAging",
"OutlookInternalVersion",
"OutlookVersion",
"Saved",
"Sensitivity",
"Size",
"Subject",
"UnRead",
"UserProperties",
"AutoForwarded",
"DeferredDeliveryTime",
"DeleteAfterSubmit",
"ExpiryTime",
"FlagDueBy",
"FlagRequest ",
"FlagStatus",
"OriginatorDeliveryReportRequested",
"ReceivedTime",
"Recipients",
"ReminderSet",
"ReminderTime",
"ReplyRecipients",
"SaveSentMessageFolder",
"SenderName",
"Sent",
"SentOn",
"Submitted",
"Links",
"DownloadState",
"ItemProperties",
"MarkForDownload",
"IsConflict",
"MeetingWorkspaceURL",
"FlagIcon",
"AutoResolvedWinner",
"Conflicts",
"SenderEmailAddress",
"SenderEmailType",
"PropertyAccessor",
"ConversationID",
"SendUsingAccount",
"IsLatestVersion",
"RTFBody",
"RetentionExpirationDate",
"RetentionPolicyName",
"BodyFormat"
RSS:
"Application",
"Class",
"Session",
"Parent",
"Actions",
"Attachments",
"BillingInformation",
"Body",
"Categories",
"Companies",
"ConversationIndex",
"ConversationTopic",
"CreationTime",
"EntryID",
"FormDescription",
"GetInspector",
"Importance",
"LastModificationTime",
"MAPIOBJECT",
"MessageClass",
"Mileage",
"NoAging",
"OutlookInternalVersion",
"OutlookVersion",
"Saved",
"Sensitivity",
"Size",
"Subject",
"UnRead",
"UserProperties",
"ExpiryTime",
"HTMLBody",
"ReceivedTime",
"SenderName",
"SentOn",
"Links",
"ItemProperties",
"BodyFormat",
"DownloadState",
"InternetCodepage",
"MarkForDownload",
"IsConflict",
"AutoResolvedWinner",
"Conflicts",
"SenderEmailAddress",
"SenderEmailType",
"PropertyAccessor",
"TaskSubject",
"TaskDueDate",
"TaskStartDate",
"TaskCompletedDate",
"ToDoTaskOrdinal",
"ReminderOverrideDefault",
"ReminderPlaySound",
"ReminderSet",
"ReminderSoundFile",
"ReminderTime",
"IsMarkedAsTask",
"ConversationID",
"RTFBody"
Notes:
"Application",
"Class",
"Session",
"Parent",
"Body",
"Categories",
"Color",
"CreationTime",
"EntryID",
"GetInspector",
"Height",
"LastModificationTime",
"Left",
"MessageClass",
"Saved",
"Size",
"Subject",
"Top",
"Width",
"Links",
"DownloadState",
"ItemProperties",
"MarkForDownload",
"IsConflict",
"AutoResolvedWinner",
"Conflicts",
"PropertyAccessor"
Contact:
"Application",
"Class",
"Session",
"Parent",
"Actions",
"Attachments",
"BillingInformation",
"Body",
"Categories",
"Companies",
"ConversationIndex",
"ConversationTopic",
"CreationTime",
"EntryID",
"FormDescription",
"GetInspector",
"Importance",
"LastModificationTime",
"MAPIOBJECT",
"MessageClass",
"Mileage",
"NoAging",
"OutlookInternalVersion",
"OutlookVersion",
"Saved",
"Sensitivity",
"Size",
"Subject",
"UnRead",
"UserProperties",
"Account",
"Anniversary",
"AssistantName",
"AssistantTelephoneNumber",
"Birthday",
"Business2TelephoneNumber",
"BusinessAddress",
"BusinessAddressCity",
"BusinessAddressCountry",
"BusinessAddressPostalCode",
"BusinessAddressPostOfficeBox",
"BusinessAddressState",
"BusinessAddressStreet",
"BusinessFaxNumber",
"BusinessHomePage",
"BusinessTelephoneNumber",
"CallbackTelephoneNumber",
"CarTelephoneNumber",
"Children",
"CompanyAndFullName",
"CompanyLastFirstNoSpace",
"CompanyLastFirstSpaceOnly",
"CompanyMainTelephoneNumber",
"CompanyName",
"ComputerNetworkName",
"CustomerID",
"Department",
"Email1Address",
"Email1AddressType",
"Email1DisplayName",
"Email1EntryID",
"Email2Address",
"Email2AddressType",
"Email2DisplayName",
"Email2EntryID",
"Email3Address",
"Email3AddressType",
"Email3DisplayName",
"Email3EntryID",
"FileAs",
"FirstName",
"FTPSite",
"FullName",
"FullNameAndCompany",
"Gender",
"GovernmentIDNumber",
"Hobby",
"Home2TelephoneNumber",
"HomeAddress",
"HomeAddressCity",
"HomeAddressCountry",
"HomeAddressPostalCode",
"HomeAddressPostOfficeBox",
"HomeAddressState",
"HomeAddressStreet",
"HomeFaxNumber",
"HomeTelephoneNumber",
"Initials",
"InternetFreeBusyAddress",
"ISDNNumber",
"JobTitle",
"Journal",
"Language",
"LastFirstAndSuffix",
"LastFirstNoSpace",
"LastFirstNoSpaceCompany",
"LastFirstSpaceOnly",
"LastFirstSpaceOnlyCompany",
"LastName",
"LastNameAndFirstName",
"MailingAddress",
"MailingAddressCity",
"MailingAddressCountry",
"MailingAddressPostalCode",
"MailingAddressPostOfficeBox",
"MailingAddressState",
"MailingAddressStreet",
"ManagerName",
"MiddleName",
"MobileTelephoneNumber",
"NetMeetingAlias",
"NetMeetingServer",
"NickName",
"OfficeLocation",
"OrganizationalIDNumber",
"OtherAddress",
"OtherAddressCity",
"OtherAddressCountry",
"OtherAddressPostalCode",
"OtherAddressPostOfficeBox",
"OtherAddressState",
"OtherAddressStreet",
"OtherFaxNumber",
"OtherTelephoneNumber",
"PagerNumber",
"PersonalHomePage",
"PrimaryTelephoneNumber",
"Profession",
"RadioTelephoneNumber",
"ReferredBy",
"SelectedMailingAddress",
"Spouse",
"Suffix",
"TelexNumber",
"Title",
"TTYTDDTelephoneNumber",
"User1",
"User2",
"User3",
"User4",
"UserCertificate",
"WebPage",
"YomiCompanyName",
"YomiFirstName",
"YomiLastName",
"Links",
"ItemProperties",
"LastFirstNoSpaceAndSuffix",
"DownloadState",
"IMAddress",
"MarkForDownload",
"IsConflict",
"AutoResolvedWinner",
"Conflicts",
"HasPicture",
"PropertyAccessor",
"TaskSubject",
"TaskDueDate",
"TaskStartDate",
"TaskCompletedDate",
"ToDoTaskOrdinal",
"ReminderOverrideDefault",
"ReminderPlaySound",
"ReminderSet",
"ReminderSoundFile",
"ReminderTime",
"IsMarkedAsTask",
"BusinessCardLayoutXml",
"BusinessCardType",
"ConversationID",
"RTFBody"
Conversations:
"Application",
"Class",
"Session",
"Parent",
"Actions",
"Attachments",
"BillingInformation",
"Body",
"Categories",
"Companies",
"ConversationIndex",
"ConversationTopic",
"CreationTime",
"EntryID",
"FormDescription",
"GetInspector",
"Importance",
"LastModificationTime",
"MAPIOBJECT",
"MessageClass",
"Mileage",
"NoAging",
"OutlookInternalVersion",
"OutlookVersion",
"Saved",
"Sensitivity",
"Size",
"Subject",
"UnRead",
"UserProperties",
"AlternateRecipientAllowed",
"AutoForwarded",
"BCC",
"CC",
"DeferredDeliveryTime",
"DeleteAfterSubmit",
"ExpiryTime",
"FlagDueBy",
"FlagRequest",
"FlagStatus",
"HTMLBody",
"OriginatorDeliveryReportRequested",
"ReadReceiptRequested",
"ReceivedByEntryID",
"ReceivedByName",
"ReceivedOnBehalfOfEntryID",
"ReceivedOnBehalfOfName",
"ReceivedTime",
"RecipientReassignmentProhibited",
"Recipients",
"ReminderOverrideDefault",
"ReminderPlaySound",
"ReminderSet",
"ReminderSoundFile",
"ReminderTime",
"RemoteStatus",
"ReplyRecipientNames",
"ReplyRecipients",
"SaveSentMessageFolder",
"SenderName",
"Sent",
"SentOn",
"SentOnBehalfOfName",
"Submitted",
"[To]",
"VotingOptions",
"VotingResponse",
"Links",
"ItemProperties",
"BodyFormat",
"DownloadState",
"InternetCodepage",
"MarkForDownload",
"IsConflict",
"IsIPFax",
"FlagIcon",
"HasCoverSheet",
"AutoResolvedWinner",
"Conflicts",
"SenderEmailAddress",
"SenderEmailType",
"EnableSharedAttachments",
"Permission",
"PermissionService",
"PropertyAccessor",
"SendUsingAccount",
"TaskSubject",
"TaskDueDate",
"TaskStartDate",
"TaskCompletedDate",
"ToDoTaskOrdinal",
"IsMarkedAsTask",
"ConversationID",
"Sender",
"PermissionTemplateGuid",
"RTFBody",
"RetentionPolicyName",
"RetentionExpirationDate"
Tasks:
"Application",
"Class",
"Session",
"Parent",
"Actions",
"Attachments",
"BillingInformation",
"Body",
"Categories",
"Companies",
"ConversationIndex",
"ConversationTopic",
"CreationTime",
"EntryID",
"FormDescription",
"GetInspector",
"Importance",
"LastModificationTime",
"MAPIOBJECT",
"MessageClass",
"Mileage",
"NoAging",
"OutlookInternalVersion",
"OutlookVersion",
"Saved",
"Sensitivity",
"Size",
"Subject",
"UnRead",
"UserProperties",
"ActualWork",
"CardData",
"Complete",
"Contacts",
"ContactNames",
"DateCompleted",
"DelegationState",
"Delegator",
"DueDate",
"IsRecurring",
"Ordinal",
"Owner",
"Ownership",
"PercentComplete",
"Recipients",
"ReminderTime",
"ReminderOverrideDefault",
"ReminderPlaySound",
"ReminderSet",
"ReminderSoundFile",
"ResponseState",
"Role",
"SchedulePlusPriority",
"StartDate",
"Status",
"StatusOnCompletionRecipients",
"StatusUpdateRecipients",
"TeamTask",
"TotalWork",
"Links",
"DownloadState",
"ItemProperties",
"InternetCodepage",
"MarkForDownload",
"IsConflict",
"AutoResolvedWinner",
"Conflicts",
"PropertyAccessor",
"SendUsingAccount",
"ToDoTaskOrdinal",
"ConversationID",
"RTFBody",
Calendar:
"Application",
"Class",
"Session",
"Parent",
"Actions",
"Attachments",
"BillingInformation",
"Body",
"Categories",
"Companies",
"ConversationIndex",
"ConversationTopic",
"CreationTime",
"EntryID",
"FormDescription",
"GetInspector",
"Importance",
"LastModificationTime",
"MAPIOBJECT",
"MessageClass",
"Mileage",
"NoAging",
"OutlookInternalVersion",
"OutlookVersion",
"Saved",
"Sensitivity",
"Size",
"Subject",
"UnRead",
"UserProperties",
"AllDayEvent",
"BusyStatus",
"Duration",
"End",
"IsOnlineMeeting",
"IsRecurring",
"Location",
"MeetingStatus",
"NetMeetingAutoStart",
"NetMeetingOrganizerAlias",
"NetMeetingServer",
"NetMeetingType",
"OptionalAttendees",
"Organizer",
"Recipients",
"RecurrenceState",
"ReminderMinutesBeforeStart",
"ReminderOverrideDefault",
"ReminderPlaySound",
"ReminderSet",
"ReminderSoundFile",
"ReplyTime",
"RequiredAttendees",
"Resources",
"ResponseRequested",
"ResponseStatus",
"Start",
"NetMeetingDocPathName",
"NetShowURL",
"Links",
"ConferenceServerAllowExternal",
"ConferenceServerPassword",
"ItemProperties",
"DownloadState",
"InternetCodepage",
"MarkForDownload",
"IsConflict",
"MeetingWorkspaceURL",
"AutoResolvedWinner",
"Conflicts",
"PropertyAccessor",
"SendUsingAccount",
"GlobalAppointmentID",
"ForceUpdateToAllAttendees",
"StartUTC",
"EndUTC",
"StartInStartTimeZone",
"EndInEndTimeZone",
"StartTimeZone",
"EndTimeZone",
"ConversationID",
"RTFBody",
"BodyFormat"
e-mail (IPM.Note):
"Application",
"Class",
"Session",
"Parent",
"Actions",
"Attachments",
"BillingInformation",
"Body",
"Categories",
"Companies",
"ConversationIndex",
"ConversationTopic",
"CreationTime",
"EntryID",
"FormDescription",
"GetInspector",
"Importance",
"LastModificationTime",
"MAPIOBJECT",
"MessageClass",
"Mileage",
"NoAging",
"OutlookInternalVersion",
"OutlookVersion",
"Saved",
"Sensitivity",
"Size",
"Subject",
"UnRead",
"UserProperties",
"AlternateRecipientAllowed",
"AutoForwarded",
"BCC",
"CC",
"DeferredDeliveryTime",
"DeleteAfterSubmit",
"ExpiryTime",
"FlagDueBy",
"FlagRequest",
"FlagStatus",
"HTMLBody",
"OriginatorDeliveryReportRequested",
"ReadReceiptRequested",
"ReceivedByEntryID",
"ReceivedByName",
"ReceivedOnBehalfOfEntryID",
"ReceivedOnBehalfOfName",
"ReceivedTime",
"RecipientReassignmentProhibited",
"Recipients",
"ReminderOverrideDefault",
"ReminderPlaySound",
"ReminderSet",
"ReminderSoundFile",
"ReminderTime",
"RemoteStatus",
"ReplyRecipientNames",
"ReplyRecipients",
"SaveSentMessageFolder",
"SenderName",
"Sent",
"SentOn",
"SentOnBehalfOfName",
"Submitted",
"[To]",
"VotingOptions",
"VotingResponse",
"Links",
"ItemProperties",
"BodyFormat",
"DownloadState",
"InternetCodepage",
"MarkForDownload",
"IsConflict",
"IsIPFax",
"FlagIcon",
"HasCoverSheet",
"AutoResolvedWinner",
"Conflicts",
"SenderEmailAddress",
"SenderEmailType",
"EnableSharedAttachments",
"Permission",
"PermissionService",
"PropertyAccessor",
"SendUsingAccount",
"TaskSubject",
"TaskDueDate",
"TaskStartDate",
"TaskCompletedDate",
"ToDoTaskOrdinal",
"IsMarkedAsTask",
"ConversationID",
"Sender",
"PermissionTemplateGuid",
"RTFBody",
"RetentionPolicyName",
"RetentionExpirationDate"
The Microsoft Outlook object browser displays the classes, properties, methods, and events available from the Outlook object library.
If you do not see the Developer tab, see Run in Developer Mode in Outlook to activate the Developer tab. On the Developer tab, in the Form group, click View Code to open the Script Editor. In the Script Editor, click Object Browser on the Script menu or press F2.
All of the available Outlook objects are listed in the Classes pane of the object browser in alphabetical order. To view the members of an object, select the object in the Classes pane. The members of this object appear in alphabetical order in the Members of pane. The heading at the top of this pane will reflect the name of the object that you select. For example, if you select the AppointmentItem object in the Classes pane, the heading of the Members of pane will appear as Members of AppointmentItem.
The interfaces and members of the Microsoft.Office.Interop.Outlook namespace that provide support for interoperability between the COM object model of Outlook and managed applications that automate Outlook are described here.
I have generated the following token and am trying to verify the signature with http://jwt.io
I have also attached the contents of my jwks endpoint that should have all the details I need to verify.
So my question is: how do I get this to say signature valid on the jwt.io website? Am I missing some transformation on the certificate chain parameter?
Here is the spec for jwks for reference.
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImEzck1VZ01Gdjl0UGNsTGE2eUYzekFrZnF1RSIsImtpZCI6ImEzck1VZ01Gdjl0UGNsTGE2eUYzekFrZnF1RSJ9.eyJub25jZSI6IjYzNjA3MDM0OTc3NDIzODg2NS5OMlkxTldKbU1EZ3RZbU13TkMwME9XWTNMVGt5TlRJdE9ERXpOell4Wm1NME0yVmxNV1l5TkdOaFlXTXRaVEpqT1MwME4yRmpMVGd6WmpVdFpXWTVOVEEwWmpFMU1qWTEiLCJpYXQiOjE0NzE0MzgxODIsImF0X2hhc2giOiJLWUJpVkl1Uy1YZERzU3NHcWU5dTJBIiwic3ViIjoiMSIsImFtciI6InBhc3N3b3JkIiwiYXV0aF90aW1lIjoxNDcxNDM4MTgyLCJpZHAiOiJpZHNydiIsImlzcyI6Imh0dHBzOi8vZWx3ZWJhcHBsaWNhdGlvbjEuYXp1cmV3ZWJzaXRlcy5uZXQvaWRlbnRpdHkiLCJhdWQiOiJtdmMiLCJleHAiOjE0NzE0Mzg0ODIsIm5iZiI6MTQ3MTQzODE4Mn0.Ehck2-rA09cJzlfURhDMp-WcXm_t_dl-u0Mli3exdv1HxX8i77x5VfFPM6rP4lcpI3lpN8Yj-FefZYDTUY_UmxCYvXf6ILSrhzEfQVaXSPKX1RUQQIDJGPU6NuFLcR416JpUAkE8joYae3WPj5VsM4yNENGGjUANm4qgj6G_mYy_BiXcSqvRGRYwW5GHDsnnANrIw4oktIYS05yCbjdiNYgQZ043L6Pb2p-5eTPCFqG7WRHp208dhg8D3nhtYEov2Kxod93oKHXSp1zf-Ot0cadk6Ss4fClaTE9S1f29lbwxw7ZxI1L3R4oOL3FZPSSHGp4d3a3AdUKOjKvvTVPv6w
{
keys : [{
kty : "RSA",
use : "sig",
kid : "a3rMUgMFv9tPclLa6yF3zAkfquE",
x5t : "a3rMUgMFv9tPclLa6yF3zAkfquE",
e : "AQAB",
n : "qnTksBdxOiOlsmRNd-mMS2M3o1IDpK4uAr0T4_YqO3zYHAGAWTwsq4ms-NWynqY5HaB4EThNxuq2GWC5JKpO1YirOrwS97B5x9LJyHXPsdJcSikEI9BxOkl6WLQ0UzPxHdYTLpR4_O-0ILAlXw8NU4-jB4AP8Sn9YGYJ5w0fLw5YmWioXeWvocz1wHrZdJPxS8XnqHXwMUozVzQj-x6daOv5FmrHU1r9_bbp0a1GLv4BbTtSh4kMyz1hXylho0EvPg5p9YIKStbNAW9eNWvv5R8HN7PPei21AsUqxekK0oW9jnEdHewckToX7x5zULWKwwZIksll0XnVczVgy7fCFw",
x5c : [
"MIIDBTCCAfGgAwIBAgIQNQb+T2ncIrNA6cKvUA1GWTAJBgUrDgMCHQUAMBIxEDAOBgNVBAMTB0RldlJvb3QwHhcNMTAwMTIwMjIwMDAwWhcNMjAwMTIwMjIwMDAwWjAVMRMwEQYDVQQDEwppZHNydjN0ZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqnTksBdxOiOlsmRNd+mMS2M3o1IDpK4uAr0T4/YqO3zYHAGAWTwsq4ms+NWynqY5HaB4EThNxuq2GWC5JKpO1YirOrwS97B5x9LJyHXPsdJcSikEI9BxOkl6WLQ0UzPxHdYTLpR4/O+0ILAlXw8NU4+jB4AP8Sn9YGYJ5w0fLw5YmWioXeWvocz1wHrZdJPxS8XnqHXwMUozVzQj+x6daOv5FmrHU1r9/bbp0a1GLv4BbTtSh4kMyz1hXylho0EvPg5p9YIKStbNAW9eNWvv5R8HN7PPei21AsUqxekK0oW9jnEdHewckToX7x5zULWKwwZIksll0XnVczVgy7fCFwIDAQABo1wwWjATBgNVHSUEDDAKBggrBgEFBQcDATBDBgNVHQEEPDA6gBDSFgDaV+Q2d2191r6A38tBoRQwEjEQMA4GA1UEAxMHRGV2Um9vdIIQLFk7exPNg41NRNaeNu0I9jAJBgUrDgMCHQUAA4IBAQBUnMSZxY5xosMEW6Mz4WEAjNoNv2QvqNmk23RMZGMgr516ROeWS5D3RlTNyU8FkstNCC4maDM3E0Bi4bbzW3AwrpbluqtcyMN3Pivqdxx+zKWKiORJqqLIvN8CT1fVPxxXb/e9GOdaR8eXSmB0PgNUhM4IjgNkwBbvWC9F/lzvwjlQgciR7d4GfXPYsE1vf8tmdQaY8/PtdAkExmbrb9MihdggSoGXlELrPA91Yce+fiRcKY3rQlNWVd4DOoJ/cPXsXwry8pWjNCo5JD8Q+RQ5yZEy7YPoifwemLhTdsBz3hlZr28oCGJ3kbnpW0xGvQb3VHSTVVbeei0CfXoW6iz1"
]
}
]
}
jwt.io says to enter the key
Public Key or Certificate. Enter it in plain text only if you want to verify a token
so I have converted the JSON Web Key to a PEM format guessing it would need a base64 format, and it works!.
This is the public key built from modulus and exponent
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqnTksBdxOiOlsmRNd+mMS2M3o1IDpK4uAr0T4/YqO3zYHAGAWTwsq4ms+NWynqY5HaB4EThNxuq2GWC5JKpO1YirOrwS97B5x9LJyHXPsdJcSikEI9BxOkl6WLQ0UzPxHdYTLpR4/O+0ILAlXw8NU4+jB4AP8Sn9YGYJ5w0fLw5YmWioXeWvocz1wHrZdJPxS8XnqHXwMUozVzQj+x6daOv5FmrHU1r9/bbp0a1GLv4BbTtSh4kMyz1hXylho0EvPg5p9YIKStbNAW9eNWvv5R8HN7PPei21AsUqxekK0oW9jnEdHewckToX7x5zULWKwwZIksll0XnVczVgy7fCFwIDAQAB
-----END PUBLIC KEY-----
After some attemps I decided to write a simple test program to check if JWT signature is correct or it was a key format issue. You can test it (Java 8). It is fully functional
package test;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.util.Base64;
public class JWKTest {
private static final String[] HEX_TABLE = new String[]{
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
"30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
"40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
"50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
"60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
"70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
"80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
"90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
"b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
"c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df",
"e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff",
};
public static String toHexFromBytes(byte[] bytes) {
StringBuffer rc = new StringBuffer(bytes.length * 2);
for (int i = 0; i < bytes.length; i++) {
rc.append(HEX_TABLE[0xFF & bytes[i]]);
}
return rc.toString();
}
// Build the public key from modulus and exponent
public static PublicKey getPublicKey (String modulusB64u, String exponentB64u) throws NoSuchAlgorithmException, InvalidKeySpecException{
//conversion to BigInteger. I have transformed to Hex because new BigDecimal(byte) does not work for me
byte exponentB[] = Base64.getUrlDecoder().decode(exponentB64u);
byte modulusB[] = Base64.getUrlDecoder().decode(modulusB64u);
BigInteger exponent = new BigInteger(toHexFromBytes(exponentB), 16);
BigInteger modulus = new BigInteger(toHexFromBytes(modulusB), 16);
//Build the public key
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey pub = factory.generatePublic(spec);
return pub;
}
public final static void main (String argv[]) throws NoSuchAlgorithmException, InvalidKeySpecException, SignatureException, NoSuchProviderException, InvalidKeyException{
String exponentB64u = "AQAB";
String modulusB64u = "qnTksBdxOiOlsmRNd-mMS2M3o1IDpK4uAr0T4_YqO3zYHAGAWTwsq4ms-NWynqY5HaB4EThNxuq2GWC5JKpO1YirOrwS97B5x9LJyHXPsdJcSikEI9BxOkl6WLQ0UzPxHdYTLpR4_O-0ILAlXw8NU4-jB4AP8Sn9YGYJ5w0fLw5YmWioXeWvocz1wHrZdJPxS8XnqHXwMUozVzQj-x6daOv5FmrHU1r9_bbp0a1GLv4BbTtSh4kMyz1hXylho0EvPg5p9YIKStbNAW9eNWvv5R8HN7PPei21AsUqxekK0oW9jnEdHewckToX7x5zULWKwwZIksll0XnVczVgy7fCFw";
String jwt = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImEzck1VZ01Gdjl0UGNsTGE2eUYzekFrZnF1RSIsImtpZCI6ImEzck1VZ01Gdjl0UGNsTGE2eUYzekFrZnF1RSJ9.eyJub25jZSI6IjYzNjA3MDM0OTc3NDIzODg2NS5OMlkxTldKbU1EZ3RZbU13TkMwME9XWTNMVGt5TlRJdE9ERXpOell4Wm1NME0yVmxNV1l5TkdOaFlXTXRaVEpqT1MwME4yRmpMVGd6WmpVdFpXWTVOVEEwWmpFMU1qWTEiLCJpYXQiOjE0NzE0MzgxODIsImF0X2hhc2giOiJLWUJpVkl1Uy1YZERzU3NHcWU5dTJBIiwic3ViIjoiMSIsImFtciI6InBhc3N3b3JkIiwiYXV0aF90aW1lIjoxNDcxNDM4MTgyLCJpZHAiOiJpZHNydiIsImlzcyI6Imh0dHBzOi8vZWx3ZWJhcHBsaWNhdGlvbjEuYXp1cmV3ZWJzaXRlcy5uZXQvaWRlbnRpdHkiLCJhdWQiOiJtdmMiLCJleHAiOjE0NzE0Mzg0ODIsIm5iZiI6MTQ3MTQzODE4Mn0.Ehck2-rA09cJzlfURhDMp-WcXm_t_dl-u0Mli3exdv1HxX8i77x5VfFPM6rP4lcpI3lpN8Yj-FefZYDTUY_UmxCYvXf6ILSrhzEfQVaXSPKX1RUQQIDJGPU6NuFLcR416JpUAkE8joYae3WPj5VsM4yNENGGjUANm4qgj6G_mYy_BiXcSqvRGRYwW5GHDsnnANrIw4oktIYS05yCbjdiNYgQZ043L6Pb2p-5eTPCFqG7WRHp208dhg8D3nhtYEov2Kxod93oKHXSp1zf-Ot0cadk6Ss4fClaTE9S1f29lbwxw7ZxI1L3R4oOL3FZPSSHGp4d3a3AdUKOjKvvTVPv6w";
//Build the public key from modulus and exponent
PublicKey publicKey = getPublicKey (modulusB64u,exponentB64u);
//print key as PEM (base64 and headers)
String publicKeyPEM =
"-----BEGIN PUBLIC KEY-----\n"
+ Base64.getEncoder().encodeToString(publicKey.getEncoded()) +"\n"
+ "-----END PUBLIC KEY-----";
System.out.println( publicKeyPEM);
//get signed data and signature from JWT
String signedData = jwt.substring(0, jwt.lastIndexOf("."));
String signatureB64u = jwt.substring(jwt.lastIndexOf(".")+1,jwt.length());
byte signature[] = Base64.getUrlDecoder().decode(signatureB64u);
//verify Signature
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initVerify(publicKey);
sig.update(signedData.getBytes());
boolean v = sig.verify(signature);
System.out.println(v);
}
}