From 7e50024fda107bbb9359648709a717e970a9eef2 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Thu, 3 Oct 2019 17:45:51 +0300 Subject: [PATCH 001/362] Introduced super pom to share dependencies across all Gluu maven based projects. https://github.com/GluuFederation/oxCore/issues/132 --- demo-cdi/pom.xml | 3 +- oxJsfUtil/pom.xml | 121 +++++---- oxModel/pom.xml | 4 +- oxRadius/pom.xml | 4 +- oxSaml/pom.xml | 3 +- oxService/pom.xml | 15 +- oxUtil/pom.xml | 201 +++++++------- oxcore-parent-bom/pom.xml | 329 +++++++++++++++++++++++ persistence-annotation/pom.xml | 2 +- persistence-cdi/pom.xml | 7 +- persistence-core/pom.xml | 12 +- persistence-couchbase-sample/pom.xml | 143 +++++----- persistence-couchbase/pom.xml | 15 +- persistence-filter/pom.xml | 5 +- persistence-hybrid/pom.xml | 11 +- persistence-ldap-sample/pom.xml | 61 +++-- persistence-ldap/pom.xml | 12 +- persistence-model/pom.xml | 6 +- persistence-standalone/pom.xml | 4 +- pom.xml | 376 ++++++--------------------- server/pom.xml | 2 +- 21 files changed, 698 insertions(+), 638 deletions(-) create mode 100644 oxcore-parent-bom/pom.xml diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index fcd65af0..0e54cd42 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -2,14 +2,13 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.gluu oxcore-demo-cdi Demo CDI services org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index ff53e0e2..50b3f931 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -1,62 +1,61 @@ - - - 4.0.0 - oxcore-jsf-util - jar - oxJsfUtil - JSF2 utilities - - - org.gluu - oxcore - 4.0.0-SNAPSHOT - - - - - - src/main/resources - true - - **/*.xml - **/services/* - **/*.properties - - - - - - - - org.gluu - oxcore-service - ${project.version} - - - javax.enterprise - cdi-api - provided - - - com.sun.faces - jsf-api - provided - - - javax.servlet - javax.servlet-api - provided - - - javax.el - el-api - provided - - - org.glassfish - javax.faces - - - + + + 4.0.0 + oxcore-jsf-util + jar + oxJsfUtil + JSF2 utilities + + + org.gluu + oxcore + 4.1.0-SNAPSHOT + + + + + + src/main/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + + + org.gluu + oxcore-service + + + javax.enterprise + cdi-api + provided + + + com.sun.faces + jsf-api + provided + + + javax.servlet + javax.servlet-api + provided + + + javax.el + el-api + provided + + + org.glassfish + javax.faces + + + \ No newline at end of file diff --git a/oxModel/pom.xml b/oxModel/pom.xml index deaf3eb3..2eceeae8 100644 --- a/oxModel/pom.xml +++ b/oxModel/pom.xml @@ -9,19 +9,17 @@ org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT org.gluu oxcore-persistence-annotation - ${project.version} org.gluu oxcore-persistence-model - ${project.version} diff --git a/oxRadius/pom.xml b/oxRadius/pom.xml index f8228578..4aca56a1 100644 --- a/oxRadius/pom.xml +++ b/oxRadius/pom.xml @@ -8,19 +8,17 @@ org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT org.gluu oxcore-persistence-ldap - ${project.version} org.gluu oxcore-persistence-annotation - ${project.version} diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index 927a2144..b4ff7566 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -9,14 +9,13 @@ org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT org.gluu oxcore-util - ${project.version} org.apache.ws.security diff --git a/oxService/pom.xml b/oxService/pom.xml index dee44b8b..052960fc 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT @@ -41,24 +41,20 @@ - ${project.groupId} + org.gluu oxcore-model - ${project.version} - ${project.groupId} + org.gluu oxcore-persistence-ldap - ${project.version} - ${project.groupId} + org.gluu oxcore-persistence-couchbase - ${project.version} - ${project.groupId} + org.gluu oxcore-util - ${project.version} @@ -140,7 +136,6 @@ com.google.guava guava - ${guava.version} diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index 5edda372..ad5eabe9 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -1,102 +1,101 @@ - - - 4.0.0 - oxcore-util - jar - oxUtil - - - org.gluu - oxcore - 4.0.0-SNAPSHOT - - - - - ${project.groupId} - oxcore-persistence-annotation - ${project.version} - - - - - javax.persistence - persistence-api - - - - - org.apache.logging.log4j - log4j-api - - - org.apache.logging.log4j - log4j-1.2-api - - - org.slf4j - slf4j-api - - - org.apache.logging.log4j - log4j-slf4j-impl - - - - commons-codec - commons-codec - - - commons-configuration - commons-configuration - - - org.apache.commons - commons-text - - - commons-io - commons-io - - - commons-httpclient - commons-httpclient - - - org.apache.commons - commons-exec - - - - org.apache.httpcomponents - httpcore - - - org.apache.httpcomponents - httpclient - - - - com.fasterxml.jackson.core - jackson-annotations - - - com.fasterxml.jackson.core - jackson-core - - - com.fasterxml.jackson.core - jackson-databind - - - org.jboss.resteasy - resteasy-jackson2-provider - - - javax.servlet - javax.servlet-api - - - + + + 4.0.0 + oxcore-util + jar + oxUtil + + + org.gluu + oxcore + 4.1.0-SNAPSHOT + + + + + org.gluu + oxcore-persistence-annotation + + + + + javax.persistence + persistence-api + + + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-1.2-api + + + org.slf4j + slf4j-api + + + org.apache.logging.log4j + log4j-slf4j-impl + + + + commons-codec + commons-codec + + + commons-configuration + commons-configuration + + + org.apache.commons + commons-text + + + commons-io + commons-io + + + commons-httpclient + commons-httpclient + + + org.apache.commons + commons-exec + + + + org.apache.httpcomponents + httpcore + + + org.apache.httpcomponents + httpclient + + + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-databind + + + org.jboss.resteasy + resteasy-jackson2-provider + + + javax.servlet + javax.servlet-api + + + \ No newline at end of file diff --git a/oxcore-parent-bom/pom.xml b/oxcore-parent-bom/pom.xml new file mode 100644 index 00000000..416acabb --- /dev/null +++ b/oxcore-parent-bom/pom.xml @@ -0,0 +1,329 @@ + + + 4.0.0 + org.gluu + oxcore-parent-bom + pom + oxcore-parent-bom + 4.1.0-SNAPSHOT + + + UTF-8 + 3.0.3 + + 4.1.0-SNAPSHOT + + 3.7.0.Final + + 3.1.1.Final + 4.5.17-gluu.Final + + 2.2.19 + 2.2.19 + 2.2.1-b04 + 2.2.1-b05 + + 2.9.9 + 2.9.10 + 2.11.2 + 1.7.26 + + 27.1-jre + + + + + central + Maven Repository Switchboard + default + http://repo1.maven.org/maven2 + + + repository.jboss.org + JBoss Repository + http://repository.jboss.org/nexus/content/groups/public-jboss/ + + + gluu + Gluu repository + http://ox.gluu.org/maven + + + + + + + com.google.guava + guava + ${guava.version} + + + + + org.jboss.weld + weld-core-parent + ${weld.version} + import + pom + + + javax.el + el-api + ${uel-api.version} + provided + + + org.glassfish.web + el-impl + ${uel-impl.version} + + + com.sun.faces + jsf-api + ${jsf-api.version} + + + org.glassfish + javax.faces + ${jsf-impl.version} + + + + javax.persistence + persistence-api + 1.0.2 + + + + + org.richfaces + richfaces + ${richfaces.version} + + + org.richfaces + richfaces-core + ${richfaces.version} + + + + net.jodah + expiringmap + 0.5.9 + + + + commons-io + commons-io + 2.6 + + + commons-codec + commons-codec + 1.12 + + + org.apache.commons + commons-exec + 1.3 + + + commons-configuration + commons-configuration + 1.10 + + + org.apache.commons + commons-text + 1.6 + + + commons-beanutils + commons-beanutils + 1.9.3 + + + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + + + org.apache.logging.log4j + log4j-1.2-api + ${log4j.version} + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + test + + + org.apache.logging.log4j + log4j-slf4j-impl + ${log4j.version} + + + org.slf4j + slf4j-simple + ${slf4j.version} + + + + net.sf.ehcache + ehcache-core + 2.10.6 + + + + org.reflections + reflections + 0.9.11 + + + + + com.fasterxml.jackson.core + jackson-annotations + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-core + ${jackson.version} + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.databind.version} + + + + + org.python + jython-standalone + 2.7.1 + + + + + org.jboss.resteasy + resteasy-jaxrs + ${resteasy.version} + + + org.jboss.resteasy + resteasy-jackson2-provider + ${resteasy.version} + + + + + javax.mail + mail + 1.4.7 + + + + + net.spy + spymemcached + 2.12.3 + + + redis.clients + jedis + 2.10.2 + + + + + org.apache.httpcomponents + httpcore + 4.4.11 + + + org.apache.httpcomponents + httpclient + 4.5.8 + + + + + org.apache.ws.security + wss4j + 1.6.19 + + + + + com.unboundid + unboundid-ldapsdk + 4.0.7 + + + + + com.couchbase.client + java-client + 2.7.9 + + + + + io.dropwizard.metrics + metrics-core + 4.0.5 + + + + + org.eclipse.jetty + jetty-deploy + 9.4.19.v20190610 + provided + + + + + org.testng + testng + 6.9.4 + test + + + + com.beust + jcommander + 1.72 + test + + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + org.quartz-scheduler + quartz + 2.3.1 + + + + \ No newline at end of file diff --git a/persistence-annotation/pom.xml b/persistence-annotation/pom.xml index 4e2d00a7..3fc5f41f 100644 --- a/persistence-annotation/pom.xml +++ b/persistence-annotation/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT \ No newline at end of file diff --git a/persistence-cdi/pom.xml b/persistence-cdi/pom.xml index b549c67c..8ffaa522 100644 --- a/persistence-cdi/pom.xml +++ b/persistence-cdi/pom.xml @@ -2,14 +2,13 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.gluu oxcore-persistence-cdi Persistence CDI services org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT @@ -34,18 +33,14 @@ org.gluu oxcore-persistence-core - ${project.version} org.gluu oxcore-persistence-annotation - ${project.version} - org.gluu oxcore-persistence-ldap - ${project.version} org.slf4j diff --git a/persistence-core/pom.xml b/persistence-core/pom.xml index 5441710c..b930e0de 100644 --- a/persistence-core/pom.xml +++ b/persistence-core/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT @@ -38,24 +38,20 @@ - ${project.groupId} + org.gluu oxcore-util - ${project.version} - ${project.groupId} + org.gluu oxcore-persistence-filter - ${project.version} - ${project.groupId} + org.gluu oxcore-persistence-model - ${project.version} org.gluu oxcore-persistence-annotation - ${project.version} diff --git a/persistence-couchbase-sample/pom.xml b/persistence-couchbase-sample/pom.xml index f1179648..339aa665 100644 --- a/persistence-couchbase-sample/pom.xml +++ b/persistence-couchbase-sample/pom.xml @@ -1,74 +1,71 @@ - - - 4.0.0 - org.gluu - oxcore-persistence-couchbase-sample - Persistence Couchbase sample - Sample project to show persistence-couchbase functionality - - - org.gluu - oxcore - 4.0.0-SNAPSHOT - - - - ${maven.min-version} - - - - - - src/main/resources - - **/*.json - **/*.xml - **/*.yml - **/*.properties - - - - - - src/test/resources - - **/*.json - **/*.xml - **/*.yml - **/*.properties - - - - - - - - org.gluu - oxcore-persistence-couchbase - ${project.version} - - - org.apache.logging.log4j - log4j-slf4j-impl - - - - - org.gluu - oxcore-persistence-annotation - ${project.version} - - - org.slf4j - slf4j-simple - - - - - org.testng - testng - - - + + + 4.0.0 + oxcore-persistence-couchbase-sample + Persistence Couchbase sample + Sample project to show persistence-couchbase functionality + + + org.gluu + oxcore + 4.1.0-SNAPSHOT + + + + ${maven.min-version} + + + + + + src/main/resources + + **/*.json + **/*.xml + **/*.yml + **/*.properties + + + + + + src/test/resources + + **/*.json + **/*.xml + **/*.yml + **/*.properties + + + + + + + + org.gluu + oxcore-persistence-couchbase + + + org.apache.logging.log4j + log4j-slf4j-impl + + + + + org.gluu + oxcore-persistence-annotation + + + org.slf4j + slf4j-simple + + + + + org.testng + testng + + + \ No newline at end of file diff --git a/persistence-couchbase/pom.xml b/persistence-couchbase/pom.xml index cf13b511..4958a9bc 100644 --- a/persistence-couchbase/pom.xml +++ b/persistence-couchbase/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT @@ -28,29 +28,24 @@ - ${project.groupId} + org.gluu oxcore-util - ${project.version} - ${project.groupId} + org.gluu oxcore-persistence-filter - ${project.version} - ${project.groupId} + org.gluu oxcore-persistence-core - ${project.version} - ${project.groupId} + org.gluu oxcore-persistence-ldap - ${project.version} org.gluu oxcore-persistence-annotation - ${project.version} diff --git a/persistence-filter/pom.xml b/persistence-filter/pom.xml index 432621dc..856731db 100644 --- a/persistence-filter/pom.xml +++ b/persistence-filter/pom.xml @@ -8,14 +8,13 @@ org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT - ${project.groupId} + org.gluu oxcore-util - ${project.version} diff --git a/persistence-hybrid/pom.xml b/persistence-hybrid/pom.xml index f3eb9468..df2c7fef 100644 --- a/persistence-hybrid/pom.xml +++ b/persistence-hybrid/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT @@ -28,19 +28,16 @@ - ${project.groupId} + org.gluu oxcore-util - ${project.version} - ${project.groupId} + org.gluu oxcore-persistence-core - ${project.version} - ${project.groupId} + org.gluu oxcore-persistence-cdi - ${project.version} diff --git a/persistence-ldap-sample/pom.xml b/persistence-ldap-sample/pom.xml index 0f120d57..6dbcb423 100644 --- a/persistence-ldap-sample/pom.xml +++ b/persistence-ldap-sample/pom.xml @@ -1,33 +1,30 @@ - - - 4.0.0 - org.gluu - oxcore-persistence-ldap-sample - persistence-ldapSample - Sample project to show persistence-ldap functionality - - - org.gluu - oxcore - 4.0.0-SNAPSHOT - - - - ${maven.min-version} - - - - - org.gluu - oxcore-persistence-ldap - ${project.version} - - - org.gluu - oxcore-persistence-annotation - ${project.version} - - - + + + 4.0.0 + oxcore-persistence-ldap-sample + persistence-ldapSample + Sample project to show persistence-ldap functionality + + + org.gluu + oxcore + 4.1.0-SNAPSHOT + + + + ${maven.min-version} + + + + + org.gluu + oxcore-persistence-ldap + + + org.gluu + oxcore-persistence-annotation + + + \ No newline at end of file diff --git a/persistence-ldap/pom.xml b/persistence-ldap/pom.xml index 74afc174..3fdcbacb 100644 --- a/persistence-ldap/pom.xml +++ b/persistence-ldap/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT @@ -28,24 +28,20 @@ - ${project.groupId} + org.gluu oxcore-util - ${project.version} - ${project.groupId} + org.gluu oxcore-persistence-filter - ${project.version} - ${project.groupId} + org.gluu oxcore-persistence-core - ${project.version} org.gluu oxcore-persistence-annotation - ${project.version} diff --git a/persistence-model/pom.xml b/persistence-model/pom.xml index bc968d4c..817472d0 100644 --- a/persistence-model/pom.xml +++ b/persistence-model/pom.xml @@ -8,19 +8,17 @@ org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT org.gluu oxcore-persistence-annotation - ${project.version} - ${project.groupId} + org.gluu oxcore-util - ${project.version} diff --git a/persistence-standalone/pom.xml b/persistence-standalone/pom.xml index 1da83e90..6383d412 100644 --- a/persistence-standalone/pom.xml +++ b/persistence-standalone/pom.xml @@ -2,14 +2,13 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.gluu oxcore-persistence-standalone Persistence standalone services org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT @@ -34,7 +33,6 @@ org.gluu oxcore-persistence-cdi - ${project.version} javax.enterprise diff --git a/pom.xml b/pom.xml index e208e10a..9b0bd832 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.gluu oxcore pom - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT oxCore http://ox.gluu.org @@ -17,44 +17,8 @@ UTF-8 3.0.3 - - 3.7.0.Final - - 3.1.1.Final - 4.5.17-gluu.Final - - 2.2.19 - 2.2.19 - 2.2.1-b04 - 2.2.1-b05 - - 2.9.9 - 2.9.10 - 2.11.2 - 1.7.26 - - 27.1-jre - - - central - Maven Repository Switchboard - default - http://repo1.maven.org/maven2 - - - repository.jboss.org - JBoss Repository - http://repository.jboss.org/nexus/content/groups/public-jboss/ - - - gluu - Gluu repository - http://ox.gluu.org/maven - - - https://github.com/GluuFederation/oxCore scm:git:git://github.com/GluuFederation/oxCore.git @@ -83,285 +47,97 @@ demo-cdi - - - - - org.jboss.weld - weld-core-parent - ${weld.version} + org.gluu + oxcore-parent-bom + 4.1.0-SNAPSHOT import pom - - javax.el - el-api - ${uel-api.version} - provided - - - org.glassfish.web - el-impl - ${uel-impl.version} - - - com.sun.faces - jsf-api - ${jsf-api.version} - - - org.glassfish - javax.faces - ${jsf-impl.version} - - - javax.persistence - persistence-api - 1.0.2 - - - - - org.richfaces - richfaces - ${richfaces.version} - - - org.richfaces - richfaces-core - ${richfaces.version} - - - - net.jodah - expiringmap - 0.5.9 - - - - commons-io - commons-io - 2.6 - - - commons-codec - commons-codec - 1.12 - - - org.apache.commons - commons-exec - 1.3 - - - commons-configuration - commons-configuration - 1.10 - - - org.apache.commons - commons-text - 1.6 - - - commons-beanutils - commons-beanutils - 1.9.3 - - - - - org.apache.logging.log4j - log4j-api - ${log4j.version} - - - org.apache.logging.log4j - log4j-1.2-api - ${log4j.version} - - - org.apache.logging.log4j - log4j-core - ${log4j.version} - - - - org.slf4j - slf4j-api - ${slf4j.version} - - - org.slf4j - slf4j-log4j12 - ${slf4j.version} - test - - - org.apache.logging.log4j - log4j-slf4j-impl - ${log4j.version} - - - org.slf4j - slf4j-simple - ${slf4j.version} - - - - net.sf.ehcache - ehcache-core - 2.10.6 - - - - org.reflections - reflections - 0.9.11 - - - - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} + org.gluu + oxcore-demo-cdi + ${project.version} - com.fasterxml.jackson.core - jackson-core - ${jackson.version} + org.gluu + oxcore-jsf-util + ${project.version} - com.fasterxml.jackson.core - jackson-databind - ${jackson.databind.version} + org.gluu + oxcore-radius + ${project.version} - - - - org.python - jython-standalone - 2.7.1 - - - - - org.jboss.resteasy - resteasy-jaxrs - ${resteasy.version} - - - org.jboss.resteasy - resteasy-jackson2-provider - ${resteasy.version} - - - - - javax.mail - mail - 1.4.7 - - - - - net.spy - spymemcached - 2.12.3 - - - redis.clients - jedis - 2.10.2 - - - - - org.apache.httpcomponents - httpcore - 4.4.11 - - - org.apache.httpcomponents - httpclient - 4.5.8 - - - - - org.apache.ws.security - wss4j - 1.6.19 - - - - - com.unboundid - unboundid-ldapsdk - 4.0.7 - - - - - com.couchbase.client - java-client - 2.7.9 - - - - - io.dropwizard.metrics - metrics-core - 4.0.5 - - - - - org.eclipse.jetty - jetty-deploy - 9.4.19.v20190610 - provided - - - - - org.testng - testng - 6.9.4 - test - - - - org.testng - testng - 6.9.4 - test + org.gluu + oxcore-saml + ${project.version} - - com.beust - jcommander - 1.72 - test - - - - javax.servlet - javax.servlet-api - 3.1.0 - provided - - - org.quartz-scheduler - quartz - 2.3.1 - - + org.gluu + oxcore-service + ${project.version} + + + org.gluu + oxcore-util + ${project.version} + + + org.gluu + oxcore-persistence-annotation + ${project.version} + + + org.gluu + oxcore-persistence-cdi + ${project.version} + + + org.gluu + oxcore-persistence-core + ${project.version} + + + org.gluu + oxcore-persistence-couchbase + ${project.version} + + + org.gluu + oxcore-persistence-filter + ${project.version} + + + org.gluu + oxcore-persistence-hybrid + ${project.version} + + + org.gluu + oxcore-persistence-ldap + ${project.version} + + + org.gluu + oxcore-server + ${project.version} + + + org.gluu + oxcore-persistence-model + ${project.version} + + + org.gluu + oxcore-model + ${project.version} + + diff --git a/server/pom.xml b/server/pom.xml index 9e4aac16..ebc6f1ec 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.0.0-SNAPSHOT + 4.1.0-SNAPSHOT From 686a14c8dee2dc3d76f2aa7920a9287bf674d05c Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Fri, 4 Oct 2019 09:17:07 +0300 Subject: [PATCH 002/362] added bunch of new dependencies to super pom https://github.com/GluuFederation/oxCore/issues/132 --- oxcore-parent-bom/pom.xml | 58 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/oxcore-parent-bom/pom.xml b/oxcore-parent-bom/pom.xml index 416acabb..004fddf3 100644 --- a/oxcore-parent-bom/pom.xml +++ b/oxcore-parent-bom/pom.xml @@ -118,6 +118,11 @@ commons-io 2.6 + + commons-lang + commons-lang + 2.6 + commons-codec commons-codec @@ -211,6 +216,21 @@ jackson-databind ${jackson.databind.version} + + com.fasterxml.jackson.datatype + jackson-datatype-json-org + ${jackson.version} + + + com.fasterxml.jackson.module + jackson-module-jaxb-annotations + ${jackson.version} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-cbor + ${jackson.version} + @@ -219,18 +239,45 @@ 2.7.1 - + + + org.jboss.resteasy + resteasy-cdi + ${resteasy.version} + + + org.jboss.resteasy + resteasy-client + ${resteasy.version} + + + org.jboss.resteasy + resteasy-servlet-initializer + ${resteasy.version} + org.jboss.resteasy resteasy-jaxrs ${resteasy.version} + + org.jboss.resteasy + resteasy-jaxb-provider + ${resteasy.version} + org.jboss.resteasy resteasy-jackson2-provider ${resteasy.version} + + + org.json + json + ${json.version} + + javax.mail @@ -302,9 +349,16 @@ org.testng testng - 6.9.4 + 6.14.3 test + + junit + junit + 4.12 + test + + com.beust From 4c9c3be8256896c2e406ae59b5af36e234806961 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Fri, 4 Oct 2019 09:39:23 +0300 Subject: [PATCH 003/362] added bouncycastle and nimbus to super pom https://github.com/GluuFederation/oxCore/issues/132 --- oxcore-parent-bom/pom.xml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/oxcore-parent-bom/pom.xml b/oxcore-parent-bom/pom.xml index 004fddf3..75865a71 100644 --- a/oxcore-parent-bom/pom.xml +++ b/oxcore-parent-bom/pom.xml @@ -26,6 +26,7 @@ 2.9.9 2.9.10 + 20180813 2.11.2 1.7.26 @@ -49,6 +50,11 @@ Gluu repository http://ox.gluu.org/maven + + bouncycastle + Bouncy Castle + http://repo2.maven.org/maven2/org/bouncycastle + @@ -59,6 +65,23 @@ ${guava.version} + + + org.bouncycastle + bcprov-jdk15on + 1.54 + + + org.bouncycastle + bcpkix-jdk15on + 1.54 + + + com.nimbusds + nimbus-jose-jwt + 6.3 + + org.jboss.weld From 44f3bea106954924ad9892384f6db55d31bc98d8 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Fri, 4 Oct 2019 10:11:54 +0300 Subject: [PATCH 004/362] removed oxcore-parent-bom from oxCore project. It has now own repo for convenience. https://github.com/GluuFederation/oxcore-parent-bom/blob/master/pom.xml https://github.com/GluuFederation/oxCore/issues/132 --- oxcore-parent-bom/pom.xml | 406 -------------------------------------- 1 file changed, 406 deletions(-) delete mode 100644 oxcore-parent-bom/pom.xml diff --git a/oxcore-parent-bom/pom.xml b/oxcore-parent-bom/pom.xml deleted file mode 100644 index 75865a71..00000000 --- a/oxcore-parent-bom/pom.xml +++ /dev/null @@ -1,406 +0,0 @@ - - - 4.0.0 - org.gluu - oxcore-parent-bom - pom - oxcore-parent-bom - 4.1.0-SNAPSHOT - - - UTF-8 - 3.0.3 - - 4.1.0-SNAPSHOT - - 3.7.0.Final - - 3.1.1.Final - 4.5.17-gluu.Final - - 2.2.19 - 2.2.19 - 2.2.1-b04 - 2.2.1-b05 - - 2.9.9 - 2.9.10 - 20180813 - 2.11.2 - 1.7.26 - - 27.1-jre - - - - - central - Maven Repository Switchboard - default - http://repo1.maven.org/maven2 - - - repository.jboss.org - JBoss Repository - http://repository.jboss.org/nexus/content/groups/public-jboss/ - - - gluu - Gluu repository - http://ox.gluu.org/maven - - - bouncycastle - Bouncy Castle - http://repo2.maven.org/maven2/org/bouncycastle - - - - - - - com.google.guava - guava - ${guava.version} - - - - - org.bouncycastle - bcprov-jdk15on - 1.54 - - - org.bouncycastle - bcpkix-jdk15on - 1.54 - - - com.nimbusds - nimbus-jose-jwt - 6.3 - - - - - org.jboss.weld - weld-core-parent - ${weld.version} - import - pom - - - javax.el - el-api - ${uel-api.version} - provided - - - org.glassfish.web - el-impl - ${uel-impl.version} - - - com.sun.faces - jsf-api - ${jsf-api.version} - - - org.glassfish - javax.faces - ${jsf-impl.version} - - - - javax.persistence - persistence-api - 1.0.2 - - - - - org.richfaces - richfaces - ${richfaces.version} - - - org.richfaces - richfaces-core - ${richfaces.version} - - - - net.jodah - expiringmap - 0.5.9 - - - - commons-io - commons-io - 2.6 - - - commons-lang - commons-lang - 2.6 - - - commons-codec - commons-codec - 1.12 - - - org.apache.commons - commons-exec - 1.3 - - - commons-configuration - commons-configuration - 1.10 - - - org.apache.commons - commons-text - 1.6 - - - commons-beanutils - commons-beanutils - 1.9.3 - - - - - org.apache.logging.log4j - log4j-api - ${log4j.version} - - - org.apache.logging.log4j - log4j-1.2-api - ${log4j.version} - - - org.apache.logging.log4j - log4j-core - ${log4j.version} - - - - org.slf4j - slf4j-api - ${slf4j.version} - - - org.slf4j - slf4j-log4j12 - ${slf4j.version} - test - - - org.apache.logging.log4j - log4j-slf4j-impl - ${log4j.version} - - - org.slf4j - slf4j-simple - ${slf4j.version} - - - - net.sf.ehcache - ehcache-core - 2.10.6 - - - - org.reflections - reflections - 0.9.11 - - - - - com.fasterxml.jackson.core - jackson-annotations - ${jackson.version} - - - com.fasterxml.jackson.core - jackson-core - ${jackson.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.databind.version} - - - com.fasterxml.jackson.datatype - jackson-datatype-json-org - ${jackson.version} - - - com.fasterxml.jackson.module - jackson-module-jaxb-annotations - ${jackson.version} - - - com.fasterxml.jackson.dataformat - jackson-dataformat-cbor - ${jackson.version} - - - - - org.python - jython-standalone - 2.7.1 - - - - - org.jboss.resteasy - resteasy-cdi - ${resteasy.version} - - - org.jboss.resteasy - resteasy-client - ${resteasy.version} - - - org.jboss.resteasy - resteasy-servlet-initializer - ${resteasy.version} - - - org.jboss.resteasy - resteasy-jaxrs - ${resteasy.version} - - - org.jboss.resteasy - resteasy-jaxb-provider - ${resteasy.version} - - - org.jboss.resteasy - resteasy-jackson2-provider - ${resteasy.version} - - - - - org.json - json - ${json.version} - - - - - javax.mail - mail - 1.4.7 - - - - - net.spy - spymemcached - 2.12.3 - - - redis.clients - jedis - 2.10.2 - - - - - org.apache.httpcomponents - httpcore - 4.4.11 - - - org.apache.httpcomponents - httpclient - 4.5.8 - - - - - org.apache.ws.security - wss4j - 1.6.19 - - - - - com.unboundid - unboundid-ldapsdk - 4.0.7 - - - - - com.couchbase.client - java-client - 2.7.9 - - - - - io.dropwizard.metrics - metrics-core - 4.0.5 - - - - - org.eclipse.jetty - jetty-deploy - 9.4.19.v20190610 - provided - - - - - org.testng - testng - 6.14.3 - test - - - junit - junit - 4.12 - test - - - - - com.beust - jcommander - 1.72 - test - - - - javax.servlet - javax.servlet-api - 3.1.0 - provided - - - org.quartz-scheduler - quartz - 2.3.1 - - - - \ No newline at end of file From 3d3f92c377092b88505ac869b47812780fd5322d Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Tue, 8 Oct 2019 16:47:18 +0100 Subject: [PATCH 005/362] Fix inum filter --- .../src/main/java/org/gluu/service/LookupService.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/LookupService.java b/oxService/src/main/java/org/gluu/service/LookupService.java index 10ee5103..85f21c0e 100644 --- a/oxService/src/main/java/org/gluu/service/LookupService.java +++ b/oxService/src/main/java/org/gluu/service/LookupService.java @@ -81,24 +81,18 @@ public List getDisplayNameEntries(String baseDn, List List entries = (List) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); if (entries == null) { Filter searchFilter = buildInumFilter(inums); - entries = ldapEntryManager.findEntries(baseDn, DisplayNameEntry.class, searchFilter); - cacheService.put(OxConstants.CACHE_LOOKUP_NAME, key, entries); } - return entries; } public Filter buildInumFilter(List inums) { List inumFilters = new ArrayList(inums.size()); for (String inum : inums) { - inumFilters.add(Filter.createEqualityFilter(OxConstants.INUM, inum)); + inumFilters.add(Filter.createEqualityFilter(OxConstants.INUM, inum).multiValued(false)); } - - Filter searchFilter = Filter.createORFilter(inumFilters); - - return searchFilter; + return Filter.createORFilter(inumFilters); } public List getInumsFromDns(List dns) { From 9d6d7fcc44dd8890a44977fed989e45e61b81540 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 8 Oct 2019 19:30:51 +0300 Subject: [PATCH 006/362] Skip join filter if multivalued is set --- .../persist/couchbase/impl/CouchbaseFilterConverter.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java index 560c9a76..f9054716 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java @@ -86,6 +86,11 @@ public ConvertedExpression convertToCouchbaseFilter(Filter genericFilter, Map Date: Wed, 9 Oct 2019 11:33:30 +0300 Subject: [PATCH 007/362] Fix lookup cache conflict with other caches --- oxService/src/main/java/org/gluu/service/LookupService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/service/LookupService.java b/oxService/src/main/java/org/gluu/service/LookupService.java index 85f21c0e..27169959 100644 --- a/oxService/src/main/java/org/gluu/service/LookupService.java +++ b/oxService/src/main/java/org/gluu/service/LookupService.java @@ -50,7 +50,7 @@ public class LookupService implements Serializable { * @return DisplayNameEntry object */ public DisplayNameEntry getDisplayNameEntry(String dn) throws Exception { - String key = dn; + String key = "l_" + dn; DisplayNameEntry entry = (DisplayNameEntry) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); if (entry == null) { entry = ldapEntryManager.find(key, DisplayNameEntry.class, null); @@ -119,6 +119,8 @@ private String getCompoundKey(List inums) { for (String inum : inums) { if (compoundKey.length() > 0) { compoundKey.append("_"); + } else { + compoundKey.append("l_") } compoundKey.append(inum); } From 6b3365db2eb7b87ebe7524e6ac363e8ba4ce9620 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Wed, 9 Oct 2019 09:49:41 +0100 Subject: [PATCH 008/362] Fix compilation error --- oxService/src/main/java/org/gluu/service/LookupService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/service/LookupService.java b/oxService/src/main/java/org/gluu/service/LookupService.java index 27169959..a208ee40 100644 --- a/oxService/src/main/java/org/gluu/service/LookupService.java +++ b/oxService/src/main/java/org/gluu/service/LookupService.java @@ -120,7 +120,7 @@ private String getCompoundKey(List inums) { if (compoundKey.length() > 0) { compoundKey.append("_"); } else { - compoundKey.append("l_") + compoundKey.append("l_"); } compoundKey.append(inum); } From 7b97ae19374a72cbd3379e069cc2e6cff1ea5728 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 9 Oct 2019 17:44:03 +0300 Subject: [PATCH 009/362] Fix authenticate with baseDN --- .../gluu/persist/PersistenceEntryManager.java | 2 +- .../org/gluu/couchbase/CouchbaseSample.java | 2 +- .../CouchbaseSampleEntryManager.java | 4 ++-- .../couchbase/impl/CouchbaseEntryManager.java | 22 ++++++++++++++++--- .../hybrid/impl/HybridEntryManager.java | 4 ++-- .../persist/ldap/impl/LdapEntryManager.java | 19 +++++++++++++--- 6 files changed, 41 insertions(+), 12 deletions(-) diff --git a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java index 6fa162a5..87a73af5 100644 --- a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java @@ -36,7 +36,7 @@ public interface PersistenceEntryManager extends EntityManager { boolean authenticate(String primaryKey, String password); - boolean authenticate(String primaryKey, String userName, String password); + boolean authenticate(String baseDN, Class entryClass, String userName, String password); void persist(Object entry); diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSample.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSample.java index b1dce2ca..7622cac5 100644 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSample.java +++ b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSample.java @@ -70,7 +70,7 @@ public static void main(String[] args) { for (SimpleUser user : users) { boolean result1 = couchbaseEntryManager.authenticate(user.getDn(), "test"); - boolean result2 = couchbaseEntryManager.authenticate("ou=people,o=gluu", user.getUserId(), "test"); + boolean result2 = couchbaseEntryManager.authenticate("ou=people,o=gluu", SimpleUser.class, user.getUserId(), "test"); System.out.println("authetication result: " + result1 + ", " + result2); } diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleEntryManager.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleEntryManager.java index 14a6ec1f..f40e1983 100644 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleEntryManager.java +++ b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleEntryManager.java @@ -17,9 +17,9 @@ public class CouchbaseSampleEntryManager { private Properties getSampleConnectionProperties() { Properties connectionProperties = new Properties(); - connectionProperties.put("couchbase.servers", "cb-dev-backend.gluu.org"); + connectionProperties.put("couchbase.servers", "test.gluu.info"); connectionProperties.put("couchbase.auth.userName", "admin"); - connectionProperties.put("couchbase.auth.userPassword", "jun8azar"); + connectionProperties.put("couchbase.auth.userPassword", "secret"); // connectionProperties.put("couchbase.buckets", "gluu"); connectionProperties.put("couchbase.buckets", "gluu, gluu_user, gluu_token"); diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java index 6fa7f0c2..76d5f9aa 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java @@ -617,12 +617,28 @@ private List getAttributeDataList(JsonObject entry) { } @Override - public boolean authenticate(String baseDN, String userName, String password) { - Filter searchFilter = Filter.createEqualityFilter(CouchbaseOperationService.UID, userName); + public boolean authenticate(String baseDN, Class entryClass, String userName, String password) { + if (StringHelper.isEmptyString(baseDN)) { + throw new MappingException("Base DN to find entries is null"); + } + + // Check entry class + checkEntryClass(entryClass, false); + String[] objectClasses = getTypeObjectClasses(entryClass); + List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); + + // Find entries + Filter searchFilter = Filter.createEqualityFilter(Filter.createLowercaseFilter(CouchbaseOperationService.UID), userName); + if (objectClasses.length > 0) { + searchFilter = addObjectClassFilter(searchFilter, objectClasses); + } + + // Prepare properties types to allow build filter properly + Map propertiesAnnotationsMap = prepareEntryPropertiesTypes(entryClass, propertiesAnnotations); ConvertedExpression convertedExpression; try { - convertedExpression = toCouchbaseFilter(searchFilter, null); + convertedExpression = toCouchbaseFilter(searchFilter, propertiesAnnotationsMap); } catch (SearchException ex) { throw new EntryPersistenceException(String.format("Failed to convert filter %s to expression", searchFilter)); } diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java index 973b4dd8..f9370acc 100644 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java +++ b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java @@ -102,9 +102,9 @@ public boolean authenticate(String bindDn, String password) { } @Override - public boolean authenticate(String baseDN, String userName, String password) { + public boolean authenticate(String baseDN, Class entryClass, String userName, String password) { PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.authenticate(baseDN, userName, password); + return persistenceEntryManager.authenticate(baseDN, entryClass, userName, password); } @Override diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java index 5bc8689a..fd9fe54c 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java @@ -699,11 +699,24 @@ private List getAttributeDataList(SearchResultEntry entry) { } @Override - public boolean authenticate(String baseDN, String userName, String password) { + public boolean authenticate(String baseDN, Class entryClass, String userName, String password) { + if (StringHelper.isEmptyString(baseDN)) { + throw new MappingException("Base DN to count entries is null"); + } + + // Check entry class + checkEntryClass(entryClass, false); + String[] objectClasses = getTypeObjectClasses(entryClass); + + // Find entries + Filter searchFilter = Filter.createEqualityFilter(LdapOperationsServiceImpl.UID, userName); + if (objectClasses.length > 0) { + searchFilter = addObjectClassFilter(searchFilter, objectClasses); + } + SearchScope scope = SearchScope.SUB; try { - Filter filter = Filter.createEqualityFilter(LdapOperationsServiceImpl.UID, userName); - SearchResult searchResult = operationService.search(baseDN, toLdapFilter(filter), toLdapSearchScope(scope), null, 0, 1, 1, null, (String[]) null); + SearchResult searchResult = operationService.search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(scope), null, 0, 1, 1, null, (String[]) null); if ((searchResult == null) || (searchResult.getEntryCount() != 1)) { return false; } From 0de0494f2dee6bb1581d961160e927dbf6567bfc Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 10 Oct 2019 19:11:01 +0300 Subject: [PATCH 010/362] Fix search by dn --- oxService/src/main/java/org/gluu/service/LookupService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/service/LookupService.java b/oxService/src/main/java/org/gluu/service/LookupService.java index a208ee40..d44fcb96 100644 --- a/oxService/src/main/java/org/gluu/service/LookupService.java +++ b/oxService/src/main/java/org/gluu/service/LookupService.java @@ -53,7 +53,7 @@ public DisplayNameEntry getDisplayNameEntry(String dn) throws Exception { String key = "l_" + dn; DisplayNameEntry entry = (DisplayNameEntry) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); if (entry == null) { - entry = ldapEntryManager.find(key, DisplayNameEntry.class, null); + entry = ldapEntryManager.find(dn, DisplayNameEntry.class, null); cacheService.put(OxConstants.CACHE_LOOKUP_NAME, key, entry); } From c9cf5f87a1ffb82fa8c143d8d8cb3ea490584858 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 17 Oct 2019 10:42:23 +0300 Subject: [PATCH 011/362] Lower case user name on authenticate and search --- .../gluu/couchbase/CouchbaseCustomMultiValuedTypesSample.java | 3 ++- .../org/gluu/couchbase/CouchbaseSampleUserSearchSample.java | 3 ++- .../org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomMultiValuedTypesSample.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomMultiValuedTypesSample.java index 4fc320d3..8c89a422 100644 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomMultiValuedTypesSample.java +++ b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomMultiValuedTypesSample.java @@ -8,6 +8,7 @@ import org.gluu.persist.couchbase.operation.impl.CouchbaseConnectionProvider; import org.gluu.persist.model.base.CustomObjectAttribute; import org.gluu.search.filter.Filter; +import org.gluu.util.StringHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -67,7 +68,7 @@ public static void main(String[] args) { LOG.info("Cusom attributes '{}'", foundUpdatedUser.getCustomAttributes()); - Filter filter = Filter.createEqualityFilter(Filter.createLowercaseFilter("givenName"), "jon"); + Filter filter = Filter.createEqualityFilter(Filter.createLowercaseFilter("givenName"), StringHelper.toLowerCase("jon")); List foundUpdatedUsers = couchbaseEntryManager.findEntries("o=gluu", SimpleUser.class, filter); System.out.println(foundUpdatedUsers); diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleUserSearchSample.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleUserSearchSample.java index 3cf0fcd4..87ff4c52 100644 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleUserSearchSample.java +++ b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleUserSearchSample.java @@ -13,6 +13,7 @@ import org.gluu.log.LoggingHelper; import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; import org.gluu.search.filter.Filter; +import org.gluu.util.StringHelper; /** * @author Yuriy Movchan Date: 09/18/2019 @@ -59,7 +60,7 @@ public void run() { long userUid = Math.round(Math.random() * countUsers); String uid = String.format("user%06d", userUid); try { - Filter filter = Filter.createEqualityFilter(Filter.createLowercaseFilter("uid"), uid); + Filter filter = Filter.createEqualityFilter(Filter.createLowercaseFilter("uid"), StringHelper.toLowerCase(uid)); // Filter filter = Filter.createEqualityFilter("uid", uid); List foundUsers = couchbaseEntryManager.findEntries("ou=people,o=gluu", SimpleUser.class, filter); if (foundUsers.size() > 0) { diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java index 76d5f9aa..d2d99f89 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java @@ -628,7 +628,7 @@ public boolean authenticate(String baseDN, Class entryClass, String userN List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); // Find entries - Filter searchFilter = Filter.createEqualityFilter(Filter.createLowercaseFilter(CouchbaseOperationService.UID), userName); + Filter searchFilter = Filter.createEqualityFilter(Filter.createLowercaseFilter(CouchbaseOperationService.UID), StringHelper.toLowerCase(userName)); if (objectClasses.length > 0) { searchFilter = addObjectClassFilter(searchFilter, objectClasses); } From 78ffae4a22957807de814c56e854226f49751cb5 Mon Sep 17 00:00:00 2001 From: Jose G Date: Mon, 21 Oct 2019 08:06:44 -0500 Subject: [PATCH 012/362] Add methods required for https://github.com/GluuFederation/oxTrust/issues/885 --- .../custom/script/type/scim/DummyScimType.java | 10 ++++++++++ .../model/custom/script/type/scim/ScimType.java | 16 ++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java index 39662320..e6621b5f 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java @@ -89,4 +89,14 @@ public boolean postDeleteGroup(Object user, Map co return false; } + @Override + public boolean getUser(Object user, Map configurationAttributes) { + return false; + } + + @Override + public boolean getGroup(Object group, Map configurationAttributes) { + return false; + } + } diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java index 1c1f7f75..11443913 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java @@ -27,16 +27,20 @@ public interface ScimType extends BaseExternalType { boolean postDeleteUser(Object user, Map configurationAttributes); - boolean createGroup(Object user, Map configurationAttributes); + boolean createGroup(Object group, Map configurationAttributes); - boolean postCreateGroup(Object user, Map configurationAttributes); + boolean postCreateGroup(Object group, Map configurationAttributes); - boolean updateGroup(Object user, Map configurationAttributes); + boolean updateGroup(Object group, Map configurationAttributes); - boolean postUpdateGroup(Object user, Map configurationAttributes); + boolean postUpdateGroup(Object group, Map configurationAttributes); - boolean deleteGroup(Object user, Map configurationAttributes); + boolean deleteGroup(Object group, Map configurationAttributes); - boolean postDeleteGroup(Object user, Map configurationAttributes); + boolean postDeleteGroup(Object group, Map configurationAttributes); + + boolean getUser(Object user, Map configurationAttributes); + + boolean getGroup(Object group, Map configurationAttributes); } From a3b6f0cd06e11adba7fc9a2893df46e7f4e5ab77 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 28 Oct 2019 10:11:07 +0300 Subject: [PATCH 013/362] Update opensaml library --- oxSaml/pom.xml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index b4ff7566..f2d8ba0d 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -22,9 +22,12 @@ wss4j - commons-beanutils - commons-beanutils - 1.9.3 + org.apache.ws.security + wss4j + + + org.opensaml + opensaml \ No newline at end of file From bf7903093f5e5891cb9064c7b420e7bf0c059fb1 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 28 Oct 2019 10:48:23 +0300 Subject: [PATCH 014/362] Fix beanutils dependecies --- oxSaml/pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index f2d8ba0d..366d1baa 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -17,6 +17,10 @@ org.gluu oxcore-util + + commons-beanutils + commons-beanutils + org.apache.ws.security wss4j From 24c385e3f189dee8066dbbdcaf7ec7e554c5fbb0 Mon Sep 17 00:00:00 2001 From: yuriyz Date: Fri, 1 Nov 2019 14:23:09 +0200 Subject: [PATCH 015/362] oxcore : added spontaneous script type https://github.com/GluuFederation/oxAuth/issues/839 --- .../model/custom/script/CustomScriptType.java | 3 ++ .../DummySpontaneousScopeType.java | 28 +++++++++++++++++++ .../spontaneous/SpontaneousScopeType.java | 8 ++++++ 3 files changed, 39 insertions(+) create mode 100644 oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java create mode 100644 oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java b/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java index 131e5e0b..779e1385 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java @@ -30,6 +30,8 @@ import org.gluu.model.custom.script.type.scope.DynamicScopeType; import org.gluu.model.custom.script.type.session.ApplicationSessionType; import org.gluu.model.custom.script.type.session.DummyApplicationSessionType; +import org.gluu.model.custom.script.type.spontaneous.DummySpontaneousScopeType; +import org.gluu.model.custom.script.type.spontaneous.SpontaneousScopeType; import org.gluu.model.custom.script.type.uma.UmaClaimsGatheringType; import org.gluu.model.custom.script.type.uma.UmaDummyClaimsGatheringType; import org.gluu.model.custom.script.type.uma.UmaDummyRptPolicyType; @@ -70,6 +72,7 @@ public enum CustomScriptType implements AttributeEnum { new DummyConsentGatheringType()), DYNAMIC_SCOPE("dynamic_scope", "Dynamic Scopes", DynamicScopeType.class, CustomScript.class, "DynamicScope", new DummyDynamicScopeType()), + SPONTANEOUS_SCOPE("spontaneous_scope", "Spontaneous Scopes", SpontaneousScopeType.class, CustomScript.class, "SpontaneousScope", new DummySpontaneousScopeType()), SCIM("scim", "SCIM", ScimType.class, CustomScript.class, "ScimEventHandler", new DummyScimType()); private String value; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java new file mode 100644 index 00000000..ff2e0116 --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java @@ -0,0 +1,28 @@ +package org.gluu.model.custom.script.type.spontaneous; + +import org.gluu.model.SimpleCustomProperty; + +import java.util.Map; + +public class DummySpontaneousScopeType implements SpontaneousScopeType { + + @Override + public boolean allowScope(Object context) { + return false; + } + + @Override + public boolean init(Map configurationAttributes) { + return true; + } + + @Override + public boolean destroy(Map configurationAttributes) { + return true; + } + + @Override + public int getApiVersion() { + return 0; + } +} diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java new file mode 100644 index 00000000..ab107c53 --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java @@ -0,0 +1,8 @@ +package org.gluu.model.custom.script.type.spontaneous; + +import org.gluu.model.custom.script.type.BaseExternalType; + +public interface SpontaneousScopeType extends BaseExternalType { + + boolean allowScope(Object context); +} From b2f113a9867ab57f805d08e8064eee6ad2365c49 Mon Sep 17 00:00:00 2001 From: yuriyz Date: Fri, 1 Nov 2019 16:10:00 +0200 Subject: [PATCH 016/362] oxcore : update spontaneous script type (changed method to manipulateScopes) https://github.com/GluuFederation/oxAuth/issues/839 --- .../script/type/spontaneous/DummySpontaneousScopeType.java | 3 +-- .../custom/script/type/spontaneous/SpontaneousScopeType.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java index ff2e0116..acbff26e 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java @@ -7,8 +7,7 @@ public class DummySpontaneousScopeType implements SpontaneousScopeType { @Override - public boolean allowScope(Object context) { - return false; + public void manipulateScopes(Object context) { } @Override diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java index ab107c53..89a70331 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java @@ -4,5 +4,5 @@ public interface SpontaneousScopeType extends BaseExternalType { - boolean allowScope(Object context); + void manipulateScopes(Object context); } From 8c91a9c627683d8a94afeb040a45e4b0f5120be3 Mon Sep 17 00:00:00 2001 From: Jose G Date: Wed, 6 Nov 2019 11:36:11 -0500 Subject: [PATCH 017/362] Add setter --- .../main/java/org/gluu/service/cache/MemcachedProvider.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java b/oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java index 25715e77..7a9760de 100644 --- a/oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java @@ -27,6 +27,10 @@ public class MemcachedProvider extends AbstractCacheProvider { public MemcachedProvider() { } + public void setCacheConfiguration(CacheConfiguration cacheConfiguration) { + this.cacheConfiguration = cacheConfiguration; + } + @PostConstruct public void init() { this.memcachedConfiguration = cacheConfiguration.getMemcachedConfiguration(); From 907aa1ea4a9c95bf2fb347a8224139ec2045fdde Mon Sep 17 00:00:00 2001 From: Jose G Date: Wed, 6 Nov 2019 14:02:40 -0500 Subject: [PATCH 018/362] Add bean to have access to casa configuration from within cust script, https://github.com/GluuFederation/casa/issues/88 --- .../model/casa/ApplicationConfiguration.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 oxService/src/main/java/org/gluu/model/casa/ApplicationConfiguration.java diff --git a/oxService/src/main/java/org/gluu/model/casa/ApplicationConfiguration.java b/oxService/src/main/java/org/gluu/model/casa/ApplicationConfiguration.java new file mode 100644 index 00000000..edf26dfb --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/casa/ApplicationConfiguration.java @@ -0,0 +1,24 @@ +package org.gluu.model.casa; + +import org.gluu.persist.annotation.AttributeName; +import org.gluu.persist.annotation.DataEntry; +import org.gluu.persist.annotation.JsonObject; +import org.gluu.persist.annotation.ObjectClass; +import org.gluu.persist.model.base.Entry; + +@DataEntry +@ObjectClass(value = "oxApplicationConfiguration") +public class ApplicationConfiguration extends Entry { + + @AttributeName(name = "oxConfApplication") + private String settings; + + public String getSettings() { + return settings; + } + + public void setSettings(String settings) { + this.settings = settings; + } + +} From c568616b08fab6a3160c0abdbea57eb55398a8db Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 12 Nov 2019 21:21:31 +0300 Subject: [PATCH 019/362] Allow to produce local memory cache --- .../service/cache/CacheProviderFactory.java | 18 +++++++++++ .../org/gluu/service/cache/LocalCache.java | 31 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 oxService/src/main/java/org/gluu/service/cache/LocalCache.java diff --git a/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java b/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java index 61c11060..7ea54fc8 100644 --- a/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java +++ b/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java @@ -65,4 +65,22 @@ public CacheProvider getCacheProvider() { return cacheProvider; } + @Produces + @LocalCache + @ApplicationScoped + public CacheProvider getLocalCacheProvider() { + log.debug("Started to create local cache provider"); + + CacheProviderType cacheProviderType = CacheProviderType.IN_MEMORY; + AbstractCacheProvider cacheProvider = instance.select(InMemoryCacheProvider.class).get(); + + if (cacheProvider == null) { + throw new RuntimeException("Failed to initialize cacheProvider, cacheProviderType is unsupported: " + cacheProviderType); + } + + cacheProvider.create(); + + return cacheProvider; + } + } diff --git a/oxService/src/main/java/org/gluu/service/cache/LocalCache.java b/oxService/src/main/java/org/gluu/service/cache/LocalCache.java new file mode 100644 index 00000000..72e4364e --- /dev/null +++ b/oxService/src/main/java/org/gluu/service/cache/LocalCache.java @@ -0,0 +1,31 @@ +package org.gluu.service.cache; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.enterprise.util.AnnotationLiteral; +import javax.inject.Qualifier; + +/** + * @author Yuriy Movchan Date: 11/12/2019 + */ +@Qualifier +@Retention(RUNTIME) +@Target({ METHOD, FIELD }) +@Documented +public @interface LocalCache { + + final class Literal extends AnnotationLiteral implements LocalCache { + + public static final Literal INSTANCE = new Literal(); + + private static final long serialVersionUID = 1L; + + } + +} From f3e6d76236ab8229615b770ee79f36d99305530a Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 12 Nov 2019 21:33:02 +0300 Subject: [PATCH 020/362] Add LocalCacheService with InMemory cache type --- .../org/gluu/service/BaseCacheService.java | 133 ++++++++++++++++++ .../java/org/gluu/service/CacheService.java | 105 +------------- .../org/gluu/service/LocalCacheService.java | 36 +++++ .../service/cache/CacheProviderFactory.java | 2 +- .../org/gluu/service/cache/LocalCache.java | 3 +- 5 files changed, 178 insertions(+), 101 deletions(-) create mode 100644 oxService/src/main/java/org/gluu/service/BaseCacheService.java create mode 100644 oxService/src/main/java/org/gluu/service/LocalCacheService.java diff --git a/oxService/src/main/java/org/gluu/service/BaseCacheService.java b/oxService/src/main/java/org/gluu/service/BaseCacheService.java new file mode 100644 index 00000000..31437065 --- /dev/null +++ b/oxService/src/main/java/org/gluu/service/BaseCacheService.java @@ -0,0 +1,133 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ +package org.gluu.service; + +import java.util.Date; +import java.util.function.Supplier; + +import javax.inject.Inject; + +import org.gluu.service.cache.CacheInterface; +import org.gluu.service.cache.CacheProvider; +import org.gluu.service.cache.CacheProviderType; +import org.slf4j.Logger; + +/** + * Provides operations with cache + * + * @author Yuriy Movchan Date: 01.24.2012 + * @author Yuriy Zabrovarnyy Date: 02.02.2017 + */ +public abstract class BaseCacheService implements CacheInterface { + + private static int DEFAULT_EXPIRATION = 60; + + @Inject + private Logger log; + + public Object get(String key) { + CacheProvider cacheProvider = getCacheProvider(); + if (cacheProvider == null) { + return null; + } + + return cacheProvider.get(key); + } + + public T getWithPut(String key, Supplier loadFunction, int expirationInSeconds) { + if (loadFunction == null) { + return (T) get(key); + } + + CacheProvider cacheProvider = getCacheProvider(); + + if (CacheProviderType.NATIVE_PERSISTENCE == cacheProvider.getProviderType()) { + return loadFunction.get(); + } + + final Object value = get(key); + if (value != null) { + log.trace("Loaded from cache, key: " + key); + return (T) value; + } else { + final T loaded = loadFunction.get(); + if (loaded == null) { + return null; + } + + try { + put(expirationInSeconds, key, loaded); + } catch (Exception e) { + log.error("Failed to put object into cache, key: " + key, e); // we don't want prevent returning loaded value due to failure with put + } + return loaded; + } + } + + public void put(int expirationInSeconds, String key, Object object) { + CacheProvider cacheProvider = getCacheProvider(); + + if (cacheProvider != null) { + cacheProvider.put(expirationInSeconds, key, object); + } + } + + public void remove(String key) { + CacheProvider cacheProvider = getCacheProvider(); + + if (cacheProvider == null) { + return; + } + + cacheProvider.remove(key); + } + + public void clear() { + CacheProvider cacheProvider = getCacheProvider(); + + if (cacheProvider != null) { + cacheProvider.clear(); + } + } + + @Override + public void cleanup(Date now) { + CacheProvider cacheProvider = getCacheProvider(); + + if (cacheProvider != null) { + cacheProvider.cleanup(now); + } + } + + public void put(String key, Object object) { + put(DEFAULT_EXPIRATION, key, object); + } + + @Deprecated // we keep it only for back-compatibility of scripts code + public Object get(String region, String key) { + return get(key); + } + + @Deprecated // we keep it only for back-compatibility of scripts code + public void put(String expirationInSeconds, String key, Object object) { + int expiration = DEFAULT_EXPIRATION; + try { + expiration = Integer.parseInt(expirationInSeconds); + } catch (NumberFormatException ex) { + // Use default expiration + log.trace("Using default expiration instead of expirationInSeconds: {}", expirationInSeconds); + } + put(expiration, key, object); + } + + @Deprecated // we keep it only for back-compatibility of scripts code + public void remove(String region, String key) { + remove(key); + } + + public abstract CacheProvider getCacheProvider(); + +} diff --git a/oxService/src/main/java/org/gluu/service/CacheService.java b/oxService/src/main/java/org/gluu/service/CacheService.java index b831f55b..6547bb4c 100644 --- a/oxService/src/main/java/org/gluu/service/CacheService.java +++ b/oxService/src/main/java/org/gluu/service/CacheService.java @@ -5,16 +5,11 @@ */ package org.gluu.service; -import org.gluu.service.cache.CacheInterface; -import org.gluu.service.cache.CacheProvider; -import org.gluu.service.cache.CacheProviderType; -import org.slf4j.Logger; - import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import javax.inject.Named; -import java.util.Date; -import java.util.function.Supplier; + +import org.gluu.service.cache.CacheProvider; /** * Provides operations with cache @@ -24,102 +19,14 @@ */ @ApplicationScoped @Named -public class CacheService implements CacheInterface { - - private static int DEFAULT_EXPIRATION = 60; +public class CacheService extends BaseCacheService { @Inject private CacheProvider cacheProvider; - @Inject - private Logger log; - - public Object get(String key) { - if (cacheProvider == null) { - return null; - } - - return cacheProvider.get(key); - } - - public T getWithPut(String key, Supplier loadFunction, int expirationInSeconds) { - if (loadFunction == null) { - return (T) get(key); - } - - if (CacheProviderType.NATIVE_PERSISTENCE == cacheProvider.getProviderType()) { - return loadFunction.get(); - } - - final Object value = get(key); - if (value != null) { - log.trace("Loaded from cache, key: " + key); - return (T) value; - } else { - final T loaded = loadFunction.get(); - if (loaded == null) { - return null; - } - - try { - put(expirationInSeconds, key, loaded); - } catch (Exception e) { - log.error("Failed to put object into cache, key: " + key, e); // we don't want prevent returning loaded value due to failure with put - } - return loaded; - } - } - - public void put(int expirationInSeconds, String key, Object object) { - if (cacheProvider != null) { - cacheProvider.put(expirationInSeconds, key, object); - } - } - - public void remove(String key) { - if (cacheProvider == null) { - return; - } - - cacheProvider.remove(key); - } - - public void clear() { - if (cacheProvider != null) { - cacheProvider.clear(); - } + @Override + public CacheProvider getCacheProvider() { + return cacheProvider; } - @Override - public void cleanup(Date now) { - if (cacheProvider != null) { - cacheProvider.cleanup(now); - } - } - - public void put(String key, Object object) { - put(DEFAULT_EXPIRATION, key, object); - } - - @Deprecated // we keep it only for back-compatibility of scripts code - public Object get(String region, String key) { - return get(key); - } - - @Deprecated // we keep it only for back-compatibility of scripts code - public void put(String expirationInSeconds, String key, Object object) { - int expiration = DEFAULT_EXPIRATION; - try { - expiration = Integer.parseInt(expirationInSeconds); - } catch (NumberFormatException ex) { - // Use default expiration - log.trace("Using default expiration instead of expirationInSeconds: {}", expirationInSeconds); - } - put(expiration, key, object); - } - - @Deprecated // we keep it only for back-compatibility of scripts code - public void remove(String region, String key) { - remove(key); - } } diff --git a/oxService/src/main/java/org/gluu/service/LocalCacheService.java b/oxService/src/main/java/org/gluu/service/LocalCacheService.java new file mode 100644 index 00000000..8df9c605 --- /dev/null +++ b/oxService/src/main/java/org/gluu/service/LocalCacheService.java @@ -0,0 +1,36 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ +package org.gluu.service; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.inject.Named; + +import org.gluu.service.cache.CacheProvider; +import org.gluu.service.cache.LocalCache; + +/** + * Provides operations with cache + * + * @author Yuriy Movchan Date: 01.24.2012 + * @author Yuriy Zabrovarnyy Date: 02.02.2017 + */ +@ApplicationScoped +@Named +@LocalCache +public class LocalCacheService extends CacheService { + + @Inject + @LocalCache + private CacheProvider cacheProvider; + + @Override + public CacheProvider getCacheProvider() { + return cacheProvider; + } + + +} diff --git a/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java b/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java index 7ea54fc8..6d3a9bef 100644 --- a/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java +++ b/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java @@ -66,8 +66,8 @@ public CacheProvider getCacheProvider() { } @Produces - @LocalCache @ApplicationScoped + @LocalCache public CacheProvider getLocalCacheProvider() { log.debug("Started to create local cache provider"); diff --git a/oxService/src/main/java/org/gluu/service/cache/LocalCache.java b/oxService/src/main/java/org/gluu/service/cache/LocalCache.java index 72e4364e..02aa9606 100644 --- a/oxService/src/main/java/org/gluu/service/cache/LocalCache.java +++ b/oxService/src/main/java/org/gluu/service/cache/LocalCache.java @@ -2,6 +2,7 @@ import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.Documented; @@ -16,7 +17,7 @@ */ @Qualifier @Retention(RUNTIME) -@Target({ METHOD, FIELD }) +@Target({ TYPE, METHOD, FIELD }) @Documented public @interface LocalCache { From 0d7386db14669f38b5eb6218036bf0b72b684aba Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 12 Nov 2019 22:10:51 +0300 Subject: [PATCH 021/362] Add LocalCacheService with InMemory cache type --- .../main/java/org/gluu/service/AttributeService.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/AttributeService.java b/oxService/src/main/java/org/gluu/service/AttributeService.java index b8466db9..2ca3a927 100644 --- a/oxService/src/main/java/org/gluu/service/AttributeService.java +++ b/oxService/src/main/java/org/gluu/service/AttributeService.java @@ -42,6 +42,9 @@ public abstract class AttributeService implements Serializable { @Inject protected CacheService cacheService; + @Inject + protected LocalCacheService localCacheService; + public List getAttributesByAttribute(String attributeName, String attributeValue, String baseDn) { String[] targetArray = new String[] { attributeValue }; Filter filter = Filter.createSubstringFilter(attributeName, null, targetArray, null); @@ -95,11 +98,13 @@ public List getAllAttributes() { @SuppressWarnings("unchecked") public List getAllAttributes(String baseDn) { - List attributeList = (List) cacheService.get(OxConstants.CACHE_ATTRIBUTE_NAME, + CacheService usedCacheService = getCacheService(); + + List attributeList = (List) usedCacheService.get(OxConstants.CACHE_ATTRIBUTE_NAME, OxConstants.CACHE_ATTRIBUTE_KEY_LIST); if (attributeList == null) { attributeList = getAllAtributesImpl(baseDn); - cacheService.put(OxConstants.CACHE_ATTRIBUTE_NAME, OxConstants.CACHE_ATTRIBUTE_KEY_LIST, attributeList); + usedCacheService.put(OxConstants.CACHE_ATTRIBUTE_NAME, OxConstants.CACHE_ATTRIBUTE_KEY_LIST, attributeList); } return attributeList; @@ -111,6 +116,8 @@ protected List getAllAtributesImpl(String baseDn) { return attributeList; } + protected abstract CacheService getCacheService(); + public abstract String getDnForAttribute(String inum); } From 2d142f80dd50722da1882ddb63e8c49048da0ac2 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 12 Nov 2019 22:56:01 +0300 Subject: [PATCH 022/362] Fix cache produce method --- .../main/java/org/gluu/service/cache/CacheProviderFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java b/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java index 6d3a9bef..fb7589cf 100644 --- a/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java +++ b/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java @@ -68,7 +68,7 @@ public CacheProvider getCacheProvider() { @Produces @ApplicationScoped @LocalCache - public CacheProvider getLocalCacheProvider() { + public CacheProvider getLocalCacheProvider() { log.debug("Started to create local cache provider"); CacheProviderType cacheProviderType = CacheProviderType.IN_MEMORY; From 04bf35da0c083e9816a10d75951dd4784b30cb8e Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 12 Nov 2019 23:34:53 +0300 Subject: [PATCH 023/362] Fix CDI dependecy issue --- .../src/main/java/org/gluu/service/AttributeService.java | 4 ++-- .../src/main/java/org/gluu/service/BaseCacheService.java | 2 +- oxService/src/main/java/org/gluu/service/CacheService.java | 2 +- .../src/main/java/org/gluu/service/LocalCacheService.java | 5 ++--- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/AttributeService.java b/oxService/src/main/java/org/gluu/service/AttributeService.java index 2ca3a927..04f61976 100644 --- a/oxService/src/main/java/org/gluu/service/AttributeService.java +++ b/oxService/src/main/java/org/gluu/service/AttributeService.java @@ -98,7 +98,7 @@ public List getAllAttributes() { @SuppressWarnings("unchecked") public List getAllAttributes(String baseDn) { - CacheService usedCacheService = getCacheService(); + BaseCacheService usedCacheService = getCacheService(); List attributeList = (List) usedCacheService.get(OxConstants.CACHE_ATTRIBUTE_NAME, OxConstants.CACHE_ATTRIBUTE_KEY_LIST); @@ -116,7 +116,7 @@ protected List getAllAtributesImpl(String baseDn) { return attributeList; } - protected abstract CacheService getCacheService(); + protected abstract BaseCacheService getCacheService(); public abstract String getDnForAttribute(String inum); diff --git a/oxService/src/main/java/org/gluu/service/BaseCacheService.java b/oxService/src/main/java/org/gluu/service/BaseCacheService.java index 31437065..4e100e5f 100644 --- a/oxService/src/main/java/org/gluu/service/BaseCacheService.java +++ b/oxService/src/main/java/org/gluu/service/BaseCacheService.java @@ -128,6 +128,6 @@ public void remove(String region, String key) { remove(key); } - public abstract CacheProvider getCacheProvider(); + protected abstract CacheProvider getCacheProvider(); } diff --git a/oxService/src/main/java/org/gluu/service/CacheService.java b/oxService/src/main/java/org/gluu/service/CacheService.java index 6547bb4c..8a782600 100644 --- a/oxService/src/main/java/org/gluu/service/CacheService.java +++ b/oxService/src/main/java/org/gluu/service/CacheService.java @@ -25,7 +25,7 @@ public class CacheService extends BaseCacheService { private CacheProvider cacheProvider; @Override - public CacheProvider getCacheProvider() { + protected CacheProvider getCacheProvider() { return cacheProvider; } diff --git a/oxService/src/main/java/org/gluu/service/LocalCacheService.java b/oxService/src/main/java/org/gluu/service/LocalCacheService.java index 8df9c605..ce2a51d9 100644 --- a/oxService/src/main/java/org/gluu/service/LocalCacheService.java +++ b/oxService/src/main/java/org/gluu/service/LocalCacheService.java @@ -20,15 +20,14 @@ */ @ApplicationScoped @Named -@LocalCache -public class LocalCacheService extends CacheService { +public class LocalCacheService extends BaseCacheService { @Inject @LocalCache private CacheProvider cacheProvider; @Override - public CacheProvider getCacheProvider() { + protected CacheProvider getCacheProvider() { return cacheProvider; } From ac754e0ab239e231d16d77c5a9a30553e36d2673 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 14 Nov 2019 14:04:43 +0300 Subject: [PATCH 024/362] Force Couchbase to wait index updated before search user by uid --- .../src/main/java/org/gluu/persist/model/base/SimpleUser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java index 8391220c..5ae8ed4a 100644 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java +++ b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java @@ -29,7 +29,8 @@ public class SimpleUser implements Serializable { @DN private String dn; - @AttributeName(name = "uid") + + @AttributeName(name = "uid", consistency = true) private String userId; @AttributeName(name = "oxAuthPersistentJWT") From 949d98075e1e99f85cc3613738e944632958b453 Mon Sep 17 00:00:00 2001 From: yurem Date: Sun, 17 Nov 2019 19:58:07 +0300 Subject: [PATCH 025/362] Fix native cache clean up filter --- .../gluu/service/cache/NativePersistenceCacheProvider.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index 10647da5..656595ee 100644 --- a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -200,7 +200,9 @@ public void cleanup(final Date now) { public void cleanup(final Date now, int batchSize) { log.debug("Start NATIVE_PERSISTENCE clean up"); try { - Filter filter = Filter.createLessOrEqualFilter("oxAuthExpiration", entryManager.encodeTime(baseDn, now)); + Filter filter = Filter.createANDFilter( + Filter.createEqualityFilter("del", true), + Filter.createLessOrEqualFilter("exp", entryManager.encodeTime(baseDn, now))); final int removedCount = entryManager.remove(baseDn, NativePersistenceCacheEntity.class, filter, batchSize); log.debug("End NATIVE_PERSISTENCE clean up, items removed: " + removedCount); From 90eaf86d16067203f7f226de681e49b944f22004 Mon Sep 17 00:00:00 2001 From: yurem Date: Sun, 17 Nov 2019 22:37:44 +0300 Subject: [PATCH 026/362] Allow to change cleaner interval without restarting oxAuth oxAuth #1201 --- .../org/gluu/config/oxtrust/AppConfiguration.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index d2949dd8..f1379bea 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -173,6 +173,8 @@ public class AppConfiguration implements Configuration, Serializable { private int cleanServiceInterval; private Boolean enforceEmailUniqueness = true; + private Boolean useLocalCache = false; + public ScimProperties getScimProperties() { return scimProperties; } @@ -1007,4 +1009,13 @@ public Boolean getEnforceEmailUniqueness() { public void setEnforceEmailUniqueness(Boolean enforceEmailUniqueness) { this.enforceEmailUniqueness = enforceEmailUniqueness; } + + public Boolean getUseLocalCache() { + return useLocalCache; + } + + public void setUseLocalCache(Boolean useLocalCache) { + this.useLocalCache = useLocalCache; + } + } From 6ea985e7fef9244186bb0c099934b4fb518cea5f Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Sat, 23 Nov 2019 19:28:18 +0100 Subject: [PATCH 027/362] Fix duplicate dependency warning && missing opensaml version error --- oxSaml/pom.xml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index 366d1baa..c3e97305 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -25,13 +25,10 @@ org.apache.ws.security wss4j - - org.apache.ws.security - wss4j - org.opensaml opensaml + 2.6.4 - \ No newline at end of file + From a97599cc7fefae3eaf1091555cf54caeab55afe5 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Sun, 24 Nov 2019 12:18:21 +0100 Subject: [PATCH 028/362] Set source ldap dafault max connections to 2 --- .../main/java/org/gluu/model/ldap/GluuLdapConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxUtil/src/main/java/org/gluu/model/ldap/GluuLdapConfiguration.java b/oxUtil/src/main/java/org/gluu/model/ldap/GluuLdapConfiguration.java index 39a2724a..5f936a25 100644 --- a/oxUtil/src/main/java/org/gluu/model/ldap/GluuLdapConfiguration.java +++ b/oxUtil/src/main/java/org/gluu/model/ldap/GluuLdapConfiguration.java @@ -38,7 +38,7 @@ public class GluuLdapConfiguration implements Serializable { @JsonProperty("servers") private List serversStringsList; - private int maxConnections; + private int maxConnections = 2; private boolean useSSL; @JsonIgnore From 27f4ca7054263117d6cd09277f5aeebe73d93d3f Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 26 Nov 2019 12:57:36 +0300 Subject: [PATCH 029/362] Use remove to remove item from cache --- .../org/gluu/service/cache/NativePersistenceCacheProvider.java | 2 +- .../org/gluu/service/cache/NativePersistenceConfiguration.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index 656595ee..ded85fc4 100644 --- a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -134,7 +134,7 @@ public void put(int expirationInSeconds, String key, Object object) { private boolean silentlyRemoveEntityIfExists(String dn) { try { if (entryManager.find(NativePersistenceCacheEntity.class, dn) != null) { - entryManager.removeRecursively(dn); + entryManager.remove(dn); return true; } } catch (Exception e) { diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceConfiguration.java b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceConfiguration.java index e258ca06..af9b32ab 100644 --- a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceConfiguration.java +++ b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceConfiguration.java @@ -14,7 +14,7 @@ public class NativePersistenceConfiguration implements Serializable { private int defaultPutExpiration = 60; // in seconds @XmlElement(name = "defaultCleanupBatchSize") - private int defaultCleanupBatchSize = 25; // 25 objects per iteration + private int defaultCleanupBatchSize = 1000; // 1000 objects per iteration @JsonIgnore private String baseDn; From 6e6e285299e95704bab51c8ecc6f38f04ca3c67a Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Tue, 26 Nov 2019 14:53:00 +0100 Subject: [PATCH 030/362] Pre-populate class and method according to interface #1865 --- .../custom/script/model/CustomScript.java | 7 ++ .../custom/script/model/ScriptTemplate.java | 94 +++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 oxService/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/model/CustomScript.java b/oxService/src/main/java/org/gluu/model/custom/script/model/CustomScript.java index a03d2f5c..6246bc2a 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/model/CustomScript.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/model/CustomScript.java @@ -149,6 +149,13 @@ public void setDescription(String description) { } public String getScript() { + + if(script==null && scriptType==CustomScriptType.PERSON_AUTHENTICATION){ + script=ScriptTemplate.AUTHEN.getValue(); + } + else if(script==null && scriptType!=CustomScriptType.PERSON_AUTHENTICATION){ + script=ScriptTemplate.NO_AUTHEN.getValue(); + } return script; } diff --git a/oxService/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java b/oxService/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java new file mode 100644 index 00000000..c41af06f --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java @@ -0,0 +1,94 @@ +package org.gluu.model.custom.script.model; + +public enum ScriptTemplate { + + AUTHEN( "from org.gluu.service.cdi.util import CdiUtil\n" + + "from org.gluu.model.custom.script.type.auth import PersonAuthenticationType\n" + + "\n" + + "import java\n" + + "\n" + + "class SamplePersonScript(PersonAuthenticationType):\n" + + " def __init__(self, currentTimeMillis):\n" + + " \n" + + "\n" + + " def init(self, configurationAttributes):\n" + + " return True \n" + + "\n" + + " def destroy(self, configurationAttributes):\n" + + " return True\n" + + "\n" + + " def getApiVersion(self):\n" + + " return 1\n" + + "\n" + + " def isValidAuthenticationMethod(self, usageType, configurationAttributes):\n" + + " return True\n" + + "\n" + + " def getAlternativeAuthenticationMethod(self, usageType, configurationAttributes):\n" + + " return None\n" + + "\n" + + " def authenticate(self, configurationAttributes, requestParameters, step):\n" + + " return True\n" + + "\n" + + " def prepareForStep(self, configurationAttributes, requestParameters, step):\n" + + " \n" + + "\n" + + " def getExtraParametersForStep(self, configurationAttributes, step):\n" + + " return None\n" + + "\n" + + " def getCountAuthenticationSteps(self, configurationAttributes):\n" + + " return 1\n" + + "\n" + + " def getPageForStep(self, configurationAttributes, step):\n" + + " return \"\"\n" + + "\n" + + " def logout(self, configurationAttributes, requestParameters):\n" + + " return True\n"), + NO_AUTHEN("from org.gluu.service.cdi.util import CdiUtil\n" + + "from org.gluu.oxauth.security import Identity\n" + + "from org.gluu.model.custom.script.type.authz import ConsentGatheringType\n" + + "from org.gluu.util import StringHelper\n" + + "\n" + + "import java\n" + + "import random\n" + + "\n" + + "class SampleScript(ConsentGatheringType):\n" + + "\n" + + " def __init__(self, currentTimeMillis):\n" + + "\n" + + " def init(self, configurationAttributes):\n" + + " return True\n" + + "\n" + + " def destroy(self, configurationAttributes):\n" + + " return True\n" + + "\n" + + " def getApiVersion(self):\n" + + " return 1\n" + + "\n" + + " \n" + + " def authorize(self, step, context): \n" + + " return True\n" + + "\n" + + " def getNextStep(self, step, context):\n" + + " return -1\n" + + "\n" + + " def prepareForStep(self, step, context):\n" + + " return True\n" + + "\n" + + " def getStepsCount(self, context):\n" + + " return 2\n" + + "\n" + + " def getPageForStep(self, step, context):\n" + + " return \"\"\n"); + + + private final String value; + + + ScriptTemplate(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } +} From 64b65e6640a0e2417af46af1ea60ca88d9021b1b Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 27 Nov 2019 11:06:57 +0300 Subject: [PATCH 031/362] Registered clients disappear oxAuth #1199 --- .../java/org/gluu/couchbase/CouchbaseSampleBatchJob.java | 8 ++++---- .../src/main/java/org/gluu/ldap/LdapSampleBatchJob.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleBatchJob.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleBatchJob.java index 2472e927..607592e8 100644 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleBatchJob.java +++ b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleBatchJob.java @@ -105,9 +105,9 @@ public void performAction(List objects) { } }; - final Filter filter3 = Filter.createPresenceFilter("oxAuthClientSecretExpiresAt"); + final Filter filter3 = Filter.createPresenceFilter("oxAuthExpiration"); List result3 = couchbaseEntryManager.findEntries("o=gluu", SimpleClient.class, filter3, SearchScope.SUB, - new String[] {"oxAuthClientSecretExpiresAt"}, clientBatchOperation, 0, 0, 1000); + new String[] {"oxAuthExpiration"}, clientBatchOperation, 0, 0, 1000); LOG.info("Result count (without collecting results): " + result3.size()); @@ -124,9 +124,9 @@ public void performAction(List objects) { } }; - final Filter filter4 = Filter.createPresenceFilter("oxAuthClientSecretExpiresAt"); + final Filter filter4 = Filter.createPresenceFilter("oxAuthExpiration"); List result4 = couchbaseEntryManager.findEntries("o=gluu", SimpleClient.class, filter4, SearchScope.SUB, - new String[] {"oxAuthClientSecretExpiresAt"}, clientBatchOperation2, 0, 0, 1000); + new String[] {"oxAuthExpiration"}, clientBatchOperation2, 0, 0, 1000); LOG.info("Result count (with collecting results): " + result4.size()); } diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleBatchJob.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleBatchJob.java index 73c9ae8e..a7b56c91 100644 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleBatchJob.java +++ b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleBatchJob.java @@ -108,9 +108,9 @@ public void performAction(List objects) { } }; - final Filter filter3 = Filter.createPresenceFilter("oxAuthClientSecretExpiresAt"); + final Filter filter3 = Filter.createPresenceFilter("oxAuthExpiration"); List result3 = ldapEntryManager.findEntries("o=gluu", SimpleClient.class, filter3, SearchScope.SUB, - new String[] {"oxAuthClientSecretExpiresAt"}, clientBatchOperation, 0, 0, 1000); + new String[] {"oxAuthExpiration"}, clientBatchOperation, 0, 0, 1000); LOG.info("Result count (without collecting results): " + result3.size()); @@ -127,9 +127,9 @@ public void performAction(List objects) { } }; - final Filter filter4 = Filter.createPresenceFilter("oxAuthClientSecretExpiresAt"); + final Filter filter4 = Filter.createPresenceFilter("oxAuthExpiration"); List result4 = ldapEntryManager.findEntries("o=gluu", SimpleClient.class, filter4, SearchScope.SUB, - new String[] {"oxAuthClientSecretExpiresAt"}, clientBatchOperation2, 0, 0, 1000); + new String[] {"oxAuthExpiration"}, clientBatchOperation2, 0, 0, 1000); LOG.info("Result count (with collecting results): " + result4.size()); } From 74311f0204e32da2a151b79df81ac4eb88123e6c Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 28 Nov 2019 19:31:59 +0300 Subject: [PATCH 032/362] Fix LDAP removal with filter when entry not extends DeletableEntity #167 --- .../gluu/persist/impl/BaseEntryManager.java | 6 ++++++ .../persist/ldap/impl/LdapEntryManager.java | 19 ++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java index 44e18503..25f483bf 100644 --- a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java @@ -1677,6 +1677,12 @@ private Object getListItem(String propertyName, Setter propertyNameSetter, Sette return result; } + protected Object getDNValue(Object entry) { + Class entryClass = entry.getClass(); + + return getDNValue(entryClass, entryClass); + } + protected Object getDNValue(Object entry, Class entryClass) { // Check if entry has DN property String dnProperty = getDNPropertyName(entryClass); diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java index fd9fe54c..43985998 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java @@ -327,7 +327,7 @@ public int remove(String baseDN, Class entryClass, Filter filter, int cou searchFilter = filter; } - DeleteBatchOperation batchOperation = new DeleteBatchOperation(this); + DeleteBatchOperation batchOperation = new DeleteBatchOperation(this); SearchResult searchResult = null; try { LdapBatchOperationWraper batchOperationWraper = new LdapBatchOperationWraper(batchOperation, this, entryClass, @@ -945,7 +945,7 @@ public int getCountEntries() { } } - private static final class DeleteBatchOperation extends DefaultBatchOperation { + private static final class DeleteBatchOperation extends DefaultBatchOperation { private int countEntries = 0; private LdapEntryManager ldapEntryManager; @@ -955,17 +955,18 @@ public DeleteBatchOperation(LdapEntryManager ldapEntryManager) { } @Override - public void performAction(List entries) { - for (DeletableEntity entity : entries) { + public void performAction(List entries) { + for (T entity : entries) { try { - if (ldapEntryManager.hasBranchesSupport(entity.getDn())) { - ldapEntryManager.removeRecursively(entity.getDn()); + String dnValue = ldapEntryManager.getDNValue(entity).toString(); + if (ldapEntryManager.hasBranchesSupport(dnValue)) { + ldapEntryManager.removeRecursively(dnValue); } else { - ldapEntryManager.remove(entity.getDn()); + ldapEntryManager.remove(dnValue); } - LOG.trace("Removed {}", entity.getDn()); + LOG.trace("Removed {}", dnValue); } catch (Exception e) { - LOG.error("Failed to remove entry, dn: " + entity.getDn(), e); + LOG.error("Failed to remove entry, entity: " + entity, e); } } } From 2b75c26a5018f90ad7c4d4342f8cadf28e8c1c66 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 28 Nov 2019 19:39:47 +0300 Subject: [PATCH 033/362] Fix LDAP removal with filter when entry not extends DeletableEntity #167 --- .../cache/NativePersistenceCacheEntity.java | 37 +++---------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java index 906d6d5e..98e24d80 100644 --- a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java +++ b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java @@ -1,6 +1,7 @@ package org.gluu.service.cache; import org.gluu.persist.model.base.Deletable; +import org.gluu.persist.model.base.DeletableEntity; import org.gluu.persist.annotation.AttributeName; import org.gluu.persist.annotation.DN; import org.gluu.persist.annotation.DataEntry; @@ -11,7 +12,7 @@ @DataEntry @ObjectClass(value = "cache") -public class NativePersistenceCacheEntity implements Serializable, Deletable { +public class NativePersistenceCacheEntity extends DeletableEntity implements Serializable, Deletable { @DN private String dn; @@ -19,10 +20,6 @@ public class NativePersistenceCacheEntity implements Serializable, Deletable { private String id; @AttributeName(name = "iat") private Date creationDate; - @AttributeName(name = "exp") - private Date expirationDate; - @AttributeName(name = "del") - private boolean deletable = true; @AttributeName(name = "dat") private String data; @@ -50,14 +47,6 @@ public void setCreationDate(Date creationDate) { this.creationDate = creationDate; } - public Date getExpirationDate() { - return expirationDate; - } - - public void setExpirationDate(Date expirationDate) { - this.expirationDate = expirationDate; - } - public String getData() { return data; } @@ -66,23 +55,9 @@ public void setData(String data) { this.data = data; } - public boolean isDeletable() { - return deletable; - } - - public void setDeletable(boolean deletable) { - this.deletable = deletable; - } - @Override - public String toString() { - return "NativePersistenceCacheEntity{" + - "dn='" + dn + '\'' + - ", id='" + id + '\'' + - ", creationDate=" + creationDate + - ", expirationDate=" + expirationDate + - ", deletable=" + deletable + - ", data='" + data + '\'' + - '}'; - } + public String toString() { + return "NativePersistenceCacheEntity [dn=" + dn + ", id=" + id + ", creationDate=" + creationDate + ", data=" + data + + ", toString()=" + super.toString() + "]"; + } } From ff81cce2d8f1599ba78ce6bce693b15c011d5e6f Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 28 Nov 2019 20:13:58 +0300 Subject: [PATCH 034/362] Add trace messages to base cache --- .../org/gluu/service/BaseCacheService.java | 44 +++++++++++++------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/BaseCacheService.java b/oxService/src/main/java/org/gluu/service/BaseCacheService.java index 4e100e5f..7a8b64a0 100644 --- a/oxService/src/main/java/org/gluu/service/BaseCacheService.java +++ b/oxService/src/main/java/org/gluu/service/BaseCacheService.java @@ -31,10 +31,15 @@ public abstract class BaseCacheService implements CacheInterface { public Object get(String key) { CacheProvider cacheProvider = getCacheProvider(); if (cacheProvider == null) { + log.error("Cache provider is invalid!"); return null; } - return cacheProvider.get(key); + log.trace("Request data, key '{}'", key); + Object value = cacheProvider.get(key); + log.trace("Loaded data, key '{}': '{}'", key, value); + + return value; } public T getWithPut(String key, Supplier loadFunction, int expirationInSeconds) { @@ -45,23 +50,26 @@ public T getWithPut(String key, Supplier loadFunction, int expirationInSe CacheProvider cacheProvider = getCacheProvider(); if (CacheProviderType.NATIVE_PERSISTENCE == cacheProvider.getProviderType()) { + log.trace("Loading data from DB without cache, key '{}'", key); return loadFunction.get(); } final Object value = get(key); if (value != null) { - log.trace("Loaded from cache, key: " + key); + log.trace("Loaded from cache, key: '{}'", key); return (T) value; } else { + log.trace("Key not in cache. Searching value via load function, key: '{}'", key); final T loaded = loadFunction.get(); if (loaded == null) { + log.trace("Key not in cache. There is no value, key: '{}'", key); return null; } try { put(expirationInSeconds, key, loaded); } catch (Exception e) { - log.error("Failed to put object into cache, key: " + key, e); // we don't want prevent returning loaded value due to failure with put + log.error("Failed to put object into cache, key: '{}'", key, e); // we don't want prevent returning loaded value due to failure with put } return loaded; } @@ -69,37 +77,47 @@ public T getWithPut(String key, Supplier loadFunction, int expirationInSe public void put(int expirationInSeconds, String key, Object object) { CacheProvider cacheProvider = getCacheProvider(); - - if (cacheProvider != null) { - cacheProvider.put(expirationInSeconds, key, object); + if (cacheProvider == null) { + log.error("Cache provider is invalid!"); + return; } + + log.trace("Put data, key '{}': '{}'", key, object); + cacheProvider.put(expirationInSeconds, key, object); } public void remove(String key) { CacheProvider cacheProvider = getCacheProvider(); - if (cacheProvider == null) { + log.error("Cache provider is invalid!"); return; } + log.trace("Remove data, key '{}'", key); cacheProvider.remove(key); } public void clear() { CacheProvider cacheProvider = getCacheProvider(); - - if (cacheProvider != null) { - cacheProvider.clear(); + if (cacheProvider == null) { + log.error("Cache provider is invalid!"); + return; } + + log.trace("Clear cache"); + cacheProvider.clear(); } @Override public void cleanup(Date now) { CacheProvider cacheProvider = getCacheProvider(); + if (cacheProvider == null) { + log.error("Cache provider is invalid!"); + return; + } - if (cacheProvider != null) { - cacheProvider.cleanup(now); - } + log.trace("Clean up cache"); + cacheProvider.cleanup(now); } public void put(String key, Object object) { From c092f76202750e25726bc9cb26ebb1399e3df7fc Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 28 Nov 2019 22:16:55 +0300 Subject: [PATCH 035/362] Use scan consistency in cache --- .../org/gluu/service/cache/NativePersistenceCacheEntity.java | 2 +- .../org/gluu/service/cache/NativePersistenceCacheProvider.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java index 98e24d80..c96febc0 100644 --- a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java +++ b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java @@ -16,7 +16,7 @@ public class NativePersistenceCacheEntity extends DeletableEntity implements Ser @DN private String dn; - @AttributeName(name = "uuid") + @AttributeName(name = "uuid", consistency = true /* get by key requires scan consistency too */) private String id; @AttributeName(name = "iat") private Date creationDate; diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index ded85fc4..01d2c110 100644 --- a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -231,4 +231,5 @@ public void setBaseDn(String baseDn) { public void setCacheConfiguration(CacheConfiguration cacheConfiguration) { this.cacheConfiguration = cacheConfiguration; } + } From 2a381003dd776b0f5b8107acc3471cda50b43fca Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 29 Nov 2019 14:59:30 +0300 Subject: [PATCH 036/362] Fix native cache entry expiration --- .../gluu/service/cache/NativePersistenceCacheProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index 01d2c110..97eda86f 100644 --- a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -121,12 +121,12 @@ public void put(int expirationInSeconds, String key, Object object) { entity.setId(key); entity.setDn(createDn(key)); entity.setCreationDate(creationDate); - entity.setExpirationDate(expirationDate.getTime()); + entity.setNewExpirationDate(expirationDate.getTime()); entity.setDeletable(true); silentlyRemoveEntityIfExists(entity.getDn()); entryManager.persist(entity); - } catch (Exception e) { + } catch (Exception e) {e.printStackTrace(); log.trace("Failed to put entry, key: " + originalKey + ", hashedKey: " + key + ", message: " + e.getMessage(), e); // log as trace since it is perfectly valid that entry is removed by timer for example } } From b1d48b2e0b4b27d21e28b477e694800298c502ca Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 29 Nov 2019 15:11:21 +0300 Subject: [PATCH 037/362] Fix cache logging error --- .../gluu/service/cache/NativePersistenceCacheProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index 97eda86f..8a68e200 100644 --- a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -126,8 +126,8 @@ public void put(int expirationInSeconds, String key, Object object) { silentlyRemoveEntityIfExists(entity.getDn()); entryManager.persist(entity); - } catch (Exception e) {e.printStackTrace(); - log.trace("Failed to put entry, key: " + originalKey + ", hashedKey: " + key + ", message: " + e.getMessage(), e); // log as trace since it is perfectly valid that entry is removed by timer for example + } catch (Exception e) { + log.error("Failed to put entry, key: " + originalKey + ", hashedKey: " + key + ", message: " + e.getMessage(), e); // log as trace since it is perfectly valid that entry is removed by timer for example } } From 74111c8f13e9b81eb3b9ea4ac8ce64542ab24ced Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 29 Nov 2019 16:10:39 +0300 Subject: [PATCH 038/362] Fix expiration check --- .../org/gluu/service/cache/NativePersistenceCacheProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index 8a68e200..836226af 100644 --- a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -78,7 +78,7 @@ public Object get(String key) { key = hashKey(key); NativePersistenceCacheEntity entity = entryManager.find(NativePersistenceCacheEntity.class, createDn(key)); if (entity != null && entity.getData() != null) { - if (isExpired(entity.getExpirationDate()) && entity.isDeletable()) { + if (isExpired(entity.getNewExpirationDate()) && entity.isDeletable()) { log.trace("Cache entity exists but expired, return null, expirationDate:" + entity.getExpirationDate() + ", key: " + key); remove(key); return null; From e074445be121a888723f6514218e73390d52ef0c Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 29 Nov 2019 16:23:24 +0300 Subject: [PATCH 039/362] Fix typo in get DN value --- .../src/main/java/org/gluu/persist/impl/BaseEntryManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java index 25f483bf..48e6478e 100644 --- a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java @@ -1680,7 +1680,7 @@ private Object getListItem(String propertyName, Setter propertyNameSetter, Sette protected Object getDNValue(Object entry) { Class entryClass = entry.getClass(); - return getDNValue(entryClass, entryClass); + return getDNValue(entry, entryClass); } protected Object getDNValue(Object entry, Class entryClass) { From 5d9d5727167b5568eb4a8419be13af4a7cd6fe49 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 29 Nov 2019 16:53:56 +0300 Subject: [PATCH 040/362] Native cache optimizations --- .../service/cache/NativePersistenceCacheProvider.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index 836226af..715df056 100644 --- a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -29,6 +29,9 @@ public class NativePersistenceCacheProvider extends AbstractCacheProvider Date: Fri, 29 Nov 2019 18:56:01 +0300 Subject: [PATCH 041/362] Fix date parsing --- .../persist/couchbase/impl/CouchbaseEntryManager.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java index d2d99f89..8f726f72 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java @@ -67,6 +67,8 @@ */ public class CouchbaseEntryManager extends BaseEntryManager implements Serializable { + private static final String JSON_DATA_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS"; + private static final long serialVersionUID = 2127241817126412574L; private static final Logger LOG = LoggerFactory.getLogger(CouchbaseConnectionProvider.class); @@ -77,8 +79,6 @@ public class CouchbaseEntryManager extends BaseEntryManager implements Serializa private final CouchbaseFilterConverter FILTER_CONVERTER; private static final GenericKeyConverter KEY_CONVERTER = new GenericKeyConverter(); - private SimpleDateFormat jsonDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); - private CouchbaseOperationsServiceImpl operationService; private List subscribers; @@ -595,6 +595,7 @@ private List getAttributeDataList(JsonObject entry) { } else if (attributeObject instanceof String) { Object value = attributeObject.toString(); try { + SimpleDateFormat jsonDateFormat = new SimpleDateFormat(JSON_DATA_FORMAT); value = jsonDateFormat.parse(attributeObject.toString()); } catch (Exception ex) {} attributeValueObjects = new Object[] { value }; @@ -833,6 +834,7 @@ public String encodeTime(String baseDN, Date date) { return null; } + SimpleDateFormat jsonDateFormat = new SimpleDateFormat(JSON_DATA_FORMAT); return jsonDateFormat.format(date); } @@ -847,10 +849,11 @@ public Date decodeTime(String baseDN, String date) { return null; } + SimpleDateFormat jsonDateFormat = new SimpleDateFormat(JSON_DATA_FORMAT); Date decodedDate; try { decodedDate = jsonDateFormat.parse(date); - } catch (ParseException ex) { + } catch (Exception ex) { LOG.error("Failed to decode generalized time '{}'", date, ex); return null; From 86f8040d98273fe774c8ebeef00f819a8685657a Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 29 Nov 2019 19:23:36 +0300 Subject: [PATCH 042/362] Native cache bug fixes --- .../cache/NativePersistenceCacheEntity.java | 2 +- .../cache/NativePersistenceCacheProvider.java | 14 ++++---- .../cache/NativePersistenceConfiguration.java | 35 +++++++++++++++---- .../org/gluu/service/util/PageService.java | 8 ++--- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java index c96febc0..98e24d80 100644 --- a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java +++ b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java @@ -16,7 +16,7 @@ public class NativePersistenceCacheEntity extends DeletableEntity implements Ser @DN private String dn; - @AttributeName(name = "uuid", consistency = true /* get by key requires scan consistency too */) + @AttributeName(name = "uuid") private String id; @AttributeName(name = "iat") private Date creationDate; diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index 715df056..a9318ca5 100644 --- a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -29,16 +29,18 @@ public class NativePersistenceCacheProvider extends AbstractCacheProvider Date: Fri, 29 Nov 2019 19:24:35 +0300 Subject: [PATCH 043/362] Add native cache benchmarking test --- .../CouchbaseNativeBenchmarkCacheTest.java | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeBenchmarkCacheTest.java diff --git a/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeBenchmarkCacheTest.java b/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeBenchmarkCacheTest.java new file mode 100644 index 00000000..d5b143a4 --- /dev/null +++ b/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeBenchmarkCacheTest.java @@ -0,0 +1,96 @@ +package org.gluu.service.cache; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import java.io.IOException; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.UUID; + +import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; +import org.gluu.persist.couchbase.impl.CouchbaseEntryManagerFactory; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * @author Yuriy Movchan Date: 11/29/2019 + */ +public class CouchbaseNativeBenchmarkCacheTest { + + private CouchbaseEntryManager entryManager; + + @BeforeClass + public void init() { + this.entryManager = createCouchbaseEntryManager(); + } + + @AfterClass + public void destroy() { + this.entryManager.destroy(); + } + + @Test(enabled = false, threadPoolSize = 300, invocationCount = 10000) // manual + public void couchbaseCacheProvider() throws IOException { + final String baseDn = "ou=cache,o=gluu"; + + final CacheConfiguration cacheConfiguration = new CacheConfiguration(); + cacheConfiguration.setNativePersistenceConfiguration(new NativePersistenceConfiguration()); + cacheConfiguration.getNativePersistenceConfiguration().setBaseDn(""); + + NativePersistenceCacheProvider provider = new NativePersistenceCacheProvider(); + provider.setBaseDn(baseDn); + provider.setCacheConfiguration(cacheConfiguration); + provider.setEntryManager(this.entryManager); + + Map sessionAttributes = new HashMap<>(); + sessionAttributes.put("attr1", "value1"); + sessionAttributes.put("attr2", "value2"); + + SampleSessionId sessionId = new SampleSessionId(); + sessionId.setId(UUID.randomUUID().toString()); + sessionId.setDn(sessionId.getId()); + sessionId.setAuthenticationTime(new Date()); + sessionId.setState(SessionIdState.AUTHENTICATED); + sessionId.setSessionAttributes(sessionAttributes); + + provider.put(130, sessionId.getId(), sessionId); + + final SampleSessionId fromCache = (SampleSessionId) provider.get(sessionId.getId()); + + assertNotNull(fromCache, "Failed to get by key: " + sessionId.getId() + " Cache key: " + provider.hashKey(sessionId.getId())); + assertEquals(fromCache.getId(), sessionId.getId(), "Get session with invaid key: " + sessionId.getId()); + } + + // MODIFY ACCORDING TO YOUR SERVER + private Properties getSampleConnectionProperties() { + Properties connectionProperties = new Properties(); + + connectionProperties.put("couchbase.servers", "test.gluu.org"); + connectionProperties.put("couchbase.auth.userName", "admin"); + connectionProperties.put("couchbase.auth.userPassword", "test"); + connectionProperties.put("couchbase.buckets", "gluu, gluu_cache"); + + connectionProperties.put("couchbase.bucket.default", "gluu"); + connectionProperties.put("couchbase.bucket.gluu_cache.mapping", "cache"); + + connectionProperties.put("couchbase.password.encryption.method", "CRYPT-SHA-256"); + + return connectionProperties; + } + + private CouchbaseEntryManager createCouchbaseEntryManager() { + CouchbaseEntryManagerFactory couchbaseEntryManagerFactory = new CouchbaseEntryManagerFactory(); + couchbaseEntryManagerFactory.create(); + Properties connectionProperties = getSampleConnectionProperties(); + + CouchbaseEntryManager couchbaseEntryManager = couchbaseEntryManagerFactory.createEntryManager(connectionProperties); + System.out.println("Created CouchbaseEntryManager: " + couchbaseEntryManager); + + return couchbaseEntryManager; + } + +} From 0b38f3e9eb6307345a3cb714ea721616416f2a4d Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 29 Nov 2019 19:45:31 +0300 Subject: [PATCH 044/362] Add git ignore --- oxService/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 oxService/.gitignore diff --git a/oxService/.gitignore b/oxService/.gitignore new file mode 100644 index 00000000..466ffd09 --- /dev/null +++ b/oxService/.gitignore @@ -0,0 +1 @@ +/test-output/ From 5d6a7d88f01eb20854b9a9320e7959755c1defe2 Mon Sep 17 00:00:00 2001 From: yurem Date: Sat, 30 Nov 2019 11:48:18 +0300 Subject: [PATCH 045/362] Native cache option deleteBeforePut is mandatory --- .../cache/NativePersistenceCacheProvider.java | 6 +----- .../cache/NativePersistenceConfiguration.java | 14 +------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index a9318ca5..fa592535 100644 --- a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -33,14 +33,12 @@ public class NativePersistenceCacheProvider extends AbstractCacheProvider Date: Tue, 3 Dec 2019 18:04:32 +0200 Subject: [PATCH 046/362] Added sentinel pool support to oxcore redis cache provider. #144 https://github.com/GluuFederation/oxCore/issues/144 --- .../service/cache/RedisClusterProvider.java | 18 +-- .../service/cache/RedisConfiguration.java | 11 ++ .../service/cache/RedisProviderFactory.java | 24 ++-- .../gluu/service/cache/RedisProviderType.java | 2 +- .../service/cache/RedisSentinelProvider.java | 113 ++++++++++++++++++ 5 files changed, 149 insertions(+), 19 deletions(-) create mode 100644 oxService/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisClusterProvider.java b/oxService/src/main/java/org/gluu/service/cache/RedisClusterProvider.java index 21c5e674..0c736799 100644 --- a/oxService/src/main/java/org/gluu/service/cache/RedisClusterProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/RedisClusterProvider.java @@ -1,19 +1,18 @@ package org.gluu.service.cache; -import java.io.IOException; -import java.io.Serializable; -import java.util.HashSet; -import java.util.Set; - import org.apache.commons.lang.SerializationUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPoolConfig; +import java.io.IOException; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + /** * Important : keep it weld free. It's reused by oxd ! * @@ -37,7 +36,12 @@ public void create() { poolConfig.setMaxTotal(1000); poolConfig.setMinIdle(2); - pool = new JedisCluster(hosts(getRedisConfiguration().getServers()), poolConfig); + if (StringUtils.isBlank(redisConfiguration.getDecryptedPassword())) { + pool = new JedisCluster(hosts(getRedisConfiguration().getServers()), poolConfig); + } else { + // default maxAttempts and timeouts are taken from jedis constants + pool = new JedisCluster(hosts(getRedisConfiguration().getServers()), 2000, 2000, 5, redisConfiguration.getDecryptedPassword(), poolConfig); + } testConnection(); LOG.debug("RedisClusterProvider started."); diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisConfiguration.java b/oxService/src/main/java/org/gluu/service/cache/RedisConfiguration.java index a70aa9c3..340d1ed6 100644 --- a/oxService/src/main/java/org/gluu/service/cache/RedisConfiguration.java +++ b/oxService/src/main/java/org/gluu/service/cache/RedisConfiguration.java @@ -19,6 +19,8 @@ public class RedisConfiguration implements Serializable { private int defaultPutExpiration = 60; // in seconds + private String sentinelMasterName = ""; + private String password; private String decryptedPassword; @@ -83,6 +85,14 @@ public void setDecryptedPassword(String decryptedPassword) { this.decryptedPassword = decryptedPassword; } + public String getSentinelMasterName() { + return sentinelMasterName; + } + + public void setSentinelMasterName(String sentinelMasterName) { + this.sentinelMasterName = sentinelMasterName; + } + @Override public String toString() { return "RedisConfiguration{" + @@ -91,6 +101,7 @@ public String toString() { ", redisProviderType=" + redisProviderType + ", useSSL=" + useSSL + ", sslTrustStoreFilePath=" + sslTrustStoreFilePath + + ", sentinelMasterName=" + sentinelMasterName + '}'; } } diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisProviderFactory.java b/oxService/src/main/java/org/gluu/service/cache/RedisProviderFactory.java index 92b6eaff..09b67c17 100644 --- a/oxService/src/main/java/org/gluu/service/cache/RedisProviderFactory.java +++ b/oxService/src/main/java/org/gluu/service/cache/RedisProviderFactory.java @@ -31,17 +31,19 @@ public static AbstractRedisProvider create(RedisConfiguration redisConfiguration LOG.debug("Creating RedisProvider ... configuration:" + redisConfiguration); switch (redisConfiguration.getRedisProviderType()) { - case STANDALONE: - return new RedisStandaloneProvider(redisConfiguration); - case CLUSTER: - return new RedisClusterProvider(redisConfiguration); - case SHARDED: - return new RedisShardedProvider(redisConfiguration); - default: - LOG.error("Failed to create RedisProvider. RedisProviderType is not supported by current version of oxcore: " - + redisConfiguration.getRedisProviderType() + ", redisConfiguration:" + redisConfiguration); - throw new RuntimeException( - "RedisProviderType is not supported by current version of oxcore: " + redisConfiguration.getRedisProviderType()); + case STANDALONE: + return new RedisStandaloneProvider(redisConfiguration); + case CLUSTER: + return new RedisClusterProvider(redisConfiguration); + case SHARDED: + return new RedisShardedProvider(redisConfiguration); + case SENTINEL: + return new RedisSentinelProvider(redisConfiguration); + default: + LOG.error("Failed to create RedisProvider. RedisProviderType is not supported by current version of oxcore: " + + redisConfiguration.getRedisProviderType() + ", redisConfiguration:" + redisConfiguration); + throw new RuntimeException( + "RedisProviderType is not supported by current version of oxcore: " + redisConfiguration.getRedisProviderType()); } } catch (Exception e) { LOG.error("Failed to create RedisProvider."); diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisProviderType.java b/oxService/src/main/java/org/gluu/service/cache/RedisProviderType.java index be5a3f1a..fc6fd20c 100644 --- a/oxService/src/main/java/org/gluu/service/cache/RedisProviderType.java +++ b/oxService/src/main/java/org/gluu/service/cache/RedisProviderType.java @@ -7,5 +7,5 @@ */ @XmlEnum(String.class) public enum RedisProviderType { - STANDALONE, CLUSTER, SHARDED + STANDALONE, CLUSTER, SHARDED, SENTINEL } diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java b/oxService/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java new file mode 100644 index 00000000..0701c539 --- /dev/null +++ b/oxService/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java @@ -0,0 +1,113 @@ +package org.gluu.service.cache; + +import com.google.common.collect.Sets; +import org.apache.commons.lang.SerializationUtils; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPoolConfig; +import redis.clients.jedis.JedisSentinelPool; + +import java.io.Serializable; + +/** + * @author Yuriy Zabrovarnyy + */ +public class RedisSentinelProvider extends AbstractRedisProvider { + + private static final Logger LOG = LoggerFactory.getLogger(RedisSentinelProvider.class); + + private JedisSentinelPool pool; + + public RedisSentinelProvider(RedisConfiguration redisConfiguration) { + super(redisConfiguration); + } + + public void create() { + try { + LOG.debug("Starting RedisSentinelProvider ... configuration:" + getRedisConfiguration()); + + JedisPoolConfig poolConfig = new JedisPoolConfig(); + poolConfig.setMaxTotal(1000); + poolConfig.setMinIdle(2); + + if (StringUtils.isBlank(redisConfiguration.getDecryptedPassword())) { + pool = new JedisSentinelPool( + getRedisConfiguration().getSentinelMasterName(), + Sets.newHashSet(StringUtils.split(getRedisConfiguration().getServers().trim(), ",")), + poolConfig); + } else { + pool = new JedisSentinelPool( + getRedisConfiguration().getSentinelMasterName(), + Sets.newHashSet(StringUtils.split(getRedisConfiguration().getServers().trim(), ",")), + poolConfig, + redisConfiguration.getDecryptedPassword()); + } + + testConnection(); + LOG.debug("RedisSentinelProvider started."); + } catch (Exception e) { + LOG.error("Failed to start RedisSentinelProvider."); + throw new IllegalStateException("Error starting RedisSentinelProvider", e); + } + } + + public void destroy() { + LOG.debug("Destroying RedisSentinelProvider"); + + try { + pool.close(); + } catch (Exception e) { + LOG.error("Failed to destroy RedisSentinelProvider", e); + return; + } + + LOG.debug("Destroyed RedisSentinelProvider"); + } + + @Override + public JedisSentinelPool getDelegate() { + return pool; + } + + @Override + public Object get(String key) { + byte[] value = pool.getResource().get(key.getBytes()); + Object deserialized = null; + if (value != null && value.length > 0) { + deserialized = SerializationUtils.deserialize(value); + } + return deserialized; + } + + @Override + public void put(int expirationInSeconds, String key, Object object) { + String status = pool.getResource().setex(key.getBytes(), expirationInSeconds, SerializationUtils.serialize((Serializable) object)); + LOG.trace("put - key: " + key + ", status: " + status); + } + + @Override + public void put(String key, Object object) { + String status = pool.getResource().set(key.getBytes(), SerializationUtils.serialize((Serializable) object)); + LOG.trace("put - key: " + key + ", status: " + status); + } + + @Override + public void remove(String key) { + Long entriesRemoved = pool.getResource().del(key.getBytes()); + LOG.trace("remove - key: " + key + ", entriesRemoved: " + entriesRemoved); + } + + @Override + public void clear() { + Jedis jedis = pool.getResource(); + + try { + jedis.flushAll(); + LOG.trace("clear"); + } finally { + jedis.close(); + } + } +} From acfb05380c6e7fc3eee0836613de15c1676c39e2 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Wed, 4 Dec 2019 09:51:57 +0200 Subject: [PATCH 047/362] rename: sentinelMasterName -> sentinelMasterGroupName https://github.com/GluuFederation/oxCore/issues/144 --- .../org/gluu/service/cache/RedisConfiguration.java | 12 ++++++------ .../gluu/service/cache/RedisSentinelProvider.java | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisConfiguration.java b/oxService/src/main/java/org/gluu/service/cache/RedisConfiguration.java index 340d1ed6..d11a47ef 100644 --- a/oxService/src/main/java/org/gluu/service/cache/RedisConfiguration.java +++ b/oxService/src/main/java/org/gluu/service/cache/RedisConfiguration.java @@ -19,7 +19,7 @@ public class RedisConfiguration implements Serializable { private int defaultPutExpiration = 60; // in seconds - private String sentinelMasterName = ""; + private String sentinelMasterGroupName = ""; private String password; @@ -85,12 +85,12 @@ public void setDecryptedPassword(String decryptedPassword) { this.decryptedPassword = decryptedPassword; } - public String getSentinelMasterName() { - return sentinelMasterName; + public String getSentinelMasterGroupName() { + return sentinelMasterGroupName; } - public void setSentinelMasterName(String sentinelMasterName) { - this.sentinelMasterName = sentinelMasterName; + public void setSentinelMasterGroupName(String sentinelMasterGroupName) { + this.sentinelMasterGroupName = sentinelMasterGroupName; } @Override @@ -101,7 +101,7 @@ public String toString() { ", redisProviderType=" + redisProviderType + ", useSSL=" + useSSL + ", sslTrustStoreFilePath=" + sslTrustStoreFilePath + - ", sentinelMasterName=" + sentinelMasterName + + ", sentinelMasterGroupName=" + sentinelMasterGroupName + '}'; } } diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java b/oxService/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java index 0701c539..d230919c 100644 --- a/oxService/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java @@ -34,12 +34,12 @@ public void create() { if (StringUtils.isBlank(redisConfiguration.getDecryptedPassword())) { pool = new JedisSentinelPool( - getRedisConfiguration().getSentinelMasterName(), + getRedisConfiguration().getSentinelMasterGroupName(), Sets.newHashSet(StringUtils.split(getRedisConfiguration().getServers().trim(), ",")), poolConfig); } else { pool = new JedisSentinelPool( - getRedisConfiguration().getSentinelMasterName(), + getRedisConfiguration().getSentinelMasterGroupName(), Sets.newHashSet(StringUtils.split(getRedisConfiguration().getServers().trim(), ",")), poolConfig, redisConfiguration.getDecryptedPassword()); From dbaacc8d7dc3e301a32b67bf92812ab85de90c5a Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Thu, 5 Dec 2019 11:49:13 +0100 Subject: [PATCH 048/362] Add public test method --- .../org/gluu/service/cache/AbstractRedisProvider.java | 8 ++++++++ .../java/org/gluu/service/cache/MemcachedProvider.java | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/oxService/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java b/oxService/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java index 1de9004a..92ea3954 100644 --- a/oxService/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java @@ -26,6 +26,14 @@ public void testConnection() { } } + public boolean isConnected() { + put(2, "testKey", "testValue"); + if (!"testValue".equals(get("testKey"))) { + return false; + } + return true; + } + public abstract void create(); public abstract void destroy(); diff --git a/oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java b/oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java index 7a9760de..d6b8ec09 100644 --- a/oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java @@ -65,6 +65,14 @@ private void testConnection() { } } + public boolean isConnected() { + put(2, "connectionTest", "connectionTestValue"); + if (!"connectionTestValue".equals(get("connectionTest"))) { + return false; + } + return true; + } + @PreDestroy public void destroy() { log.debug("Destroying MemcachedProvider"); From d9b62e9f12092a88c6d472aa3d8dedb53be6d606 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Tue, 10 Dec 2019 08:27:16 +0200 Subject: [PATCH 049/362] Changed parent pom reference oxcore-parent-bom -> gluu-core-bom --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9b0bd832..8b807901 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ org.gluu - oxcore-parent-bom + gluu-core-bom 4.1.0-SNAPSHOT import pom From 89d753aba96e8c1c0b24248638e719b246186351 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 12 Dec 2019 19:02:57 +0300 Subject: [PATCH 050/362] Add method to get cache provider by configuration --- .../java/org/gluu/service/cache/CacheProviderFactory.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java b/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java index fb7589cf..4326a3dd 100644 --- a/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java +++ b/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java @@ -33,7 +33,11 @@ public CacheProvider getCacheProvider() { AbstractCacheProvider cacheProvider = null; - CacheProviderType cacheProviderType = cacheConfiguration.getCacheProviderType(); + return getCacheProvider(cacheProvider); + } + + public CacheProvider getCacheProvider(AbstractCacheProvider cacheProvider) { + CacheProviderType cacheProviderType = cacheConfiguration.getCacheProviderType(); if (cacheProviderType == null) { log.error("Failed to initialize cacheProvider, cacheProviderType is null. Fallback to IN_MEMORY type."); @@ -63,7 +67,7 @@ public CacheProvider getCacheProvider() { cacheProvider.create(); return cacheProvider; - } + } @Produces @ApplicationScoped From f822dfd35f0c8317a9f48031289c6446afec250b Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 12 Dec 2019 20:19:57 +0300 Subject: [PATCH 051/362] Add method to get cache provider by configuration --- .../java/org/gluu/service/cache/CacheProviderFactory.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java b/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java index 4326a3dd..f6871c18 100644 --- a/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java +++ b/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java @@ -31,12 +31,11 @@ public class CacheProviderFactory { public CacheProvider getCacheProvider() { log.debug("Started to create cache provider"); - AbstractCacheProvider cacheProvider = null; - return getCacheProvider(cacheProvider); + return getCacheProvider(cacheConfiguration); } - public CacheProvider getCacheProvider(AbstractCacheProvider cacheProvider) { + public CacheProvider getCacheProvider(CacheConfiguration cacheConfiguration) { CacheProviderType cacheProviderType = cacheConfiguration.getCacheProviderType(); if (cacheProviderType == null) { @@ -45,6 +44,7 @@ public CacheProvider getCacheProvider(AbstractCacheProvider cacheProvider) { } // Create proxied bean + AbstractCacheProvider cacheProvider = null; switch (cacheProviderType) { case IN_MEMORY: cacheProvider = instance.select(InMemoryCacheProvider.class).get(); From 74a37010bd06297c8476e0f71d3ebfe8f529e3eb Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 13 Dec 2019 14:07:37 +0300 Subject: [PATCH 052/362] Branch for version 4.2 --- demo-cdi/pom.xml | 2 +- oxJsfUtil/pom.xml | 2 +- oxModel/pom.xml | 2 +- oxRadius/pom.xml | 2 +- oxSaml/pom.xml | 2 +- oxService/pom.xml | 2 +- oxUtil/pom.xml | 2 +- persistence-annotation/pom.xml | 2 +- persistence-cdi/pom.xml | 2 +- persistence-core/pom.xml | 2 +- persistence-couchbase-sample/pom.xml | 2 +- persistence-couchbase/pom.xml | 2 +- persistence-filter/pom.xml | 2 +- persistence-hybrid/pom.xml | 2 +- persistence-ldap-sample/pom.xml | 2 +- persistence-ldap/pom.xml | 2 +- persistence-model/pom.xml | 2 +- persistence-standalone/pom.xml | 2 +- pom.xml | 4 ++-- server/pom.xml | 2 +- 20 files changed, 21 insertions(+), 21 deletions(-) diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index 0e54cd42..54f94194 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index 50b3f931..324a1b3e 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/oxModel/pom.xml b/oxModel/pom.xml index 2eceeae8..7c173e80 100644 --- a/oxModel/pom.xml +++ b/oxModel/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/oxRadius/pom.xml b/oxRadius/pom.xml index 4aca56a1..2935d29f 100644 --- a/oxRadius/pom.xml +++ b/oxRadius/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index c3e97305..00606683 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/oxService/pom.xml b/oxService/pom.xml index 052960fc..16e28a1a 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index ad5eabe9..b21c8106 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/persistence-annotation/pom.xml b/persistence-annotation/pom.xml index 3fc5f41f..0b5608c5 100644 --- a/persistence-annotation/pom.xml +++ b/persistence-annotation/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT \ No newline at end of file diff --git a/persistence-cdi/pom.xml b/persistence-cdi/pom.xml index 8ffaa522..4242fe05 100644 --- a/persistence-cdi/pom.xml +++ b/persistence-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/persistence-core/pom.xml b/persistence-core/pom.xml index b930e0de..03d38837 100644 --- a/persistence-core/pom.xml +++ b/persistence-core/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/persistence-couchbase-sample/pom.xml b/persistence-couchbase-sample/pom.xml index 339aa665..69199d07 100644 --- a/persistence-couchbase-sample/pom.xml +++ b/persistence-couchbase-sample/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/persistence-couchbase/pom.xml b/persistence-couchbase/pom.xml index 4958a9bc..a825364f 100644 --- a/persistence-couchbase/pom.xml +++ b/persistence-couchbase/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/persistence-filter/pom.xml b/persistence-filter/pom.xml index 856731db..a3d147aa 100644 --- a/persistence-filter/pom.xml +++ b/persistence-filter/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/persistence-hybrid/pom.xml b/persistence-hybrid/pom.xml index df2c7fef..1ca7d8cf 100644 --- a/persistence-hybrid/pom.xml +++ b/persistence-hybrid/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/persistence-ldap-sample/pom.xml b/persistence-ldap-sample/pom.xml index 6dbcb423..d253de04 100644 --- a/persistence-ldap-sample/pom.xml +++ b/persistence-ldap-sample/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/persistence-ldap/pom.xml b/persistence-ldap/pom.xml index 3fdcbacb..7756d577 100644 --- a/persistence-ldap/pom.xml +++ b/persistence-ldap/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/persistence-model/pom.xml b/persistence-model/pom.xml index 817472d0..2ed419d0 100644 --- a/persistence-model/pom.xml +++ b/persistence-model/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/persistence-standalone/pom.xml b/persistence-standalone/pom.xml index 6383d412..8bb6f445 100644 --- a/persistence-standalone/pom.xml +++ b/persistence-standalone/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT diff --git a/pom.xml b/pom.xml index 8b807901..c3d59f9b 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.gluu oxcore pom - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT oxCore http://ox.gluu.org @@ -52,7 +52,7 @@ org.gluu gluu-core-bom - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT import pom diff --git a/server/pom.xml b/server/pom.xml index ebc6f1ec..9f7dd01a 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.1.0-SNAPSHOT + 4.2.0-SNAPSHOT From 1977fe65a53e6c3b0182f0a99c057d2b7e73f26a Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 17 Dec 2019 14:12:22 +0300 Subject: [PATCH 053/362] Support LDAP configuration update via EntryManager API #175 --- .../persist/annotation/ConfiguratonEntry.java | 22 ++++++++ .../gluu/persist/annotation/DataEntry.java | 4 +- .../gluu/persist/impl/BaseEntryManager.java | 26 +++++++-- .../couchbase/impl/CouchbaseEntryManager.java | 6 +- .../hybrid/impl/HybridEntryManager.java | 2 +- .../org/gluu/ldap/LdapSampleEntryManager.java | 2 +- .../MailUniquenessConfigurationSample.java | 56 +++++++++++++++++++ .../model/MailUniquenessConfiguration.java | 48 ++++++++++++++++ .../persist/ldap/impl/LdapEntryManager.java | 11 ++-- 9 files changed, 161 insertions(+), 16 deletions(-) create mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/ConfiguratonEntry.java create mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/MailUniquenessConfigurationSample.java create mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/model/MailUniquenessConfiguration.java diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/ConfiguratonEntry.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/ConfiguratonEntry.java new file mode 100644 index 00000000..87e82683 --- /dev/null +++ b/persistence-annotation/src/main/java/org/gluu/persist/annotation/ConfiguratonEntry.java @@ -0,0 +1,22 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.persist.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Mark POJO class as Persistance schema entry + * + * @author Yuriy Movchan Date: 10.07.2010 + */ +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +public @interface ConfiguratonEntry { +} diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/DataEntry.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/DataEntry.java index b7d0cef2..f8622ad1 100644 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/DataEntry.java +++ b/persistence-annotation/src/main/java/org/gluu/persist/annotation/DataEntry.java @@ -21,9 +21,9 @@ public @interface DataEntry { /** - * (Optional) Specify that this entry contains schema definition. + * (Optional) Specify that this entry contains LDAP configuration definition. */ - boolean schemaDefinition() default false; + boolean configurationDefinition() default false; /** * (Optional) Specify sortBy properties to sort by default list of Entries. diff --git a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java index 48e6478e..b247f30b 100644 --- a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java @@ -192,7 +192,7 @@ public int countEntries(Object entry) { } @SuppressWarnings("unchecked") - protected T merge(T entry, boolean isSchemaUpdate, AttributeModificationType schemaModificationType) { + protected T merge(T entry, boolean isSchemaUpdate, boolean isConfigurationUpdate, AttributeModificationType schemaModificationType) { if (entry == null) { throw new MappingException("Entry to persist is null"); } @@ -215,7 +215,9 @@ protected T merge(T entry, boolean isSchemaUpdate, AttributeModificationType attributesFromLdap = new ArrayList(); } else { List currentLdapReturnAttributesList = getAttributesList(entry, propertiesAnnotations, false); - currentLdapReturnAttributesList.add("objectClass"); + if (!isConfigurationUpdate) { + currentLdapReturnAttributesList.add("objectClass"); + } attributesFromLdap = find(dnValue.toString(), propertiesAnnotationsMap, currentLdapReturnAttributesList.toArray(EMPTY_STRING_ARRAY)); } @@ -228,7 +230,7 @@ protected T merge(T entry, boolean isSchemaUpdate, AttributeModificationType propertiesAnnotations, attributesToPersistMap, attributesFromLdapMap, isSchemaUpdate, schemaModificationType); - updateMergeChanges(dnValue.toString(), entry, isSchemaUpdate, entryClass, attributesFromLdapMap, attributeDataModifications); + updateMergeChanges(dnValue.toString(), entry, isSchemaUpdate | isConfigurationUpdate, entryClass, attributesFromLdapMap, attributeDataModifications); LOG.debug(String.format("LDAP attributes for merge: %s", attributeDataModifications)); @@ -237,7 +239,7 @@ protected T merge(T entry, boolean isSchemaUpdate, AttributeModificationType return (T) find(entryClass, dnValue.toString(), null, propertiesAnnotations, propertiesAnnotationsMap); } - protected abstract void updateMergeChanges(String baseDn, T entry, boolean isSchemaUpdate, Class entryClass, + protected abstract void updateMergeChanges(String baseDn, T entry, boolean isConfigurationUpdate, Class entryClass, Map attributesFromLdapMap, List attributeDataModifications); @@ -651,6 +653,22 @@ protected boolean isSchemaEntry(Class entryClass) { return ReflectHelper.getAnnotationByType(entryAnnotations, SchemaEntry.class) != null; } + protected boolean isConfigurationEntry(Class entryClass) { + if (entryClass == null) { + throw new MappingException("Entry class is null"); + } + + // Check if entry is LDAP Entry + List entryAnnotations = ReflectHelper.getClassAnnotations(entryClass, LDAP_ENTRY_TYPE_ANNOTATIONS); + + DataEntry dataEntry = (DataEntry) ReflectHelper.getAnnotationByType(entryAnnotations, DataEntry.class); + if (dataEntry == null) { + return false; + } + + return dataEntry.configurationDefinition(); + } + protected String[] getEntrySortBy(Class entryClass) { if (entryClass == null) { throw new MappingException("Entry class is null"); diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java index 8f726f72..16113c4c 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java @@ -118,15 +118,15 @@ public T merge(T entry) { if (isSchemaEntry(entryClass)) { throw new UnsupportedOperationException("Server doesn't support dynamic schema modifications"); } else { - return merge(entry, false, null); + return merge(entry, false, false, null); } } @Override - protected void updateMergeChanges(String baseDn, T entry, boolean isSchemaUpdate, Class entryClass, Map attributesFromDbMap, + protected void updateMergeChanges(String baseDn, T entry, boolean isConfigurationUpdate, Class entryClass, Map attributesFromDbMap, List attributeDataModifications) { // Update object classes if entry contains custom object classes - if (!isSchemaUpdate) { + if (!isConfigurationUpdate) { String[] objectClasses = getObjectClasses(entry, entryClass); if (ArrayHelper.isEmpty(objectClasses)) { throw new UnsupportedOperationException(String.format("There is no attribute with objectClasses to persist! Entry is invalid: '%s'", entry)); diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java index f9370acc..9b279c41 100644 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java +++ b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java @@ -408,7 +408,7 @@ protected String encodeTime(Date date) { } @Override - protected void updateMergeChanges(String baseDn, T entry, boolean isSchemaUpdate, Class entryClass, + protected void updateMergeChanges(String baseDn, T entry, boolean isConfigurationUpdate, Class entryClass, Map attributesFromLdapMap, List attributeDataModifications) { throw new UnsupportedOperationException("Method not implemented."); } diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleEntryManager.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleEntryManager.java index 3f65fd8c..873173ff 100644 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleEntryManager.java +++ b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleEntryManager.java @@ -18,7 +18,7 @@ private Properties getSampleConnectionProperties() { Properties connectionProperties = new Properties(); connectionProperties.put("ldap.bindDN", "cn=Directory Manager"); - connectionProperties.put("ldap.bindPassword", "test"); + connectionProperties.put("ldap.bindPassword", "test!"); connectionProperties.put("ldap.servers", "localhost:1636"); connectionProperties.put("ldap.useSSL", "true"); connectionProperties.put("ldap.maxconnections", "3"); diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/MailUniquenessConfigurationSample.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/MailUniquenessConfigurationSample.java new file mode 100644 index 00000000..9d67bfae --- /dev/null +++ b/persistence-ldap-sample/src/main/java/org/gluu/ldap/MailUniquenessConfigurationSample.java @@ -0,0 +1,56 @@ +package org.gluu.ldap; + +import java.util.List; + +import org.apache.log4j.Logger; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.status.StatusLogger; +import org.gluu.ldap.model.MailUniquenessConfiguration; +import org.gluu.ldap.model.SimpleAttribute; +import org.gluu.ldap.model.SimpleGrant; +import org.gluu.ldap.model.SimpleSession; +import org.gluu.ldap.model.SimpleUser; +import org.gluu.log.LoggingHelper; +import org.gluu.persist.ldap.impl.LdapEntryManager; +import org.gluu.persist.model.PagedResult; +import org.gluu.persist.model.SearchScope; +import org.gluu.persist.model.SortOrder; +import org.gluu.persist.model.base.CustomAttribute; +import org.gluu.search.filter.Filter; + +/** + * @author Yuriy Movchan Date: 11/03/2016 + */ +public final class MailUniquenessConfigurationSample { + + private static final Logger LOG; + + static { + StatusLogger.getLogger().setLevel(Level.OFF); + LoggingHelper.configureConsoleAppender(); + LOG = Logger.getLogger(MailUniquenessConfigurationSample.class); + } + + private MailUniquenessConfigurationSample() { + } + + public static void main(String[] args) { + // Prepare sample connection details + LdapSampleEntryManager ldapSampleEntryManager = new LdapSampleEntryManager(); + + // Create LDAP entry manager + LdapEntryManager ldapEntryManager = ldapSampleEntryManager.createLdapEntryManager(); + + MailUniquenessConfiguration conf = ldapEntryManager.find("cn=Unique mail address,cn=Plugins,cn=config", MailUniquenessConfiguration.class, null); + System.out.println("Current mail uniqueness: " + conf.isEnabled()); + + conf.setEnabled(!conf.isEnabled()); + + // Upate configuration in LDAP + ldapEntryManager.merge(conf); + + MailUniquenessConfiguration conf2 = ldapEntryManager.find("cn=Unique mail address,cn=Plugins,cn=config", MailUniquenessConfiguration.class, null); + System.out.println("After update mail uniqueness: " + conf2.isEnabled()); + } + +} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/MailUniquenessConfiguration.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/MailUniquenessConfiguration.java new file mode 100644 index 00000000..71dcb243 --- /dev/null +++ b/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/MailUniquenessConfiguration.java @@ -0,0 +1,48 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.ldap.model; + +import java.io.Serializable; + +import org.gluu.persist.annotation.AttributeName; +import org.gluu.persist.annotation.DN; +import org.gluu.persist.annotation.DataEntry; +import org.gluu.persist.annotation.ObjectClass; + +/** + * @author Yuriy Movchan + * Date: 12/17/2019 + */ +@DataEntry(configurationDefinition = true) +@ObjectClass(value = "ds-cfg-plugin") +public class MailUniquenessConfiguration implements Serializable { + + private static final long serialVersionUID = -1634191420188575733L; + + @DN + private String dn; + + @AttributeName(name = "ds-cfg-enabled") + private boolean enabled; + + public String getDn() { + return dn; + } + + public void setDn(String dn) { + this.dn = dn; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + +} diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java index 43985998..ce6c3ef7 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java @@ -112,21 +112,22 @@ public T merge(T entry) { checkEntryClass(entryClass, true); if (isSchemaEntry(entryClass)) { if (getSupportedLDAPVersion() > 2) { - return merge(entry, true, AttributeModificationType.ADD); + return merge(entry, true, false, AttributeModificationType.ADD); } else { throw new UnsupportedOperationException("Server doesn't support dynamic schema modifications"); } } else { - return merge(entry, false, null); + boolean configurationEntry = isConfigurationEntry(entryClass); + return merge(entry, false, configurationEntry, null); } } @Override - protected void updateMergeChanges(String baseDn, T entry, boolean isSchemaUpdate, Class entryClass, Map attributesFromLdapMap, + protected void updateMergeChanges(String baseDn, T entry, boolean isConfigurationUpdate, Class entryClass, Map attributesFromLdapMap, List attributeDataModifications) { // Update object classes if entry contains custom object classes if (getSupportedLDAPVersion() > 2) { - if (!isSchemaUpdate) { + if (!isConfigurationUpdate) { String[] objectClasses = getObjectClasses(entry, entryClass); String[] objectClassesFromLdap = attributesFromLdapMap.get(OBJECT_CLASS.toLowerCase()).getStringValues(); @@ -144,7 +145,7 @@ public void remove(Object entry) { checkEntryClass(entryClass, true); if (isSchemaEntry(entryClass)) { if (getSupportedLDAPVersion() > 2) { - merge(entry, true, AttributeModificationType.REMOVE); + merge(entry, true, false, AttributeModificationType.REMOVE); } else { throw new UnsupportedOperationException("Server doesn't support dynamic schema modifications"); } From 3c9e675056831ebac6f471b2ea0e57f51060dd0b Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 17 Dec 2019 14:14:55 +0300 Subject: [PATCH 054/362] Support LDAP configuration update via EntryManager API #175 --- .../persist/annotation/ConfiguratonEntry.java | 22 ------------------- .../org/gluu/ldap/LdapSampleEntryManager.java | 2 +- 2 files changed, 1 insertion(+), 23 deletions(-) delete mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/ConfiguratonEntry.java diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/ConfiguratonEntry.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/ConfiguratonEntry.java deleted file mode 100644 index 87e82683..00000000 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/ConfiguratonEntry.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Mark POJO class as Persistance schema entry - * - * @author Yuriy Movchan Date: 10.07.2010 - */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface ConfiguratonEntry { -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleEntryManager.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleEntryManager.java index 873173ff..3f65fd8c 100644 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleEntryManager.java +++ b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleEntryManager.java @@ -18,7 +18,7 @@ private Properties getSampleConnectionProperties() { Properties connectionProperties = new Properties(); connectionProperties.put("ldap.bindDN", "cn=Directory Manager"); - connectionProperties.put("ldap.bindPassword", "test!"); + connectionProperties.put("ldap.bindPassword", "test"); connectionProperties.put("ldap.servers", "localhost:1636"); connectionProperties.put("ldap.useSSL", "true"); connectionProperties.put("ldap.maxconnections", "3"); From 71b2e552fcef7a35d5656710a7c5011ad492d658 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Sun, 22 Dec 2019 17:06:24 +0200 Subject: [PATCH 055/362] added workaround for jedis localhost bug `HostAndPort.setLocalhost("127.0.0.1");` https://github.com/GluuFederation/oxCore/issues/144 ahttps://github.com/xetorthio/jedis/issues/1367 --- .../main/java/org/gluu/service/cache/AbstractRedisProvider.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/oxService/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java b/oxService/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java index 92ea3954..24033430 100644 --- a/oxService/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java @@ -2,6 +2,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import redis.clients.jedis.HostAndPort; /** * @author yuriyz @@ -13,6 +14,7 @@ public abstract class AbstractRedisProvider { public AbstractRedisProvider(RedisConfiguration redisConfiguration) { this.redisConfiguration = redisConfiguration; + HostAndPort.setLocalhost("127.0.0.1"); } public RedisConfiguration getRedisConfiguration() { From e23b8057728162b96a8ebddfa5861fa217a6baee Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 26 Dec 2019 18:26:21 +0300 Subject: [PATCH 056/362] Fix findEntries defect #176 --- .../java/org/gluu/ldap/model/SimpleUser.java | 2 +- .../impl/LdapOperationsServiceImpl.java | 40 ++++++++++++++++--- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleUser.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleUser.java index cfcc9469..4dc9516f 100644 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleUser.java +++ b/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleUser.java @@ -23,7 +23,7 @@ * @author Yuriy Movchan * Date: 11/03/2016 */ -@DataEntry(sortBy = { "uid" }) +@DataEntry(sortBy = { "userId" }) @ObjectClass(value = "gluuPerson") public class SimpleUser implements Serializable { diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationsServiceImpl.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationsServiceImpl.java index e7b5c026..df463bff 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationsServiceImpl.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationsServiceImpl.java @@ -350,21 +350,30 @@ private SearchResult searchImpl(String dn, Filter filter, SearchScope scope, searchLimit = 100; } - boolean collectSearchResult; + boolean collectSearchResult = false; LDAPConnection ldapConnection = null; try { ldapConnection = getConnectionPool().getConnection(); ASN1OctetString cookie = null; + SimplePagedResponse simplePagedResponse = null; if (start > 0) { try { - cookie = scrollSimplePagedResultsControl(ldapConnection, dn, filter, scope, controls, start); + simplePagedResponse = scrollSimplePagedResultsControl(ldapConnection, dn, filter, scope, controls, start); + cookie = simplePagedResponse.getCookie(); } catch (InvalidSimplePageControlException ex) { throw new LDAPSearchException(ex.getResultCode(), "Failed to scroll to specified start", ex); } catch (LDAPException ex) { throw new LDAPSearchException(ex.getResultCode(), "Failed to scroll to specified start", ex); } } + + if ((cookie != null) && (cookie.getValueLength() == 0)) { + SearchResult searchResultTemp = simplePagedResponse.getLastSearchResult(); + return new SearchResult(searchResultTemp.getMessageID(), searchResultTemp.getResultCode(), searchResultTemp.getDiagnosticMessage(), + searchResultTemp.getMatchedDN(), searchResultTemp.getReferralURLs(), searchResultEntries, searchResultReferences, + searchResultEntries.size(), searchResultReferences.size(), searchResultTemp.getResponseControls()); + } do { collectSearchResult = true; @@ -431,17 +440,18 @@ private SearchResult searchImpl(String dn, Filter filter, SearchScope scope, return searchResult; } - private ASN1OctetString scrollSimplePagedResultsControl(LDAPConnection ldapConnection, String dn, Filter filter, SearchScope scope, + private SimplePagedResponse scrollSimplePagedResultsControl(LDAPConnection ldapConnection, String dn, Filter filter, SearchScope scope, Control[] controls, int start) throws LDAPException, InvalidSimplePageControlException { SearchRequest searchRequest = new SearchRequest(dn, scope, filter, "dn"); int currentStartIndex = start; ASN1OctetString cookie = null; + SearchResult searchResult = null; do { int pageSize = Math.min(currentStartIndex, 100); searchRequest.setControls(new Control[] {new SimplePagedResultsControl(pageSize, cookie, true)}); setControls(searchRequest, controls); - SearchResult searchResult = ldapConnection.search(searchRequest); + searchResult = ldapConnection.search(searchRequest); currentStartIndex -= searchResult.getEntryCount(); try { @@ -455,7 +465,7 @@ private ASN1OctetString scrollSimplePagedResultsControl(LDAPConnection ldapConne } } while ((cookie != null) && (cookie.getValueLength() > 0) && (currentStartIndex > 0)); - return cookie; + return new SimplePagedResponse(cookie, searchResult); } /* @@ -1159,6 +1169,26 @@ public int compare(T entry1, T entry2, String attributeName) { public boolean isConnected() { return connectionProvider.isConnected(); } + + private class SimplePagedResponse { + + private ASN1OctetString cookie; + private SearchResult lastSearchResult; + + public SimplePagedResponse(ASN1OctetString cookie, SearchResult lastSearchResult) { + this.cookie = cookie; + this.lastSearchResult = lastSearchResult; + } + + public ASN1OctetString getCookie() { + return cookie; + } + + public SearchResult getLastSearchResult() { + return lastSearchResult; + } + + } } From 24980f42d87452663ef47a868354a2f85374361a Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 26 Dec 2019 18:32:55 +0300 Subject: [PATCH 057/362] Fix findEntries defect #176 --- .../persist/ldap/operation/impl/LdapOperationsServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationsServiceImpl.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationsServiceImpl.java index df463bff..09003c8a 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationsServiceImpl.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationsServiceImpl.java @@ -350,7 +350,7 @@ private SearchResult searchImpl(String dn, Filter filter, SearchScope scope, searchLimit = 100; } - boolean collectSearchResult = false; + boolean collectSearchResult; LDAPConnection ldapConnection = null; try { From 3a0337c72a7873d95ab4a773446c5f30adc9d9e5 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Thu, 26 Dec 2019 17:20:55 +0100 Subject: [PATCH 058/362] Add test connection to RedisProvider --- .../java/org/gluu/service/cache/RedisProvider.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisProvider.java b/oxService/src/main/java/org/gluu/service/cache/RedisProvider.java index cca38a76..3f1b60b2 100644 --- a/oxService/src/main/java/org/gluu/service/cache/RedisProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/RedisProvider.java @@ -55,6 +55,10 @@ public void create() { } } + public void setCacheConfiguration(CacheConfiguration cacheConfiguration){ + this.cacheConfiguration=cacheConfiguration; + } + private void decryptPassword(RedisConfiguration redisConfiguration) { try { String encryptedPassword = redisConfiguration.getPassword(); @@ -67,6 +71,10 @@ private void decryptPassword(RedisConfiguration redisConfiguration) { } } + public boolean isConnected(){ + return redisProvider.isConnected(); + } + @PreDestroy public void destroy() { @@ -108,4 +116,6 @@ public CacheProviderType getProviderType() { return CacheProviderType.REDIS; } + + } From 9e89f213b49d1adccd3439fc3d3a9000c76a06f4 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Thu, 2 Jan 2020 13:28:04 +0100 Subject: [PATCH 059/362] Fix HybridEntryManager getPersistenceType method --- .../java/org/gluu/persist/hybrid/impl/HybridEntryManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java index 9b279c41..a4591595 100644 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java +++ b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java @@ -23,6 +23,7 @@ import org.gluu.persist.impl.BaseEntryManager; import org.gluu.persist.key.impl.GenericKeyConverter; import org.gluu.persist.key.impl.model.ParsedKey; +import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; import org.gluu.persist.model.AttributeData; import org.gluu.persist.model.AttributeDataModification; import org.gluu.persist.model.BatchOperation; @@ -274,8 +275,7 @@ public boolean hasBranchesSupport(String dn) { @Override public String getPersistenceType(String primaryKey) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(primaryKey); - return persistenceEntryManager.getPersistenceType(primaryKey); + return HybridEntryManagerFactory.PERSISTANCE_TYPE; } private PersistenceEntryManager getPersistenceEntryManagerByKey(String key) { From bdc25181bca55457515dc497f4e43fdd72048036 Mon Sep 17 00:00:00 2001 From: Jose G Date: Fri, 3 Jan 2020 10:33:19 -0500 Subject: [PATCH 060/362] Allow usage of class outside weld environment (otherwise NPE) --- .../main/java/org/gluu/service/cache/MemcachedProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java b/oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java index d6b8ec09..d46a450e 100644 --- a/oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java +++ b/oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java @@ -4,6 +4,7 @@ import net.spy.memcached.internal.OperationFuture; import net.spy.memcached.ops.OperationStatus; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -16,8 +17,7 @@ @ApplicationScoped public class MemcachedProvider extends AbstractCacheProvider { - @Inject - private Logger log; + private Logger log = LoggerFactory.getLogger(MemcachedProvider.class); @Inject private CacheConfiguration cacheConfiguration; From 0f3da2998dfd369f8c75e31f3ad061659dbcb153 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Tue, 7 Jan 2020 16:49:22 +0100 Subject: [PATCH 061/362] Revert persistence type --- .../org/gluu/persist/hybrid/impl/HybridEntryManager.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java index a4591595..19615f5e 100644 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java +++ b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java @@ -19,11 +19,9 @@ import org.gluu.persist.exception.KeyConversionException; import org.gluu.persist.exception.MappingException; import org.gluu.persist.exception.operation.ConfigurationException; -import org.gluu.persist.exception.operation.DeleteException; import org.gluu.persist.impl.BaseEntryManager; import org.gluu.persist.key.impl.GenericKeyConverter; import org.gluu.persist.key.impl.model.ParsedKey; -import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; import org.gluu.persist.model.AttributeData; import org.gluu.persist.model.AttributeDataModification; import org.gluu.persist.model.BatchOperation; @@ -275,7 +273,8 @@ public boolean hasBranchesSupport(String dn) { @Override public String getPersistenceType(String primaryKey) { - return HybridEntryManagerFactory.PERSISTANCE_TYPE; + PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(primaryKey); + return persistenceEntryManager.getPersistenceType(primaryKey); } private PersistenceEntryManager getPersistenceEntryManagerByKey(String key) { From 74c9ed3eab88afa6c003d72a875b0e91f383b20d Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Wed, 8 Jan 2020 17:56:35 +0100 Subject: [PATCH 062/362] Fix getSchema Method --- .../gluu/service/DataSourceTypeService.java | 24 +++++++++++++++++++ .../java/org/gluu/service/SchemaService.java | 8 ++++++- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 oxService/src/main/java/org/gluu/service/DataSourceTypeService.java diff --git a/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java b/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java new file mode 100644 index 00000000..7feede8d --- /dev/null +++ b/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java @@ -0,0 +1,24 @@ +package org.gluu.service; + +import org.gluu.persist.PersistenceEntryManager; +import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; + +import java.io.Serializable; +import javax.enterprise.context.RequestScoped; +import javax.inject.Inject; +import javax.inject.Named; + +@RequestScoped +@Named +public class DataSourceTypeService implements Serializable { + + private static final long serialVersionUID = -1941135478226842653L; + + @Inject + private PersistenceEntryManager entryManager; + + public boolean isLDAP(String key) { + return entryManager.getPersistenceType(key).equals(LdapEntryManagerFactory.PERSISTANCE_TYPE); + } + +} diff --git a/oxService/src/main/java/org/gluu/service/SchemaService.java b/oxService/src/main/java/org/gluu/service/SchemaService.java index efdb8424..d16f9da1 100644 --- a/oxService/src/main/java/org/gluu/service/SchemaService.java +++ b/oxService/src/main/java/org/gluu/service/SchemaService.java @@ -43,6 +43,12 @@ public class SchemaService { @Inject private PersistenceEntryManager ldapEntryManager; + @Inject + private DataSourceTypeService dataSourceTypeService; + + @Inject + private AttributeService attributeService; + /** * Load schema from DS * @@ -495,7 +501,7 @@ public Set getObjectClassesByAttribute(SchemaEntry schemaEntry, String a * @return DN string for DS schema */ public String getDnForSchema() { - if (ldapEntryManager.getOperationService() instanceof LdapOperationService) { + if (dataSourceTypeService.isLDAP(attributeService.getDnForAttribute(null))) { return ((LdapOperationService) ldapEntryManager.getOperationService()).getSubschemaSubentry(); } else { return ""; From 8cfc3a14bcb63c5a5a6a16537a4a9572556b60e2 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Wed, 8 Jan 2020 18:56:32 +0200 Subject: [PATCH 063/362] oxcore : removed deletable=true since it cause problems searching by example. https://github.com/GluuFederation/oxAuth/issues/1133 (cherry picked from commit fd60cb6) --- .../main/java/org/gluu/persist/model/base/DeletableEntity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java b/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java index 2a649c99..57dcdb7d 100644 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java +++ b/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java @@ -16,7 +16,7 @@ public class DeletableEntity extends BaseEntry implements Deletable { @AttributeName(name = "exp") private Date newExpirationDate; @AttributeName(name = "del") - private boolean deletable = true; + private boolean deletable; @Override public boolean isDeletable() { From 190137da3012f8a0b27fff74c143cd1e96607d12 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Wed, 8 Jan 2020 19:02:56 +0200 Subject: [PATCH 064/362] oxcore : switched deletable marker interface from primitive to object. https://github.com/GluuFederation/oxAuth/issues/1133 (cherry picked from commit 31cf48f) --- .../main/java/org/gluu/persist/model/base/Deletable.java | 2 +- .../java/org/gluu/persist/model/base/DeletableEntity.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/Deletable.java b/persistence-model/src/main/java/org/gluu/persist/model/base/Deletable.java index befa8435..b5a151ce 100644 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/Deletable.java +++ b/persistence-model/src/main/java/org/gluu/persist/model/base/Deletable.java @@ -4,5 +4,5 @@ * @author Yuriy Zabrovarnyy */ public interface Deletable { - boolean isDeletable(); + Boolean isDeletable(); } diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java b/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java index 57dcdb7d..472a49c5 100644 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java +++ b/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java @@ -16,14 +16,14 @@ public class DeletableEntity extends BaseEntry implements Deletable { @AttributeName(name = "exp") private Date newExpirationDate; @AttributeName(name = "del") - private boolean deletable; + private Boolean deletable; @Override - public boolean isDeletable() { + public Boolean isDeletable() { return deletable; } - public void setDeletable(boolean deletable) { + public void setDeletable(Boolean deletable) { this.deletable = deletable; } @@ -49,7 +49,7 @@ public boolean canDelete() { public boolean canDelete(Date now) { Date exp = expirationDate != null ? expirationDate : newExpirationDate; - return deletable && (exp == null || exp.before(now)); + return deletable != null && deletable && (exp == null || exp.before(now)); } @Override From b0a2ecee6f71e139582ed08c5eb1bdba416fad00 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Wed, 8 Jan 2020 19:25:24 +0100 Subject: [PATCH 065/362] Set correct scope --- .../src/main/java/org/gluu/service/DataSourceTypeService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java b/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java index 7feede8d..febfd2d2 100644 --- a/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java +++ b/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java @@ -4,11 +4,11 @@ import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; import java.io.Serializable; -import javax.enterprise.context.RequestScoped; +import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import javax.inject.Named; -@RequestScoped +@ApplicationScoped @Named public class DataSourceTypeService implements Serializable { From 5cb2b98c5e948558c4cb65f71fecba92bc7dc43b Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 8 Jan 2020 20:23:41 +0300 Subject: [PATCH 066/362] Add method to used operation services --- .../hybrid/impl/HybridPersistenceOperationService.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridPersistenceOperationService.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridPersistenceOperationService.java index 41e4d3a6..efef1c98 100644 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridPersistenceOperationService.java +++ b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridPersistenceOperationService.java @@ -28,4 +28,8 @@ public boolean isConnected() { return true; } + public List getPersistenceOperationServices() { + return persistenceOperationServices; + } + } From fdb64ac63d6eaef8da14f6a1194196bd937ead19 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 8 Jan 2020 20:43:10 +0300 Subject: [PATCH 067/362] Update Schema Serie to allow work in Hybrid case --- oxService/pom.xml | 5 +++ .../java/org/gluu/service/SchemaService.java | 45 ++++++++++++++----- .../hybrid/impl/HybridEntryManager.java | 4 ++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/oxService/pom.xml b/oxService/pom.xml index 16e28a1a..1970cb1a 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -51,6 +51,11 @@ org.gluu oxcore-persistence-couchbase + + + ${project.groupId} + oxcore-persistence-hybrid + ${project.version} org.gluu diff --git a/oxService/src/main/java/org/gluu/service/SchemaService.java b/oxService/src/main/java/org/gluu/service/SchemaService.java index d16f9da1..e8852807 100644 --- a/oxService/src/main/java/org/gluu/service/SchemaService.java +++ b/oxService/src/main/java/org/gluu/service/SchemaService.java @@ -20,7 +20,12 @@ import org.gluu.model.SchemaEntry; import org.gluu.persist.PersistenceEntryManager; +import org.gluu.persist.hybrid.impl.HybridEntryManager; +import org.gluu.persist.hybrid.impl.HybridPersistenceOperationService; +import org.gluu.persist.ldap.impl.LdapEntryManager; +import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; import org.gluu.persist.ldap.operation.LdapOperationService; +import org.gluu.persist.operation.PersistenceOperationService; import org.gluu.util.StringHelper; import org.gluu.util.exception.InvalidSchemaUpdateException; import org.slf4j.Logger; @@ -41,7 +46,7 @@ public class SchemaService { private Logger log; @Inject - private PersistenceEntryManager ldapEntryManager; + private PersistenceEntryManager persistenceEntryManager; @Inject private DataSourceTypeService dataSourceTypeService; @@ -57,7 +62,8 @@ public class SchemaService { public SchemaEntry getSchema() { String shemaDn = getDnForSchema(); if (StringHelper.isNotEmpty(shemaDn)) { - SchemaEntry schemaEntry = ldapEntryManager.find(getDnForSchema(), SchemaEntry.class, null); + PersistenceEntryManager ldapPersistenceEntryManager = getPersistenceEntryManager(); + SchemaEntry schemaEntry = ldapPersistenceEntryManager.find(getDnForSchema(), SchemaEntry.class, null); return schemaEntry; } @@ -87,7 +93,8 @@ public void addObjectClass(String objectClass, String attributeTypes, String sch schemaEntry.addObjectClass(objectClassDefinition); log.debug("Adding new objectClass: {}", schemaEntry); - ldapEntryManager.merge(schemaEntry); + PersistenceEntryManager ldapPersistenceEntryManager = getPersistenceEntryManager(); + ldapPersistenceEntryManager.merge(schemaEntry); } /** @@ -111,7 +118,8 @@ private void removeObjectClassWithDefinition(String objectClassDefinition) { schemaEntry.addObjectClass(objectClassDefinition); log.debug("Removing objectClass: {}", schemaEntry); - ldapEntryManager.remove(schemaEntry); + PersistenceEntryManager ldapPersistenceEntryManager = getPersistenceEntryManager(); + ldapPersistenceEntryManager.remove(schemaEntry); } /** @@ -165,7 +173,8 @@ public void addAttributeTypeToObjectClass(String objectClass, String attributeTy newSchemaEntry.addObjectClass(newObjectClassDefinition); log.debug("Adding attributeType to objectClass: {}", newSchemaEntry); - ldapEntryManager.merge(newSchemaEntry); + PersistenceEntryManager ldapPersistenceEntryManager = getPersistenceEntryManager(); + ldapPersistenceEntryManager.merge(newSchemaEntry); } /** @@ -212,7 +221,8 @@ public void removeAttributeTypeFromObjectClass(String objectClass, String attrib schemaEntry.addObjectClass(newObjectClassDefinition); log.debug("Removing attributeType from objectClass: {}", schemaEntry); - ldapEntryManager.merge(schemaEntry); + PersistenceEntryManager ldapPersistenceEntryManager = getPersistenceEntryManager(); + ldapPersistenceEntryManager.merge(schemaEntry); } @@ -231,7 +241,8 @@ public void addStringAttribute(String oid, String name, String schemaAddAttribut schemaEntry.addAttributeType(String.format(schemaAddAttributeDefinition, oid, name)); log.debug("Adding new attributeType: {}", schemaEntry); log.info("merging data"); - ldapEntryManager.merge(schemaEntry); + PersistenceEntryManager ldapPersistenceEntryManager = getPersistenceEntryManager(); + ldapPersistenceEntryManager.merge(schemaEntry); } /** @@ -251,7 +262,8 @@ public void removeStringAttribute(String attributeType) throws Exception { schemaEntry.addAttributeType(attributeTypeDefinition); log.debug("Removing attributeType: {}", schemaEntry); - ldapEntryManager.remove(schemaEntry); + PersistenceEntryManager ldapPersistenceEntryManager = getPersistenceEntryManager(); + ldapPersistenceEntryManager.remove(schemaEntry); } } @@ -501,11 +513,24 @@ public Set getObjectClassesByAttribute(SchemaEntry schemaEntry, String a * @return DN string for DS schema */ public String getDnForSchema() { - if (dataSourceTypeService.isLDAP(attributeService.getDnForAttribute(null))) { - return ((LdapOperationService) ldapEntryManager.getOperationService()).getSubschemaSubentry(); + PersistenceEntryManager ldapPersistenceEntryManager = getPersistenceEntryManager(); + if (ldapPersistenceEntryManager != null) { + return ((LdapOperationService) ldapPersistenceEntryManager.getOperationService()).getSubschemaSubentry(); } else { return ""; } } + + private PersistenceEntryManager getPersistenceEntryManager() { + if (dataSourceTypeService.isLDAP(attributeService.getDnForAttribute(null))) { + if (persistenceEntryManager instanceof HybridEntryManager) { + return ((HybridEntryManager) persistenceEntryManager).getPersistenceEntryManager(LdapEntryManagerFactory.PERSISTANCE_TYPE); + } + + return persistenceEntryManager; + } + + return null; + } } diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java index 19615f5e..4c546254 100644 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java +++ b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java @@ -412,4 +412,8 @@ protected void updateMergeChanges(String baseDn, T entry, boolean isConfigur throw new UnsupportedOperationException("Method not implemented."); } + public PersistenceEntryManager getPersistenceEntryManager(String persistanceType) { + return persistenceEntryManagers.get(persistanceType); + } + } From 0ba641eeb5fa99cd9fe2342083c912e92001bb09 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 8 Jan 2020 22:21:18 +0300 Subject: [PATCH 068/362] Add methods to allow determine entry manager persistence type and get specific sub manager --- .../gluu/service/DataSourceTypeService.java | 2 +- .../java/org/gluu/service/SchemaService.java | 10 ++++++-- .../gluu/persist/PersistenceEntryManager.java | 5 ++-- .../gluu/persist/impl/BaseEntryManager.java | 2 +- .../couchbase/impl/CouchbaseEntryManager.java | 18 ++++++++++++-- .../impl/CouchbaseEntryManagerFactory.java | 8 +++---- .../hybrid/impl/HybridEntryManager.java | 24 +++++++++++++++---- .../impl/HybridEntryManagerFactory.java | 8 +++---- .../persist/ldap/impl/LdapEntryManager.java | 19 ++++++++++++--- .../ldap/impl/LdapEntryManagerFactory.java | 8 +++---- 10 files changed, 76 insertions(+), 28 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java b/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java index febfd2d2..97b0003c 100644 --- a/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java +++ b/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java @@ -18,7 +18,7 @@ public class DataSourceTypeService implements Serializable { private PersistenceEntryManager entryManager; public boolean isLDAP(String key) { - return entryManager.getPersistenceType(key).equals(LdapEntryManagerFactory.PERSISTANCE_TYPE); + return entryManager.getPersistenceType(key).equals(LdapEntryManagerFactory.PERSISTENCE_TYPE); } } diff --git a/oxService/src/main/java/org/gluu/service/SchemaService.java b/oxService/src/main/java/org/gluu/service/SchemaService.java index e8852807..5b111d0a 100644 --- a/oxService/src/main/java/org/gluu/service/SchemaService.java +++ b/oxService/src/main/java/org/gluu/service/SchemaService.java @@ -15,17 +15,20 @@ import java.util.Set; import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Instance; import javax.inject.Inject; import javax.inject.Named; import org.gluu.model.SchemaEntry; import org.gluu.persist.PersistenceEntryManager; import org.gluu.persist.hybrid.impl.HybridEntryManager; +import org.gluu.persist.hybrid.impl.HybridEntryManagerFactory; import org.gluu.persist.hybrid.impl.HybridPersistenceOperationService; import org.gluu.persist.ldap.impl.LdapEntryManager; import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; import org.gluu.persist.ldap.operation.LdapOperationService; import org.gluu.persist.operation.PersistenceOperationService; +import org.gluu.service.cdi.util.CdiUtil; import org.gluu.util.StringHelper; import org.gluu.util.exception.InvalidSchemaUpdateException; import org.slf4j.Logger; @@ -48,6 +51,9 @@ public class SchemaService { @Inject private PersistenceEntryManager persistenceEntryManager; + @Inject + private Instance hybridEntryManagerInstance; + @Inject private DataSourceTypeService dataSourceTypeService; @@ -523,8 +529,8 @@ public String getDnForSchema() { private PersistenceEntryManager getPersistenceEntryManager() { if (dataSourceTypeService.isLDAP(attributeService.getDnForAttribute(null))) { - if (persistenceEntryManager instanceof HybridEntryManager) { - return ((HybridEntryManager) persistenceEntryManager).getPersistenceEntryManager(LdapEntryManagerFactory.PERSISTANCE_TYPE); + if (persistenceEntryManager.getPersistenceType().equals(HybridEntryManagerFactory.PERSISTENCE_TYPE)) { + return persistenceEntryManager.getPersistenceEntryManager(LdapEntryManagerFactory.PERSISTENCE_TYPE); } return persistenceEntryManager; diff --git a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java index 87a73af5..e28dc39a 100644 --- a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java @@ -17,8 +17,6 @@ import javax.persistence.Query; import org.gluu.persist.event.DeleteNotifier; -import org.gluu.persist.exception.operation.DeleteException; -import org.gluu.persist.key.impl.KeyShortcuter; import org.gluu.persist.model.AttributeData; import org.gluu.persist.model.BatchOperation; import org.gluu.persist.model.PagedResult; @@ -26,7 +24,6 @@ import org.gluu.persist.model.SortOrder; import org.gluu.persist.operation.PersistenceOperationService; import org.gluu.search.filter.Filter; -import org.gluu.util.ArrayHelper; /** * Methods which Entry Manager must provide @@ -85,6 +82,7 @@ PagedResult findPagedEntries(String primaryKey, Class entryClass, Filt void removeRecursively(String primaryKey); boolean hasBranchesSupport(String primaryKey); + String getPersistenceType(); String getPersistenceType(String primaryKey); Date decodeTime(String primaryKey, String date); @@ -107,6 +105,7 @@ Map> groupListByProperties(Class entryClass, List entries, void importEntry(String dn, List data); PersistenceOperationService getOperationService(); + PersistenceEntryManager getPersistenceEntryManager(String persistenceType); boolean destroy(); diff --git a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java index b247f30b..99992efa 100644 --- a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java @@ -1830,7 +1830,7 @@ public int getHashCode(Object entry) { return key.hashCode(); } - + protected byte[][] toBinaryValues(String[] attributeValues) { byte[][] binaryValues = new byte[attributeValues.length][]; diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java index 16113c4c..9444efb1 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java @@ -8,7 +8,6 @@ package org.gluu.persist.couchbase.impl; import java.io.Serializable; -import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -21,6 +20,7 @@ import javax.inject.Inject; +import org.gluu.persist.PersistenceEntryManager; import org.gluu.persist.annotation.AttributeName; import org.gluu.persist.couchbase.model.ConvertedExpression; import org.gluu.persist.couchbase.model.SearchReturnDataType; @@ -872,9 +872,23 @@ public boolean hasBranchesSupport(String dn) { return false; } + @Override + public String getPersistenceType() { + return CouchbaseEntryManagerFactory.PERSISTENCE_TYPE; + } + @Override public String getPersistenceType(String primaryKey) { - return CouchbaseEntryManagerFactory.PERSISTANCE_TYPE; + return CouchbaseEntryManagerFactory.PERSISTENCE_TYPE; + } + + @Override + public PersistenceEntryManager getPersistenceEntryManager(String persistenceType) { + if (CouchbaseEntryManagerFactory.PERSISTENCE_TYPE.equals(persistenceType)) { + return this; + } + + return null; } @Override diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManagerFactory.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManagerFactory.java index fd53a0db..bdc90cfd 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManagerFactory.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManagerFactory.java @@ -37,7 +37,7 @@ public class CouchbaseEntryManagerFactory extends Initializable implements Persi private static final Logger LOG = LoggerFactory.getLogger(CouchbaseEntryManagerFactory.class); - public static final String PERSISTANCE_TYPE = "couchbase"; + public static final String PERSISTENCE_TYPE = "couchbase"; private DefaultCouchbaseEnvironment.Builder builder; private CouchbaseEnvironment couchbaseEnvironment; @@ -93,13 +93,13 @@ protected void initInternal() { @Override public String getPersistenceType() { - return PERSISTANCE_TYPE; + return PERSISTENCE_TYPE; } @Override public HashMap getConfigurationFileNames() { HashMap confs = new HashMap(); - confs.put(PERSISTANCE_TYPE, "gluu-couchbase.properties"); + confs.put(PERSISTENCE_TYPE, "gluu-couchbase.properties"); return confs; } @@ -110,7 +110,7 @@ public CouchbaseEnvironment getCouchbaseEnvironment() { @Override public CouchbaseEntryManager createEntryManager(Properties conf) { - Properties entryManagerConf = PropertiesHelper.filterProperties(conf, PERSISTANCE_TYPE); + Properties entryManagerConf = PropertiesHelper.filterProperties(conf, PERSISTENCE_TYPE); // Allow proper initialization if (this.couchbaseConnectionProperties == null) { diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java index 4c546254..e9b9cede 100644 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java +++ b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java @@ -22,6 +22,7 @@ import org.gluu.persist.impl.BaseEntryManager; import org.gluu.persist.key.impl.GenericKeyConverter; import org.gluu.persist.key.impl.model.ParsedKey; +import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; import org.gluu.persist.model.AttributeData; import org.gluu.persist.model.AttributeDataModification; import org.gluu.persist.model.BatchOperation; @@ -271,12 +272,31 @@ public boolean hasBranchesSupport(String dn) { return persistenceEntryManager.hasBranchesSupport(dn); } + @Override + public String getPersistenceType() { + return HybridEntryManagerFactory.PERSISTENCE_TYPE; + } + @Override public String getPersistenceType(String primaryKey) { PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(primaryKey); return persistenceEntryManager.getPersistenceType(primaryKey); } + @Override + public PersistenceEntryManager getPersistenceEntryManager(String persistenceType) { + PersistenceEntryManager persistenceEntryManager = persistenceEntryManagers.get(persistenceType); + if (persistenceEntryManager != null) { + return persistenceEntryManager; + } + + if (HybridEntryManagerFactory.PERSISTENCE_TYPE.equals(persistenceType)) { + return this; + } + + return null; + } + private PersistenceEntryManager getPersistenceEntryManagerByKey(String key) { if ("_".equals(key)) { return defaultPersistenceEntryManager; @@ -412,8 +432,4 @@ protected void updateMergeChanges(String baseDn, T entry, boolean isConfigur throw new UnsupportedOperationException("Method not implemented."); } - public PersistenceEntryManager getPersistenceEntryManager(String persistanceType) { - return persistenceEntryManagers.get(persistanceType); - } - } diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManagerFactory.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManagerFactory.java index 21ea8d07..2a98e43d 100644 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManagerFactory.java +++ b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManagerFactory.java @@ -45,7 +45,7 @@ public class HybridEntryManagerFactory implements PersistenceEntryManagerFactory public static final String BASE_DIR; public static final String DIR = BASE_DIR + File.separator + "conf" + File.separator; - public static final String PERSISTANCE_TYPE = "hybrid"; + public static final String PERSISTENCE_TYPE = "hybrid"; public static final String PROPERTIES_FILE = "gluu-hybrid.properties"; private static final Logger LOG = LoggerFactory.getLogger(HybridEntryManagerFactory.class); @@ -59,13 +59,13 @@ public class HybridEntryManagerFactory implements PersistenceEntryManagerFactory @Override public String getPersistenceType() { - return PERSISTANCE_TYPE; + return PERSISTENCE_TYPE; } @Override public HashMap getConfigurationFileNames() { HashMap confs = new HashMap(); - confs.put(PERSISTANCE_TYPE, PROPERTIES_FILE); + confs.put(PERSISTENCE_TYPE, PROPERTIES_FILE); HashMap allConfs = getAllConfigurationFileNames(PROPERTIES_FILE); confs.putAll(allConfs); @@ -123,7 +123,7 @@ public HybridEntryManager createEntryManager(Properties conf) { сonnectionProperties.put(persistenceType, entryManagerConf); } - this.hybridMappingProperties = PropertiesHelper.filterProperties(conf, PERSISTANCE_TYPE); + this.hybridMappingProperties = PropertiesHelper.filterProperties(conf, PERSISTENCE_TYPE); HybridPersistenceOperationService hybridOperationService = new HybridPersistenceOperationService(operationServices); diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java index ce6c3ef7..2a94de7e 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java @@ -22,6 +22,7 @@ import java.util.Set; import org.apache.commons.codec.binary.Base64; +import org.gluu.persist.PersistenceEntryManager; import org.gluu.persist.event.DeleteNotifier; import org.gluu.persist.exception.AuthenticationException; import org.gluu.persist.exception.EntryDeleteException; @@ -31,7 +32,6 @@ import org.gluu.persist.exception.operation.SearchException; import org.gluu.persist.exception.operation.SearchScopeException; import org.gluu.persist.impl.BaseEntryManager; -import org.gluu.persist.ldap.operation.LdapOperationService; import org.gluu.persist.ldap.operation.impl.LdapOperationsServiceImpl; import org.gluu.persist.model.AttributeData; import org.gluu.persist.model.AttributeDataModification; @@ -41,7 +41,6 @@ import org.gluu.persist.model.PagedResult; import org.gluu.persist.model.SearchScope; import org.gluu.persist.model.SortOrder; -import org.gluu.persist.model.base.DeletableEntity; import org.gluu.persist.reflect.property.PropertyAnnotation; import org.gluu.search.filter.Filter; import org.gluu.util.ArrayHelper; @@ -910,9 +909,23 @@ public boolean hasBranchesSupport(String dn) { return true; } + @Override + public String getPersistenceType() { + return LdapEntryManagerFactory.PERSISTENCE_TYPE; + } + @Override public String getPersistenceType(String primaryKey) { - return LdapEntryManagerFactory.PERSISTANCE_TYPE; + return LdapEntryManagerFactory.PERSISTENCE_TYPE; + } + + @Override + public PersistenceEntryManager getPersistenceEntryManager(String persistenceType) { + if (LdapEntryManagerFactory.PERSISTENCE_TYPE.equals(persistenceType)) { + return this; + } + + return null; } @Override diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManagerFactory.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManagerFactory.java index ce1ffc99..02deca03 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManagerFactory.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManagerFactory.java @@ -23,27 +23,27 @@ @ApplicationScoped public class LdapEntryManagerFactory implements PersistenceEntryManagerFactory { - public static final String PERSISTANCE_TYPE = "ldap"; + public static final String PERSISTENCE_TYPE = "ldap"; public static final String LDAP_DEFAULT_PROPERTIES_FILE = "gluu-ldap.properties"; private static final Logger LOG = LoggerFactory.getLogger(LdapEntryManagerFactory.class); @Override public String getPersistenceType() { - return PERSISTANCE_TYPE; + return PERSISTENCE_TYPE; } @Override public HashMap getConfigurationFileNames() { HashMap confs = new HashMap(); - confs.put(PERSISTANCE_TYPE, LDAP_DEFAULT_PROPERTIES_FILE); + confs.put(PERSISTENCE_TYPE, LDAP_DEFAULT_PROPERTIES_FILE); return confs; } @Override public LdapEntryManager createEntryManager(Properties conf) { - Properties entryManagerConf = PropertiesHelper.filterProperties(conf, PERSISTANCE_TYPE); + Properties entryManagerConf = PropertiesHelper.filterProperties(conf, PERSISTENCE_TYPE); LdapConnectionProvider connectionProvider = new LdapConnectionProvider(entryManagerConf); if (!connectionProvider.isCreated()) { From 600bdc2faf2df4edd000874eeef45c4f17f95515 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Mon, 13 Jan 2020 09:36:17 +0100 Subject: [PATCH 069/362] Fix custom scripts --- .../java/org/gluu/model/custom/script/model/CustomScript.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/model/custom/script/model/CustomScript.java b/oxService/src/main/java/org/gluu/model/custom/script/model/CustomScript.java index 6246bc2a..9a72654e 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/model/CustomScript.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/model/CustomScript.java @@ -61,7 +61,7 @@ public class CustomScript extends BaseEntry { @JsonObject @AttributeName(name = "oxModuleProperty") - private List moduleProperties; + private List moduleProperties =new ArrayList<>(); @JsonObject @AttributeName(name = "oxConfigurationProperty") From acbe6a06bbf97b37de3a1d80dad0d41a3a9a5789 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 15 Jan 2020 19:37:35 +0300 Subject: [PATCH 070/362] Move cache services to separate module oxcore-cache --- .../main/java/org/gluu/service/cache/AbstractCacheProvider.java | 0 .../main/java/org/gluu/service/cache/AbstractRedisProvider.java | 0 .../src/main/java/org/gluu/service/cache/CacheConfiguration.java | 0 .../src/main/java/org/gluu/service/cache/CacheInterface.java | 0 .../src/main/java/org/gluu/service/cache/CacheProvider.java | 0 .../main/java/org/gluu/service/cache/CacheProviderFactory.java | 0 .../src/main/java/org/gluu/service/cache/CacheProviderType.java | 0 .../main/java/org/gluu/service/cache/InMemoryCacheProvider.java | 0 .../main/java/org/gluu/service/cache/InMemoryConfiguration.java | 0 .../src/main/java/org/gluu/service/cache/LocalCache.java | 0 .../main/java/org/gluu/service/cache/MemcachedConfiguration.java | 0 .../org/gluu/service/cache/MemcachedConnectionFactoryType.java | 0 .../src/main/java/org/gluu/service/cache/MemcachedProvider.java | 0 .../java/org/gluu/service/cache/NativePersistenceCacheEntity.java | 0 .../org/gluu/service/cache/NativePersistenceCacheProvider.java | 0 .../org/gluu/service/cache/NativePersistenceConfiguration.java | 0 .../main/java/org/gluu/service/cache/RedisClusterProvider.java | 0 .../src/main/java/org/gluu/service/cache/RedisConfiguration.java | 0 .../src/main/java/org/gluu/service/cache/RedisProvider.java | 0 .../main/java/org/gluu/service/cache/RedisProviderFactory.java | 0 .../src/main/java/org/gluu/service/cache/RedisProviderType.java | 0 .../main/java/org/gluu/service/cache/RedisSentinelProvider.java | 0 .../src/main/java/org/gluu/service/cache/RedisSetParams.java | 0 .../main/java/org/gluu/service/cache/RedisShardedProvider.java | 0 .../main/java/org/gluu/service/cache/RedisStandaloneProvider.java | 0 25 files changed, 0 insertions(+), 0 deletions(-) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/AbstractCacheProvider.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/CacheConfiguration.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/CacheInterface.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/CacheProvider.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/CacheProviderFactory.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/CacheProviderType.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/InMemoryConfiguration.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/LocalCache.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/MemcachedConfiguration.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/MemcachedConnectionFactoryType.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/MemcachedProvider.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/NativePersistenceConfiguration.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/RedisClusterProvider.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/RedisConfiguration.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/RedisProvider.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/RedisProviderFactory.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/RedisProviderType.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/RedisSetParams.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/RedisShardedProvider.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java (100%) diff --git a/oxService/src/main/java/org/gluu/service/cache/AbstractCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/AbstractCacheProvider.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/AbstractCacheProvider.java rename to core-cache/src/main/java/org/gluu/service/cache/AbstractCacheProvider.java diff --git a/oxService/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java b/core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java rename to core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java diff --git a/oxService/src/main/java/org/gluu/service/cache/CacheConfiguration.java b/core-cache/src/main/java/org/gluu/service/cache/CacheConfiguration.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/CacheConfiguration.java rename to core-cache/src/main/java/org/gluu/service/cache/CacheConfiguration.java diff --git a/oxService/src/main/java/org/gluu/service/cache/CacheInterface.java b/core-cache/src/main/java/org/gluu/service/cache/CacheInterface.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/CacheInterface.java rename to core-cache/src/main/java/org/gluu/service/cache/CacheInterface.java diff --git a/oxService/src/main/java/org/gluu/service/cache/CacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/CacheProvider.java rename to core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java diff --git a/oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java b/core-cache/src/main/java/org/gluu/service/cache/CacheProviderFactory.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/CacheProviderFactory.java rename to core-cache/src/main/java/org/gluu/service/cache/CacheProviderFactory.java diff --git a/oxService/src/main/java/org/gluu/service/cache/CacheProviderType.java b/core-cache/src/main/java/org/gluu/service/cache/CacheProviderType.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/CacheProviderType.java rename to core-cache/src/main/java/org/gluu/service/cache/CacheProviderType.java diff --git a/oxService/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java rename to core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java diff --git a/oxService/src/main/java/org/gluu/service/cache/InMemoryConfiguration.java b/core-cache/src/main/java/org/gluu/service/cache/InMemoryConfiguration.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/InMemoryConfiguration.java rename to core-cache/src/main/java/org/gluu/service/cache/InMemoryConfiguration.java diff --git a/oxService/src/main/java/org/gluu/service/cache/LocalCache.java b/core-cache/src/main/java/org/gluu/service/cache/LocalCache.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/LocalCache.java rename to core-cache/src/main/java/org/gluu/service/cache/LocalCache.java diff --git a/oxService/src/main/java/org/gluu/service/cache/MemcachedConfiguration.java b/core-cache/src/main/java/org/gluu/service/cache/MemcachedConfiguration.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/MemcachedConfiguration.java rename to core-cache/src/main/java/org/gluu/service/cache/MemcachedConfiguration.java diff --git a/oxService/src/main/java/org/gluu/service/cache/MemcachedConnectionFactoryType.java b/core-cache/src/main/java/org/gluu/service/cache/MemcachedConnectionFactoryType.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/MemcachedConnectionFactoryType.java rename to core-cache/src/main/java/org/gluu/service/cache/MemcachedConnectionFactoryType.java diff --git a/oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java b/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/MemcachedProvider.java rename to core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java rename to core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java rename to core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java diff --git a/oxService/src/main/java/org/gluu/service/cache/NativePersistenceConfiguration.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceConfiguration.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/NativePersistenceConfiguration.java rename to core-cache/src/main/java/org/gluu/service/cache/NativePersistenceConfiguration.java diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisClusterProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/RedisClusterProvider.java rename to core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisConfiguration.java b/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/RedisConfiguration.java rename to core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/RedisProvider.java rename to core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisProviderFactory.java b/core-cache/src/main/java/org/gluu/service/cache/RedisProviderFactory.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/RedisProviderFactory.java rename to core-cache/src/main/java/org/gluu/service/cache/RedisProviderFactory.java diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisProviderType.java b/core-cache/src/main/java/org/gluu/service/cache/RedisProviderType.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/RedisProviderType.java rename to core-cache/src/main/java/org/gluu/service/cache/RedisProviderType.java diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java rename to core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisSetParams.java b/core-cache/src/main/java/org/gluu/service/cache/RedisSetParams.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/RedisSetParams.java rename to core-cache/src/main/java/org/gluu/service/cache/RedisSetParams.java diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisShardedProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/RedisShardedProvider.java rename to core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java diff --git a/oxService/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java rename to core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java From 144a120e6bcc09155c2424568a8ae88aab4e620e Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 15 Jan 2020 19:38:01 +0300 Subject: [PATCH 071/362] Move cache services to separate module oxcore-cache --- core-cache/pom.xml | 173 ++++++++++++++++++ .../src/main/resources/META-INF/beans.xml | 7 + oxService/pom.xml | 5 + pom.xml | 1 + 4 files changed, 186 insertions(+) create mode 100644 core-cache/pom.xml create mode 100644 core-cache/src/main/resources/META-INF/beans.xml diff --git a/core-cache/pom.xml b/core-cache/pom.xml new file mode 100644 index 00000000..9aa63233 --- /dev/null +++ b/core-cache/pom.xml @@ -0,0 +1,173 @@ + + + 4.0.0 + org.gluu + oxcore-cache + Caches support + + + org.gluu + oxcore + 4.1.0.Final + + + + ${maven.min-version} + + + + + + src/main/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + src/test/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + + + + ${project.groupId} + oxcore-model + ${project.version} + + + ${project.groupId} + oxcore-persistence-ldap + ${project.version} + + + ${project.groupId} + oxcore-persistence-couchbase + ${project.version} + + + ${project.groupId} + oxcore-persistence-hybrid + ${project.version} + + + ${project.groupId} + oxcore-util + ${project.version} + + + + + javax.enterprise + cdi-api + provided + + + com.sun.faces + jsf-api + provided + + + javax.servlet + javax.servlet-api + provided + + + org.jboss.weld + weld-core-impl + provided + + + + javax.inject + javax.inject + + + javax.validation + validation-api + + + + org.jboss.spec.javax.ejb + jboss-ejb-api_3.2_spec + provided + + + + com.sun.faces + jsf-impl + provided + + + + org.glassfish.web + el-impl + provided + + + + + org.python + jython-standalone + + + + + net.spy + spymemcached + + + redis.clients + jedis + + + net.jodah + expiringmap + + + + + io.dropwizard.metrics + metrics-core + + + + + com.google.guava + guava + ${guava.version} + + + + + org.quartz-scheduler + quartz + + + + + org.testng + testng + + + + + javax.mail + mail + + + + \ No newline at end of file diff --git a/core-cache/src/main/resources/META-INF/beans.xml b/core-cache/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000..2f4f7e27 --- /dev/null +++ b/core-cache/src/main/resources/META-INF/beans.xml @@ -0,0 +1,7 @@ + + + diff --git a/oxService/pom.xml b/oxService/pom.xml index 1970cb1a..81321b76 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -61,6 +61,11 @@ org.gluu oxcore-util + + ${project.groupId} + oxcore-cache + ${project.version} + diff --git a/pom.xml b/pom.xml index c3d59f9b..f65ed2aa 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,7 @@ persistence-couchbase-sample oxModel oxSaml + core-cache oxService server oxJsfUtil From f0504c2d4d75087546ba64441270898e50eab49b Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 15 Jan 2020 20:08:14 +0300 Subject: [PATCH 072/362] Fix version in cache module --- core-cache/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-cache/pom.xml b/core-cache/pom.xml index 9aa63233..2b775329 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.1.0.Final + 4.2.0-SNAPSHOT From 5c09dc4e99a0ae4fb159fdb2a4381bbd035dd240 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 15 Jan 2020 20:18:37 +0300 Subject: [PATCH 073/362] Remove unused dependencies --- core-cache/pom.xml | 92 +--------------------------------------------- 1 file changed, 2 insertions(+), 90 deletions(-) diff --git a/core-cache/pom.xml b/core-cache/pom.xml index 2b775329..32e99cb6 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -45,84 +45,21 @@ ${project.groupId} - oxcore-model - ${project.version} - - - ${project.groupId} - oxcore-persistence-ldap - ${project.version} - - - ${project.groupId} - oxcore-persistence-couchbase - ${project.version} - - - ${project.groupId} - oxcore-persistence-hybrid - ${project.version} - - - ${project.groupId} - oxcore-util + oxcore-persistence-core ${project.version} - + javax.enterprise cdi-api provided - - com.sun.faces - jsf-api - provided - - - javax.servlet - javax.servlet-api - provided - - - org.jboss.weld - weld-core-impl - provided - javax.inject javax.inject - - javax.validation - validation-api - - - - org.jboss.spec.javax.ejb - jboss-ejb-api_3.2_spec - provided - - - - com.sun.faces - jsf-impl - provided - - - - org.glassfish.web - el-impl - provided - - - - - org.python - jython-standalone - @@ -138,36 +75,11 @@ expiringmap - - - io.dropwizard.metrics - metrics-core - - - - - com.google.guava - guava - ${guava.version} - - - - - org.quartz-scheduler - quartz - - org.testng testng - - - - javax.mail - mail - \ No newline at end of file From 1b8fa9b042afa967e730ab1b9113fb997071a809 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 15 Jan 2020 23:00:05 +0300 Subject: [PATCH 074/362] Add StandaloneCacheProviderFactory --- .../service/cache/AbstractRedisProvider.java | 3 - .../service/cache/CacheConfiguration.java | 5 +- .../service/cache/CacheProviderFactory.java | 4 +- .../service/cache/InMemoryCacheProvider.java | 28 ++++--- .../service/cache/InMemoryConfiguration.java | 5 +- .../service/cache/MemcachedConfiguration.java | 4 +- .../gluu/service/cache/MemcachedProvider.java | 25 +++++-- .../cache/NativePersistenceCacheEntity.java | 10 +-- .../cache/NativePersistenceCacheProvider.java | 41 +++++++---- .../cache/NativePersistenceConfiguration.java | 7 +- .../service/cache/RedisClusterProvider.java | 11 +-- .../service/cache/RedisConfiguration.java | 4 +- .../org/gluu/service/cache/RedisProvider.java | 15 +++- .../service/cache/RedisProviderFactory.java | 17 +++-- .../service/cache/RedisSentinelProvider.java | 10 ++- .../service/cache/RedisShardedProvider.java | 14 ++-- .../cache/RedisStandaloneProvider.java | 16 ++-- .../cache/StandaloneCacheProviderFactory.java | 73 +++++++++++++++++++ 18 files changed, 209 insertions(+), 83 deletions(-) create mode 100644 core-cache/src/main/java/org/gluu/service/cache/StandaloneCacheProviderFactory.java diff --git a/core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java b/core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java index 24033430..79155656 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java @@ -1,14 +1,11 @@ package org.gluu.service.cache; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import redis.clients.jedis.HostAndPort; /** * @author yuriyz */ public abstract class AbstractRedisProvider { - private final static Logger LOG = LoggerFactory.getLogger(AbstractRedisProvider.class); protected RedisConfiguration redisConfiguration; diff --git a/core-cache/src/main/java/org/gluu/service/cache/CacheConfiguration.java b/core-cache/src/main/java/org/gluu/service/cache/CacheConfiguration.java index 1513e8e0..ca77e416 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/CacheConfiguration.java +++ b/core-cache/src/main/java/org/gluu/service/cache/CacheConfiguration.java @@ -1,9 +1,10 @@ package org.gluu.service.cache; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.io.Serializable; import javax.enterprise.inject.Vetoed; -import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; /** diff --git a/core-cache/src/main/java/org/gluu/service/cache/CacheProviderFactory.java b/core-cache/src/main/java/org/gluu/service/cache/CacheProviderFactory.java index f6871c18..cc445260 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/CacheProviderFactory.java +++ b/core-cache/src/main/java/org/gluu/service/cache/CacheProviderFactory.java @@ -1,7 +1,5 @@ package org.gluu.service.cache; -import org.slf4j.Logger; - import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Any; import javax.enterprise.inject.Instance; @@ -9,6 +7,8 @@ import javax.inject.Inject; import javax.inject.Named; +import org.slf4j.Logger; + /** * @author yuriyz on 02/21/2017. */ diff --git a/core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java index f742a051..69444a6c 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java @@ -1,15 +1,17 @@ package org.gluu.service.cache; -import net.jodah.expiringmap.ExpirationPolicy; -import net.jodah.expiringmap.ExpiringMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.util.concurrent.TimeUnit; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; -import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; /** * @author yuriyz on 02/21/2017. @@ -18,7 +20,8 @@ @ApplicationScoped public class InMemoryCacheProvider extends AbstractCacheProvider { - private static final Logger LOG = LoggerFactory.getLogger(InMemoryCacheProvider.class); + @Inject + private Logger log; @Inject private CacheConfiguration cacheConfiguration; @@ -36,23 +39,28 @@ public void init() { } public void create() { - LOG.debug("Starting InMemoryCacheProvider ..."); + log.debug("Starting InMemoryCacheProvider ..."); try { map = ExpiringMap.builder().expirationPolicy(ExpirationPolicy.CREATED).variableExpiration().build(); - LOG.debug("InMemoryCacheProvider started."); + log.debug("InMemoryCacheProvider started."); } catch (Exception e) { throw new IllegalStateException("Error starting InMemoryCacheProvider", e); } } + public void configure(CacheConfiguration cacheConfiguration) { + this.log = LoggerFactory.getLogger(InMemoryCacheProvider.class); + this.cacheConfiguration = cacheConfiguration; + } + @PreDestroy public void destroy() { - LOG.debug("Destroying InMemoryCacheProvider"); + log.debug("Destroying InMemoryCacheProvider"); map.clear(); - LOG.debug("Destroyed InMemoryCacheProvider"); + log.debug("Destroyed InMemoryCacheProvider"); } @Override diff --git a/core-cache/src/main/java/org/gluu/service/cache/InMemoryConfiguration.java b/core-cache/src/main/java/org/gluu/service/cache/InMemoryConfiguration.java index 13b499fc..84ae8756 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/InMemoryConfiguration.java +++ b/core-cache/src/main/java/org/gluu/service/cache/InMemoryConfiguration.java @@ -1,9 +1,10 @@ package org.gluu.service.cache; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.io.Serializable; import javax.xml.bind.annotation.XmlElement; -import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; /** diff --git a/core-cache/src/main/java/org/gluu/service/cache/MemcachedConfiguration.java b/core-cache/src/main/java/org/gluu/service/cache/MemcachedConfiguration.java index 4c1f8dc8..ce91b434 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/MemcachedConfiguration.java +++ b/core-cache/src/main/java/org/gluu/service/cache/MemcachedConfiguration.java @@ -1,9 +1,9 @@ package org.gluu.service.cache; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - import java.io.Serializable; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + /** * @author yuriyz on 02/02/2017. diff --git a/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java b/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java index d46a450e..2128916c 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java @@ -1,23 +1,29 @@ package org.gluu.service.cache; -import net.spy.memcached.*; -import net.spy.memcached.internal.OperationFuture; -import net.spy.memcached.ops.OperationStatus; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.spy.memcached.AddrUtil; +import net.spy.memcached.BinaryConnectionFactory; +import net.spy.memcached.ConnectionFactory; +import net.spy.memcached.DefaultConnectionFactory; +import net.spy.memcached.MemcachedClient; +import net.spy.memcached.internal.OperationFuture; +import net.spy.memcached.ops.OperationStatus; + /** * @author yuriyz on 02/02/2017. */ @ApplicationScoped public class MemcachedProvider extends AbstractCacheProvider { - private Logger log = LoggerFactory.getLogger(MemcachedProvider.class); + @Inject + private Logger log; @Inject private CacheConfiguration cacheConfiguration; @@ -58,6 +64,11 @@ public void create() { } } + public void configure(CacheConfiguration cacheConfiguration) { + this.log = LoggerFactory.getLogger(InMemoryCacheProvider.class); + this.cacheConfiguration = cacheConfiguration; + } + private void testConnection() { put(2, "connectionTest", "connectionTestValue"); if (!"connectionTestValue".equals(get("connectionTest"))) { diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java index 98e24d80..d0cc1655 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java @@ -1,14 +1,14 @@ package org.gluu.service.cache; -import org.gluu.persist.model.base.Deletable; -import org.gluu.persist.model.base.DeletableEntity; +import java.io.Serializable; +import java.util.Date; + import org.gluu.persist.annotation.AttributeName; import org.gluu.persist.annotation.DN; import org.gluu.persist.annotation.DataEntry; import org.gluu.persist.annotation.ObjectClass; - -import java.io.Serializable; -import java.util.Date; +import org.gluu.persist.model.base.Deletable; +import org.gluu.persist.model.base.DeletableEntity; @DataEntry @ObjectClass(value = "cache") diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index fa592535..1ef05244 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -1,5 +1,16 @@ package org.gluu.service.cache; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Calendar; +import java.util.Date; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; @@ -10,19 +21,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.enterprise.context.ApplicationScoped; -import javax.inject.Inject; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.Calendar; -import java.util.Date; - @ApplicationScoped public class NativePersistenceCacheProvider extends AbstractCacheProvider { - private final static Logger log = LoggerFactory.getLogger(NativePersistenceCacheProvider.class); + @Inject + private Logger log; @Inject private CacheConfiguration cacheConfiguration; @@ -34,6 +37,10 @@ public class NativePersistenceCacheProvider extends AbstractCacheProvider getCacheProvider(CacheConfiguration cacheConfiguration) { + CacheProviderType cacheProviderType = cacheConfiguration.getCacheProviderType(); + + if (cacheProviderType == null) { + LOG.error("Failed to initialize cacheProvider, cacheProviderType is null. Fallback to IN_MEMORY type."); + cacheProviderType = CacheProviderType.IN_MEMORY; + } + + // Create bean + AbstractCacheProvider cacheProvider = null; + switch (cacheProviderType) { + case IN_MEMORY: + InMemoryCacheProvider inMemoryCacheProvider = new InMemoryCacheProvider(); + inMemoryCacheProvider.configure(cacheConfiguration); + inMemoryCacheProvider.init(); + + cacheProvider = inMemoryCacheProvider; + break; + case MEMCACHED: + MemcachedProvider memcachedProvider = new MemcachedProvider(); + memcachedProvider.configure(cacheConfiguration); + memcachedProvider.init(); + + cacheProvider = memcachedProvider; + break; + case REDIS: + RedisProvider redisProvider = new RedisProvider(); + redisProvider.configure(cacheConfiguration, stringEncrypter); + redisProvider.init(); + + cacheProvider = redisProvider; + break; + case NATIVE_PERSISTENCE: + NativePersistenceCacheProvider nativePersistenceCacheProvider = new NativePersistenceCacheProvider(); + nativePersistenceCacheProvider.configure(cacheConfiguration, entryManager); + nativePersistenceCacheProvider.init(); + + cacheProvider = nativePersistenceCacheProvider; + break; + } + + if (cacheProvider == null) { + throw new RuntimeException("Failed to initialize cacheProvider, cacheProviderType is unsupported: " + cacheProviderType); + } + + cacheProvider.create(); + + return cacheProvider; + } + +} From ab440d811be8427f540ae94ebb005fc1950a5101 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 15 Jan 2020 23:07:11 +0300 Subject: [PATCH 075/362] Fix log initialization --- .../src/main/java/org/gluu/service/cache/MemcachedProvider.java | 2 +- .../org/gluu/service/cache/NativePersistenceCacheProvider.java | 2 +- .../src/main/java/org/gluu/service/cache/RedisProvider.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java b/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java index 2128916c..8730af12 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java @@ -65,7 +65,7 @@ public void create() { } public void configure(CacheConfiguration cacheConfiguration) { - this.log = LoggerFactory.getLogger(InMemoryCacheProvider.class); + this.log = LoggerFactory.getLogger(MemcachedProvider.class); this.cacheConfiguration = cacheConfiguration; } diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index 1ef05244..cbe4590d 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -74,7 +74,7 @@ public void create() { } public void configure(CacheConfiguration cacheConfiguration, PersistenceEntryManager entryManager) { - this.log = LoggerFactory.getLogger(InMemoryCacheProvider.class); + this.log = LoggerFactory.getLogger(NativePersistenceCacheProvider.class); this.cacheConfiguration = cacheConfiguration; this.entryManager = entryManager; } diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java index b21cbd92..d4013d30 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java @@ -57,7 +57,7 @@ public void create() { } public void configure(CacheConfiguration cacheConfiguration, StringEncrypter stringEncrypter) { - this.log = LoggerFactory.getLogger(InMemoryCacheProvider.class); + this.log = LoggerFactory.getLogger(RedisProvider.class); this.cacheConfiguration = cacheConfiguration; this.stringEncrypter = stringEncrypter; } From 65ef236fd553442fb221b3759b2b8d5990e698a2 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 21 Jan 2020 10:54:00 +0300 Subject: [PATCH 076/362] Add reusable oxcore-standalone library to allow load CE configuration from DB --- .gitignore | 3 + .../cache/StandaloneCacheProviderFactory.java | 8 + core-standalone/pom.xml | 68 ++++ .../org/gluu/conf/model/AppConfiguration.java | 101 ++++++ .../conf/model/AppConfigurationEntry.java | 63 ++++ .../conf/model/ClaimToAttributeMapping.java | 53 +++ .../conf/model/SharedConfigurationEntry.java | 125 +++++++ .../conf/service/ConfigurationFactory.java | 316 ++++++++++++++++++ .../service/DummyConfigurationFactory.java | 27 ++ .../DummyConfigurationFactoryTest.java | 34 ++ .../CouchbaseNativeBenchmarkCacheTest.java | 4 +- .../cache/CouchbaseNativeCacheTest.java | 4 +- .../cache/InMemoryCacheProviderTest.java | 3 +- persistence-standalone/pom.xml | 12 +- .../StandalonePersistanceFactoryService.java | 1 - pom.xml | 1 + 16 files changed, 807 insertions(+), 16 deletions(-) create mode 100644 core-standalone/pom.xml create mode 100644 core-standalone/src/main/java/org/gluu/conf/model/AppConfiguration.java create mode 100644 core-standalone/src/main/java/org/gluu/conf/model/AppConfigurationEntry.java create mode 100644 core-standalone/src/main/java/org/gluu/conf/model/ClaimToAttributeMapping.java create mode 100644 core-standalone/src/main/java/org/gluu/conf/model/SharedConfigurationEntry.java create mode 100644 core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java create mode 100644 core-standalone/src/test/java/org/gluu/conf/service/DummyConfigurationFactory.java create mode 100644 core-standalone/src/test/java/org/gluu/conf/service/DummyConfigurationFactoryTest.java diff --git a/.gitignore b/.gitignore index be91110e..56bbf5c9 100644 --- a/.gitignore +++ b/.gitignore @@ -11,5 +11,8 @@ # Maven target +# Test +test-output + # Visual Studio Code project files *.factorypath \ No newline at end of file diff --git a/core-cache/src/main/java/org/gluu/service/cache/StandaloneCacheProviderFactory.java b/core-cache/src/main/java/org/gluu/service/cache/StandaloneCacheProviderFactory.java index cee3582a..f8b79373 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/StandaloneCacheProviderFactory.java +++ b/core-cache/src/main/java/org/gluu/service/cache/StandaloneCacheProviderFactory.java @@ -46,6 +46,10 @@ public CacheProvider getCacheProvider(CacheConfiguration cacheConfiguration) cacheProvider = memcachedProvider; break; case REDIS: + if (stringEncrypter == null) { + throw new RuntimeException("Factory is not initialized properly. stringEncrypter is not specified"); + } + RedisProvider redisProvider = new RedisProvider(); redisProvider.configure(cacheConfiguration, stringEncrypter); redisProvider.init(); @@ -53,6 +57,10 @@ public CacheProvider getCacheProvider(CacheConfiguration cacheConfiguration) cacheProvider = redisProvider; break; case NATIVE_PERSISTENCE: + if (entryManager == null) { + throw new RuntimeException("Factory is not initialized properly. entryManager is not specified"); + } + NativePersistenceCacheProvider nativePersistenceCacheProvider = new NativePersistenceCacheProvider(); nativePersistenceCacheProvider.configure(cacheConfiguration, entryManager); nativePersistenceCacheProvider.init(); diff --git a/core-standalone/pom.xml b/core-standalone/pom.xml new file mode 100644 index 00000000..fa1bafca --- /dev/null +++ b/core-standalone/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + org.gluu + oxcore-standalone + Configuration factories for standalone applications + + + org.gluu + oxcore + 4.1.0.Final + + + + ${maven.min-version} + + + + + + src/main/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + src/test/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + + + org.gluu + oxcore-persistence-cdi + ${project.version} + + + org.gluu + oxcore-cache + ${project.version} + + + org.gluu + oxcore-persistence-standalone + ${project.version} + + + + + org.testng + testng + + + + \ No newline at end of file diff --git a/core-standalone/src/main/java/org/gluu/conf/model/AppConfiguration.java b/core-standalone/src/main/java/org/gluu/conf/model/AppConfiguration.java new file mode 100644 index 00000000..c6f8cf76 --- /dev/null +++ b/core-standalone/src/main/java/org/gluu/conf/model/AppConfiguration.java @@ -0,0 +1,101 @@ +/* + * oxTrust is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.conf.model; + +import java.io.Serializable; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + + +/** + * Base application configuration + * + * @author Yuriy Movchan + * @version 0.1, 11/02/2015 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class AppConfiguration implements Serializable { + + private static final long serialVersionUID = -587414854758989561L; + + private String applicationName; + private String openIdProviderUrl; + private String openIdClientId; + private String openIdClientPassword; + private List openIdScopes; + private String openIdRedirectUrl; + + private String openIdPostLogoutRedirectUri; + + private List openIdClaimMapping; + + public String getApplicationName() { + return applicationName; + } + + public void setApplicationName(String applicationName) { + this.applicationName = applicationName; + } + + public String getOpenIdProviderUrl() { + return openIdProviderUrl; + } + + public void setOpenIdProviderUrl(String openIdProviderUrl) { + this.openIdProviderUrl = openIdProviderUrl; + } + + public String getOpenIdClientId() { + return openIdClientId; + } + + public void setOpenIdClientId(String openIdClientId) { + this.openIdClientId = openIdClientId; + } + + public String getOpenIdClientPassword() { + return openIdClientPassword; + } + + public void setOpenIdClientPassword(String openIdClientPassword) { + this.openIdClientPassword = openIdClientPassword; + } + + public List getOpenIdScopes() { + return openIdScopes; + } + + public void setOpenIdScopes(List openIdScopes) { + this.openIdScopes = openIdScopes; + } + + public String getOpenIdRedirectUrl() { + return openIdRedirectUrl; + } + + public void setOpenIdRedirectUrl(String openIdRedirectUrl) { + this.openIdRedirectUrl = openIdRedirectUrl; + } + + public List getOpenIdClaimMapping() { + return openIdClaimMapping; + } + + public void setOpenIdClaimMapping(List openIdClaimMapping) { + this.openIdClaimMapping = openIdClaimMapping; + } + + public String getOpenIdPostLogoutRedirectUri() { + return openIdPostLogoutRedirectUri; + } + + public void setOpenIdPostLogoutRedirectUri(String openIdPostLogoutRedirectUri) { + this.openIdPostLogoutRedirectUri = openIdPostLogoutRedirectUri; + } + +} diff --git a/core-standalone/src/main/java/org/gluu/conf/model/AppConfigurationEntry.java b/core-standalone/src/main/java/org/gluu/conf/model/AppConfigurationEntry.java new file mode 100644 index 00000000..b183d3e1 --- /dev/null +++ b/core-standalone/src/main/java/org/gluu/conf/model/AppConfigurationEntry.java @@ -0,0 +1,63 @@ +/* + * oxTrust is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.conf.model; + +import java.io.Serializable; + +import org.gluu.persist.annotation.AttributeName; +import org.gluu.persist.annotation.DN; +import org.gluu.persist.annotation.DataEntry; +import org.gluu.persist.annotation.JsonObject; +import org.gluu.persist.annotation.ObjectClass; + +/** + * @author Yuriy Movchan + * @version 0.1, 03/25/2016 + */ +@DataEntry +@ObjectClass(value = "oxApplicationConfiguration") +public class AppConfigurationEntry implements Serializable { + + private static final long serialVersionUID = 1847361642302974184L; + + @DN + private String dn; + + @AttributeName(name = "oxRevision") + private long revision; + + @JsonObject + @AttributeName(name = "oxConfApplication") + private AppConfiguration application; + + public AppConfigurationEntry() {} + + public String getDn() { + return dn; + } + + public void setDn(String dn) { + this.dn = dn; + } + + public long getRevision() { + return revision; + } + + public void setRevision(long revision) { + this.revision = revision; + } + + public AppConfiguration getApplication() { + return application; + } + + public void setApplication(AppConfiguration application) { + this.application = application; + } + +} diff --git a/core-standalone/src/main/java/org/gluu/conf/model/ClaimToAttributeMapping.java b/core-standalone/src/main/java/org/gluu/conf/model/ClaimToAttributeMapping.java new file mode 100644 index 00000000..b9f0512d --- /dev/null +++ b/core-standalone/src/main/java/org/gluu/conf/model/ClaimToAttributeMapping.java @@ -0,0 +1,53 @@ +/* + * oxTrust is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +/** + * CAS oxAuth application configuration + * + * @author Yuriy Movchan + * @version 0.1, 03/25/2016 + */ +package org.gluu.conf.model; + +import java.io.Serializable; + +/** + * Claim to attribute mapping + * + * @author Yuriy Movchan + * @version 0.1, 03/25/2016 + */ +public class ClaimToAttributeMapping implements Serializable { + + private static final long serialVersionUID = 3450326508968717097L; + + private String claim; + private String attribute; + + public String getClaim() { + return claim; + } + + public void setClaim(String claim) { + this.claim = claim; + } + + public String getAttribute() { + return attribute; + } + + public void setAttribute(String attribute) { + this.attribute = attribute; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("ClaimToAttributeMapping [claim=").append(claim).append(", attribute=").append(attribute).append("]"); + return builder.toString(); + } + +} diff --git a/core-standalone/src/main/java/org/gluu/conf/model/SharedConfigurationEntry.java b/core-standalone/src/main/java/org/gluu/conf/model/SharedConfigurationEntry.java new file mode 100644 index 00000000..77956a2b --- /dev/null +++ b/core-standalone/src/main/java/org/gluu/conf/model/SharedConfigurationEntry.java @@ -0,0 +1,125 @@ +/* + * oxTrust is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.conf.model; + +import java.io.Serializable; +import java.util.Date; + +import org.gluu.model.SmtpConfiguration; +import org.gluu.persist.annotation.AttributeName; +import org.gluu.persist.annotation.CustomObjectClass; +import org.gluu.persist.annotation.DataEntry; +import org.gluu.persist.annotation.JsonObject; +import org.gluu.persist.annotation.ObjectClass; +import org.gluu.persist.model.base.InumEntry; +import org.gluu.service.cache.CacheConfiguration; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * GluuConfiguration + * + * @author Yuriy Movchan Date: 01/21/2020 + */ +@DataEntry +@ObjectClass(value = "gluuConfiguration") +@JsonIgnoreProperties(ignoreUnknown = true) +public class SharedConfigurationEntry extends InumEntry implements Serializable { + + private static final long serialVersionUID = -1817003894646725601L; + + @AttributeName + private String description; + + @AttributeName + private String displayName; + + @AttributeName(name = "gluuLastUpdate", updateOnly = true) + private Date lastUpdate; + + @AttributeName(name = "gluuConfigurationPollingInterval") + private String pollingInterval; + + @AttributeName(name = "oxTrustEmail") + private String contactEmail; + + @AttributeName(name = "oxSmtpConfiguration") + @JsonObject + private SmtpConfiguration smtpConfiguration; + + @AttributeName(name = "oxCacheConfiguration") + @JsonObject + private CacheConfiguration cacheConfiguration; + + @CustomObjectClass + private String[] customObjectClasses; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public Date getLastUpdate() { + return lastUpdate; + } + + public void setLastUpdate(Date lastUpdate) { + this.lastUpdate = lastUpdate; + } + + public String getPollingInterval() { + return pollingInterval; + } + + public void setPollingInterval(String pollingInterval) { + this.pollingInterval = pollingInterval; + } + + public String getContactEmail() { + return contactEmail; + } + + public void setContactEmail(String contactEmail) { + this.contactEmail = contactEmail; + } + + public SmtpConfiguration getSmtpConfiguration() { + return smtpConfiguration; + } + + public void setSmtpConfiguration(SmtpConfiguration smtpConfiguration) { + this.smtpConfiguration = smtpConfiguration; + } + + public CacheConfiguration getCacheConfiguration() { + return cacheConfiguration; + } + + public void setCacheConfiguration(CacheConfiguration cacheConfiguration) { + this.cacheConfiguration = cacheConfiguration; + } + + public String[] getCustomObjectClasses() { + return customObjectClasses; + } + + public void setCustomObjectClasses(String[] customObjectClasses) { + this.customObjectClasses = customObjectClasses; + } + +} \ No newline at end of file diff --git a/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java b/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java new file mode 100644 index 00000000..df16a390 --- /dev/null +++ b/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java @@ -0,0 +1,316 @@ +/* + * oxTrust is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.conf.service; + +import java.io.File; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.apache.commons.lang.StringUtils; +import org.gluu.conf.model.AppConfiguration; +import org.gluu.conf.model.AppConfigurationEntry; +import org.gluu.conf.model.SharedConfigurationEntry; +import org.gluu.persist.PersistenceEntryManager; +import org.gluu.persist.PersistenceEntryManagerFactory; +import org.gluu.persist.exception.BasePersistenceException; +import org.gluu.persist.model.PersistenceConfiguration; +import org.gluu.persist.service.PersistanceFactoryService; +import org.gluu.persist.service.StandalonePersistanceFactoryService; +import org.gluu.service.cache.CacheConfiguration; +import org.gluu.service.cache.InMemoryConfiguration; +import org.gluu.util.StringHelper; +import org.gluu.util.exception.ConfigurationException; +import org.gluu.util.properties.FileConfiguration; +import org.gluu.util.security.PropertiesDecrypter; +import org.gluu.util.security.StringEncrypter; +import org.gluu.util.security.StringEncrypter.EncryptionException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Base OpenId configuration + * + * @author Yuriy Movchan + * @version 0.1, 11/02/2015 + */ +public abstract class ConfigurationFactory { + + private final Logger LOG = LoggerFactory.getLogger(ConfigurationFactory.class); + + static { + if (System.getProperty("gluu.base") != null) { + BASE_DIR = System.getProperty("gluu.base"); + } else if ((System.getProperty("catalina.base") != null) && (System.getProperty("catalina.base.ignore") == null)) { + BASE_DIR = System.getProperty("catalina.base"); + } else if (System.getProperty("catalina.home") != null) { + BASE_DIR = System.getProperty("catalina.home"); + } else if (System.getProperty("jboss.home.dir") != null) { + BASE_DIR = System.getProperty("jboss.home.dir"); + } else { + BASE_DIR = null; + } + } + + public static final String BASE_DIR; + public static final String DIR = BASE_DIR + File.separator + "conf" + File.separator; + + private static final String BASE_PROPERTIES_FILE = DIR + "gluu.properties"; + public static final String DEFAULT_PROPERTIES_FILE = DIR + "openid.properties"; + + private static final String SALT_FILE_NAME = "salt"; + + private static final String SHARED_CONFIGURATION_DN = "ou=configuration,o=gluu"; + + private String confDir, saltFilePath; + + private FileConfiguration baseConfiguration; + + private C appConfiguration; + + private PersistanceFactoryService persistanceFactoryService; + private PersistenceConfiguration persistenceConfiguration; + + private String cryptoConfigurationSalt; + + private PersistenceEntryManager persistenceEntryManager; + + @SuppressWarnings("unused") + private long baseConfigurationFileLastModifiedTime; + + private boolean loaded = false; + private long loadedRevision = -1; + + private AtomicBoolean isActive; + + protected ConfigurationFactory() { + this.isActive = new AtomicBoolean(true); + try { + create(); + } finally { + this.isActive.set(false); + } + } + + private void create() { + this.persistanceFactoryService = new StandalonePersistanceFactoryService(); + + this.persistenceConfiguration = persistanceFactoryService.loadPersistenceConfiguration(getDefaultConfigurationFileName()); + this.baseConfiguration = loadBaseConfiguration(); + + this.confDir = confDir(); + this.saltFilePath = confDir + SALT_FILE_NAME; + + this.cryptoConfigurationSalt = loadCryptoConfigurationSalt(); + + this.persistenceEntryManager = createPersistenceEntryManager(); + + if (!createFromDb()) { + LOG.error("Failed to load configuration from DB. Please fix it!!!."); + throw new ConfigurationException("Failed to load configuration from DB."); + } else { + this.loaded = true; + LOG.info("Configuration loaded successfully."); + } + } + + public void destroy() { + if (this.persistenceEntryManager != null) { + destroyPersistenceEntryManager(this.persistenceEntryManager); + } + } + + private FileConfiguration loadBaseConfiguration() { + FileConfiguration fileConfiguration = createFileConfiguration(BASE_PROPERTIES_FILE, true); + + return fileConfiguration; + } + + private FileConfiguration createFileConfiguration(String fileName, boolean isMandatory) { + try { + FileConfiguration fileConfiguration = new FileConfiguration(fileName); + + return fileConfiguration; + } catch (Exception ex) { + if (isMandatory) { + LOG.error("Failed to load configuration from {}", fileName, ex); + throw new ConfigurationException("Failed to load configuration from " + fileName, ex); + } + } + + return null; + } + + public FileConfiguration loadPersistanceConfiguration(String persistanceConfigurationFileName, boolean mandatory) { + try { + if (StringHelper.isEmpty(persistanceConfigurationFileName)) { + if (mandatory) { + throw new ConfigurationException("Failed to load Persistance configuration file!"); + } else { + return null; + } + } + + String persistanceConfigurationFilePath = DIR + persistanceConfigurationFileName; + + FileConfiguration persistanceConfiguration = new FileConfiguration(persistanceConfigurationFilePath); + if (persistanceConfiguration.isLoaded()) { + File persistanceFile = new File(persistanceConfigurationFilePath); + if (persistanceFile.exists()) { + this.baseConfigurationFileLastModifiedTime = persistanceFile.lastModified(); + } + + return persistanceConfiguration; + } + } catch (Exception ex) { + LOG.error(ex.getMessage(), ex); + throw new ConfigurationException("Failed to load DB configuration from " + persistanceConfigurationFileName, ex); + } + + if (mandatory) { + throw new ConfigurationException("Failed to load DB configuration from " + persistanceConfigurationFileName); + } + + return null; + } + + private String loadCryptoConfigurationSalt() { + try { + FileConfiguration cryptoConfiguration = new FileConfiguration(this.saltFilePath); + + return cryptoConfiguration.getString("encodeSalt"); + } catch (Exception ex) { + LOG.error("Failed to load configuration from {}", saltFilePath, ex); + throw new ConfigurationException("Failed to load configuration from " + saltFilePath, ex); + } + } + + private String confDir() { + final String confDir = getPersistenceConfiguration().getString("confDir"); + if (StringUtils.isNotBlank(confDir)) { + return confDir; + } + + return DIR; + } + + private boolean createFromDb() { + LOG.info("Loading configuration from '{}' DB...", baseConfiguration.getString("persistence.type")); + try { + final L persistenceConf = loadConfigurationFromDb(); + this.loadedRevision = persistenceConf.getRevision(); + if (persistenceConf != null) { + this.appConfiguration = (C) persistenceConf.getApplication(); + return true; + } + } catch (Exception ex) { + LOG.error(ex.getMessage(), ex); + } + + return false; + } + + private L loadConfigurationFromDb(String... returnAttributes) { + try { + final String dn = baseConfiguration.getString(getApplicationConfigurationPropertyName()); + + final L persistanceConf = this.persistenceEntryManager.find(dn, getAppConfigurationType(), returnAttributes); + return persistanceConf; + } catch (BasePersistenceException ex) { + LOG.error(ex.getMessage()); + } + + return null; + } + + protected Properties preparePersistanceProperties() { + FileConfiguration persistenceConfig = persistenceConfiguration.getConfiguration(); + Properties connectionProperties = (Properties) persistenceConfig.getProperties(); + + Properties decryptedConnectionProperties; + try { + decryptedConnectionProperties = PropertiesDecrypter.decryptAllProperties(StringEncrypter.defaultInstance(), connectionProperties, this.cryptoConfigurationSalt); + } catch (EncryptionException ex) { + throw new ConfigurationException("Failed to decript configuration properties", ex); + } + + return decryptedConnectionProperties; + } + + public PersistenceEntryManager createPersistenceEntryManager() { + Properties connectionProperties = preparePersistanceProperties(); + + PersistenceEntryManagerFactory persistenceEntryManagerFactory = persistanceFactoryService.getPersistenceEntryManagerFactory(persistenceConfiguration); + PersistenceEntryManager persistenceEntryManager = persistenceEntryManagerFactory.createEntryManager(connectionProperties); + LOG.info("Created PersistenceEntryManager: {} with operation service: {}", + new Object[] {persistenceEntryManager, + persistenceEntryManager.getOperationService() }); + + return persistenceEntryManager; + } + + private void destroyPersistenceEntryManager(final PersistenceEntryManager persistenceEntryManager) { + boolean result = persistenceEntryManager.destroy(); + if (result) { + LOG.debug("Destoyed PersistenceEntryManager: {}", persistenceEntryManager); + } else { + LOG.error("Failed to destoy PersistenceEntryManager: {}", persistenceEntryManager); + } + } + + public FileConfiguration getPersistenceConfiguration() { + return this.persistenceConfiguration.getConfiguration(); + } + + public String getCryptoConfigurationSalt() { + return cryptoConfigurationSalt; + } + + protected String getDefaultPersistanceConfigurationFileName() { + return "gluu-ldap.properties"; + } + + public C getAppConfiguration() { + return appConfiguration; + } + + public CacheConfiguration getCacheConfiguration() { + SharedConfigurationEntry sharedConfigurationEntry = persistenceEntryManager.find(SharedConfigurationEntry.class, SHARED_CONFIGURATION_DN); + if (sharedConfigurationEntry == null) { + LOG.error("Failed to load share configuration from DB. Please fix it!!!."); + throw new ConfigurationException("Failed to load shared configuration from DB."); + } + + CacheConfiguration cacheConfiguration = sharedConfigurationEntry.getCacheConfiguration(); + if (cacheConfiguration == null || cacheConfiguration.getCacheProviderType() == null) { + LOG.error("Failed to read cache configuration from DB. Please check configuration oxCacheConfiguration attribute " + + "that must contain cache configuration JSON represented by CacheConfiguration.class. Shared configuration DN: " + SHARED_CONFIGURATION_DN); + LOG.info("Creating fallback IN-MEMORY cache configuration ... "); + + cacheConfiguration = new CacheConfiguration(); + cacheConfiguration.setInMemoryConfiguration(new InMemoryConfiguration()); + + LOG.info("IN-MEMORY cache configuration is created."); + } + LOG.info("Cache configuration: " + cacheConfiguration); + return cacheConfiguration; + } + + public boolean isLoaded() { + return loaded; + } + + public long getLoadedRevision() { + return loadedRevision; + } + + protected abstract String getDefaultConfigurationFileName(); + + protected abstract Class getAppConfigurationType(); + + protected abstract String getApplicationConfigurationPropertyName(); + +} diff --git a/core-standalone/src/test/java/org/gluu/conf/service/DummyConfigurationFactory.java b/core-standalone/src/test/java/org/gluu/conf/service/DummyConfigurationFactory.java new file mode 100644 index 00000000..2c981e07 --- /dev/null +++ b/core-standalone/src/test/java/org/gluu/conf/service/DummyConfigurationFactory.java @@ -0,0 +1,27 @@ +package org.gluu.conf.service; + +import org.gluu.conf.model.AppConfiguration; +import org.gluu.conf.model.AppConfigurationEntry; + +/** + * @author Yuriy Movchan + * @version 0.1, 01/02/2020 + */ +public class DummyConfigurationFactory extends ConfigurationFactory { + + @Override + protected String getDefaultConfigurationFileName() { + return "gluu-dummy.properties"; + } + + @Override + protected Class getAppConfigurationType() { + return AppConfigurationEntry.class; + } + + @Override + protected String getApplicationConfigurationPropertyName() { + return "oxdummyConfigurationEntryDN"; + } + +} diff --git a/core-standalone/src/test/java/org/gluu/conf/service/DummyConfigurationFactoryTest.java b/core-standalone/src/test/java/org/gluu/conf/service/DummyConfigurationFactoryTest.java new file mode 100644 index 00000000..7e0cbc36 --- /dev/null +++ b/core-standalone/src/test/java/org/gluu/conf/service/DummyConfigurationFactoryTest.java @@ -0,0 +1,34 @@ +package org.gluu.conf.service; + +import static org.testng.Assert.assertNotNull; + +import org.gluu.service.cache.CacheConfiguration; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +/** + * @author Yuriy Movchan + * @version 0.1, 01/02/2020 + */ +public class DummyConfigurationFactoryTest { + + private DummyConfigurationFactory dummyConfigurationFactory; + + @BeforeClass + public void beforeClass() { + this.dummyConfigurationFactory = new DummyConfigurationFactory(); + } + + @Test(enabled = false) + public void checkAppConfigurationLoad() { + assertNotNull(dummyConfigurationFactory.getAppConfiguration()); + } + + @Test(enabled = false) + public void checkCacheConfiguration() { + CacheConfiguration cacheConfiguration = dummyConfigurationFactory.getCacheConfiguration(); + assertNotNull(cacheConfiguration); + assertNotNull(cacheConfiguration.getCacheProviderType()); + } + +} diff --git a/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeBenchmarkCacheTest.java b/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeBenchmarkCacheTest.java index d5b143a4..29620c32 100644 --- a/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeBenchmarkCacheTest.java +++ b/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeBenchmarkCacheTest.java @@ -42,9 +42,9 @@ public void couchbaseCacheProvider() throws IOException { cacheConfiguration.getNativePersistenceConfiguration().setBaseDn(""); NativePersistenceCacheProvider provider = new NativePersistenceCacheProvider(); + provider.configure(cacheConfiguration, entryManager); + provider.setBaseDn(baseDn); - provider.setCacheConfiguration(cacheConfiguration); - provider.setEntryManager(this.entryManager); Map sessionAttributes = new HashMap<>(); sessionAttributes.put("attr1", "value1"); diff --git a/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeCacheTest.java b/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeCacheTest.java index 6e4a1727..2d8d418f 100644 --- a/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeCacheTest.java +++ b/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeCacheTest.java @@ -27,9 +27,9 @@ public void couchbaseCacheProvider() throws IOException { cacheConfiguration.getNativePersistenceConfiguration().setBaseDn(""); NativePersistenceCacheProvider provider = new NativePersistenceCacheProvider(); + provider.configure(cacheConfiguration, manager); + provider.setBaseDn(baseDn); - provider.setCacheConfiguration(cacheConfiguration); - provider.setEntryManager(manager); Map sessionAttributes = new HashMap<>(); sessionAttributes.put("attr1", "value1"); diff --git a/oxService/src/test/java/org/gluu/service/cache/InMemoryCacheProviderTest.java b/oxService/src/test/java/org/gluu/service/cache/InMemoryCacheProviderTest.java index 797f976d..88082641 100644 --- a/oxService/src/test/java/org/gluu/service/cache/InMemoryCacheProviderTest.java +++ b/oxService/src/test/java/org/gluu/service/cache/InMemoryCacheProviderTest.java @@ -18,8 +18,9 @@ public class InMemoryCacheProviderTest { @BeforeClass public void beforeClass() { + CacheConfiguration cacheConfiguration = new CacheConfiguration(); cache = new InMemoryCacheProvider(); - cache.setCacheConfiguration(new CacheConfiguration()); + cache.configure(cacheConfiguration); cache.create(); } diff --git a/persistence-standalone/pom.xml b/persistence-standalone/pom.xml index 8bb6f445..a1158485 100644 --- a/persistence-standalone/pom.xml +++ b/persistence-standalone/pom.xml @@ -1,4 +1,5 @@ - 4.0.0 @@ -34,19 +35,10 @@ org.gluu oxcore-persistence-cdi - - javax.enterprise - cdi-api - org.reflections reflections - - com.google.guava - guava - 20.0 - \ No newline at end of file diff --git a/persistence-standalone/src/main/java/org/gluu/persist/service/StandalonePersistanceFactoryService.java b/persistence-standalone/src/main/java/org/gluu/persist/service/StandalonePersistanceFactoryService.java index 7cf456a0..365ac3a3 100644 --- a/persistence-standalone/src/main/java/org/gluu/persist/service/StandalonePersistanceFactoryService.java +++ b/persistence-standalone/src/main/java/org/gluu/persist/service/StandalonePersistanceFactoryService.java @@ -16,7 +16,6 @@ * Factory which creates Persistence Entry Manager * * @author Yuriy Movchan Date: 05/10/2019 - * @param */ public class StandalonePersistanceFactoryService extends PersistanceFactoryService { diff --git a/pom.xml b/pom.xml index f65ed2aa..9a0e029f 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ oxModel oxSaml core-cache + core-standalone oxService server oxJsfUtil From 991f5b89c59bca22491fe287a3e73a8c38a84f85 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 21 Jan 2020 11:53:39 +0300 Subject: [PATCH 077/362] FIx dependecies --- persistence-standalone/pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/persistence-standalone/pom.xml b/persistence-standalone/pom.xml index a1158485..f4968c4f 100644 --- a/persistence-standalone/pom.xml +++ b/persistence-standalone/pom.xml @@ -39,6 +39,13 @@ org.reflections reflections + + + + javax.enterprise + cdi-api + provided + \ No newline at end of file From ce585298f75986c348fd19c3a9bd821ec251e613 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 21 Jan 2020 15:18:53 +0300 Subject: [PATCH 078/362] Add method to get string encrypter --- .../conf/service/ConfigurationFactory.java | 67 ++++++++++++++----- 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java b/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java index df16a390..b2385ed7 100644 --- a/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java +++ b/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java @@ -75,9 +75,12 @@ public abstract class ConfigurationFactory Date: Wed, 22 Jan 2020 15:15:06 +0300 Subject: [PATCH 079/362] Allow to get entry manager to externally load configuration --- .../conf/service/ConfigurationFactory.java | 47 ++++--------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java b/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java index b2385ed7..b9229a20 100644 --- a/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java +++ b/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java @@ -129,12 +129,6 @@ public void destroy() { } } - private FileConfiguration loadBaseConfiguration() { - FileConfiguration fileConfiguration = createFileConfiguration(BASE_PROPERTIES_FILE, true); - - return fileConfiguration; - } - private FileConfiguration createFileConfiguration(String fileName, boolean isMandatory) { try { FileConfiguration fileConfiguration = new FileConfiguration(fileName); @@ -150,37 +144,10 @@ private FileConfiguration createFileConfiguration(String fileName, boolean isMan return null; } - public FileConfiguration loadPersistanceConfiguration(String persistanceConfigurationFileName, boolean mandatory) { - try { - if (StringHelper.isEmpty(persistanceConfigurationFileName)) { - if (mandatory) { - throw new ConfigurationException("Failed to load Persistance configuration file!"); - } else { - return null; - } - } - - String persistanceConfigurationFilePath = DIR + persistanceConfigurationFileName; - - FileConfiguration persistanceConfiguration = new FileConfiguration(persistanceConfigurationFilePath); - if (persistanceConfiguration.isLoaded()) { - File persistanceFile = new File(persistanceConfigurationFilePath); - if (persistanceFile.exists()) { - this.baseConfigurationFileLastModifiedTime = persistanceFile.lastModified(); - } - - return persistanceConfiguration; - } - } catch (Exception ex) { - LOG.error(ex.getMessage(), ex); - throw new ConfigurationException("Failed to load DB configuration from " + persistanceConfigurationFileName, ex); - } - - if (mandatory) { - throw new ConfigurationException("Failed to load DB configuration from " + persistanceConfigurationFileName); - } + private FileConfiguration loadBaseConfiguration() { + FileConfiguration fileConfiguration = createFileConfiguration(BASE_PROPERTIES_FILE, true); - return null; + return fileConfiguration; } private String loadCryptoConfigurationSalt() { @@ -269,7 +236,7 @@ protected Properties preparePersistanceProperties() { return decryptedConnectionProperties; } - public PersistenceEntryManager createPersistenceEntryManager() { + private PersistenceEntryManager createPersistenceEntryManager() { Properties connectionProperties = preparePersistanceProperties(); PersistenceEntryManagerFactory persistenceEntryManagerFactory = persistanceFactoryService.getPersistenceEntryManagerFactory(persistenceConfiguration); @@ -290,7 +257,7 @@ private void destroyPersistenceEntryManager(final PersistenceEntryManager persis } } - public StringEncrypter createStringEncrypter() { + private StringEncrypter createStringEncrypter() { String encodeSalt = this.cryptoConfigurationSalt; if (StringHelper.isEmpty(encodeSalt)) { @@ -318,6 +285,10 @@ public String getCryptoConfigurationSalt() { return cryptoConfigurationSalt; } + public PersistenceEntryManager getPersistenceEntryManager() { + return persistenceEntryManager; + } + protected String getDefaultPersistanceConfigurationFileName() { return "gluu-ldap.properties"; } From 01bb9b0dabb616cdc54b502b09b0e7dbebcb498f Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 23 Jan 2020 17:33:39 +0300 Subject: [PATCH 080/362] Cache should supports mehods hasKey and allow to put data without expiration #177 --- .../service/cache/AbstractRedisProvider.java | 2 + .../org/gluu/service/cache/CacheProvider.java | 10 +++ .../service/cache/InMemoryCacheProvider.java | 15 ++++ .../gluu/service/cache/MemcachedProvider.java | 18 +++++ .../cache/NativePersistenceCacheProvider.java | 73 +++++++++++++------ .../service/cache/RedisClusterProvider.java | 8 ++ .../org/gluu/service/cache/RedisProvider.java | 15 +++- .../service/cache/RedisSentinelProvider.java | 7 ++ .../service/cache/RedisShardedProvider.java | 7 ++ .../cache/RedisStandaloneProvider.java | 7 ++ .../cache/StandaloneCacheProviderFactory.java | 7 ++ 11 files changed, 145 insertions(+), 24 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java b/core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java index 79155656..23d0cc64 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java @@ -38,6 +38,8 @@ public boolean isConnected() { public abstract void destroy(); public abstract Object getDelegate(); + + public abstract boolean hasKey(String key); public abstract Object get(String key); diff --git a/core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java index 461d0686..00e47458 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java @@ -9,6 +9,11 @@ public abstract class CacheProvider implements CacheInterface { */ public abstract T getDelegate(); + /* + * Method to check if there is key in cache + */ + public abstract boolean hasKey(String key); + /** * Fetches an object for the given key from the cache and returns it if found. * Only the specified cache region will be searched. @@ -18,6 +23,11 @@ public abstract class CacheProvider implements CacheInterface { */ public abstract Object get(String key); + /* + * Put value with specified key without expiration + */ + public abstract void put(String key, Object object); + public abstract void put(int expirationInSeconds, String key, Object object); /** diff --git a/core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java index 69444a6c..1b4053cb 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java @@ -68,11 +68,26 @@ public ExpiringMap getDelegate() { return map; } + @Override + public boolean hasKey(String key) { + return map.containsKey(key); + } + @Override public Object get(String key) { return map.get(key); } + @Override + public void put(String key, Object object) { + // if key already exists and hash is the same for value then expiration time is + // not updated + // net.jodah.expiringmap.ExpiringMap.putInternal() + // therefore we first remove entry and then put it + map.remove(key); + map.put(key, object, ExpirationPolicy.CREATED, Long.MAX_VALUE, TimeUnit.DAYS); + } + @Override public void put(int expirationInSeconds, String key, Object object) { // if key already exists and hash is the same for value then expiration time is diff --git a/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java b/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java index 8730af12..e6010b7c 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java @@ -101,6 +101,13 @@ public MemcachedClient getDelegate() { return client; } + @Override + public boolean hasKey(String key) { + Object value = get(key); + + return value != null; + } + @Override public Object get(String key) { try { @@ -116,6 +123,17 @@ public Object get(String key) { } } + @Override + public void put(String key, Object object) { + try { + OperationFuture set = client.set(key, 0, object); + OperationStatus status = set.getStatus(); // block + log.trace("set - key:" + key + ", expiration: " + 0 + ", status:" + status + ", get:" + get(key)); + } catch (Exception e) { + log.error("Failed to put object in cache, key: " + key, e); + } + } + @Override public void put(int expirationInSeconds, String key, Object object) { try { diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index cbe4590d..4675e57b 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -48,8 +48,8 @@ public void create() { deleteExpiredOnGetRequest = cacheConfiguration.getNativePersistenceConfiguration().isDeleteExpiredOnGetRequest(); if (StringUtils.isBlank(baseDn)) { - log.error("Failed to create NATIVE_PERSISTENCE cache provider. 'baseDn' in LdapCacheConfiguration is not initialized. It has to be set by client application (e.g. oxAuth has to set it in ApplicationFactory.)"); - throw new RuntimeException("Failed to create NATIVE_PERSISTENCE cache provider. 'baseDn' in LdapCacheConfiguration is not initialized. It has to be set by client application."); + log.error("Failed to create NATIVE_PERSISTENCE cache provider. 'baseDn' in CacheConfiguration is not initialized. It has to be set by client application (e.g. oxAuth has to set it in ApplicationFactory.)"); + throw new RuntimeException("Failed to create NATIVE_PERSISTENCE cache provider. 'baseDn' in CacheConfiguration is not initialized. It has to be set by client application."); } String branchDn = String.format("ou=cache,%s", baseDn); @@ -88,6 +88,22 @@ public PersistenceEntryManager getDelegate() { return entryManager; } + @Override + public boolean hasKey(String key) { + try { + key = hashKey(key); + boolean hasKey = entryManager.contains(createDn(key), NativePersistenceCacheEntity.class); + +// log.trace("Contains key in cache, key: " + key + ", dn: " + createDn(key)) + ", contains: " + hasKey); + return hasKey; + } catch (Exception e) { + // ignore, we call cache first which is empty and then fill it in + // log.trace("No entry with key: " + originalKey + ", message: " + e.getMessage() + ", hashedKey: " + key); + } + + return false; + } + @Override public Object get(String key) { try { @@ -102,7 +118,7 @@ public Object get(String key) { return null; } Object o = fromString(entity.getData()); - //log.trace("Returned object from cache, key: " + originalKey + ", dn: " + entity.getDn()); +// log.trace("Returned object from cache, key: " + key + ", dn: " + entity.getDn()); return o; } } catch (Exception e) { @@ -120,34 +136,47 @@ public static String hashKey(String key) { return DigestUtils.sha256Hex(key); } + @Override + public void put(String key, Object object) { + Date creationDate = new Date(); + Date expirationDate = new Date(Long.MAX_VALUE); + + putImpl(key, object, creationDate, expirationDate); + } + @Override public void put(int expirationInSeconds, String key, Object object) { - String originalKey = key; + Date creationDate = new Date(); - try { - key = hashKey(key); - Date creationDate = new Date(); + expirationInSeconds = expirationInSeconds > 0 ? expirationInSeconds : cacheConfiguration.getNativePersistenceConfiguration().getDefaultPutExpiration(); - expirationInSeconds = expirationInSeconds > 0 ? expirationInSeconds : cacheConfiguration.getNativePersistenceConfiguration().getDefaultPutExpiration(); + Calendar expirationDate = Calendar.getInstance(); + expirationDate.setTime(creationDate); + expirationDate.add(Calendar.SECOND, expirationInSeconds); - Calendar expirationDate = Calendar.getInstance(); - expirationDate.setTime(creationDate); - expirationDate.add(Calendar.SECOND, expirationInSeconds); + putImpl(key, object, creationDate, expirationDate.getTime()); + } - NativePersistenceCacheEntity entity = new NativePersistenceCacheEntity(); - entity.setData(asString(object)); - entity.setId(key); - entity.setDn(createDn(key)); - entity.setCreationDate(creationDate); - entity.setNewExpirationDate(expirationDate.getTime()); - entity.setDeletable(true); + private void putImpl(String key, Object object, Date creationDate, Date expirationDate) { + String originalKey = key; - silentlyRemoveEntityIfExists(entity.getDn()); - entryManager.persist(entity); + try { + key = hashKey(key); + + NativePersistenceCacheEntity entity = new NativePersistenceCacheEntity(); + entity.setData(asString(object)); + entity.setId(key); + entity.setDn(createDn(key)); + entity.setCreationDate(creationDate); + entity.setNewExpirationDate(expirationDate); + entity.setDeletable(true); + + silentlyRemoveEntityIfExists(entity.getDn()); + entryManager.persist(entity); } catch (Exception e) { - log.error("Failed to put entry, key: " + originalKey + ", hashedKey: " + key + ", message: " + e.getMessage(), e); // log as trace since it is perfectly valid that entry is removed by timer for example + log.error("Failed to put entry, key: " + originalKey + ", hashedKey: " + key + ", message: " + e.getMessage(), e); // log as trace since it is perfectly valid that entry is removed by timer for example } - } + } private boolean silentlyRemoveEntityIfExists(String dn) { try { diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java index b35c7825..b46188e4 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java @@ -83,6 +83,13 @@ public JedisCluster getDelegate() { return pool; } + @Override + public boolean hasKey(String key) { + Boolean hasKey = pool.exists(key); + + return Boolean.TRUE.equals(hasKey); + } + @Override public Object get(String key) { byte[] value = pool.get(key.getBytes()); @@ -115,4 +122,5 @@ public void remove(String key) { public void clear() { LOG.trace("clear not allowed for cluster deployments"); } + } diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java index d4013d30..d3f4fddf 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java @@ -95,6 +95,14 @@ public AbstractRedisProvider getDelegate() { return redisProvider; } + @Override + public boolean hasKey(String key) { + if (key == null) { + return false; + } + return redisProvider.hasKey(key); + } + @Override public Object get(String key) { if (key == null) { @@ -103,6 +111,11 @@ public Object get(String key) { return redisProvider.get(key); } + @Override + public void put(String key, Object object) { + redisProvider.put(key, object); + } + @Override public void put(int expirationInSeconds, String key, Object object) { redisProvider.put(expirationInSeconds > 0 ? expirationInSeconds : defaultPutExpiration, key, object); @@ -123,6 +136,4 @@ public CacheProviderType getProviderType() { return CacheProviderType.REDIS; } - - } diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java index 4feb4587..2a529f66 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java @@ -75,6 +75,13 @@ public JedisSentinelPool getDelegate() { return pool; } + @Override + public boolean hasKey(String key) { + Boolean hasKey = pool.getResource().exists(key); + + return Boolean.TRUE.equals(hasKey); + } + @Override public Object get(String key) { byte[] value = pool.getResource().get(key.getBytes()); diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java index 720d901b..7c116138 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java @@ -99,6 +99,13 @@ public ShardedJedisPool getDelegate() { return pool; } + @Override + public boolean hasKey(String key) { + Boolean hasKey = pool.getResource().exists(key); + + return Boolean.TRUE.equals(hasKey); + } + @Override public Object get(String key) { ShardedJedis jedis = pool.getResource(); diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java index 021e182a..476ce932 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java @@ -88,6 +88,13 @@ public JedisPool getDelegate() { return pool; } + @Override + public boolean hasKey(String key) { + Boolean hasKey = pool.getResource().exists(key); + + return Boolean.TRUE.equals(hasKey); + } + @Override public Object get(String key) { Jedis jedis = pool.getResource(); diff --git a/core-cache/src/main/java/org/gluu/service/cache/StandaloneCacheProviderFactory.java b/core-cache/src/main/java/org/gluu/service/cache/StandaloneCacheProviderFactory.java index f8b79373..209a0e70 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/StandaloneCacheProviderFactory.java +++ b/core-cache/src/main/java/org/gluu/service/cache/StandaloneCacheProviderFactory.java @@ -1,6 +1,7 @@ package org.gluu.service.cache; import org.gluu.persist.PersistenceEntryManager; +import org.gluu.util.StringHelper; import org.gluu.util.security.StringEncrypter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,6 +64,12 @@ public CacheProvider getCacheProvider(CacheConfiguration cacheConfiguration) NativePersistenceCacheProvider nativePersistenceCacheProvider = new NativePersistenceCacheProvider(); nativePersistenceCacheProvider.configure(cacheConfiguration, entryManager); + + // TODO: Remove after configuration fix + if (StringHelper.isEmpty(cacheConfiguration.getNativePersistenceConfiguration().getBaseDn())) { + cacheConfiguration.getNativePersistenceConfiguration().setBaseDn("o=gluu"); + } + nativePersistenceCacheProvider.init(); cacheProvider = nativePersistenceCacheProvider; From 1ba5bcd4933d4f3785c38b09fcb1a4bbeb53a600 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 27 Jan 2020 14:54:50 +0300 Subject: [PATCH 081/362] Fix module version --- core-standalone/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-standalone/pom.xml b/core-standalone/pom.xml index fa1bafca..10a8956b 100644 --- a/core-standalone/pom.xml +++ b/core-standalone/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.1.0.Final + 4.2.0-SNAPSHOT From e3333777a176476efa92d7cd9737dfe9c84a0f47 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Mon, 27 Jan 2020 16:01:05 +0200 Subject: [PATCH 082/362] oxcore : Added Connect front channel logout custom interception script https://github.com/GluuFederation/oxAuth/issues/1113 --- .../model/custom/script/CustomScriptType.java | 6 ++-- .../type/logout/DummyEndSessionType.java | 35 +++++++++++++++++++ .../script/type/logout/EndSessionType.java | 13 +++++++ 3 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java create mode 100644 oxService/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java b/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java index 779e1385..ccda17d4 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java @@ -6,9 +6,6 @@ package org.gluu.model.custom.script; -import java.util.HashMap; -import java.util.Map; - import org.gluu.model.custom.script.model.CustomScript; import org.gluu.model.custom.script.model.auth.AuthenticationCustomScript; import org.gluu.model.custom.script.type.BaseExternalType; @@ -22,6 +19,8 @@ import org.gluu.model.custom.script.type.id.IdGeneratorType; import org.gluu.model.custom.script.type.introspection.DummyIntrospectionType; import org.gluu.model.custom.script.type.introspection.IntrospectionType; +import org.gluu.model.custom.script.type.logout.DummyEndSessionType; +import org.gluu.model.custom.script.type.logout.EndSessionType; import org.gluu.model.custom.script.type.owner.DummyResourceOwnerPasswordCredentialsType; import org.gluu.model.custom.script.type.owner.ResourceOwnerPasswordCredentialsType; import org.gluu.model.custom.script.type.scim.DummyScimType; @@ -73,6 +72,7 @@ public enum CustomScriptType implements AttributeEnum { DYNAMIC_SCOPE("dynamic_scope", "Dynamic Scopes", DynamicScopeType.class, CustomScript.class, "DynamicScope", new DummyDynamicScopeType()), SPONTANEOUS_SCOPE("spontaneous_scope", "Spontaneous Scopes", SpontaneousScopeType.class, CustomScript.class, "SpontaneousScope", new DummySpontaneousScopeType()), + END_SESSION("end_session", "End Session", EndSessionType.class, CustomScript.class, "EndSession", new DummyEndSessionType()), SCIM("scim", "SCIM", ScimType.class, CustomScript.class, "ScimEventHandler", new DummyScimType()); private String value; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java new file mode 100644 index 00000000..19871430 --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java @@ -0,0 +1,35 @@ +package org.gluu.model.custom.script.type.logout; + +import org.gluu.model.SimpleCustomProperty; + +import java.util.Map; + +/** + * @author Yuriy Zabrovarnyy + */ +public class DummyEndSessionType implements EndSessionType { + @Override + public boolean init(Map configurationAttributes) { + return true; + } + + @Override + public boolean destroy(Map configurationAttributes) { + return true; + } + + @Override + public int getApiVersion() { + return 1; + } + + @Override + public String getHtml(Object context) { + return null; + } + + @Override + public String getPage(Object context) { + return null; + } +} diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java new file mode 100644 index 00000000..a4a40031 --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java @@ -0,0 +1,13 @@ +package org.gluu.model.custom.script.type.logout; + +import org.gluu.model.custom.script.type.BaseExternalType; + +/** + * @author Yuriy Zabrovarnyy + */ +public interface EndSessionType extends BaseExternalType { + + String getFrontchannelHtml(Object context); + + String getFrontchannelPage(Object context); +} From c04d2a108038084e7fcf16d8f93c8d29e95c1cb5 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Mon, 27 Jan 2020 16:02:57 +0200 Subject: [PATCH 083/362] oxcore : Added Connect front channel logout custom interception script https://github.com/GluuFederation/oxAuth/issues/1113 --- .../model/custom/script/type/logout/DummyEndSessionType.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java index 19871430..0d7fc94b 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java @@ -24,12 +24,12 @@ public int getApiVersion() { } @Override - public String getHtml(Object context) { + public String getFrontchannelHtml(Object context) { return null; } @Override - public String getPage(Object context) { + public String getFrontchannelPage(Object context) { return null; } } From 61356cdaaae4c09487e7adcaa55b98dcc4735724 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Mon, 27 Jan 2020 18:06:23 +0200 Subject: [PATCH 084/362] oxcore : corrected front channel logout custom interception script https://github.com/GluuFederation/oxAuth/issues/1113 --- .../model/custom/script/type/logout/DummyEndSessionType.java | 5 ----- .../gluu/model/custom/script/type/logout/EndSessionType.java | 2 -- 2 files changed, 7 deletions(-) diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java index 0d7fc94b..8709476e 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java @@ -27,9 +27,4 @@ public int getApiVersion() { public String getFrontchannelHtml(Object context) { return null; } - - @Override - public String getFrontchannelPage(Object context) { - return null; - } } diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java index a4a40031..d92a4c29 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java @@ -8,6 +8,4 @@ public interface EndSessionType extends BaseExternalType { String getFrontchannelHtml(Object context); - - String getFrontchannelPage(Object context); } From 2093927699cba0190b72173b4bbf2f817fcd25e7 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 27 Jan 2020 22:11:38 +0300 Subject: [PATCH 085/362] Don't create branches if DB not supports tree based model --- .../src/main/java/org/gluu/service/metric/MetricService.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/oxService/src/main/java/org/gluu/service/metric/MetricService.java b/oxService/src/main/java/org/gluu/service/metric/MetricService.java index 47707e21..537a5f7e 100644 --- a/oxService/src/main/java/org/gluu/service/metric/MetricService.java +++ b/oxService/src/main/java/org/gluu/service/metric/MetricService.java @@ -119,6 +119,10 @@ public void createBranch(String branchDn, String ou) { } public void prepareBranch(Date creationDate, ApplicationType applicationType) { + if (!getEntryManager().hasBranchesSupport(baseDn())) { + return; + } + String baseDn = buildDn(null, creationDate, applicationType); // Create ou=YYYY-MM branch if needed if (!containsBranch(baseDn)) { From b9197381515eaf363a8629f53673232a4aa3d578 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Thu, 6 Feb 2020 12:10:21 +0100 Subject: [PATCH 086/362] Add notification update field --- .../java/org/gluu/config/oxtrust/AppConfiguration.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index f1379bea..25ffc19f 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -140,6 +140,7 @@ public class AppConfiguration implements Configuration, Serializable { private boolean scimTestMode; private boolean oxTrustApiTestMode; + private boolean enableUpdateNotification; private boolean rptConnectionPoolUseConnectionPooling; private int rptConnectionPoolMaxTotal; @@ -1018,4 +1019,11 @@ public void setUseLocalCache(Boolean useLocalCache) { this.useLocalCache = useLocalCache; } + public boolean isEnableUpdateNotification() { + return enableUpdateNotification; + } + + public void setEnableUpdateNotification(boolean enableUpdateNotification) { + this.enableUpdateNotification = enableUpdateNotification; + } } From 26e5e21fc4f63b25be08fc9ba6e36c55ae841abf Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 7 Feb 2020 13:03:27 +0300 Subject: [PATCH 087/362] Library for java extensions --- core-java-ext/pom.xml | 32 +++++ .../org/gluu/i18n/ExtendedResourceBundle.java | 117 ++++++++++++++++++ ...ExtendedResourceBundleControlProvider.java | 68 ++++++++++ ...ava.util.spi.ResourceBundleControlProvider | 1 + pom.xml | 1 + 5 files changed, 219 insertions(+) create mode 100644 core-java-ext/pom.xml create mode 100644 core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundle.java create mode 100644 core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundleControlProvider.java create mode 100644 core-java-ext/src/main/resources/META-INF/services/java.util.spi.ResourceBundleControlProvider diff --git a/core-java-ext/pom.xml b/core-java-ext/pom.xml new file mode 100644 index 00000000..b3fce2b7 --- /dev/null +++ b/core-java-ext/pom.xml @@ -0,0 +1,32 @@ + + + 4.0.0 + oxcore-java-ext + jar + Java extensions + + + org.gluu + oxcore + 4.2.0-SNAPSHOT + + + + + + src/main/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + + + + \ No newline at end of file diff --git a/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundle.java b/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundle.java new file mode 100644 index 00000000..bbbf3ece --- /dev/null +++ b/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundle.java @@ -0,0 +1,117 @@ +package org.gluu.i18n; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchKey; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.Properties; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Logger; + +/** + * Custom i18n resource bundle with realod support + * + * @author Yuriy Movchan + * @version 02/07/2020 + */ +public class ExtendedResourceBundle extends ResourceBundle { + + private static final Logger LOG = Logger.getLogger(ExtendedResourceBundle.class.getName()); + + private WatchKey watcher = null; + private Date watcherLastUpdate = new Date(); + + private String baseName; + private Path externalResource; + private Properties properties; + private Date lastUpdate; + + private final ReentrantLock updateLock = new ReentrantLock(); + + public ExtendedResourceBundle(String baseName, Path externalResource, Properties properties) throws IOException { + this.baseName = baseName; + this.externalResource = externalResource; + this.properties = properties; + + this.lastUpdate = new Date(); + this.watcher = externalResource.register(FileSystems.getDefault().newWatchService(), StandardWatchEventKinds.ENTRY_MODIFY); + } + + @Override + protected Object handleGetObject(String key) { + if (properties != null) { + if ((externalResource != null) && (watcher != null)) { + checkWatcher(); + + updateLock.lock(); + try { + if (watcherLastUpdate.after(this.lastUpdate)) { + loadPropertiesFromFile(properties, externalResource); + this.lastUpdate = new Date(); + } + } catch (IOException ex) { + LOG.warning("Failed to reload message bundle:" + externalResource); + } finally { + updateLock.unlock(); + } + } + + return properties.get(key); + } + + return parent.getObject(key); + } + + private void checkWatcher() { + if (!watcher.pollEvents().isEmpty()) { + watcherLastUpdate = new Date(); + } + } + + @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + public Enumeration getKeys() { + if (properties != null) { + Set keys = properties.keySet(); + return Collections.enumeration(keys); + } + + return parent.getKeys(); + } + + public String getBaseName() { + return baseName; + } + + protected static void loadPropertiesFromFile(Properties properties, Path externalResource) throws IOException { + if (externalResource == null) { + return; + } + + InputStreamReader input = null; + try { + File file = externalResource.toFile(); + if (file.exists()) { + input = new FileReader(externalResource.toFile()); + properties.load(input); // External bundle (will overwrite same keys). + } + } catch (IOException ex) { + LOG.warning("Failed to read properties file"); + throw ex; + } finally { + try { + input.close(); + } catch (Exception ex) {} + } + } + +} diff --git a/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundleControlProvider.java b/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundleControlProvider.java new file mode 100644 index 00000000..703b8ffa --- /dev/null +++ b/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundleControlProvider.java @@ -0,0 +1,68 @@ +package org.gluu.i18n; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Locale; +import java.util.Properties; +import java.util.ResourceBundle; +import java.util.ResourceBundle.Control; +import java.util.logging.Logger; +import java.util.spi.ResourceBundleControlProvider; + +/** + * Custom resource bundle loader java extension + * + * @author Yuriy Movchan + * @version 02/07/2020 + */ +public class ExtendedResourceBundleControlProvider implements ResourceBundleControlProvider { + + private static final Logger LOG = Logger.getLogger(ExtendedResourceBundleControlProvider.class.getName()); + + private static Path EXTERNAL_PATH; + + static { + if (System.getProperty("server.base") != null) { + Path customPath = Paths.get(System.getProperty("server.base") + "/custom/i18n"); + File file = customPath.toFile(); + if (file.exists() && file.isDirectory()) { + EXTERNAL_PATH = customPath; + } + } + } + + public ResourceBundle.Control getControl(String baseName) { + return new CustomControl(); + } + + protected static class CustomControl extends Control { + + @Override + public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) + throws IllegalAccessException, InstantiationException, IOException { + LOG.info("Attempting to laa bundel with baseName: " + baseName); + + String resourceName = toResourceName(toBundleName(baseName, locale), "properties"); + Properties properties = new Properties(); + + try (InputStream input = loader.getResourceAsStream(resourceName)) { + InputStreamReader inputReader = new InputStreamReader(input, "UTF-8"); + properties.load(inputReader); // Default (internal) bundle. + } + + Path externalResource = null; + if (EXTERNAL_PATH != null) { + externalResource = EXTERNAL_PATH.resolve(resourceName); + } + ExtendedResourceBundle.loadPropertiesFromFile(properties, externalResource); + + return new ExtendedResourceBundle(baseName, externalResource, properties); + } + + } + +} \ No newline at end of file diff --git a/core-java-ext/src/main/resources/META-INF/services/java.util.spi.ResourceBundleControlProvider b/core-java-ext/src/main/resources/META-INF/services/java.util.spi.ResourceBundleControlProvider new file mode 100644 index 00000000..4ecce640 --- /dev/null +++ b/core-java-ext/src/main/resources/META-INF/services/java.util.spi.ResourceBundleControlProvider @@ -0,0 +1 @@ +org.gluu.i18n.ResourceBundleControlProvider \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9a0e029f..c03a1482 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,7 @@ oxSaml core-cache core-standalone + core-java-ext oxService server oxJsfUtil From 22ba5c2f9660ac512e653e1c428ef51f588efaa0 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 7 Feb 2020 14:52:46 +0300 Subject: [PATCH 088/362] Fix service name --- .../org/gluu/i18n/ExtendedResourceBundle.java | 7 ++----- .../ExtendedResourceBundleControlProvider.java | 18 +++++++++++++----- ...java.util.spi.ResourceBundleControlProvider | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundle.java b/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundle.java index bbbf3ece..065c95be 100644 --- a/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundle.java +++ b/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundle.java @@ -15,7 +15,6 @@ import java.util.ResourceBundle; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; -import java.util.logging.Logger; /** * Custom i18n resource bundle with realod support @@ -25,8 +24,6 @@ */ public class ExtendedResourceBundle extends ResourceBundle { - private static final Logger LOG = Logger.getLogger(ExtendedResourceBundle.class.getName()); - private WatchKey watcher = null; private Date watcherLastUpdate = new Date(); @@ -59,7 +56,7 @@ protected Object handleGetObject(String key) { this.lastUpdate = new Date(); } } catch (IOException ex) { - LOG.warning("Failed to reload message bundle:" + externalResource); + System.err.println("Failed to reload message bundle:" + externalResource); } finally { updateLock.unlock(); } @@ -105,7 +102,7 @@ protected static void loadPropertiesFromFile(Properties properties, Path externa properties.load(input); // External bundle (will overwrite same keys). } } catch (IOException ex) { - LOG.warning("Failed to read properties file"); + System.err.println("Failed to load message bundle:" + externalResource); throw ex; } finally { try { diff --git a/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundleControlProvider.java b/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundleControlProvider.java index 703b8ffa..95eec9ce 100644 --- a/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundleControlProvider.java +++ b/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundleControlProvider.java @@ -10,7 +10,6 @@ import java.util.Properties; import java.util.ResourceBundle; import java.util.ResourceBundle.Control; -import java.util.logging.Logger; import java.util.spi.ResourceBundleControlProvider; /** @@ -21,8 +20,6 @@ */ public class ExtendedResourceBundleControlProvider implements ResourceBundleControlProvider { - private static final Logger LOG = Logger.getLogger(ExtendedResourceBundleControlProvider.class.getName()); - private static Path EXTERNAL_PATH; static { @@ -36,15 +33,21 @@ public class ExtendedResourceBundleControlProvider implements ResourceBundleCont } public ResourceBundle.Control getControl(String baseName) { + if (baseName.startsWith("com.sun") || baseName.startsWith("org.apache")) { +// System.out.println("Using default control to load bundle with baseName: " + baseName); + return null; + } + + System.out.println("Preparing control to load bundle with baseName: " + baseName); + +// return null; return new CustomControl(); } protected static class CustomControl extends Control { - @Override public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException { - LOG.info("Attempting to laa bundel with baseName: " + baseName); String resourceName = toResourceName(toBundleName(baseName, locale), "properties"); Properties properties = new Properties(); @@ -53,6 +56,11 @@ public ResourceBundle newBundle(String baseName, Locale locale, String format, C InputStreamReader inputReader = new InputStreamReader(input, "UTF-8"); properties.load(inputReader); // Default (internal) bundle. } + + if (properties.isEmpty()) { + System.out.println("Using default control to load bundle with baseName: " + baseName); + return null; + } Path externalResource = null; if (EXTERNAL_PATH != null) { diff --git a/core-java-ext/src/main/resources/META-INF/services/java.util.spi.ResourceBundleControlProvider b/core-java-ext/src/main/resources/META-INF/services/java.util.spi.ResourceBundleControlProvider index 4ecce640..7dd9f673 100644 --- a/core-java-ext/src/main/resources/META-INF/services/java.util.spi.ResourceBundleControlProvider +++ b/core-java-ext/src/main/resources/META-INF/services/java.util.spi.ResourceBundleControlProvider @@ -1 +1 @@ -org.gluu.i18n.ResourceBundleControlProvider \ No newline at end of file +org.gluu.i18n.ExtendedResourceBundleControlProvider \ No newline at end of file From 8355c89187026d6deadef59d349b5708c8aba6d6 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 7 Feb 2020 16:01:16 +0300 Subject: [PATCH 089/362] Support JSF validation messages customizations #179 --- .../java/org/gluu/i18n/ExtendedResourceBundle.java | 4 +++- .../i18n/ExtendedResourceBundleControlProvider.java | 13 ++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundle.java b/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundle.java index 065c95be..00a5dcc3 100644 --- a/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundle.java +++ b/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundle.java @@ -40,7 +40,9 @@ public ExtendedResourceBundle(String baseName, Path externalResource, Properties this.properties = properties; this.lastUpdate = new Date(); - this.watcher = externalResource.register(FileSystems.getDefault().newWatchService(), StandardWatchEventKinds.ENTRY_MODIFY); + + Path baseFolder = externalResource.getParent(); + this.watcher = baseFolder.register(FileSystems.getDefault().newWatchService(), StandardWatchEventKinds.ENTRY_MODIFY); } @Override diff --git a/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundleControlProvider.java b/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundleControlProvider.java index 95eec9ce..d22ed6e9 100644 --- a/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundleControlProvider.java +++ b/core-java-ext/src/main/java/org/gluu/i18n/ExtendedResourceBundleControlProvider.java @@ -33,15 +33,14 @@ public class ExtendedResourceBundleControlProvider implements ResourceBundleCont } public ResourceBundle.Control getControl(String baseName) { - if (baseName.startsWith("com.sun") || baseName.startsWith("org.apache")) { -// System.out.println("Using default control to load bundle with baseName: " + baseName); - return null; - } + if (baseName.equals("javax.faces.Messages")) { + System.out.println("Preparing control to load bundle with baseName: " + baseName); + return new CustomControl(); + } - System.out.println("Preparing control to load bundle with baseName: " + baseName); +// System.out.println("Using default control to load bundle with baseName: " + baseName); -// return null; - return new CustomControl(); + return null; } protected static class CustomControl extends Control { From b0169c5624f88158e3b8f8046b3fde96aa5f3d1b Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 28 Feb 2020 08:56:39 +0300 Subject: [PATCH 090/362] Use version specified in gluu-core-bom --- pom.xml | 81 --------------------------------------------------------- 1 file changed, 81 deletions(-) diff --git a/pom.xml b/pom.xml index c03a1482..5c9f898f 100644 --- a/pom.xml +++ b/pom.xml @@ -59,87 +59,6 @@ import pom - - - org.gluu - oxcore-demo-cdi - ${project.version} - - - org.gluu - oxcore-jsf-util - ${project.version} - - - org.gluu - oxcore-radius - ${project.version} - - - org.gluu - oxcore-saml - ${project.version} - - - org.gluu - oxcore-service - ${project.version} - - - org.gluu - oxcore-util - ${project.version} - - - org.gluu - oxcore-persistence-annotation - ${project.version} - - - org.gluu - oxcore-persistence-cdi - ${project.version} - - - org.gluu - oxcore-persistence-core - ${project.version} - - - org.gluu - oxcore-persistence-couchbase - ${project.version} - - - org.gluu - oxcore-persistence-filter - ${project.version} - - - org.gluu - oxcore-persistence-hybrid - ${project.version} - - - org.gluu - oxcore-persistence-ldap - ${project.version} - - - org.gluu - oxcore-server - ${project.version} - - - org.gluu - oxcore-persistence-model - ${project.version} - - - org.gluu - oxcore-model - ${project.version} - From afae24c04ca5ce3ae9e85831029810ee9beb697b Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 28 Feb 2020 12:09:47 +0300 Subject: [PATCH 091/362] Allow to use custom resource bundles without adding them to package --- .../main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/oxJsfUtil/src/main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java b/oxJsfUtil/src/main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java index c9d1b44f..64e88423 100644 --- a/oxJsfUtil/src/main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java +++ b/oxJsfUtil/src/main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java @@ -152,6 +152,11 @@ public ResourceBundle newBundle(String baseName, Locale locale, String format, C InputStream input = null; try { input = loader.getResourceAsStream(resourceName); + + // Fall back to default bundle + if (input == null) { + resourceName = toResourceName(toBundleName(baseName, Locale.ROOT), "properties"); + } InputStreamReader inputReader = new InputStreamReader(input, "UTF-8"); properties.load(inputReader); // Default (internal) bundle. } finally { From 48fec2ed7c802d47af502fd416f058c91213b781 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 28 Feb 2020 12:23:51 +0300 Subject: [PATCH 092/362] Allow to use custom resource bundles without adding them to package --- .../src/main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java | 1 + 1 file changed, 1 insertion(+) diff --git a/oxJsfUtil/src/main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java b/oxJsfUtil/src/main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java index 64e88423..61ee798e 100644 --- a/oxJsfUtil/src/main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java +++ b/oxJsfUtil/src/main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java @@ -156,6 +156,7 @@ public ResourceBundle newBundle(String baseName, Locale locale, String format, C // Fall back to default bundle if (input == null) { resourceName = toResourceName(toBundleName(baseName, Locale.ROOT), "properties"); + input = loader.getResourceAsStream(resourceName); } InputStreamReader inputReader = new InputStreamReader(input, "UTF-8"); properties.load(inputReader); // Default (internal) bundle. From 7cd9559c1edcb5968855c461c7901f42c8cefce4 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 28 Feb 2020 12:41:31 +0300 Subject: [PATCH 093/362] Allow to use custom resource bundles without adding them to package --- .../main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oxJsfUtil/src/main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java b/oxJsfUtil/src/main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java index 61ee798e..b271a438 100644 --- a/oxJsfUtil/src/main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java +++ b/oxJsfUtil/src/main/java/org/gluu/jsf2/i18n/ExtendedResourceBundle.java @@ -155,8 +155,8 @@ public ResourceBundle newBundle(String baseName, Locale locale, String format, C // Fall back to default bundle if (input == null) { - resourceName = toResourceName(toBundleName(baseName, Locale.ROOT), "properties"); - input = loader.getResourceAsStream(resourceName); + String defaultResourceName = toResourceName(toBundleName(baseName, Locale.ROOT), "properties"); + input = loader.getResourceAsStream(defaultResourceName); } InputStreamReader inputReader = new InputStreamReader(input, "UTF-8"); properties.load(inputReader); // Default (internal) bundle. From cc603b8df702b0f9e304fde09fcedb2548f013cc Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 28 Feb 2020 14:42:34 +0300 Subject: [PATCH 094/362] Use ui_locales_supported from confguration instead of JSF locales list oxAuth #1275 --- .../org/gluu/util/ilocale/LocaleUtil.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 oxUtil/src/main/java/org/gluu/util/ilocale/LocaleUtil.java diff --git a/oxUtil/src/main/java/org/gluu/util/ilocale/LocaleUtil.java b/oxUtil/src/main/java/org/gluu/util/ilocale/LocaleUtil.java new file mode 100644 index 00000000..9bdcef2b --- /dev/null +++ b/oxUtil/src/main/java/org/gluu/util/ilocale/LocaleUtil.java @@ -0,0 +1,58 @@ +/* + * oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.util.ilocale; + +import java.util.List; +import java.util.Locale; + +import org.apache.commons.lang.LocaleUtils; +import org.apache.commons.lang3.tuple.Pair; + +/** + * @author Javier Rojas Blum Date: 11.27.2013 + * @author Yuriy Movchan Date: 02/28/2020 + */ +public class LocaleUtil { + + public static Locale localeMatch(List requestedLocales, List availableLocales) { + if (requestedLocales == null || availableLocales == null) { + return null; + } + + for (String requestedLocale : requestedLocales) { + Pair> locales = toLocaleList(requestedLocale); + Locale reqInQuestion = locales.getLeft(); + List lookupList = locales.getRight(); + + for (Locale localeInQuestion : lookupList) { + for (Locale availableLocale : availableLocales) { + if (localeInQuestion.equals(availableLocale)) { + return availableLocale; + } + } + } + + for (Locale availableLocale : availableLocales) { + if (reqInQuestion.getLanguage().equals(availableLocale.getLanguage())) { + return availableLocale; + } + } + } + + return null; + } + + public static Pair> toLocaleList(String locale) { + // LocaleUtils uses an underscore format (e.g. en_US), but the new Java standard + // is a hyphenated format (e.g. en-US). This allows us to use LocaleUtils' validation. + Locale localeLanguage = LocaleUtils.toLocale(locale.replace('-', '_')); + List localeList = LocaleUtils.localeLookupList(localeLanguage); + + return Pair.of(localeLanguage, localeList); + } + +} \ No newline at end of file From 8b93eccea87a21f0e6795626c1ee92af8b38f72e Mon Sep 17 00:00:00 2001 From: Madhumita Date: Fri, 6 Mar 2020 12:48:08 +0530 Subject: [PATCH 095/362] #1284 1. Init method added to BaseExternalType interface (init(customScript, configAttr)) 2. All custom scripts after 4.2 version will have API version greater than 10. We use this API version to determine which init method is to be invoked --- .../custom/script/type/BaseExternalType.java | 4 ++- .../auth/DummyPersonAuthenticationType.java | 7 ++-- .../type/authz/DummyConsentGatheringType.java | 7 ++-- .../client/DummyClientRegistrationType.java | 7 ++-- .../script/type/id/DummyIdGeneratorType.java | 7 ++-- .../introspection/DummyIntrospectionType.java | 7 ++-- .../type/logout/DummyEndSessionType.java | 6 +++- ...yResourceOwnerPasswordCredentialsType.java | 6 +++- .../script/type/scim/DummyScimType.java | 6 +++- .../type/scope/DummyDynamicScopeType.java | 7 ++-- .../session/DummyApplicationSessionType.java | 7 ++-- .../DummySpontaneousScopeType.java | 36 +++++++++++-------- .../type/uma/UmaDummyClaimsGatheringType.java | 7 ++-- .../type/uma/UmaDummyRptPolicyType.java | 7 ++-- .../type/user/DummyCacheRefreshType.java | 7 ++-- .../script/type/user/DummyUpdateUserType.java | 7 ++-- .../type/user/DummyUserRegistrationType.java | 7 ++-- .../custom/script/CustomScriptManager.java | 7 +++- 18 files changed, 105 insertions(+), 44 deletions(-) diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java index db4773c4..59557c64 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java @@ -7,7 +7,7 @@ import java.util.Map; import org.gluu.model.SimpleCustomProperty; - +import org.gluu.model.custom.script.model.CustomScript; /** * Base interface for external python script * @@ -16,6 +16,8 @@ public interface BaseExternalType { boolean init(Map configurationAttributes); + + boolean init(CustomScript customScript, Map configurationAttributes); boolean destroy(Map configurationAttributes); diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java index 5b73f53b..16803aff 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java @@ -11,7 +11,7 @@ import org.gluu.model.AuthenticationScriptUsageType; import org.gluu.model.SimpleCustomProperty; - +import org.gluu.model.custom.script.model.CustomScript; /** * Dummy implementation of interface PersonAuthenticationType * @@ -23,7 +23,10 @@ public class DummyPersonAuthenticationType implements PersonAuthenticationType { public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java index ae521702..fd243497 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java @@ -3,7 +3,7 @@ import java.util.Map; import org.gluu.model.SimpleCustomProperty; - +import org.gluu.model.custom.script.model.CustomScript; /** * Dummy implementation of interface AuthorizationType * @@ -15,7 +15,10 @@ public class DummyConsentGatheringType implements ConsentGatheringType { public boolean init(Map configurationAttributes) { return false; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return false; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java index eeb30cd6..ecab4bb1 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java @@ -7,7 +7,7 @@ import java.util.Map; import org.gluu.model.SimpleCustomProperty; - +import org.gluu.model.custom.script.model.CustomScript; /** * Dummy implementation of interface ClientRegistrationType * @@ -19,7 +19,10 @@ public class DummyClientRegistrationType implements ClientRegistrationType { public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java index 9de8df3f..8e39a550 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java @@ -7,7 +7,7 @@ import java.util.Map; import org.gluu.model.SimpleCustomProperty; - +import org.gluu.model.custom.script.model.CustomScript; /** * Dummy implementation of interface IdGeneratorType * @@ -19,7 +19,10 @@ public class DummyIdGeneratorType implements IdGeneratorType { public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java index 25419e1b..a7dcb07d 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java @@ -3,7 +3,7 @@ import java.util.Map; import org.gluu.model.SimpleCustomProperty; - +import org.gluu.model.custom.script.model.CustomScript; /** * @author Yuriy Zabrovarnyy */ @@ -12,7 +12,10 @@ public class DummyIntrospectionType implements IntrospectionType { public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java index 8709476e..35f6f5ca 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java @@ -3,6 +3,7 @@ import org.gluu.model.SimpleCustomProperty; import java.util.Map; +import org.gluu.model.custom.script.model.CustomScript; /** * @author Yuriy Zabrovarnyy @@ -12,7 +13,10 @@ public class DummyEndSessionType implements EndSessionType { public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java index 1a612988..18fe2be0 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java @@ -3,6 +3,7 @@ import java.util.Map; import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.model.CustomScript; /** * @author Yuriy Zabrovarnyy @@ -12,7 +13,10 @@ public class DummyResourceOwnerPasswordCredentialsType implements ResourceOwnerP public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java index e6621b5f..96c25ef6 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java @@ -8,6 +8,7 @@ import java.util.Map; import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.model.CustomScript; /** * @author Val Pecaoco @@ -18,7 +19,10 @@ public class DummyScimType implements ScimType { public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java index 63b1fefd..d5ee7828 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java @@ -8,7 +8,7 @@ import java.util.Map; import org.gluu.model.SimpleCustomProperty; - +import org.gluu.model.custom.script.model.CustomScript; /** * Dummy implementation of interface DynamicScopeType * @@ -20,7 +20,10 @@ public class DummyDynamicScopeType implements DynamicScopeType { public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java index 261864dc..6994eb47 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java @@ -4,7 +4,7 @@ * Copyright (c) 2014, Gluu */ package org.gluu.model.custom.script.type.session; - +import org.gluu.model.custom.script.model.CustomScript; import java.util.Map; import org.gluu.model.SimpleCustomProperty; @@ -20,7 +20,10 @@ public class DummyApplicationSessionType implements ApplicationSessionType { public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java index acbff26e..60887ca3 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java @@ -3,25 +3,31 @@ import org.gluu.model.SimpleCustomProperty; import java.util.Map; +import org.gluu.model.custom.script.model.CustomScript; public class DummySpontaneousScopeType implements SpontaneousScopeType { - @Override - public void manipulateScopes(Object context) { - } + @Override + public void manipulateScopes(Object context) { + } - @Override - public boolean init(Map configurationAttributes) { - return true; - } + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } - @Override - public boolean destroy(Map configurationAttributes) { - return true; - } + @Override + public boolean init(Map configurationAttributes) { + return true; + } - @Override - public int getApiVersion() { - return 0; - } + @Override + public boolean destroy(Map configurationAttributes) { + return true; + } + + @Override + public int getApiVersion() { + return 0; + } } diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java index 1de8936a..4fc9cb56 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java @@ -3,7 +3,7 @@ import java.util.Map; import org.gluu.model.SimpleCustomProperty; - +import org.gluu.model.custom.script.model.CustomScript; /** * @author yuriyz on 06/16/2017. */ @@ -38,7 +38,10 @@ public String getPageForStep(int step, Object gatheringContext) { public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java index 2c5c1f0c..ad020527 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java @@ -6,7 +6,7 @@ import org.gluu.model.SimpleCustomProperty; import org.gluu.model.uma.ClaimDefinition; - +import org.gluu.model.custom.script.model.CustomScript; /** * @author yuriyz on 05/30/2017. */ @@ -16,7 +16,10 @@ public class UmaDummyRptPolicyType implements UmaRptPolicyType { public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java index a817b251..3ddb65c3 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java @@ -9,7 +9,7 @@ import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.model.bind.BindCredentials; - +import org.gluu.model.custom.script.model.CustomScript; /** * Dummy implementation of interface CacheRefreshType * @@ -21,7 +21,10 @@ public class DummyCacheRefreshType implements CacheRefreshType { public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java index a73dde8a..69a340d0 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java @@ -8,7 +8,7 @@ import java.util.Map; import org.gluu.model.SimpleCustomProperty; - +import org.gluu.model.custom.script.model.CustomScript; /** * Dummy implementation of interface UpdateUserType * @@ -21,7 +21,10 @@ public class DummyUpdateUserType implements UpdateUserType { public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java index 8c903ec5..536f40d1 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java @@ -8,7 +8,7 @@ import java.util.Map; import org.gluu.model.SimpleCustomProperty; - +import org.gluu.model.custom.script.model.CustomScript; /** * Dummy implementation of interface UserRegistrationType * @@ -20,7 +20,10 @@ public class DummyUserRegistrationType implements UserRegistrationType { public boolean init(Map configurationAttributes) { return true; } - + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } @Override public boolean destroy(Map configurationAttributes) { return true; diff --git a/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java index 3c93ee0e..bd793eef 100644 --- a/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java +++ b/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java @@ -401,7 +401,12 @@ public BaseExternalType createExternalTypeFromStringWithPythonException(CustomSc boolean initialized = false; try { - initialized = externalType.init(configurationAttributes); + if (externalType.getApiVersion() > 10) { + initialized = externalType.init(customScript, configurationAttributes); + } else { + initialized = externalType.init(configurationAttributes); + log.warn(" Update the script's init method to init(self, customScript, configurationAttributes)", customScript.getName()); + } } catch (Exception ex) { log.error("Failed to initialize custom script: '{}'", ex, customScript.getName()); } From 51bea1fab038700375831da11f3142e3242185ba Mon Sep 17 00:00:00 2001 From: Jose G Date: Wed, 11 Mar 2020 09:16:57 -0500 Subject: [PATCH 096/362] Add attributes to track user edition, see https://github.com/GluuFederation/oxAuth/issues/1271 --- .../gluu/persist/model/base/SimpleUser.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java index 5ae8ed4a..72ae642b 100644 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java +++ b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java @@ -33,6 +33,12 @@ public class SimpleUser implements Serializable { @AttributeName(name = "uid", consistency = true) private String userId; + @AttributeName + private String updatedAt; + + @AttributeName(name = "oxCreationTimestamp") + private String createdAt; + @AttributeName(name = "oxAuthPersistentJWT") private String[] oxAuthPersistentJwt; @@ -66,6 +72,22 @@ public void setOxAuthPersistentJwt(String[] oxAuthPersistentJwt) { this.oxAuthPersistentJwt = oxAuthPersistentJwt; } + public String getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(String updatedAt) { + this.updatedAt = updatedAt; + } + + public String getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + public List getCustomAttributes() { return customAttributes; } From d7ed7f1cc6f83c388c287c784f39f2c2d46b71aa Mon Sep 17 00:00:00 2001 From: Jose G Date: Wed, 11 Mar 2020 09:19:10 -0500 Subject: [PATCH 097/362] Use proper data type, see https://github.com/GluuFederation/oxAuth/issues/1271 --- .../org/gluu/persist/model/base/SimpleUser.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java index 72ae642b..e6d4aaf3 100644 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java +++ b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java @@ -8,6 +8,7 @@ import java.io.Serializable; import java.util.ArrayList; +import java.util.Date; import java.util.List; import org.gluu.persist.annotation.AttributeName; @@ -34,10 +35,10 @@ public class SimpleUser implements Serializable { private String userId; @AttributeName - private String updatedAt; + private Date updatedAt; @AttributeName(name = "oxCreationTimestamp") - private String createdAt; + private Date createdAt; @AttributeName(name = "oxAuthPersistentJWT") private String[] oxAuthPersistentJwt; @@ -72,19 +73,19 @@ public void setOxAuthPersistentJwt(String[] oxAuthPersistentJwt) { this.oxAuthPersistentJwt = oxAuthPersistentJwt; } - public String getUpdatedAt() { + public Date getUpdatedAt() { return updatedAt; } - public void setUpdatedAt(String updatedAt) { + public void setUpdatedAt(Date updatedAt) { this.updatedAt = updatedAt; } - public String getCreatedAt() { + public Date getCreatedAt() { return createdAt; } - public void setCreatedAt(String createdAt) { + public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; } From beb4da7603f25bb65ccaa15c127013a6876e2833 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Wed, 18 Mar 2020 15:05:13 +0200 Subject: [PATCH 098/362] (4.2 ) Redis : Introduce more connection parameters for jedis client to get better performance #182 --- .../service/cache/AbstractRedisProvider.java | 9 +++ .../service/cache/RedisClusterProvider.java | 24 ++---- .../service/cache/RedisConfiguration.java | 74 ++++++++++++++++++- .../service/cache/RedisSentinelProvider.java | 36 ++++----- .../service/cache/RedisShardedProvider.java | 18 ++--- .../cache/RedisStandaloneProvider.java | 31 +++----- 6 files changed, 121 insertions(+), 71 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java b/core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java index 23d0cc64..3284b6d7 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/AbstractRedisProvider.java @@ -1,6 +1,7 @@ package org.gluu.service.cache; import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.JedisPoolConfig; /** * @author yuriyz @@ -14,6 +15,14 @@ public AbstractRedisProvider(RedisConfiguration redisConfiguration) { HostAndPort.setLocalhost("127.0.0.1"); } + public JedisPoolConfig createPoolConfig() { + JedisPoolConfig poolConfig = new JedisPoolConfig(); + poolConfig.setMaxTotal(redisConfiguration.getMaxTotalConnections()); + poolConfig.setMaxIdle(redisConfiguration.getMaxIdleConnections()); + poolConfig.setMinIdle(2); + return poolConfig; + } + public RedisConfiguration getRedisConfiguration() { return redisConfiguration; } diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java index b46188e4..ffb57c8c 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java @@ -1,19 +1,18 @@ package org.gluu.service.cache; -import java.io.IOException; -import java.io.Serializable; -import java.util.HashSet; -import java.util.Set; - import org.apache.commons.lang.SerializationUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPoolConfig; +import java.io.IOException; +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + /** * Important : keep it weld free. It's reused by oxd ! * @@ -33,16 +32,9 @@ public void create() { try { LOG.debug("Starting RedisClusterProvider ... configuration:" + getRedisConfiguration()); - JedisPoolConfig poolConfig = new JedisPoolConfig(); - poolConfig.setMaxTotal(1000); - poolConfig.setMinIdle(2); - - if (StringUtils.isBlank(redisConfiguration.getDecryptedPassword())) { - pool = new JedisCluster(hosts(getRedisConfiguration().getServers()), poolConfig); - } else { - // default maxAttempts and timeouts are taken from jedis constants - pool = new JedisCluster(hosts(getRedisConfiguration().getServers()), 2000, 2000, 5, redisConfiguration.getDecryptedPassword(), poolConfig); - } + JedisPoolConfig poolConfig = createPoolConfig(); + String password = StringUtils.isBlank(redisConfiguration.getDecryptedPassword()) ? null : redisConfiguration.getDecryptedPassword(); + pool = new JedisCluster(hosts(getRedisConfiguration().getServers()), redisConfiguration.getConnectionTimeout(), redisConfiguration.getSoTimeout(), redisConfiguration.getMaxRetryAttempts(), password, poolConfig); testConnection(); LOG.debug("RedisClusterProvider started."); diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java b/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java index d6fbea62..93e0386d 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java @@ -1,10 +1,10 @@ package org.gluu.service.cache; -import java.io.Serializable; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.io.Serializable; + /** * @author yuriyz on 02/23/2017. */ @@ -29,6 +29,71 @@ public class RedisConfiguration implements Serializable { private String sslTrustStoreFilePath = ""; + /** + * The cap on the number of "idle" instances in the pool. If maxIdle + * is set too low on heavily loaded systems it is possible you will see + * objects being destroyed and almost immediately new objects being created. + * This is a result of the active threads momentarily returning objects + * faster than they are requesting them, causing the number of idle + * objects to rise above maxIdle. The best value for maxIdle for heavily + * loaded system will vary but the default is a good starting point. + */ + private int maxIdleConnections = 10; + + private int maxTotalConnections = 10000; + + private int connectionTimeout = 3000; + + /** + * With this option set to a non-zero timeout, a read() call on the InputStream associated with this Socket will block for only this amount of time. + * If the timeout expires, a java.net.SocketTimeoutException is raised, though the Socket is still valid. + * The option must be enabled prior to entering the blocking operation to have effect. The timeout must be > 0. + * A timeout of zero is interpreted as an infinite timeout. + */ + private int soTimeout = 3000; + + private int maxRetryAttempts = 5; + + public int getMaxIdleConnections() { + return maxIdleConnections; + } + + public void setMaxIdleConnections(int maxIdleConnections) { + this.maxIdleConnections = maxIdleConnections; + } + + public int getConnectionTimeout() { + return connectionTimeout; + } + + public void setConnectionTimeout(int connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + + public int getSoTimeout() { + return soTimeout; + } + + public void setSoTimeout(int soTimeout) { + this.soTimeout = soTimeout; + } + + public int getMaxRetryAttempts() { + return maxRetryAttempts; + } + + public void setMaxRetryAttempts(int maxRetryAttempts) { + this.maxRetryAttempts = maxRetryAttempts; + } + + public int getMaxTotalConnections() { + return maxTotalConnections; + } + + public void setMaxTotalConnections(int maxTotalConnections) { + this.maxTotalConnections = maxTotalConnections; + } + public String getServers() { return servers; } @@ -102,6 +167,11 @@ public String toString() { ", useSSL=" + useSSL + ", sslTrustStoreFilePath=" + sslTrustStoreFilePath + ", sentinelMasterGroupName=" + sentinelMasterGroupName + + ", maxIdleConnections=" + maxIdleConnections + + ", maxTotalConnections=" + maxTotalConnections + + ", connectionTimeout=" + connectionTimeout + + ", soTimeout=" + soTimeout + + ", maxRetryAttempts=" + maxRetryAttempts + '}'; } } diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java index 2a529f66..e5fd1f90 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java @@ -1,17 +1,16 @@ package org.gluu.service.cache; -import java.io.Serializable; - +import com.google.common.collect.Sets; import org.apache.commons.lang.SerializationUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - -import com.google.common.collect.Sets; - import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisSentinelPool; +import redis.clients.jedis.Protocol; + +import java.io.Serializable; /** * Important : keep it weld free. It's reused by oxd ! @@ -32,22 +31,17 @@ public void create() { try { LOG.debug("Starting RedisSentinelProvider ... configuration:" + getRedisConfiguration()); - JedisPoolConfig poolConfig = new JedisPoolConfig(); - poolConfig.setMaxTotal(1000); - poolConfig.setMinIdle(2); - - if (StringUtils.isBlank(redisConfiguration.getDecryptedPassword())) { - pool = new JedisSentinelPool( - getRedisConfiguration().getSentinelMasterGroupName(), - Sets.newHashSet(StringUtils.split(getRedisConfiguration().getServers().trim(), ",")), - poolConfig); - } else { - pool = new JedisSentinelPool( - getRedisConfiguration().getSentinelMasterGroupName(), - Sets.newHashSet(StringUtils.split(getRedisConfiguration().getServers().trim(), ",")), - poolConfig, - redisConfiguration.getDecryptedPassword()); - } + JedisPoolConfig poolConfig = createPoolConfig(); + String password = StringUtils.isBlank(redisConfiguration.getDecryptedPassword()) ? null : redisConfiguration.getDecryptedPassword(); + + pool = new JedisSentinelPool( + getRedisConfiguration().getSentinelMasterGroupName(), + Sets.newHashSet(StringUtils.split(getRedisConfiguration().getServers().trim(), ",")), + poolConfig, + redisConfiguration.getConnectionTimeout(), + redisConfiguration.getSoTimeout(), + password, + Protocol.DEFAULT_DATABASE); testConnection(); LOG.debug("RedisSentinelProvider started."); diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java index 7c116138..ab8587b3 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java @@ -1,23 +1,21 @@ package org.gluu.service.cache; -import java.io.File; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import javax.net.ssl.SSLParameters; - import org.apache.commons.lang.SerializationUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.conn.ssl.DefaultHostnameVerifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisShardInfo; import redis.clients.jedis.ShardedJedis; import redis.clients.jedis.ShardedJedisPool; +import javax.net.ssl.SSLParameters; +import java.io.File; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + /** * Important : keep it weld free. It's reused by oxd ! * @@ -37,9 +35,7 @@ public void create() { try { LOG.debug("Starting RedisShardedProvider ... configuration:" + redisConfiguration); - JedisPoolConfig poolConfig = new JedisPoolConfig(); - poolConfig.setMaxTotal(1000); - poolConfig.setMinIdle(2); + JedisPoolConfig poolConfig = createPoolConfig(); pool = new ShardedJedisPool(poolConfig, shards(redisConfiguration)); diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java index 476ce932..1a91243b 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java @@ -1,22 +1,16 @@ package org.gluu.service.cache; -import java.io.File; -import java.io.Serializable; - -import javax.annotation.PreDestroy; -import javax.net.ssl.SSLParameters; - import org.apache.commons.lang.SerializationUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.conn.ssl.DefaultHostnameVerifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import redis.clients.jedis.*; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPool; -import redis.clients.jedis.JedisPoolConfig; -import redis.clients.jedis.Protocol; +import javax.annotation.PreDestroy; +import javax.net.ssl.SSLParameters; +import java.io.File; +import java.io.Serializable; /** * Important : keep it weld free. It's reused by oxd ! @@ -37,11 +31,10 @@ public void create() { LOG.debug("Starting RedisStandaloneProvider ..."); try { - JedisPoolConfig poolConfig = new JedisPoolConfig(); - poolConfig.setMaxTotal(1000); - poolConfig.setMinIdle(2); + JedisPoolConfig poolConfig = createPoolConfig(); HostAndPort hostAndPort = RedisClusterProvider.hosts(redisConfiguration.getServers()).iterator().next(); + String password = StringUtils.isBlank(redisConfiguration.getDecryptedPassword()) ? null : redisConfiguration.getDecryptedPassword(); if (redisConfiguration.getUseSSL()) { if (StringUtils.isNotBlank(redisConfiguration.getSslTrustStoreFilePath())) { @@ -49,22 +42,18 @@ public void create() { pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), true, RedisProviderFactory.createTrustStoreSslSocketFactory(new File(redisConfiguration.getSslTrustStoreFilePath())), new SSLParameters(), new DefaultHostnameVerifier()); } else { - pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), Protocol.DEFAULT_TIMEOUT, redisConfiguration.getDecryptedPassword(), true, + pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), redisConfiguration.getConnectionTimeout(), redisConfiguration.getDecryptedPassword(), true, RedisProviderFactory.createTrustStoreSslSocketFactory(new File(redisConfiguration.getSslTrustStoreFilePath())), new SSLParameters(), new DefaultHostnameVerifier()); } } else { if (StringUtils.isBlank(redisConfiguration.getDecryptedPassword())) { pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), true); } else { - pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), Protocol.DEFAULT_TIMEOUT, redisConfiguration.getDecryptedPassword(), true); + pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), redisConfiguration.getConnectionTimeout(), redisConfiguration.getDecryptedPassword(), true); } } } else { - if (StringUtils.isBlank(redisConfiguration.getDecryptedPassword())) { - pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort()); - } else { - pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), Protocol.DEFAULT_TIMEOUT, redisConfiguration.getDecryptedPassword()); - } + pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), redisConfiguration.getConnectionTimeout(), password); } testConnection(); From 516720983a4d559fea5c79259331527c8a0e8a11 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Fri, 20 Mar 2020 16:43:04 +0200 Subject: [PATCH 099/362] (4.2) set default maxTotalConnections = 500 --- .../main/java/org/gluu/service/cache/RedisConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java b/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java index 93e0386d..e9280d0f 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java @@ -40,7 +40,7 @@ public class RedisConfiguration implements Serializable { */ private int maxIdleConnections = 10; - private int maxTotalConnections = 10000; + private int maxTotalConnections = 500; private int connectionTimeout = 3000; From 21bff792a60bce27148cd6eb441d38ccc7f5fe70 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Wed, 25 Mar 2020 09:36:42 +0100 Subject: [PATCH 100/362] Remove svn fields --- .../gluu/config/oxtrust/AppConfiguration.java | 30 +------------------ 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index 25ffc19f..51689a75 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -52,9 +52,6 @@ public class AppConfiguration implements Configuration, Serializable { private boolean updateStatus; - private String svnConfigurationStoreRoot; - private String svnConfigurationStorePassword; - private String keystorePath; private String keystorePassword; @@ -91,8 +88,6 @@ public class AppConfiguration implements Configuration, Serializable { private String servicesRestartTrigger; - private boolean persistSVN; - private String oxAuthSectorIdentifierUrl; private String oxAuthClientId; @@ -320,21 +315,6 @@ public void setUpdateStatus(boolean updateStatus) { this.updateStatus = updateStatus; } - public String getSvnConfigurationStoreRoot() { - return svnConfigurationStoreRoot; - } - - public void setSvnConfigurationStoreRoot(String svnConfigurationStoreRoot) { - this.svnConfigurationStoreRoot = svnConfigurationStoreRoot; - } - - public String getSvnConfigurationStorePassword() { - return svnConfigurationStorePassword; - } - - public void setSvnConfigurationStorePassword(String svnConfigurationStorePassword) { - this.svnConfigurationStorePassword = svnConfigurationStorePassword; - } public String getKeystorePath() { return keystorePath; @@ -519,15 +499,7 @@ public String getServicesRestartTrigger() { public void setServicesRestartTrigger(String servicesRestartTrigger) { this.servicesRestartTrigger = servicesRestartTrigger; } - - public boolean isPersistSVN() { - return persistSVN; - } - - public void setPersistSVN(boolean persistSVN) { - this.persistSVN = persistSVN; - } - + public String getOxAuthSectorIdentifierUrl() { return oxAuthSectorIdentifierUrl; } From 788621de982fd264ea7cd3ffdc02af690e86f89b Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Wed, 25 Mar 2020 11:15:07 +0100 Subject: [PATCH 101/362] Remove fields related to photos --- .../gluu/config/oxtrust/AppConfiguration.java | 57 +------------------ 1 file changed, 1 insertion(+), 56 deletions(-) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index 51689a75..27dcca31 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -42,12 +42,6 @@ public class AppConfiguration implements Configuration, Serializable { private String[] contactObjectClassTypes; private String[] contactObjectClassDisplayNames; - private String photoRepositoryRootDir; - private int photoRepositoryThumbWidth; - private int photoRepositoryThumbHeight; - private int photoRepositoryCountLeveles; - private int photoRepositoryCountFoldersPerLevel; - private String ldifStore; private boolean updateStatus; @@ -61,8 +55,6 @@ public class AppConfiguration implements Configuration, Serializable { private String spMetadataPath; - private String logoLocation; - private String idpSecurityKey; private String idpSecurityKeyPassword; private String idpSecurityCert; @@ -259,45 +251,7 @@ public void setContactObjectClassDisplayNames(String[] contactObjectClassDisplay this.contactObjectClassDisplayNames = contactObjectClassDisplayNames; } - public String getPhotoRepositoryRootDir() { - return photoRepositoryRootDir; - } - - public void setPhotoRepositoryRootDir(String photoRepositoryRootDir) { - this.photoRepositoryRootDir = photoRepositoryRootDir; - } - - public int getPhotoRepositoryThumbWidth() { - return photoRepositoryThumbWidth; - } - - public void setPhotoRepositoryThumbWidth(int photoRepositoryThumbWidth) { - this.photoRepositoryThumbWidth = photoRepositoryThumbWidth; - } - - public int getPhotoRepositoryThumbHeight() { - return photoRepositoryThumbHeight; - } - - public void setPhotoRepositoryThumbHeight(int photoRepositoryThumbHeight) { - this.photoRepositoryThumbHeight = photoRepositoryThumbHeight; - } - - public int getPhotoRepositoryCountLeveles() { - return photoRepositoryCountLeveles; - } - - public void setPhotoRepositoryCountLeveles(int photoRepositoryCountLeveles) { - this.photoRepositoryCountLeveles = photoRepositoryCountLeveles; - } - public int getPhotoRepositoryCountFoldersPerLevel() { - return photoRepositoryCountFoldersPerLevel; - } - - public void setPhotoRepositoryCountFoldersPerLevel(int photoRepositoryCountFoldersPerLevel) { - this.photoRepositoryCountFoldersPerLevel = photoRepositoryCountFoldersPerLevel; - } public String getLdifStore() { return ldifStore; @@ -355,15 +309,6 @@ public String getSpMetadataPath() { public void setSpMetadataPath(String spMetadataPath) { this.spMetadataPath = spMetadataPath; } - - public String getLogoLocation() { - return logoLocation; - } - - public void setLogoLocation(String logoLocation) { - this.logoLocation = logoLocation; - } - public String getIdpSecurityKey() { return idpSecurityKey; } @@ -499,7 +444,7 @@ public String getServicesRestartTrigger() { public void setServicesRestartTrigger(String servicesRestartTrigger) { this.servicesRestartTrigger = servicesRestartTrigger; } - + public String getOxAuthSectorIdentifierUrl() { return oxAuthSectorIdentifierUrl; } From 52f65e3ce5092d36c13d813eeaf02928414cfbf5 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 26 Mar 2020 09:13:17 +0300 Subject: [PATCH 102/362] Use couchbase TTL for auto-expiration of entities #127 --- .../gluu/persist/annotation/Expiration.java | 23 ++++++++ .../gluu/persist/PersistenceEntryManager.java | 1 + .../gluu/persist/impl/BaseEntryManager.java | 59 +++++++++++++++++-- .../couchbase/impl/CouchbaseEntryManager.java | 11 +++- .../operation/CouchbaseOperationService.java | 1 + .../impl/CouchbaseOperationsServiceImpl.java | 11 +++- .../hybrid/impl/HybridEntryManager.java | 8 ++- .../persist/ldap/impl/LdapEntryManager.java | 11 +++- 8 files changed, 113 insertions(+), 12 deletions(-) create mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/Expiration.java diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/Expiration.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/Expiration.java new file mode 100644 index 00000000..f79e7f2d --- /dev/null +++ b/persistence-annotation/src/main/java/org/gluu/persist/annotation/Expiration.java @@ -0,0 +1,23 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.persist.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Persistance Expiration + * + * @author Yuriy Movchan Date: 03/26/2020 + */ +@Target({ FIELD }) +@Retention(RUNTIME) +public @interface Expiration { +} diff --git a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java index e28dc39a..0e17be5c 100644 --- a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java @@ -82,6 +82,7 @@ PagedResult findPagedEntries(String primaryKey, Class entryClass, Filt void removeRecursively(String primaryKey); boolean hasBranchesSupport(String primaryKey); + boolean hasExpirationSupport(String primaryKey); String getPersistenceType(); String getPersistenceType(String primaryKey); diff --git a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java index 99992efa..979cce52 100644 --- a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java @@ -30,6 +30,7 @@ import org.gluu.persist.annotation.CustomObjectClass; import org.gluu.persist.annotation.DN; import org.gluu.persist.annotation.DataEntry; +import org.gluu.persist.annotation.Expiration; import org.gluu.persist.annotation.JsonObject; import org.gluu.persist.annotation.ObjectClass; import org.gluu.persist.annotation.SchemaEntry; @@ -67,6 +68,7 @@ public abstract class BaseEntryManager implements PersistenceEntryManager { JsonObject.class }; private static final Class[] LDAP_CUSTOM_OBJECT_CLASS_PROPERTY_ANNOTATION = { CustomObjectClass.class }; private static final Class[] LDAP_DN_PROPERTY_ANNOTATION = { DN.class }; + private static final Class[] LDAP_EXPIRATION_PROPERTY_ANNOTATION = { Expiration.class }; public static final String OBJECT_CLASS = "objectClass"; public static final String[] EMPTY_STRING_ARRAY = new String[0]; @@ -106,6 +108,8 @@ public void persist(Object entry) { Object dnValue = getDNValue(entry, entryClass); + int expirationValue = getExpirationValue(entry, entryClass); + List attributes = getAttributesListForPersist(entry, propertiesAnnotations); // Add object classes @@ -114,10 +118,10 @@ public void persist(Object entry) { LOG.debug(String.format("LDAP attributes for persist: %s", attributes)); - persist(dnValue.toString(), attributes); + persist(dnValue.toString(), attributes, expirationValue); } - protected abstract void persist(String dn, List attributes); + protected abstract void persist(String dn, List attributes, int expiration); @Override @SuppressWarnings("unchecked") @@ -767,11 +771,24 @@ protected void setCustomObjectClasses(Object entry, Class entryClass, String[ protected String getDNPropertyName(Class entryClass) { List propertiesAnnotations = getEntryDnAnnotations(entryClass); if (propertiesAnnotations.size() == 0) { - throw new MappingException("Entry should has property with annotation LdapDN"); + throw new MappingException("Entry should has property with annotation DN"); } if (propertiesAnnotations.size() > 1) { - throw new MappingException("Entry should has only one property with annotation LdapDN"); + throw new MappingException("Entry should has only one property with annotation DN"); + } + + return propertiesAnnotations.get(0).getPropertyName(); + } + + protected String getExpirationPropertyName(Class entryClass) { + List propertiesAnnotations = getEntryExpirationAnnotations(entryClass); + if (propertiesAnnotations.size() == 0) { + return null; + } + + if (propertiesAnnotations.size() > 1) { + throw new MappingException("Entry should has only one property with annotation Expiration"); } return propertiesAnnotations.get(0).getPropertyName(); @@ -1444,6 +1461,10 @@ protected List getEntryDnAnnotations(Class entryClass return getEntryClassAnnotations(entryClass, "dn_", LDAP_DN_PROPERTY_ANNOTATION); } + protected List getEntryExpirationAnnotations(Class entryClass) { + return getEntryClassAnnotations(entryClass, "exp_", LDAP_EXPIRATION_PROPERTY_ANNOTATION); + } + protected List getEntryCustomObjectClassAnnotations(Class entryClass) { return getEntryClassAnnotations(entryClass, "custom_", LDAP_CUSTOM_OBJECT_CLASS_PROPERTY_ANNOTATION); } @@ -1719,6 +1740,36 @@ protected Object getDNValue(Object entry, Class entryClass) { return dnValue; } + protected int getExpirationValue(Object entry, Class entryClass) { + // Check if entry has Expiration property + String expirationProperty = getExpirationPropertyName(entryClass); + + if (expirationProperty == null) { + // No entry expiration property + return 0; + } + + // Get Expiration value + Getter expirationGetter = getGetter(entryClass, expirationProperty); + if (expirationGetter == null) { + throw new MappingException("Entry should has getter for property " + expirationGetter); + } + + Class propertyType = expirationGetter.getReturnType(); + if (!((propertyType == Integer.class) || (propertyType == Integer.TYPE))) { + throw new MappingException("Entry expiration property should has Integer type. Property: '" + + expirationGetter + "'"); + } + + Object expirationValue = expirationGetter.get(entry); + if (expirationValue == null) { + // No entry expiration or null + return 0; + } + + return (int) expirationValue; + } + private String getEntryKey(T entry, boolean caseSensetive, Getter[] propertyGetters) { StringBuilder sb = new StringBuilder("key"); for (Getter getter : propertyGetters) { diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java index 9444efb1..6ab56931 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java @@ -166,7 +166,7 @@ public void remove(Object entry) { } @Override - protected void persist(String dn, List attributes) { + protected void persist(String dn, List attributes, int expiration) { JsonObject jsonObject = JsonObject.create(); for (AttributeData attribute : attributes) { String attributeName = attribute.getName(); @@ -203,7 +203,7 @@ protected void persist(String dn, List attributes) { // Persist entry try { - boolean result = operationService.addEntry(toCouchbaseKey(dn).getKey(), jsonObject); + boolean result = operationService.addEntry(toCouchbaseKey(dn).getKey(), jsonObject, expiration); if (!result) { throw new EntryPersistenceException(String.format("Failed to persist entry: %s", dn)); } @@ -779,7 +779,7 @@ public List exportEntry(String dn) { } @Override public void importEntry(String dn, List attributes) { - persist(dn, attributes); + persist(dn, attributes, 0); } private ConvertedExpression toCouchbaseFilter(Filter genericFilter, Map propertiesAnnotationsMap) throws SearchException { @@ -872,6 +872,11 @@ public boolean hasBranchesSupport(String dn) { return false; } + @Override + public boolean hasExpirationSupport(String primaryKey) { + return true; + } + @Override public String getPersistenceType() { return CouchbaseEntryManagerFactory.PERSISTENCE_TYPE; diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java index bed400b6..a9880ff1 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java @@ -47,6 +47,7 @@ public interface CouchbaseOperationService extends PersistenceOperationService { boolean authenticate(String key, String password) throws SearchException, AuthenticationException; boolean addEntry(String key, JsonObject atts) throws DuplicateEntryException, PersistenceException; + boolean addEntry(String key, JsonObject jsonObject, int expirity) throws DuplicateEntryException, PersistenceException; boolean updateEntry(String key, List mods) throws UnsupportedOperationException, PersistenceException; diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationsServiceImpl.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationsServiceImpl.java index 8cb0bae3..f8cd7fb2 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationsServiceImpl.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationsServiceImpl.java @@ -159,10 +159,15 @@ private boolean authenticateImpl(final String key, final String password) throws @Override public boolean addEntry(String key, JsonObject jsonObject) throws DuplicateEntryException, PersistenceException { + return addEntry(key, jsonObject, 0); + } + + @Override + public boolean addEntry(String key, JsonObject jsonObject, int expirity) throws DuplicateEntryException, PersistenceException { Instant startTime = OperationDurationUtil.instance().now(); BucketMapping bucketMapping = connectionProvider.getBucketMappingByKey(key); - boolean result = addEntryImpl(bucketMapping, key, jsonObject); + boolean result = addEntryImpl(bucketMapping, key, jsonObject, expirity); Duration duration = OperationDurationUtil.instance().duration(startTime); OperationDurationUtil.instance().logDebug("Couchbase operation: add, duration: {}, bucket: {}, key: {}, json: {}", duration, bucketMapping.getBucketName(), key, jsonObject); @@ -170,9 +175,9 @@ public boolean addEntry(String key, JsonObject jsonObject) throws DuplicateEntry return result; } - private boolean addEntryImpl(BucketMapping bucketMapping, String key, JsonObject jsonObject) throws PersistenceException { + private boolean addEntryImpl(BucketMapping bucketMapping, String key, JsonObject jsonObject, int expirity) throws PersistenceException { try { - JsonDocument jsonDocument = JsonDocument.create(key, jsonObject); + JsonDocument jsonDocument = JsonDocument.create(key, expirity, jsonObject); JsonDocument result = bucketMapping.getBucket().upsert(jsonDocument); if (result != null) { return true; diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java index e9b9cede..d8dfa283 100644 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java +++ b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java @@ -272,6 +272,12 @@ public boolean hasBranchesSupport(String dn) { return persistenceEntryManager.hasBranchesSupport(dn); } + @Override + public boolean hasExpirationSupport(String dn) { + PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(dn); + return persistenceEntryManager.hasExpirationSupport(dn); + } + @Override public String getPersistenceType() { return HybridEntryManagerFactory.PERSISTENCE_TYPE; @@ -397,7 +403,7 @@ public void removeRecursively(String dn) { //************************************************************************* @Override - protected void persist(String dn, List attributes) { + protected void persist(String dn, List attributes, int expiration) { throw new UnsupportedOperationException("Method not implemented."); } diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java index 2a94de7e..bf43420d 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java @@ -158,8 +158,12 @@ public void remove(Object entry) { remove(dnValue.toString()); } - @Override protected void persist(String dn, List attributes) { + persist(dn, attributes); + } + + @Override + protected void persist(String dn, List attributes, int expiration) { List ldapAttributes = new ArrayList(attributes.size()); for (AttributeData attribute : attributes) { String attributeName = attribute.getName(); @@ -909,6 +913,11 @@ public boolean hasBranchesSupport(String dn) { return true; } + @Override + public boolean hasExpirationSupport(String primaryKey) { + return false; + } + @Override public String getPersistenceType() { return LdapEntryManagerFactory.PERSISTENCE_TYPE; From c3b8a2f41e0d34b1a3e9484afc6f4455aa7ed9ad Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 26 Mar 2020 09:13:30 +0300 Subject: [PATCH 103/362] Use couchbase TTL for auto-expiration of entities #127 --- .../cache/NativePersistenceCacheEntity.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java index d0cc1655..0fb09f44 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java @@ -6,6 +6,7 @@ import org.gluu.persist.annotation.AttributeName; import org.gluu.persist.annotation.DN; import org.gluu.persist.annotation.DataEntry; +import org.gluu.persist.annotation.Expiration; import org.gluu.persist.annotation.ObjectClass; import org.gluu.persist.model.base.Deletable; import org.gluu.persist.model.base.DeletableEntity; @@ -16,6 +17,8 @@ public class NativePersistenceCacheEntity extends DeletableEntity implements Ser @DN private String dn; + @Expiration + private int ttl; @AttributeName(name = "uuid") private String id; @AttributeName(name = "iat") @@ -31,7 +34,15 @@ public void setDn(String dn) { this.dn = dn; } - public String getId() { + public int getTtl() { + return ttl; + } + + public void setTtl(int ttl) { + this.ttl = ttl; + } + + public String getId() { return id; } @@ -57,7 +68,7 @@ public void setData(String data) { @Override public String toString() { - return "NativePersistenceCacheEntity [dn=" + dn + ", id=" + id + ", creationDate=" + creationDate + ", data=" + data - + ", toString()=" + super.toString() + "]"; + return "NativePersistenceCacheEntity [dn=" + dn + ", ttl=" + ttl + ", id=" + id + ", creationDate=" + creationDate + ", data=" + + data + "]"; } } From fd7db93462840b5a1a597f6608127ce6a2d376aa Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 26 Mar 2020 10:16:29 +0300 Subject: [PATCH 104/362] Use couchbase TTL for auto-expiration of entities #127 --- .../org/gluu/service/cache/CacheProvider.java | 1 + .../cache/NativePersistenceCacheProvider.java | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java index 00e47458..833df7aa 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java @@ -26,6 +26,7 @@ public abstract class CacheProvider implements CacheInterface { /* * Put value with specified key without expiration */ + @Deprecated public abstract void put(String key, Object object); public abstract void put(int expirationInSeconds, String key, Object object); diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index 4675e57b..af731091 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -139,9 +139,8 @@ public static String hashKey(String key) { @Override public void put(String key, Object object) { Date creationDate = new Date(); - Date expirationDate = new Date(Long.MAX_VALUE); - putImpl(key, object, creationDate, expirationDate); + putImpl(key, object, creationDate, Integer.MAX_VALUE); } @Override @@ -150,25 +149,28 @@ public void put(int expirationInSeconds, String key, Object object) { expirationInSeconds = expirationInSeconds > 0 ? expirationInSeconds : cacheConfiguration.getNativePersistenceConfiguration().getDefaultPutExpiration(); + + putImpl(key, object, creationDate, expirationInSeconds); + } + + private void putImpl(String key, Object object, Date creationDate, int expirationInSeconds) { Calendar expirationDate = Calendar.getInstance(); expirationDate.setTime(creationDate); expirationDate.add(Calendar.SECOND, expirationInSeconds); - putImpl(key, object, creationDate, expirationDate.getTime()); - } - - private void putImpl(String key, Object object, Date creationDate, Date expirationDate) { - String originalKey = key; + + String originalKey = key; try { key = hashKey(key); NativePersistenceCacheEntity entity = new NativePersistenceCacheEntity(); + entity.setTtl(expirationInSeconds); entity.setData(asString(object)); entity.setId(key); entity.setDn(createDn(key)); entity.setCreationDate(creationDate); - entity.setNewExpirationDate(expirationDate); + entity.setNewExpirationDate(expirationDate.getTime()); entity.setDeletable(true); silentlyRemoveEntityIfExists(entity.getDn()); From f99919ac9b401187dba3abd9f5525f21f4fadfab Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 26 Mar 2020 10:27:13 +0300 Subject: [PATCH 105/362] Use couchbase TTL for auto-expiration of entities #127 --- .../gluu/service/cache/NativePersistenceCacheProvider.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index af731091..1afd88c2 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -243,7 +243,10 @@ private String asString(Object o) { @Override public void cleanup(final Date now) { - cleanup(now, cacheConfiguration.getNativePersistenceConfiguration().getDefaultCleanupBatchSize()); + NativePersistenceConfiguration nativePersistenceConfiguration = cacheConfiguration.getNativePersistenceConfiguration(); + if (!entryManager.hasExpirationSupport(nativePersistenceConfiguration.getBaseDn())) { + cleanup(now, cacheConfiguration.getNativePersistenceConfiguration().getDefaultCleanupBatchSize()); + } } public void cleanup(final Date now, int batchSize) { From 2a8cb45e18e670c5a644b645a979344ee363c050 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Thu, 26 Mar 2020 09:37:23 +0200 Subject: [PATCH 106/362] removed put method without expiration from Cache service --- .../org/gluu/service/cache/CacheProvider.java | 6 ---- .../service/cache/InMemoryCacheProvider.java | 22 ++++----------- .../gluu/service/cache/MemcachedProvider.java | 28 ++++--------------- .../cache/NativePersistenceCacheProvider.java | 28 +++++++------------ .../org/gluu/service/cache/RedisProvider.java | 15 ++++------ 5 files changed, 26 insertions(+), 73 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java index 833df7aa..a5769769 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/CacheProvider.java @@ -23,12 +23,6 @@ public abstract class CacheProvider implements CacheInterface { */ public abstract Object get(String key); - /* - * Put value with specified key without expiration - */ - @Deprecated - public abstract void put(String key, Object object); - public abstract void put(int expirationInSeconds, String key, Object object); /** diff --git a/core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java index 1b4053cb..aad2c7bb 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/InMemoryCacheProvider.java @@ -1,17 +1,15 @@ package org.gluu.service.cache; -import java.util.concurrent.TimeUnit; +import net.jodah.expiringmap.ExpirationPolicy; +import net.jodah.expiringmap.ExpiringMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.jodah.expiringmap.ExpirationPolicy; -import net.jodah.expiringmap.ExpiringMap; +import java.util.concurrent.TimeUnit; /** * @author yuriyz on 02/21/2017. @@ -78,16 +76,6 @@ public Object get(String key) { return map.get(key); } - @Override - public void put(String key, Object object) { - // if key already exists and hash is the same for value then expiration time is - // not updated - // net.jodah.expiringmap.ExpiringMap.putInternal() - // therefore we first remove entry and then put it - map.remove(key); - map.put(key, object, ExpirationPolicy.CREATED, Long.MAX_VALUE, TimeUnit.DAYS); - } - @Override public void put(int expirationInSeconds, String key, Object object) { // if key already exists and hash is the same for value then expiration time is diff --git a/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java b/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java index e6010b7c..52c78570 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/MemcachedProvider.java @@ -1,21 +1,16 @@ package org.gluu.service.cache; +import net.spy.memcached.*; +import net.spy.memcached.internal.OperationFuture; +import net.spy.memcached.ops.OperationStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import net.spy.memcached.AddrUtil; -import net.spy.memcached.BinaryConnectionFactory; -import net.spy.memcached.ConnectionFactory; -import net.spy.memcached.DefaultConnectionFactory; -import net.spy.memcached.MemcachedClient; -import net.spy.memcached.internal.OperationFuture; -import net.spy.memcached.ops.OperationStatus; - /** * @author yuriyz on 02/02/2017. */ @@ -123,17 +118,6 @@ public Object get(String key) { } } - @Override - public void put(String key, Object object) { - try { - OperationFuture set = client.set(key, 0, object); - OperationStatus status = set.getStatus(); // block - log.trace("set - key:" + key + ", expiration: " + 0 + ", status:" + status + ", get:" + get(key)); - } catch (Exception e) { - log.error("Failed to put object in cache, key: " + key, e); - } - } - @Override public void put(int expirationInSeconds, String key, Object object) { try { diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index 1afd88c2..7d20e16e 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -1,16 +1,5 @@ package org.gluu.service.cache; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.Calendar; -import java.util.Date; - -import javax.annotation.PostConstruct; -import javax.enterprise.context.ApplicationScoped; -import javax.inject.Inject; - import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; @@ -21,6 +10,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Calendar; +import java.util.Date; + @ApplicationScoped public class NativePersistenceCacheProvider extends AbstractCacheProvider { @@ -136,13 +135,6 @@ public static String hashKey(String key) { return DigestUtils.sha256Hex(key); } - @Override - public void put(String key, Object object) { - Date creationDate = new Date(); - - putImpl(key, object, creationDate, Integer.MAX_VALUE); - } - @Override public void put(int expirationInSeconds, String key, Object object) { Date creationDate = new Date(); diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java index d3f4fddf..86cccac2 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java @@ -1,15 +1,15 @@ package org.gluu.service.cache; -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.enterprise.context.ApplicationScoped; -import javax.inject.Inject; - import org.apache.commons.lang.StringUtils; import org.gluu.util.security.StringEncrypter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + /** * @author yuriyz on 02/23/2017. */ @@ -111,11 +111,6 @@ public Object get(String key) { return redisProvider.get(key); } - @Override - public void put(String key, Object object) { - redisProvider.put(key, object); - } - @Override public void put(int expirationInSeconds, String key, Object object) { redisProvider.put(expirationInSeconds > 0 ? expirationInSeconds : defaultPutExpiration, key, object); From 2303559744bc0e04a6612ec76f30306754bf871a Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Thu, 26 Mar 2020 12:21:28 +0200 Subject: [PATCH 107/362] (4.2) changed int->Integer for @Expiration --- .../cache/NativePersistenceCacheEntity.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java index 0fb09f44..debed376 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java @@ -1,16 +1,12 @@ package org.gluu.service.cache; -import java.io.Serializable; -import java.util.Date; - -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.Expiration; -import org.gluu.persist.annotation.ObjectClass; +import org.gluu.persist.annotation.*; import org.gluu.persist.model.base.Deletable; import org.gluu.persist.model.base.DeletableEntity; +import java.io.Serializable; +import java.util.Date; + @DataEntry @ObjectClass(value = "cache") public class NativePersistenceCacheEntity extends DeletableEntity implements Serializable, Deletable { @@ -18,7 +14,7 @@ public class NativePersistenceCacheEntity extends DeletableEntity implements Ser @DN private String dn; @Expiration - private int ttl; + private Integer ttl; @AttributeName(name = "uuid") private String id; @AttributeName(name = "iat") @@ -34,11 +30,11 @@ public void setDn(String dn) { this.dn = dn; } - public int getTtl() { + public Integer getTtl() { return ttl; } - public void setTtl(int ttl) { + public void setTtl(Integer ttl) { this.ttl = ttl; } From a8ca235f48d1a205820aaed8866436991b503293 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 26 Mar 2020 13:32:23 +0300 Subject: [PATCH 108/362] Use couchbase TTL for auto-expiration of entities #127 --- .../cache/NativePersistenceCacheEntity.java | 2 +- .../cache/NativePersistenceCacheProvider.java | 8 +++++- .../gluu/persist/impl/BaseEntryManager.java | 22 +++++++++------ .../couchbase/impl/CouchbaseEntryManager.java | 6 ++--- .../operation/CouchbaseOperationService.java | 4 +-- .../impl/CouchbaseOperationsServiceImpl.java | 27 ++++++++++++------- .../hybrid/impl/HybridEntryManager.java | 4 +-- .../persist/ldap/impl/LdapEntryManager.java | 4 +-- 8 files changed, 49 insertions(+), 28 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java index 0fb09f44..500656dd 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java @@ -18,7 +18,7 @@ public class NativePersistenceCacheEntity extends DeletableEntity implements Ser @DN private String dn; @Expiration - private int ttl; + private Integer ttl; @AttributeName(name = "uuid") private String id; @AttributeName(name = "iat") diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index 1afd88c2..863dbceb 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -283,5 +283,11 @@ public void setBaseDn(String baseDn) { public void setCacheConfiguration(CacheConfiguration cacheConfiguration) { this.cacheConfiguration = cacheConfiguration; } - + + public static void main(String[] args) { + NativePersistenceCacheProvider cp = new NativePersistenceCacheProvider(); + Object obj = cp.fromString("rO0ABXNyAClvcmcuZ2x1dS5veGF1dGgubW9kZWwuY29tbW9uLkNsaWVudFRva2Vuc/Aib54fThHVAgACTAAIY2xpZW50SWR0ABJMamF2YS9sYW5nL1N0cmluZztMAAt0b2tlbkhhc2hlc3QAD0xqYXZhL3V0aWwvU2V0O3hwdAApMTAwMS45MGQ0MGI2OS02ZDFmLTQxMmYtOTg5ZS00MThmN2E2Y2M1MTNzcgARamF2YS51dGlsLkhhc2hTZXS6RIWVlri3NAMAAHhwdwwAAAAQP0AAAAAAAAF0AEA3M2M1NDBhYjRlNzU2ZTk2ZjQ2NzU2ODZjNzU0ZDg1ZjZiOWExYmI0ZjI1ZWY5NTZjYmRkZTQ0NjlmZTA2OGVjeA=="); + + System.out.println(obj); + } } diff --git a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java index 979cce52..460ebf9b 100644 --- a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java @@ -108,7 +108,7 @@ public void persist(Object entry) { Object dnValue = getDNValue(entry, entryClass); - int expirationValue = getExpirationValue(entry, entryClass); + Integer expirationValue = getExpirationValue(entry, entryClass); List attributes = getAttributesListForPersist(entry, propertiesAnnotations); @@ -121,7 +121,7 @@ public void persist(Object entry) { persist(dnValue.toString(), attributes, expirationValue); } - protected abstract void persist(String dn, List attributes, int expiration); + protected abstract void persist(String dn, List attributes, Integer expiration); @Override @SuppressWarnings("unchecked") @@ -208,6 +208,8 @@ protected T merge(T entry, boolean isSchemaUpdate, boolean isConfigurationUp Object dnValue = getDNValue(entry, entryClass); + Integer expirationValue = getExpirationValue(entry, entryClass); + List attributesToPersist = getAttributesListForPersist(entry, propertiesAnnotations); Map attributesToPersistMap = getAttributesMap(attributesToPersist); @@ -238,7 +240,7 @@ protected T merge(T entry, boolean isSchemaUpdate, boolean isConfigurationUp LOG.debug(String.format("LDAP attributes for merge: %s", attributeDataModifications)); - merge(dnValue.toString(), attributeDataModifications); + merge(dnValue.toString(), attributeDataModifications, expirationValue); return (T) find(entryClass, dnValue.toString(), null, propertiesAnnotations, propertiesAnnotationsMap); } @@ -407,7 +409,7 @@ protected boolean isEmptyAttributeValues(AttributeData attributeData) { || ((attributeToPersistValues.length == 1) && StringHelper.isEmpty(String.valueOf(attributeToPersistValues[0]))); } - protected abstract void merge(String dn, List attributeDataModifications); + protected abstract void merge(String dn, List attributeDataModifications, Integer expiration); public abstract void remove(String dn); @@ -1740,13 +1742,13 @@ protected Object getDNValue(Object entry, Class entryClass) { return dnValue; } - protected int getExpirationValue(Object entry, Class entryClass) { + protected Integer getExpirationValue(Object entry, Class entryClass) { // Check if entry has Expiration property String expirationProperty = getExpirationPropertyName(entryClass); if (expirationProperty == null) { // No entry expiration property - return 0; + return null; } // Get Expiration value @@ -1764,10 +1766,14 @@ protected int getExpirationValue(Object entry, Class entryClass) { Object expirationValue = expirationGetter.get(entry); if (expirationValue == null) { // No entry expiration or null - return 0; + return null; + } + + if (expirationValue instanceof Integer) { + return (Integer) expirationValue; } - return (int) expirationValue; + return Integer.valueOf((int) expirationValue); } private String getEntryKey(T entry, boolean caseSensetive, Getter[] propertyGetters) { diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java index 6ab56931..3764a855 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java @@ -166,7 +166,7 @@ public void remove(Object entry) { } @Override - protected void persist(String dn, List attributes, int expiration) { + protected void persist(String dn, List attributes, Integer expiration) { JsonObject jsonObject = JsonObject.create(); for (AttributeData attribute : attributes) { String attributeName = attribute.getName(); @@ -213,7 +213,7 @@ protected void persist(String dn, List attributes, int expiration } @Override - public void merge(String dn, List attributeDataModifications) { + public void merge(String dn, List attributeDataModifications, Integer expirationValue) { // Update entry try { List modifications = new ArrayList(attributeDataModifications.size()); @@ -254,7 +254,7 @@ public void merge(String dn, List attributeDataModifi } if (modifications.size() > 0) { - boolean result = operationService.updateEntry(toCouchbaseKey(dn).getKey(), modifications); + boolean result = operationService.updateEntry(toCouchbaseKey(dn).getKey(), modifications, expirationValue); if (!result) { throw new EntryPersistenceException(String.format("Failed to update entry: %s", dn)); } diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java index a9880ff1..64ffedb2 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java @@ -47,9 +47,9 @@ public interface CouchbaseOperationService extends PersistenceOperationService { boolean authenticate(String key, String password) throws SearchException, AuthenticationException; boolean addEntry(String key, JsonObject atts) throws DuplicateEntryException, PersistenceException; - boolean addEntry(String key, JsonObject jsonObject, int expirity) throws DuplicateEntryException, PersistenceException; + boolean addEntry(String key, JsonObject jsonObject, Integer expiration) throws DuplicateEntryException, PersistenceException; - boolean updateEntry(String key, List mods) throws UnsupportedOperationException, PersistenceException; + boolean updateEntry(String key, List mods, Integer expiration) throws UnsupportedOperationException, PersistenceException; boolean delete(String key) throws EntryNotFoundException; int delete(String key, ScanConsistency scanConsistency, Expression expression, int count) throws DeleteException; diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationsServiceImpl.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationsServiceImpl.java index f8cd7fb2..189c1f91 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationsServiceImpl.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationsServiceImpl.java @@ -163,11 +163,11 @@ public boolean addEntry(String key, JsonObject jsonObject) throws DuplicateEntry } @Override - public boolean addEntry(String key, JsonObject jsonObject, int expirity) throws DuplicateEntryException, PersistenceException { + public boolean addEntry(String key, JsonObject jsonObject, Integer expiration) throws DuplicateEntryException, PersistenceException { Instant startTime = OperationDurationUtil.instance().now(); BucketMapping bucketMapping = connectionProvider.getBucketMappingByKey(key); - boolean result = addEntryImpl(bucketMapping, key, jsonObject, expirity); + boolean result = addEntryImpl(bucketMapping, key, jsonObject, expiration); Duration duration = OperationDurationUtil.instance().duration(startTime); OperationDurationUtil.instance().logDebug("Couchbase operation: add, duration: {}, bucket: {}, key: {}, json: {}", duration, bucketMapping.getBucketName(), key, jsonObject); @@ -175,10 +175,16 @@ public boolean addEntry(String key, JsonObject jsonObject, int expirity) throws return result; } - private boolean addEntryImpl(BucketMapping bucketMapping, String key, JsonObject jsonObject, int expirity) throws PersistenceException { + private boolean addEntryImpl(BucketMapping bucketMapping, String key, JsonObject jsonObject, Integer expiration) throws PersistenceException { try { - JsonDocument jsonDocument = JsonDocument.create(key, expirity, jsonObject); - JsonDocument result = bucketMapping.getBucket().upsert(jsonDocument); + JsonDocument jsonDocument; + if (expiration == null) { + jsonDocument = JsonDocument.create(key, jsonObject); + } else { + jsonDocument = JsonDocument.create(key, expiration, jsonObject); + } + + JsonDocument result = bucketMapping.getBucket().upsert(jsonDocument); if (result != null) { return true; } @@ -207,15 +213,15 @@ protected boolean updateEntry(String key, JsonObject attrs) throws UnsupportedOp } } - return updateEntry(key, mods); + return updateEntry(key, mods, null); } @Override - public boolean updateEntry(String key, List mods) throws UnsupportedOperationException, SearchException { + public boolean updateEntry(String key, List mods, Integer expiration) throws UnsupportedOperationException, SearchException { Instant startTime = OperationDurationUtil.instance().now(); BucketMapping bucketMapping = connectionProvider.getBucketMappingByKey(key); - boolean result = updateEntryImpl(bucketMapping, key, mods); + boolean result = updateEntryImpl(bucketMapping, key, mods, expiration); Duration duration = OperationDurationUtil.instance().duration(startTime); OperationDurationUtil.instance().logDebug("Couchbase operation: modify, duration: {}, bucket: {}, key: {}, mods: {}", duration, bucketMapping.getBucketName(), key, mods); @@ -223,9 +229,12 @@ public boolean updateEntry(String key, List mods) throws Unsupport return result; } - private boolean updateEntryImpl(BucketMapping bucketMapping, String key, List mods) throws SearchException { + private boolean updateEntryImpl(BucketMapping bucketMapping, String key, List mods, Integer expiration) throws SearchException { try { MutateInBuilder builder = bucketMapping.getBucket().mutateIn(key); + if (expiration != null) { + bucketMapping.getBucket().touch(key, expiration); + } return modifyEntry(builder, mods); } catch (final CouchbaseException ex) { diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java index d8dfa283..9f3c84b0 100644 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java +++ b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java @@ -403,12 +403,12 @@ public void removeRecursively(String dn) { //************************************************************************* @Override - protected void persist(String dn, List attributes, int expiration) { + protected void persist(String dn, List attributes, Integer expiration) { throw new UnsupportedOperationException("Method not implemented."); } @Override - protected void merge(String dn, List attributeDataModifications) { + protected void merge(String dn, List attributeDataModifications, Integer expiration) { throw new UnsupportedOperationException("Method not implemented."); } diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java index bf43420d..598540d4 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java @@ -163,7 +163,7 @@ protected void persist(String dn, List attributes) { } @Override - protected void persist(String dn, List attributes, int expiration) { + protected void persist(String dn, List attributes, Integer expiration) { List ldapAttributes = new ArrayList(attributes.size()); for (AttributeData attribute : attributes) { String attributeName = attribute.getName(); @@ -194,7 +194,7 @@ protected void persist(String dn, List attributes, int expiration } @Override - public void merge(String dn, List attributeDataModifications) { + public void merge(String dn, List attributeDataModifications, Integer expiration) { // Update entry try { List modifications = new ArrayList(attributeDataModifications.size()); From 4bb12bbbe5c6917ea22dc8e9d18a56b1f807fbc2 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 26 Mar 2020 15:51:14 +0300 Subject: [PATCH 109/362] Don't remove entry from cache if DB is CB before putting into cache --- .../cache/NativePersistenceCacheProvider.java | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index 032c1604..69c9e089 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -1,5 +1,16 @@ package org.gluu.service.cache; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Calendar; +import java.util.Date; + +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; @@ -10,16 +21,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.PostConstruct; -import javax.enterprise.context.ApplicationScoped; -import javax.inject.Inject; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.Calendar; -import java.util.Date; - @ApplicationScoped public class NativePersistenceCacheProvider extends AbstractCacheProvider { @@ -36,6 +37,8 @@ public class NativePersistenceCacheProvider extends AbstractCacheProvider 0 ? expirationInSeconds : cacheConfiguration.getNativePersistenceConfiguration().getDefaultPutExpiration(); - putImpl(key, object, creationDate, expirationInSeconds); } @@ -165,7 +171,9 @@ private void putImpl(String key, Object object, Date creationDate, int expiratio entity.setNewExpirationDate(expirationDate.getTime()); entity.setDeletable(true); - silentlyRemoveEntityIfExists(entity.getDn()); + if (!skipRemoveBeforePut) { + silentlyRemoveEntityIfExists(entity.getDn()); + } entryManager.persist(entity); } catch (Exception e) { log.error("Failed to put entry, key: " + originalKey + ", hashedKey: " + key + ", message: " + e.getMessage(), e); // log as trace since it is perfectly valid that entry is removed by timer for example From 7c1210328fb7020c25a277e2e42f7680131df75d Mon Sep 17 00:00:00 2001 From: Milton BO Date: Tue, 31 Mar 2020 14:30:18 -0400 Subject: [PATCH 110/362] Added fapi private key properties in oxTrust json config. #1924 --- .../gluu/config/oxtrust/AppConfiguration.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index 27dcca31..4f65dcb4 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -85,6 +85,8 @@ public class AppConfiguration implements Configuration, Serializable { private String oxAuthClientId; private String oxAuthClientPassword; private String oxAuthClientScope; + private String oxAuthClientFapiJWKPrivateKeyModulus; + private String oxAuthClientFapiJWKPrivateKeyPrivateExponent; private String loginRedirectUrl; private String logoutRedirectUrl; @@ -943,4 +945,21 @@ public boolean isEnableUpdateNotification() { public void setEnableUpdateNotification(boolean enableUpdateNotification) { this.enableUpdateNotification = enableUpdateNotification; } + + public String getOxAuthClientFapiJWKPrivateKeyModulus() { + return oxAuthClientFapiJWKPrivateKeyModulus; + } + + public void setOxAuthClientFapiJWKPrivateKeyModulus(String oxAuthClientFapiJWKPrivateKeyModulus) { + this.oxAuthClientFapiJWKPrivateKeyModulus = oxAuthClientFapiJWKPrivateKeyModulus; + } + + public String getOxAuthClientFapiJWKPrivateKeyPrivateExponent() { + return oxAuthClientFapiJWKPrivateKeyPrivateExponent; + } + + public void setOxAuthClientFapiJWKPrivateKeyPrivateExponent(String oxAuthClientFapiJWKPrivateKeyPrivateExponent) { + this.oxAuthClientFapiJWKPrivateKeyPrivateExponent = oxAuthClientFapiJWKPrivateKeyPrivateExponent; + } + } From 458854c0f3545f876cd9ffc53aabfbd95316d601 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 3 Apr 2020 15:24:22 +0300 Subject: [PATCH 111/362] Fix bind connection creation when LDAP server not requires pwd --- .../ldap/operation/impl/LdapConnectionProvider.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapConnectionProvider.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapConnectionProvider.java index 82b81cb7..37c32085 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapConnectionProvider.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapConnectionProvider.java @@ -44,7 +44,7 @@ public class LdapConnectionProvider { private static final String[] SSL_PROTOCOLS = {"TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3"}; private LDAPConnectionPool connectionPool; - private int creationResultCode; + private ResultCode creationResultCode; private int supportedLDAPVersion = DEFAULT_SUPPORTED_LDAP_VERSION; private String subschemaSubentry = DEFAULT_SUBSCHEMA_SUBENTRY; @@ -74,7 +74,7 @@ protected void create(Properties props) { try { init(props); } catch (LDAPException ex) { - creationResultCode = ex.getResultCode().intValue(); + creationResultCode = ex.getResultCode(); Properties clonedProperties = (Properties) props.clone(); if (clonedProperties.getProperty("bindPassword") != null) { @@ -214,7 +214,7 @@ protected void init(Properties props) throws NumberFormatException, LDAPExceptio this.supportedLDAPVersion = determineSupportedLdapVersion(); this.subschemaSubentry = determineSubschemaSubentry(); this.supportsSubtreeDeleteRequestControl = supportsSubtreeDeleteRequestControl(); - this.creationResultCode = ResultCode.SUCCESS_INT_VALUE; + this.creationResultCode = ResultCode.SUCCESS; } private LDAPConnectionPool createConnectionPoolWithWaitImpl(Properties props, FailoverServerSet failoverSet, BindRequest bindRequest, @@ -474,16 +474,16 @@ public boolean isConnected() { return isConnected; } - public int getCreationResultCode() { + public ResultCode getCreationResultCode() { return creationResultCode; } - public void setCreationResultCode(int creationResultCode) { + public void setCreationResultCode(ResultCode creationResultCode) { this.creationResultCode = creationResultCode; } public boolean isCreated() { - return ResultCode.SUCCESS_INT_VALUE == this.creationResultCode; + return ResultCode.SUCCESS == this.creationResultCode; } public String[] getServers() { From 0fa78bc056187696f86afd17b83e1f132e62282d Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 6 Apr 2020 20:23:29 +0300 Subject: [PATCH 112/362] Fix scan consistency check if filter uses LOWER keyword --- .../gluu/persist/couchbase/impl/CouchbaseFilterConverter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java index f9054716..e9dfab2e 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java @@ -165,7 +165,7 @@ public ConvertedExpression convertToCouchbaseFilter(Filter genericFilter, Map Date: Wed, 8 Apr 2020 19:37:38 +0300 Subject: [PATCH 113/362] TTL should be positive --- .../java/org/gluu/persist/impl/BaseEntryManager.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java index 460ebf9b..948b9ed7 100644 --- a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java @@ -1769,11 +1769,19 @@ protected Integer getExpirationValue(Object entry, Class entryClass) { return null; } + Integer resultExpirationValue; if (expirationValue instanceof Integer) { - return (Integer) expirationValue; + resultExpirationValue = (Integer) expirationValue; + } else { + resultExpirationValue = Integer.valueOf((int) expirationValue); + } + + // TTL can't be negative + if (resultExpirationValue < 0) { + resultExpirationValue = 0; } - return Integer.valueOf((int) expirationValue); + return resultExpirationValue; } private String getEntryKey(T entry, boolean caseSensetive, Getter[] propertyGetters) { From 926a53bcf88c86595327eae8fef9550944f89bb5 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 8 Apr 2020 20:36:04 +0300 Subject: [PATCH 114/362] Add Priority to Identity --- oxService/src/main/java/org/gluu/model/security/Identity.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/oxService/src/main/java/org/gluu/model/security/Identity.java b/oxService/src/main/java/org/gluu/model/security/Identity.java index d5fb294d..7ac6c153 100644 --- a/oxService/src/main/java/org/gluu/model/security/Identity.java +++ b/oxService/src/main/java/org/gluu/model/security/Identity.java @@ -6,6 +6,7 @@ import java.util.HashMap; import javax.annotation.PostConstruct; +import javax.annotation.Priority; import javax.enterprise.context.RequestScoped; import javax.enterprise.event.Event; import javax.enterprise.inject.Alternative; @@ -13,6 +14,7 @@ import javax.inject.Named; import javax.security.auth.Subject; import javax.security.auth.login.LoginException; +import javax.interceptor.Interceptor; import org.gluu.model.security.event.Authenticated; import org.gluu.service.security.Secure; @@ -21,6 +23,7 @@ @RequestScoped @Named @Alternative +@Priority(Interceptor.Priority.APPLICATION + 10) public class Identity implements Serializable { private static final long serialVersionUID = 3751659008033189259L; From 0ddc8b40111d105b8305978811890055c4e49ab2 Mon Sep 17 00:00:00 2001 From: Milton BO Date: Wed, 8 Apr 2020 15:44:37 -0400 Subject: [PATCH 115/362] Added Fapi keystore oxtrust json properties used to process MTLS calls. #1924 --- .../gluu/config/oxtrust/AppConfiguration.java | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index 4f65dcb4..a3a7bcfa 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -87,6 +87,9 @@ public class AppConfiguration implements Configuration, Serializable { private String oxAuthClientScope; private String oxAuthClientFapiJWKPrivateKeyModulus; private String oxAuthClientFapiJWKPrivateKeyPrivateExponent; + private String oxAuthFapiClientKeystoreType; + private String oxAuthFapiClientKeystorePath; + private String oxAuthFapiClientKeystorePassword; private String loginRedirectUrl; private String logoutRedirectUrl; @@ -962,4 +965,28 @@ public void setOxAuthClientFapiJWKPrivateKeyPrivateExponent(String oxAuthClientF this.oxAuthClientFapiJWKPrivateKeyPrivateExponent = oxAuthClientFapiJWKPrivateKeyPrivateExponent; } + public String getOxAuthFapiClientKeystoreType() { + return oxAuthFapiClientKeystoreType; + } + + public void setOxAuthFapiClientKeystoreType(String oxAuthFapiClientKeystoreType) { + this.oxAuthFapiClientKeystoreType = oxAuthFapiClientKeystoreType; + } + + public String getOxAuthFapiClientKeystorePath() { + return oxAuthFapiClientKeystorePath; + } + + public void setOxAuthFapiClientKeystorePath(String oxAuthFapiClientKeystorePath) { + this.oxAuthFapiClientKeystorePath = oxAuthFapiClientKeystorePath; + } + + public String getOxAuthFapiClientKeystorePassword() { + return oxAuthFapiClientKeystorePassword; + } + + public void setOxAuthFapiClientKeystorePassword(String oxAuthFapiClientKeystorePassword) { + this.oxAuthFapiClientKeystorePassword = oxAuthFapiClientKeystorePassword; + } + } From 3da6911cf3cc4c90270c062f9c3db4704b52229d Mon Sep 17 00:00:00 2001 From: Milton BO Date: Tue, 14 Apr 2020 15:23:10 -0400 Subject: [PATCH 116/362] Put only those properties that are needed for Fapi implementation. --- .../gluu/config/oxtrust/AppConfiguration.java | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index a3a7bcfa..bb5681aa 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -85,8 +85,6 @@ public class AppConfiguration implements Configuration, Serializable { private String oxAuthClientId; private String oxAuthClientPassword; private String oxAuthClientScope; - private String oxAuthClientFapiJWKPrivateKeyModulus; - private String oxAuthClientFapiJWKPrivateKeyPrivateExponent; private String oxAuthFapiClientKeystoreType; private String oxAuthFapiClientKeystorePath; private String oxAuthFapiClientKeystorePassword; @@ -949,22 +947,6 @@ public void setEnableUpdateNotification(boolean enableUpdateNotification) { this.enableUpdateNotification = enableUpdateNotification; } - public String getOxAuthClientFapiJWKPrivateKeyModulus() { - return oxAuthClientFapiJWKPrivateKeyModulus; - } - - public void setOxAuthClientFapiJWKPrivateKeyModulus(String oxAuthClientFapiJWKPrivateKeyModulus) { - this.oxAuthClientFapiJWKPrivateKeyModulus = oxAuthClientFapiJWKPrivateKeyModulus; - } - - public String getOxAuthClientFapiJWKPrivateKeyPrivateExponent() { - return oxAuthClientFapiJWKPrivateKeyPrivateExponent; - } - - public void setOxAuthClientFapiJWKPrivateKeyPrivateExponent(String oxAuthClientFapiJWKPrivateKeyPrivateExponent) { - this.oxAuthClientFapiJWKPrivateKeyPrivateExponent = oxAuthClientFapiJWKPrivateKeyPrivateExponent; - } - public String getOxAuthFapiClientKeystoreType() { return oxAuthFapiClientKeystoreType; } From c21fc63b14b4309a84e0788ddedd8c791d28af94 Mon Sep 17 00:00:00 2001 From: Milton BO Date: Tue, 14 Apr 2020 16:15:21 -0400 Subject: [PATCH 117/362] Reverted Fapi json properties for oxTrust --- .../gluu/config/oxtrust/AppConfiguration.java | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index bb5681aa..969a2691 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -85,9 +85,6 @@ public class AppConfiguration implements Configuration, Serializable { private String oxAuthClientId; private String oxAuthClientPassword; private String oxAuthClientScope; - private String oxAuthFapiClientKeystoreType; - private String oxAuthFapiClientKeystorePath; - private String oxAuthFapiClientKeystorePassword; private String loginRedirectUrl; private String logoutRedirectUrl; @@ -947,28 +944,4 @@ public void setEnableUpdateNotification(boolean enableUpdateNotification) { this.enableUpdateNotification = enableUpdateNotification; } - public String getOxAuthFapiClientKeystoreType() { - return oxAuthFapiClientKeystoreType; - } - - public void setOxAuthFapiClientKeystoreType(String oxAuthFapiClientKeystoreType) { - this.oxAuthFapiClientKeystoreType = oxAuthFapiClientKeystoreType; - } - - public String getOxAuthFapiClientKeystorePath() { - return oxAuthFapiClientKeystorePath; - } - - public void setOxAuthFapiClientKeystorePath(String oxAuthFapiClientKeystorePath) { - this.oxAuthFapiClientKeystorePath = oxAuthFapiClientKeystorePath; - } - - public String getOxAuthFapiClientKeystorePassword() { - return oxAuthFapiClientKeystorePassword; - } - - public void setOxAuthFapiClientKeystorePassword(String oxAuthFapiClientKeystorePassword) { - this.oxAuthFapiClientKeystorePassword = oxAuthFapiClientKeystorePassword; - } - } From e4fee1e402042b58b3221bbde738eb3ac28ea81d Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 15 Apr 2020 13:05:03 +0300 Subject: [PATCH 118/362] New libs core-cdi and core-timer-weld --- core-cdi/pom.xml | 54 ++++++++++++++ .../gluu/service/timer/event/TimerEvent.java | 0 .../service/timer/schedule/JobShedule.java | 0 .../service/timer/schedule/TimerSchedule.java | 0 .../src/main/resources/META-INF/beans.xml | 7 ++ core-timer-weld/pom.xml | 71 +++++++++++++++++++ .../service/timer/JobExecutionDelegate.java | 0 .../service/timer/JobExecutionFactory.java | 0 .../service/timer/QuartzSchedulerManager.java | 0 .../service/timer/RequestJobListener.java | 0 .../java/org/gluu/service/timer/TimerJob.java | 0 .../src/main/resources/META-INF/beans.xml | 7 ++ oxService/pom.xml | 45 ++++++------ oxUtil/pom.xml | 4 ++ pom.xml | 2 + 15 files changed, 165 insertions(+), 25 deletions(-) create mode 100644 core-cdi/pom.xml rename {oxService => core-cdi}/src/main/java/org/gluu/service/timer/event/TimerEvent.java (100%) rename {oxService => core-cdi}/src/main/java/org/gluu/service/timer/schedule/JobShedule.java (100%) rename {oxService => core-cdi}/src/main/java/org/gluu/service/timer/schedule/TimerSchedule.java (100%) create mode 100644 core-cdi/src/main/resources/META-INF/beans.xml create mode 100644 core-timer-weld/pom.xml rename {oxService => core-timer-weld}/src/main/java/org/gluu/service/timer/JobExecutionDelegate.java (100%) rename {oxService => core-timer-weld}/src/main/java/org/gluu/service/timer/JobExecutionFactory.java (100%) rename {oxService => core-timer-weld}/src/main/java/org/gluu/service/timer/QuartzSchedulerManager.java (100%) rename {oxService => core-timer-weld}/src/main/java/org/gluu/service/timer/RequestJobListener.java (100%) rename {oxService => core-timer-weld}/src/main/java/org/gluu/service/timer/TimerJob.java (100%) create mode 100644 core-timer-weld/src/main/resources/META-INF/beans.xml diff --git a/core-cdi/pom.xml b/core-cdi/pom.xml new file mode 100644 index 00000000..116a3fab --- /dev/null +++ b/core-cdi/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + oxcore-cdi + Reusable CDI classes which not depend on specific framework + + + org.gluu + oxcore + 4.2.0-SNAPSHOT + + + + ${maven.min-version} + + + + + + src/main/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + + + + org.slf4j + slf4j-api + provided + + + + + javax.enterprise + cdi-api + provided + + + + + org.quartz-scheduler + quartz + + + + \ No newline at end of file diff --git a/oxService/src/main/java/org/gluu/service/timer/event/TimerEvent.java b/core-cdi/src/main/java/org/gluu/service/timer/event/TimerEvent.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/timer/event/TimerEvent.java rename to core-cdi/src/main/java/org/gluu/service/timer/event/TimerEvent.java diff --git a/oxService/src/main/java/org/gluu/service/timer/schedule/JobShedule.java b/core-cdi/src/main/java/org/gluu/service/timer/schedule/JobShedule.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/timer/schedule/JobShedule.java rename to core-cdi/src/main/java/org/gluu/service/timer/schedule/JobShedule.java diff --git a/oxService/src/main/java/org/gluu/service/timer/schedule/TimerSchedule.java b/core-cdi/src/main/java/org/gluu/service/timer/schedule/TimerSchedule.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/timer/schedule/TimerSchedule.java rename to core-cdi/src/main/java/org/gluu/service/timer/schedule/TimerSchedule.java diff --git a/core-cdi/src/main/resources/META-INF/beans.xml b/core-cdi/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000..2f4f7e27 --- /dev/null +++ b/core-cdi/src/main/resources/META-INF/beans.xml @@ -0,0 +1,7 @@ + + + diff --git a/core-timer-weld/pom.xml b/core-timer-weld/pom.xml new file mode 100644 index 00000000..8c6f32e4 --- /dev/null +++ b/core-timer-weld/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + oxcore-timer-weld + Weld CDI timer implementation + + + org.gluu + oxcore + 4.2.0-SNAPSHOT + + + + ${maven.min-version} + + + + + + src/main/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + + + + ${project.groupId} + oxcore-cdi + + + ${project.groupId} + oxcore-util + + + + + org.slf4j + slf4j-api + provided + + + + + javax.enterprise + cdi-api + provided + + + + + org.jboss.weld + weld-core-impl + provided + + + + + org.quartz-scheduler + quartz + + + + \ No newline at end of file diff --git a/oxService/src/main/java/org/gluu/service/timer/JobExecutionDelegate.java b/core-timer-weld/src/main/java/org/gluu/service/timer/JobExecutionDelegate.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/timer/JobExecutionDelegate.java rename to core-timer-weld/src/main/java/org/gluu/service/timer/JobExecutionDelegate.java diff --git a/oxService/src/main/java/org/gluu/service/timer/JobExecutionFactory.java b/core-timer-weld/src/main/java/org/gluu/service/timer/JobExecutionFactory.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/timer/JobExecutionFactory.java rename to core-timer-weld/src/main/java/org/gluu/service/timer/JobExecutionFactory.java diff --git a/oxService/src/main/java/org/gluu/service/timer/QuartzSchedulerManager.java b/core-timer-weld/src/main/java/org/gluu/service/timer/QuartzSchedulerManager.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/timer/QuartzSchedulerManager.java rename to core-timer-weld/src/main/java/org/gluu/service/timer/QuartzSchedulerManager.java diff --git a/oxService/src/main/java/org/gluu/service/timer/RequestJobListener.java b/core-timer-weld/src/main/java/org/gluu/service/timer/RequestJobListener.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/timer/RequestJobListener.java rename to core-timer-weld/src/main/java/org/gluu/service/timer/RequestJobListener.java diff --git a/oxService/src/main/java/org/gluu/service/timer/TimerJob.java b/core-timer-weld/src/main/java/org/gluu/service/timer/TimerJob.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/timer/TimerJob.java rename to core-timer-weld/src/main/java/org/gluu/service/timer/TimerJob.java diff --git a/core-timer-weld/src/main/resources/META-INF/beans.xml b/core-timer-weld/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000..2f4f7e27 --- /dev/null +++ b/core-timer-weld/src/main/resources/META-INF/beans.xml @@ -0,0 +1,7 @@ + + + diff --git a/oxService/pom.xml b/oxService/pom.xml index 81321b76..cef0b361 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -41,30 +41,32 @@ - org.gluu + ${project.groupId} oxcore-model - org.gluu + ${project.groupId} oxcore-persistence-ldap - - org.gluu - oxcore-persistence-couchbase - - - ${project.groupId} - oxcore-persistence-hybrid - ${project.version} - + + ${project.groupId} + oxcore-persistence-couchbase + + + ${project.groupId} + oxcore-persistence-hybrid + - org.gluu + ${project.groupId} oxcore-util ${project.groupId} oxcore-cache - ${project.version} + + + ${project.groupId} + oxcore-cdi @@ -73,11 +75,6 @@ cdi-api provided - - com.sun.faces - jsf-api - provided - javax.servlet javax.servlet-api @@ -104,12 +101,16 @@ provided + + com.sun.faces + jsf-api + provided + com.sun.faces jsf-impl provided - org.glassfish.web el-impl @@ -148,12 +149,6 @@ guava - - - org.quartz-scheduler - quartz - - org.testng diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index b21c8106..02fef2d6 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -29,6 +29,10 @@ org.apache.logging.log4j log4j-api + + org.apache.logging.log4j + log4j-core + org.apache.logging.log4j log4j-1.2-api diff --git a/pom.xml b/pom.xml index 5c9f898f..f4da3146 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,8 @@ core-cache core-standalone core-java-ext + core-cdi + core-timer-weld oxService server oxJsfUtil From e40f1e1510ef50301f2023334573d8a3899b503f Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 15 Apr 2020 13:11:20 +0300 Subject: [PATCH 119/362] Global rename ldapEntryManager -> persistenceEntryManager --- .../org/gluu/service/AttributeService.java | 6 +++--- .../java/org/gluu/service/LookupService.java | 6 +++--- .../script/AbstractCustomScriptService.java | 18 +++++++++--------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/AttributeService.java b/oxService/src/main/java/org/gluu/service/AttributeService.java index 04f61976..f0ee9807 100644 --- a/oxService/src/main/java/org/gluu/service/AttributeService.java +++ b/oxService/src/main/java/org/gluu/service/AttributeService.java @@ -34,7 +34,7 @@ public abstract class AttributeService implements Serializable { protected Logger log; @Inject - protected PersistenceEntryManager ldapEntryManager; + protected PersistenceEntryManager persistenceEntryManager; @Inject protected SchemaService schemaService; @@ -48,7 +48,7 @@ public abstract class AttributeService implements Serializable { public List getAttributesByAttribute(String attributeName, String attributeValue, String baseDn) { String[] targetArray = new String[] { attributeValue }; Filter filter = Filter.createSubstringFilter(attributeName, null, targetArray, null); - List result = ldapEntryManager.findEntries(baseDn, GluuAttribute.class, filter); + List result = persistenceEntryManager.findEntries(baseDn, GluuAttribute.class, filter); return result; } @@ -111,7 +111,7 @@ public List getAllAttributes(String baseDn) { } protected List getAllAtributesImpl(String baseDn) { - List attributeList = ldapEntryManager.findEntries(baseDn, GluuAttribute.class, null); + List attributeList = persistenceEntryManager.findEntries(baseDn, GluuAttribute.class, null); return attributeList; } diff --git a/oxService/src/main/java/org/gluu/service/LookupService.java b/oxService/src/main/java/org/gluu/service/LookupService.java index d44fcb96..1ab209e4 100644 --- a/oxService/src/main/java/org/gluu/service/LookupService.java +++ b/oxService/src/main/java/org/gluu/service/LookupService.java @@ -37,7 +37,7 @@ public class LookupService implements Serializable { private Logger log; @Inject - private PersistenceEntryManager ldapEntryManager; + private PersistenceEntryManager persistenceEntryManager; @Inject private CacheService cacheService; @@ -53,7 +53,7 @@ public DisplayNameEntry getDisplayNameEntry(String dn) throws Exception { String key = "l_" + dn; DisplayNameEntry entry = (DisplayNameEntry) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); if (entry == null) { - entry = ldapEntryManager.find(dn, DisplayNameEntry.class, null); + entry = persistenceEntryManager.find(dn, DisplayNameEntry.class, null); cacheService.put(OxConstants.CACHE_LOOKUP_NAME, key, entry); } @@ -81,7 +81,7 @@ public List getDisplayNameEntries(String baseDn, List List entries = (List) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); if (entries == null) { Filter searchFilter = buildInumFilter(inums); - entries = ldapEntryManager.findEntries(baseDn, DisplayNameEntry.class, searchFilter); + entries = persistenceEntryManager.findEntries(baseDn, DisplayNameEntry.class, searchFilter); cacheService.put(OxConstants.CACHE_LOOKUP_NAME, key, entries); } return entries; diff --git a/oxService/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java b/oxService/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java index 335a600b..7db1ac36 100644 --- a/oxService/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java +++ b/oxService/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java @@ -30,26 +30,26 @@ public abstract class AbstractCustomScriptService implements Serializable { private Logger log; @Inject - private PersistenceEntryManager ldapEntryManager; + private PersistenceEntryManager persistenceEntryManager; public void add(CustomScript customScript) { - ldapEntryManager.persist(customScript); + persistenceEntryManager.persist(customScript); } public void update(CustomScript customScript) { - ldapEntryManager.merge(customScript); + persistenceEntryManager.merge(customScript); } public void remove(CustomScript customScript) { - ldapEntryManager.remove(customScript); + persistenceEntryManager.remove(customScript); } public CustomScript getCustomScriptByDn(String customScriptDn, String... returnAttributes) { - return ldapEntryManager.find(customScriptDn, CustomScript.class, returnAttributes); + return persistenceEntryManager.find(customScriptDn, CustomScript.class, returnAttributes); } public CustomScript getCustomScriptByDn(Class customScriptType, String customScriptDn) { - return (CustomScript) ldapEntryManager.find(customScriptType, customScriptDn); + return (CustomScript) persistenceEntryManager.find(customScriptType, customScriptDn); } public Optional getCustomScriptByINum(String baseDn, String inum, String... returnAttributes) { @@ -61,7 +61,7 @@ public Optional getCustomScriptByINum(String baseDn, String inum, final Filter filter = Filter.createORFilter(customScriptTypeFilters); - final List result = ldapEntryManager.findEntries(baseDn, CustomScript.class, filter, returnAttributes); + final List result = persistenceEntryManager.findEntries(baseDn, CustomScript.class, filter, returnAttributes); if (result.isEmpty()) { @@ -75,7 +75,7 @@ public Optional getCustomScriptByINum(String baseDn, String inum, public List findAllCustomScripts(String[] returnAttributes) { String baseDn = baseDn(); - List result = ldapEntryManager.findEntries(baseDn, CustomScript.class, null, returnAttributes); + List result = persistenceEntryManager.findEntries(baseDn, CustomScript.class, null, returnAttributes); return result; } @@ -95,7 +95,7 @@ public List findCustomScripts(List customScriptT Filter filter = Filter.createORFilter(customScriptTypeFilters); - List result = ldapEntryManager.findEntries(baseDn, CustomScript.class, filter, returnAttributes); + List result = persistenceEntryManager.findEntries(baseDn, CustomScript.class, filter, returnAttributes); return result; } From b130b66548d96deaca2a3cdb4d41c754e112afef Mon Sep 17 00:00:00 2001 From: Milton BO Date: Wed, 15 Apr 2020 16:56:25 -0400 Subject: [PATCH 120/362] Added methods to change logs between json or text layouts. #1308 --- .../gluu/model/types/LoggingLayoutType.java | 48 +++++++++++ .../gluu/service/logger/LoggerService.java | 79 ++++++++++++++++--- 2 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 oxModel/src/main/java/org/gluu/model/types/LoggingLayoutType.java diff --git a/oxModel/src/main/java/org/gluu/model/types/LoggingLayoutType.java b/oxModel/src/main/java/org/gluu/model/types/LoggingLayoutType.java new file mode 100644 index 00000000..efb1c348 --- /dev/null +++ b/oxModel/src/main/java/org/gluu/model/types/LoggingLayoutType.java @@ -0,0 +1,48 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.model.types; + +import java.util.HashMap; +import java.util.Map; + +/** + * Different layouts available to be used as logs. + * + */ +public enum LoggingLayoutType { + + TEXT("TEXT"), + JSON("JSON"); + + private String value; + + private static Map MAP_BY_VALUES = new HashMap(); + + static { + for (LoggingLayoutType enumType : values()) { + MAP_BY_VALUES.put(enumType.getValue(), enumType); + } + } + + LoggingLayoutType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static LoggingLayoutType getByValue(String value) { + return MAP_BY_VALUES.get(value); + } + + @Override + public String toString() { + return value; + } + +} diff --git a/oxService/src/main/java/org/gluu/service/logger/LoggerService.java b/oxService/src/main/java/org/gluu/service/logger/LoggerService.java index 3c43ca3a..286e4404 100644 --- a/oxService/src/main/java/org/gluu/service/logger/LoggerService.java +++ b/oxService/src/main/java/org/gluu/service/logger/LoggerService.java @@ -1,17 +1,15 @@ package org.gluu.service.logger; -import java.io.File; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.logging.LogManager; - -import javax.annotation.PostConstruct; -import javax.enterprise.event.Event; -import javax.enterprise.event.Observes; -import javax.inject.Inject; - import org.apache.commons.lang.StringUtils; import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.Appender; import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.ConsoleAppender; +import org.apache.logging.log4j.core.appender.RollingFileAppender; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.layout.JsonLayout; +import org.gluu.model.types.LoggingLayoutType; import org.gluu.service.cdi.async.Asynchronous; import org.gluu.service.cdi.event.ConfigurationUpdate; import org.gluu.service.cdi.event.LoggerUpdateEvent; @@ -21,6 +19,15 @@ import org.gluu.util.StringHelper; import org.slf4j.Logger; +import javax.annotation.PostConstruct; +import javax.enterprise.event.Event; +import javax.enterprise.event.Observes; +import javax.inject.Inject; +import java.io.File; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.LogManager; + /** * Logger service * @@ -82,8 +89,17 @@ private void updateLoggerConfiguration() { if (StringHelper.equalsIgnoreCase("DEFAULT", loggingLevel)) { return; } - - updateLoggers(level); + if (StringUtils.isEmpty(this.getLoggingLayout())) { + return; + } + LoggingLayoutType loggingLayout = LoggingLayoutType.getByValue(this.getLoggingLayout().toUpperCase()); + if (loggingLayout == LoggingLayoutType.TEXT) { + final LoggerContext ctx = LoggerContext.getContext(false); + ctx.reconfigure(); + updateLoggers(level); + } else if (loggingLayout == LoggingLayoutType.JSON) { + updateAppendersToJson(level); + } } public void updateLoggerSeverity(@Observes @ConfigurationUpdate Object appConfiguration) { @@ -146,7 +162,7 @@ private void updateLoggers(Level level) { } if (count > 0) { - log.info("Uppdated log level of '{}' loggers to {}", count, level.toString()); + log.info("Updated log level of '{}' loggers to {}", count, level.toString()); } } @@ -193,6 +209,44 @@ private boolean setExternalLoggerConfig() { return true; } + + private void updateAppendersToJson(Level level) { + JsonLayout jsonLayout = JsonLayout.createDefaultLayout(); + + final LoggerContext ctx = LoggerContext.getContext(false); + + final Configuration config = ctx.getConfiguration(); + LoggerConfig loggerConfig = config.getLoggerConfig("root"); + for (Map.Entry appenderEntry : loggerConfig.getAppenders().entrySet()) { + if (appenderEntry.getValue() instanceof RollingFileAppender) { + RollingFileAppender rollingFile = (RollingFileAppender) appenderEntry.getValue(); + if (rollingFile.getLayout() instanceof JsonLayout) + return; + RollingFileAppender newFileAppender = RollingFileAppender.newBuilder() + .setLayout(jsonLayout) + .withStrategy(rollingFile.getManager().getRolloverStrategy()) + .withPolicy(rollingFile.getTriggeringPolicy()) + .withFileName(rollingFile.getFileName()) + .withFilePattern(rollingFile.getFilePattern()) + .setName(rollingFile.getName()) + .build(); + loggerConfig.removeAppender(appenderEntry.getKey()); + loggerConfig.addAppender(newFileAppender, level, null); + } else if (appenderEntry.getValue() instanceof ConsoleAppender) { + ConsoleAppender consoleAppender = (ConsoleAppender) appenderEntry.getValue(); + if (consoleAppender.getLayout() instanceof JsonLayout) + return; + ConsoleAppender newConsoleAppender = ConsoleAppender.newBuilder() + .setLayout(jsonLayout) + .setTarget(consoleAppender.getTarget()) + .setName(consoleAppender.getName()) + .build(); + loggerConfig.removeAppender(appenderEntry.getKey()); + loggerConfig.addAppender(newConsoleAppender, level, null); + } + } + ctx.updateLoggers(); + } public abstract boolean isDisableJdkLogger(); @@ -200,5 +254,6 @@ private boolean setExternalLoggerConfig() { public abstract String getExternalLoggerConfiguration(); + public abstract String getLoggingLayout(); } From 5b9e652ac0d1bcd52645eb26b6631fea061113aa Mon Sep 17 00:00:00 2001 From: Milton BO Date: Thu, 16 Apr 2020 10:36:40 -0400 Subject: [PATCH 121/362] Added json property in oxTrust to set loggin layout --- .../java/org/gluu/config/oxtrust/AppConfiguration.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index 969a2691..0ef3d9cd 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -141,6 +141,7 @@ public class AppConfiguration implements Configuration, Serializable { private List clientBlackList; private String loggingLevel; + private String loggingLayout; private String shibbolethVersion; private String shibboleth3IdpRootDir; @@ -781,6 +782,14 @@ public void setLoggingLevel(String loggingLevel) { this.loggingLevel = loggingLevel; } + public String getLoggingLayout() { + return loggingLayout; + } + + public void setLoggingLayout(String loggingLayout) { + this.loggingLayout = loggingLayout; + } + public int getMetricReporterInterval() { return metricReporterInterval; } From 152c7df023f74f134416e13f4ffeb225bff6b416 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 14 Apr 2020 10:12:57 +0300 Subject: [PATCH 122/362] Store IDP/SP files in configurable document store oxCore #1939 --- core-document-store/pom.xml | 87 +++++++++ .../document/store/LocalDocumentStore.java | 32 +++ ...tandaloneDocumentStoreProviderFactory.java | 78 ++++++++ .../conf/DocumentStoreConfiguration.java | 63 ++++++ .../store/conf/DocumentStoreType.java | 11 ++ .../conf/JcaDocumentStoreConfiguration.java | 49 +++++ .../conf/LocalDocumentStoreConfiguration.java | 32 +++ .../WebDavDocumentStoreConfiguration.java | 49 +++++ .../store/provider/DocumentStore.java | 53 +++++ .../store/provider/DocumentStoreProvider.java | 12 ++ .../DocumentStoreProviderFactory.java | 88 +++++++++ .../provider/JcaDocumentStoreProvider.java | 100 ++++++++++ .../provider/LocalDocumentStoreProvider.java | 184 ++++++++++++++++++ .../provider/WebDavDocumentStoreProvider.java | 103 ++++++++++ .../service/BaseDocumentStoreService.java | 85 ++++++++ .../store/service/DocumentStoreService.java | 27 +++ .../service/LocalDocumentStoreService.java | 30 +++ .../src/main/resources/META-INF/beans.xml | 7 + oxSaml/pom.xml | 39 ++++ .../saml/metadata/SAMLMetadataParser.java | 60 +++--- oxSaml/src/main/resources/META-INF/beans.xml | 7 + pom.xml | 1 + 22 files changed, 1171 insertions(+), 26 deletions(-) create mode 100644 core-document-store/pom.xml create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/LocalDocumentStore.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreType.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/conf/JcaDocumentStoreConfiguration.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/conf/LocalDocumentStoreConfiguration.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/conf/WebDavDocumentStoreConfiguration.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStore.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStoreProvider.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStoreProviderFactory.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/service/BaseDocumentStoreService.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/service/DocumentStoreService.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/service/LocalDocumentStoreService.java create mode 100644 core-document-store/src/main/resources/META-INF/beans.xml create mode 100644 oxSaml/src/main/resources/META-INF/beans.xml diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml new file mode 100644 index 00000000..e03abf4b --- /dev/null +++ b/core-document-store/pom.xml @@ -0,0 +1,87 @@ + + + 4.0.0 + oxcore-document-store + Caches support + + + org.gluu + oxcore + 4.1.1.Final + + + + ${maven.min-version} + + + + + + src/main/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + src/test/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + + + + org.gluu + oxcore-util + ${project.version} + + + + + javax.enterprise + cdi-api + provided + + + + javax.inject + javax.inject + + + + + javax.jcr + jcr + + + + org.apache.jackrabbit + jackrabbit-core + + + + + com.fasterxml.jackson.core + jackson-annotations + + + + + org.testng + testng + + + + \ No newline at end of file diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/LocalDocumentStore.java b/core-document-store/src/main/java/org/gluu/service/document/store/LocalDocumentStore.java new file mode 100644 index 00000000..f637652c --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/LocalDocumentStore.java @@ -0,0 +1,32 @@ +package org.gluu.service.document.store; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.enterprise.util.AnnotationLiteral; +import javax.inject.Qualifier; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +@Qualifier +@Retention(RUNTIME) +@Target({ TYPE, METHOD, FIELD }) +@Documented +public @interface LocalDocumentStore { + + final class Literal extends AnnotationLiteral implements LocalDocumentStore { + + public static final Literal INSTANCE = new Literal(); + + private static final long serialVersionUID = 1L; + + } + +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java new file mode 100644 index 00000000..1e1706c5 --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java @@ -0,0 +1,78 @@ +package org.gluu.service.document.store; + +import org.gluu.service.document.store.conf.DocumentStoreConfiguration; +import org.gluu.service.document.store.conf.DocumentStoreType; +import org.gluu.service.document.store.provider.DocumentStoreProvider; +import org.gluu.service.document.store.provider.JcaDocumentStoreProvider; +import org.gluu.service.document.store.provider.LocalDocumentStoreProvider; +import org.gluu.service.document.store.provider.WebDavDocumentStoreProvider; +import org.gluu.util.security.StringEncrypter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +public class StandaloneDocumentStoreProviderFactory { + + private static final Logger LOG = LoggerFactory.getLogger(StandaloneDocumentStoreProviderFactory.class); + + private StringEncrypter stringEncrypter; + + public StandaloneDocumentStoreProviderFactory(StringEncrypter stringEncrypter) { + this.stringEncrypter = stringEncrypter; + } + + public DocumentStoreProvider getDocumentStoreProvider(DocumentStoreConfiguration documentStoreConfiguration) { + DocumentStoreType documentStoreType = documentStoreConfiguration.getDocumentStoreType(); + + if (documentStoreType == null) { + LOG.error("Failed to initialize documentStoreProvider, documentStoreProviderType is null. Fallback to LOCAL type."); + documentStoreType = DocumentStoreType.LOCAL; + } + + // Create bean + DocumentStoreProvider documentStoreProvider = null; + switch (documentStoreType) { + case LOCAL: + LocalDocumentStoreProvider localDocumentStoreProvider = new LocalDocumentStoreProvider(); + localDocumentStoreProvider.configure(documentStoreConfiguration); + localDocumentStoreProvider.init(); + + documentStoreProvider = localDocumentStoreProvider; + break; + case JCA: + if (stringEncrypter == null) { + throw new RuntimeException("Factory is not initialized properly. stringEncrypter is not specified"); + } + + JcaDocumentStoreProvider jcaDocumentStoreProvider = new JcaDocumentStoreProvider(); + jcaDocumentStoreProvider.configure(documentStoreConfiguration); + jcaDocumentStoreProvider.init(); + + documentStoreProvider = jcaDocumentStoreProvider; + break; + case WEB_DAV: + if (stringEncrypter == null) { + throw new RuntimeException("Factory is not initialized properly. stringEncrypter is not specified"); + } + + WebDavDocumentStoreProvider webDavDocumentStoreProvider = new WebDavDocumentStoreProvider(); + webDavDocumentStoreProvider.configure(documentStoreConfiguration); + webDavDocumentStoreProvider.init(); + + documentStoreProvider = webDavDocumentStoreProvider; + break; + } + + if (documentStoreProvider == null) { + throw new RuntimeException( + "Failed to initialize documentStoreProvider, documentStoreProviderType is unsupported: " + documentStoreType); + } + + documentStoreProvider.create(); + + return documentStoreProvider; + } + +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java new file mode 100644 index 00000000..31e48aea --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java @@ -0,0 +1,63 @@ +package org.gluu.service.document.store.conf; + +import java.io.Serializable; + +import javax.enterprise.inject.Vetoed; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +@Vetoed +public class DocumentStoreConfiguration implements Serializable { + + private static final long serialVersionUID = 2519892725606554887L; + + private DocumentStoreType documentStoreType = DocumentStoreType.LOCAL; + + private LocalDocumentStoreConfiguration localConfiguration = new LocalDocumentStoreConfiguration(); + + private JcaDocumentStoreConfiguration jcaConfiguration; + + private WebDavDocumentStoreConfiguration webDavConfiguration; + + public DocumentStoreType getDocumentStoreType() { + return documentStoreType; + } + + public void setDocumentStoreType(DocumentStoreType documentStoreType) { + this.documentStoreType = documentStoreType; + } + + public LocalDocumentStoreConfiguration getLocalConfiguration() { + return localConfiguration; + } + + public void setLocalConfiguration(LocalDocumentStoreConfiguration localConfiguration) { + this.localConfiguration = localConfiguration; + } + + public JcaDocumentStoreConfiguration getJcaConfiguration() { + return jcaConfiguration; + } + + public void setJcaConfiguration(JcaDocumentStoreConfiguration jcaConfiguration) { + this.jcaConfiguration = jcaConfiguration; + } + + public WebDavDocumentStoreConfiguration getWebDavConfiguration() { + return webDavConfiguration; + } + + public void setWebDavConfiguration(WebDavDocumentStoreConfiguration webDavConfiguration) { + this.webDavConfiguration = webDavConfiguration; + } + + @Override + public String toString() { + return "DocumentStoreConfiguration [documentStoreType=" + documentStoreType + ", localConfiguration=" + localConfiguration + + ", jcaConfiguration=" + jcaConfiguration + ", webDavConfiguration=" + webDavConfiguration + "]"; + } +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreType.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreType.java new file mode 100644 index 00000000..0b3de6ba --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreType.java @@ -0,0 +1,11 @@ +package org.gluu.service.document.store.conf; + +import javax.xml.bind.annotation.XmlEnum; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +@XmlEnum(String.class) +public enum DocumentStoreType { + LOCAL, JCA, WEB_DAV +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/JcaDocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/JcaDocumentStoreConfiguration.java new file mode 100644 index 00000000..e24905b5 --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/JcaDocumentStoreConfiguration.java @@ -0,0 +1,49 @@ +package org.gluu.service.document.store.conf; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class JcaDocumentStoreConfiguration implements Serializable { + + private static final long serialVersionUID = 3380170170265842427L; + + private String serverUrl; // http://localhost:8080/ + + private String userName; + + private String userPassowrd; + + public String getServerUrl() { + return serverUrl; + } + + public void setServerUrl(String serverUrl) { + this.serverUrl = serverUrl; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getUserPassowrd() { + return userPassowrd; + } + + public void setUserPassowrd(String userPassowrd) { + this.userPassowrd = userPassowrd; + } + + @Override + public String toString() { + return "JCAConfiguration [serverUrl=" + serverUrl + ", userName=" + userName + ", userPassowrd=" + userPassowrd + "]"; + } +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/LocalDocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/LocalDocumentStoreConfiguration.java new file mode 100644 index 00000000..1229a0d3 --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/LocalDocumentStoreConfiguration.java @@ -0,0 +1,32 @@ +package org.gluu.service.document.store.conf; + +import java.io.Serializable; + +import javax.xml.bind.annotation.XmlElement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class LocalDocumentStoreConfiguration implements Serializable { + + private static final long serialVersionUID = -2403247753790576983L; + + @XmlElement(name = "baseLocation") + private String baseLocation = "/"; + + public String getBaseLocation() { + return baseLocation; + } + + public void setBaseLocation(String baseLocation) { + this.baseLocation = baseLocation; + } + + @Override + public String toString() { + return "LocalConfiguration [baseLocation=" + baseLocation + "]"; + } +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/WebDavDocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/WebDavDocumentStoreConfiguration.java new file mode 100644 index 00000000..2ad41e23 --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/WebDavDocumentStoreConfiguration.java @@ -0,0 +1,49 @@ +package org.gluu.service.document.store.conf; + +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class WebDavDocumentStoreConfiguration implements Serializable { + + private static final long serialVersionUID = 3380170170265842538L; + + private String serverUrl; // http://localhost:8080/ + + private String userName; + + private String userPassowrd; + + public String getServerUrl() { + return serverUrl; + } + + public void setServerUrl(String serverUrl) { + this.serverUrl = serverUrl; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getUserPassowrd() { + return userPassowrd; + } + + public void setUserPassowrd(String userPassowrd) { + this.userPassowrd = userPassowrd; + } + + @Override + public String toString() { + return "JCAConfiguration [serverUrl=" + serverUrl + ", userName=" + userName + ", userPassowrd=" + userPassowrd + "]"; + } +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStore.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStore.java new file mode 100644 index 00000000..ab727cd0 --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStore.java @@ -0,0 +1,53 @@ +package org.gluu.service.document.store.provider; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; + +import org.gluu.service.document.store.conf.DocumentStoreType; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +public interface DocumentStore { + + /** + * Method to check if there is key in cache + */ + boolean hasDocument(String path); + + /** + * Save document into store + * @throws IOException + */ + boolean saveDocument(String path, String documentContent, Charset charset) throws IOException; + + /** + * Save document stream into store + * @throws IOException + */ + boolean saveDocumentStream(String path, InputStream documentStream) throws IOException; + + /** + * Load document from store + */ + String readDocument(String path, Charset charset) throws IOException; + + /** + * Load document from store as stream + */ + public InputStream readDocumentAsStream(String path) throws IOException; + + /** + * Removes an object document from store + */ + boolean removeDocument(String path) throws IOException; + + /** + * Rename an object in document store + */ + boolean renameDocument(String currentPath, String destinationPath) throws IOException; + + public abstract DocumentStoreType getProviderType(); + +} \ No newline at end of file diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStoreProvider.java new file mode 100644 index 00000000..71364d7b --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStoreProvider.java @@ -0,0 +1,12 @@ +package org.gluu.service.document.store.provider; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +public abstract class DocumentStoreProvider implements DocumentStore { + + public abstract void create(); + + public abstract void destroy(); + +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStoreProviderFactory.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStoreProviderFactory.java new file mode 100644 index 00000000..616705bc --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStoreProviderFactory.java @@ -0,0 +1,88 @@ +package org.gluu.service.document.store.provider; + +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Any; +import javax.enterprise.inject.Instance; +import javax.enterprise.inject.Produces; +import javax.inject.Inject; + +import org.gluu.service.document.store.LocalDocumentStore; +import org.gluu.service.document.store.conf.DocumentStoreConfiguration; +import org.gluu.service.document.store.conf.DocumentStoreType; +import org.slf4j.Logger; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +@ApplicationScoped +public class DocumentStoreProviderFactory { + + @Inject + private Logger log; + + @Inject + private DocumentStoreConfiguration documentStoreConfiguration; + + @Inject + @Any + private Instance instance; + + @Produces + @ApplicationScoped + public DocumentStoreProvider getDocumentStoreProvider() { + log.debug("Started to create document store provider"); + + + return getDocumentStoreProvider(documentStoreConfiguration); + } + + public DocumentStoreProvider getDocumentStoreProvider(DocumentStoreConfiguration documentStoreConfiguration) { + DocumentStoreType documentStoreType = documentStoreConfiguration.getDocumentStoreType(); + + if (documentStoreType == null) { + log.error("Failed to initialize DocumentStoreProvider, DocumentStoreProviderType is null. Fallback to LOCAL type."); + documentStoreType = DocumentStoreType.LOCAL; + } + + // Create proxied bean + DocumentStoreProvider documentStoreProvider = null; + switch (documentStoreType) { + case LOCAL: + documentStoreProvider = instance.select(LocalDocumentStoreProvider.class).get(); + break; + case JCA: + documentStoreProvider = instance.select(JcaDocumentStoreProvider.class).get(); + break; + case WEB_DAV: + documentStoreProvider = instance.select(WebDavDocumentStoreProvider.class).get(); + break; + } + + if (documentStoreProvider == null) { + throw new RuntimeException("Failed to initialize DocumentStoreProvider, DocumentStoreProviderType is unsupported: " + documentStoreType); + } + + documentStoreProvider.create(); + + return documentStoreProvider; + } + + @Produces + @ApplicationScoped + @LocalDocumentStore + public DocumentStoreProvider getLocalDocumentStoreProvider() { + log.debug("Started to create local document store provider"); + + DocumentStoreType documentStoreType = DocumentStoreType.LOCAL; + DocumentStoreProvider documentStoreProvider = instance.select(LocalDocumentStoreProvider.class).get(); + + if (documentStoreProvider == null) { + throw new RuntimeException("Failed to initialize DocumentStoreProvider, DocumentStoreProviderType is unsupported: " + documentStoreType); + } + + documentStoreProvider.create(); + + return documentStoreProvider; + } + +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java new file mode 100644 index 00000000..476e120e --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java @@ -0,0 +1,100 @@ +package org.gluu.service.document.store.provider; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +import org.gluu.service.document.store.conf.DocumentStoreConfiguration; +import org.gluu.service.document.store.conf.DocumentStoreType; +import org.gluu.service.document.store.conf.JcaDocumentStoreConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +@ApplicationScoped +public class JcaDocumentStoreProvider extends DocumentStoreProvider { + + @Inject + private Logger log; + + @Inject + private DocumentStoreConfiguration documentStoreConfiguration; + + private JcaDocumentStoreConfiguration jcaDocumentStoreConfiguration; + + public JcaDocumentStoreProvider() { + } + + @PostConstruct + public void init() { + this.jcaDocumentStoreConfiguration = documentStoreConfiguration.getJcaConfiguration(); + } + + public void create() { + log.debug("Starting LocalDocumentStoreProvider ..."); + } + + public void configure(DocumentStoreConfiguration documentStoreConfiguration) { + this.log = LoggerFactory.getLogger(DocumentStoreConfiguration.class); + this.documentStoreConfiguration = documentStoreConfiguration; + } + + @PreDestroy + public void destroy() { + log.debug("Destroying LocalDocumentStoreProvider"); + + log.debug("Destroyed LocalDocumentStoreProvider"); + } + + public DocumentStoreType getProviderType() { + return DocumentStoreType.LOCAL; + } + + public boolean hasDocument(String path) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean saveDocument(String path, String documentContent, Charset charset) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean saveDocumentStream(String path, InputStream documentStream) throws IOException { + // TODO Auto-generated method stub + return false; + } + + @Override + public String readDocument(String path, Charset charset) throws IOException { + // TODO Auto-generated method stub + return null; + } + + @Override + public InputStream readDocumentAsStream(String path) throws IOException { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean renameDocument(String currentPath, String destinationPath) throws IOException { + // TODO Auto-generated method stub + return false; + } + + public boolean removeDocument(String path) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java new file mode 100644 index 00000000..6b4ab542 --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java @@ -0,0 +1,184 @@ +package org.gluu.service.document.store.provider; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.gluu.service.document.store.conf.DocumentStoreConfiguration; +import org.gluu.service.document.store.conf.DocumentStoreType; +import org.gluu.service.document.store.conf.LocalDocumentStoreConfiguration; +import org.gluu.util.StringHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +@ApplicationScoped +public class LocalDocumentStoreProvider extends DocumentStoreProvider { + + @Inject + private Logger log; + + @Inject + private DocumentStoreConfiguration documentStoreConfiguration; + + private LocalDocumentStoreConfiguration localDocumentStoreConfiguration; + + private String baseLocation; + + public LocalDocumentStoreProvider() { + } + + @PostConstruct + public void init() { + this.localDocumentStoreConfiguration = documentStoreConfiguration.getLocalConfiguration(); + } + + @Override + public void create() { + log.debug("Starting LocalDocumentStoreProvider ..."); + + if (StringHelper.isEmpty(localDocumentStoreConfiguration.getBaseLocation())) { + throw new IllegalArgumentException("Base location should not be empty"); + } + + baseLocation = new File(localDocumentStoreConfiguration.getBaseLocation()).getAbsolutePath(); + } + + public void configure(DocumentStoreConfiguration documentStoreConfiguration) { + this.log = LoggerFactory.getLogger(DocumentStoreConfiguration.class); + this.documentStoreConfiguration = documentStoreConfiguration; + } + + @PreDestroy + @Override + public void destroy() { + log.debug("Destroying LocalDocumentStoreProvider"); + + log.debug("Destroyed LocalDocumentStoreProvider"); + } + + @Override + public DocumentStoreType getProviderType() { + return DocumentStoreType.LOCAL; + } + + @Override + public boolean hasDocument(String path) { + if (StringHelper.isEmpty(path)) { + throw new IllegalArgumentException("Specified path should not be empty!"); + } + + File file = buildFilePath(path); + + return file.exists(); + } + + @Override + public boolean saveDocument(String path, String documentContent, Charset charset) throws IOException { + File file = buildFilePath(path); + createParentPath(file); + + try (FileOutputStream os = FileUtils.openOutputStream(file)) { + IOUtils.write(documentContent, os, charset); + os.flush(); + + return true; + } catch (IOException ex) { + log.error("Failed to write document to file '{}'", file.getAbsolutePath(), ex); + } + + return false; + } + + @Override + public boolean saveDocumentStream(String path, InputStream documentStream) throws IOException { + File file = buildFilePath(path); + createParentPath(file); + + try (FileOutputStream os = FileUtils.openOutputStream(file)) { + IOUtils.copy(documentStream, os); + os.flush(); + + return true; + } catch (IOException ex) { + log.error("Failed to write document stream to file '{}'", file.getAbsolutePath(), ex); + } + + return false; + } + + @Override + public String readDocument(String path, Charset charset) throws IOException { + File file = buildFilePath(path); + createParentPath(file); + + return FileUtils.readFileToString(file, charset); + } + + @Override + public InputStream readDocumentAsStream(String path) throws IOException { + File file = buildFilePath(path); + + return new BufferedInputStream(FileUtils.openInputStream(file)); + } + + @Override + public boolean renameDocument(String currentPath, String destinationPath) throws IOException { + File currentFile = buildFilePath(currentPath); + File destinationFile = buildFilePath(destinationPath); + + if (!removeDocument(destinationPath)) { + log.error("Failed to remove destination file '{}'", destinationFile.getAbsolutePath()); + } + + createParentPath(destinationFile); + + try { + currentFile.renameTo(destinationFile); + } catch (Exception ex) { + log.error("Failed to rename to destination file '{}'", destinationFile.getAbsolutePath(), ex); + throw new IOException("Failed to rename to destination file " + destinationFile.getAbsolutePath(), ex); + } + + return true; + } + + @Override + public boolean removeDocument(String path) throws IOException { + if (!hasDocument(path)) { + return true; + } + + File file = buildFilePath(path); + createParentPath(file); + + return FileUtils.deleteQuietly(file); + } + + private void createParentPath(File file) throws IOException { + try { + FileUtils.forceMkdirParent(file); + } catch (IOException ex) { + log.error("Failed to create path to file '{}'", file.getAbsolutePath(), ex); + throw ex; + } + } + + private File buildFilePath(String path) { + String filePath = baseLocation + File.pathSeparator + path; + return new File(filePath); + } + +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java new file mode 100644 index 00000000..f304e998 --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java @@ -0,0 +1,103 @@ +package org.gluu.service.document.store.provider; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +import org.gluu.service.document.store.conf.DocumentStoreConfiguration; +import org.gluu.service.document.store.conf.DocumentStoreType; +import org.gluu.service.document.store.conf.WebDavDocumentStoreConfiguration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +@ApplicationScoped +public class WebDavDocumentStoreProvider extends DocumentStoreProvider { + + @Inject + private Logger log; + + @Inject + private DocumentStoreConfiguration documentStoreConfiguration; + + private WebDavDocumentStoreConfiguration webDavDocumentStoreConfiguration; + + public WebDavDocumentStoreProvider() { + } + + @PostConstruct + public void init() { + this.webDavDocumentStoreConfiguration = documentStoreConfiguration.getWebDavConfiguration(); + } + + public void create() { + log.debug("Starting LocalDocumentStoreProvider ..."); + } + + public void configure(DocumentStoreConfiguration documentStoreConfiguration) { + this.log = LoggerFactory.getLogger(DocumentStoreConfiguration.class); + this.documentStoreConfiguration = documentStoreConfiguration; + } + + @PreDestroy + public void destroy() { + log.debug("Destroying LocalDocumentStoreProvider"); + + log.debug("Destroyed LocalDocumentStoreProvider"); + } + + @Override + public DocumentStoreType getProviderType() { + return DocumentStoreType.LOCAL; + } + + @Override + public boolean hasDocument(String path) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean saveDocument(String path, String documentContent, Charset charset) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean saveDocumentStream(String path, InputStream documentStream) throws IOException { + // TODO Auto-generated method stub + return false; + } + + @Override + public String readDocument(String path, Charset charset) throws IOException { + // TODO Auto-generated method stub + return null; + } + + @Override + public InputStream readDocumentAsStream(String path) throws IOException { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean renameDocument(String currentPath, String destinationPath) throws IOException { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean removeDocument(String path) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/service/BaseDocumentStoreService.java b/core-document-store/src/main/java/org/gluu/service/document/store/service/BaseDocumentStoreService.java new file mode 100644 index 00000000..5275e328 --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/service/BaseDocumentStoreService.java @@ -0,0 +1,85 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ +package org.gluu.service.document.store.service; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; + +import javax.inject.Inject; + +import org.gluu.service.document.store.conf.DocumentStoreType; +import org.gluu.service.document.store.provider.DocumentStore; +import org.gluu.service.document.store.provider.DocumentStoreProvider; +import org.slf4j.Logger; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +@SuppressWarnings("rawtypes") +public abstract class BaseDocumentStoreService implements DocumentStore { + + @Inject + private Logger log; + + public boolean hasDocument(String path) { + DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); + + return documentStoreProvider.hasDocument(path); + } + + @Override + public boolean saveDocument(String path, String documentContent, Charset charset) throws IOException { + DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); + + return documentStoreProvider.saveDocument(path, documentContent, charset); + } + + @Override + public boolean saveDocumentStream(String path, InputStream documentStream) throws IOException { + DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); + + return documentStoreProvider.saveDocumentStream(path, documentStream); + } + + @Override + public String readDocument(String path, Charset charset) throws IOException { + DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); + + return documentStoreProvider.readDocument(path, charset); + } + + @Override + public InputStream readDocumentAsStream(String path) throws IOException { + DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); + + return documentStoreProvider.readDocumentAsStream(path); + } + + @Override + public boolean renameDocument(String currentPath, String destinationPath) throws IOException { + DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); + + return documentStoreProvider.renameDocument(currentPath, destinationPath); + } + + @Override + public boolean removeDocument(String path) throws IOException { + DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); + + return documentStoreProvider.removeDocument(path); + } + + @Override + public DocumentStoreType getProviderType() { + DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); + + return documentStoreProvider.getProviderType(); + } + + protected abstract DocumentStoreProvider getDocumentStoreProvider(); + +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/service/DocumentStoreService.java b/core-document-store/src/main/java/org/gluu/service/document/store/service/DocumentStoreService.java new file mode 100644 index 00000000..fc5574f0 --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/service/DocumentStoreService.java @@ -0,0 +1,27 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ +package org.gluu.service.document.store.service; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +import org.gluu.service.document.store.provider.DocumentStoreProvider; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +@ApplicationScoped +public class DocumentStoreService extends BaseDocumentStoreService { + + @Inject + private DocumentStoreProvider documentStoreProvider; + + @Override + protected DocumentStoreProvider getDocumentStoreProvider() { + return documentStoreProvider; + } + +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/service/LocalDocumentStoreService.java b/core-document-store/src/main/java/org/gluu/service/document/store/service/LocalDocumentStoreService.java new file mode 100644 index 00000000..2ed05414 --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/service/LocalDocumentStoreService.java @@ -0,0 +1,30 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ +package org.gluu.service.document.store.service; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +import org.gluu.service.document.store.LocalDocumentStore; +import org.gluu.service.document.store.provider.DocumentStoreProvider; + +/** + * @author Yuriy Movchan on 04/10/2020 + */ +@ApplicationScoped +public class LocalDocumentStoreService extends BaseDocumentStoreService { + + @Inject + @LocalDocumentStore + private DocumentStoreProvider documentStoreProvider; + + @Override + protected DocumentStoreProvider getDocumentStoreProvider() { + return documentStoreProvider; + } + + +} diff --git a/core-document-store/src/main/resources/META-INF/beans.xml b/core-document-store/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000..2f4f7e27 --- /dev/null +++ b/core-document-store/src/main/resources/META-INF/beans.xml @@ -0,0 +1,7 @@ + + + diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index 00606683..1dafcc7c 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -12,11 +12,50 @@ 4.2.0-SNAPSHOT + + + + src/main/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + src/test/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + + + javax.enterprise + cdi-api + provided + + + org.gluu oxcore-util + + org.gluu + oxcore-document-store + ${project.version} + + commons-beanutils commons-beanutils diff --git a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java index 950fdd1d..06f4219e 100644 --- a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java +++ b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java @@ -5,7 +5,6 @@ */ package org.gluu.saml.metadata; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -13,15 +12,16 @@ import java.net.URL; import java.util.List; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; -import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +import org.gluu.service.document.store.service.DocumentStoreService; import org.gluu.util.io.HTTPFileDownloader; +import org.slf4j.Logger; import org.xml.sax.SAXException; /** @@ -29,20 +29,26 @@ * * @author Dmitry Ognyannikov */ + +@ApplicationScoped public final class SAMLMetadataParser { - private static final Log LOG = LogFactory.getLog(SAMLMetadataParser.class); - private SAMLMetadataParser() { } + @Inject + private Logger log; + + @Inject + private DocumentStoreService documentStoreService; - public static List getEntityIdFromMetadataFile(File metadataFile) { - if (!metadataFile.isFile()) { + public List getEntityIdFromMetadataFile(String metadataFile) { + if (!documentStoreService.hasDocument(metadataFile)) { return null; } + EntityIDHandler handler = parseMetadata(metadataFile); if(handler!=null){ List entityIds = handler.getEntityIDs(); if (entityIds == null || entityIds.isEmpty()) { - LOG.error("Failed to find entityId in metadata file: " + metadataFile.getAbsolutePath()); + log.error("Failed to find entityId in metadata file: " + metadataFile); } return entityIds; }else{ @@ -50,13 +56,13 @@ public static List getEntityIdFromMetadataFile(File metadataFile) { } } - public static List getSpEntityIdFromMetadataFile(File metadataFile) { + public List getSpEntityIdFromMetadataFile(String metadataFile) { EntityIDHandler handler = parseMetadata(metadataFile); if(handler!=null){ List entityIds = handler.getSpEntityIDs(); if (entityIds == null || entityIds.isEmpty()) { - LOG.error("Failed to find entityId in metadata file: " + metadataFile.getAbsolutePath()); + log.error("Failed to find entityId in metadata file: " + metadataFile); } return entityIds; @@ -66,25 +72,26 @@ public static List getSpEntityIdFromMetadataFile(File metadataFile) { } - public static EntityIDHandler parseMetadata(File metadataFile) { - if (!metadataFile.exists()) { - LOG.error("Failed to get entityId from metadata file: " + metadataFile.getAbsolutePath()); + public EntityIDHandler parseMetadata(String metadataFile) { + if (!documentStoreService.hasDocument(metadataFile)) { + log.error("Failed to get entityId from metadata file: " + metadataFile); return null; } + InputStream is = null; try { - is = FileUtils.openInputStream(metadataFile); + is = documentStoreService.readDocumentAsStream(metadataFile); return parseMetadata(is); } catch (IOException ex) { - LOG.error("Failed to read SAML metadata file: " + metadataFile.getAbsolutePath(), ex); + log.error("Failed to read SAML metadata file: " + metadataFile, ex); return null; } finally { IOUtils.closeQuietly(is); } } - public static EntityIDHandler parseMetadata(InputStream is) { + public EntityIDHandler parseMetadata(InputStream is) { InputStreamReader isr = null; EntityIDHandler handler = null; try { @@ -93,11 +100,11 @@ public static EntityIDHandler parseMetadata(InputStream is) { handler = new EntityIDHandler(); saxParser.parse(is, handler); } catch (IOException ex) { - LOG.error("Failed to read SAML metadata", ex); + log.error("Failed to read SAML metadata", ex); } catch (ParserConfigurationException e) { - LOG.error("Failed to confugure SAX parser", e); + log.error("Failed to confugure SAX parser", e); } catch (SAXException e) { - LOG.error("Failed to parse SAML metadata", e); + log.error("Failed to parse SAML metadata", e); } finally { IOUtils.closeQuietly(isr); IOUtils.closeQuietly(is); @@ -107,16 +114,17 @@ public static EntityIDHandler parseMetadata(InputStream is) { return handler; } - public static EntityIDHandler parseMetadata(URL metadataURL) { + public EntityIDHandler parseMetadata(URL metadataURL) { String metadataFileContent = HTTPFileDownloader.getResource(metadataURL.toExternalForm(), "application/xml, text/xml", null, null); - return parseMetadata(metadataFileContent); - } - public static EntityIDHandler parseMetadata(String metadata) { - if (metadata == null) { + if (metadataFileContent == null) { return null; } - InputStream is = new StringBufferInputStream(metadata); + + InputStream is = new StringBufferInputStream(metadataFileContent); + return parseMetadata(is); } + } + diff --git a/oxSaml/src/main/resources/META-INF/beans.xml b/oxSaml/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000..2f4f7e27 --- /dev/null +++ b/oxSaml/src/main/resources/META-INF/beans.xml @@ -0,0 +1,7 @@ + + + diff --git a/pom.xml b/pom.xml index f4da3146..1181060a 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ oxModel oxSaml core-cache + core-document-store core-standalone core-java-ext core-cdi From 333b5d2bfd12f0f49de907f20a8386988e058256 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 14 Apr 2020 10:42:14 +0300 Subject: [PATCH 123/362] Store IDP/SP files in configurable document store oxCore #1939 --- .../main/java/org/gluu/saml/metadata/SAMLMetadataParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java index 06f4219e..17a9c283 100644 --- a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java +++ b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java @@ -31,7 +31,7 @@ */ @ApplicationScoped -public final class SAMLMetadataParser { +public class SAMLMetadataParser { @Inject private Logger log; From 2539ca18e4551764cd94f29b5029d208d2e5e183 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 14 Apr 2020 11:21:18 +0300 Subject: [PATCH 124/362] Store IDP/SP files in configurable document store oxCore #1939 --- .../document/store/provider/LocalDocumentStoreProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java index 6b4ab542..62344c37 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java @@ -177,7 +177,7 @@ private void createParentPath(File file) throws IOException { } private File buildFilePath(String path) { - String filePath = baseLocation + File.pathSeparator + path; + String filePath = baseLocation + File.separator + path; return new File(filePath); } From b61774e96825a9a4d445a3ef69d5915f31d35bbf Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 14 Apr 2020 11:23:18 +0300 Subject: [PATCH 125/362] Store IDP/SP files in configurable document store oxCore #1939 --- .../document/store/provider/JcaDocumentStoreProvider.java | 2 +- .../document/store/provider/WebDavDocumentStoreProvider.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java index 476e120e..dbd68c90 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java @@ -54,7 +54,7 @@ public void destroy() { } public DocumentStoreType getProviderType() { - return DocumentStoreType.LOCAL; + return DocumentStoreType.JCA; } public boolean hasDocument(String path) { diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java index f304e998..c3896a23 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java @@ -55,7 +55,7 @@ public void destroy() { @Override public DocumentStoreType getProviderType() { - return DocumentStoreType.LOCAL; + return DocumentStoreType.WEB_DAV; } @Override From ef64bd6ec1be2ddd5219a9e7c2895f14478d2bcd Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 14 Apr 2020 17:36:04 +0300 Subject: [PATCH 126/362] Add logging to local document store --- .../store/provider/LocalDocumentStoreProvider.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java index 62344c37..a3a65021 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java @@ -76,6 +76,8 @@ public DocumentStoreType getProviderType() { @Override public boolean hasDocument(String path) { + log.debug("Has document: '{}'", path); + if (StringHelper.isEmpty(path)) { throw new IllegalArgumentException("Specified path should not be empty!"); } @@ -87,6 +89,8 @@ public boolean hasDocument(String path) { @Override public boolean saveDocument(String path, String documentContent, Charset charset) throws IOException { + log.debug("Save document: '{}'", path); + File file = buildFilePath(path); createParentPath(file); @@ -104,6 +108,8 @@ public boolean saveDocument(String path, String documentContent, Charset charset @Override public boolean saveDocumentStream(String path, InputStream documentStream) throws IOException { + log.debug("Save document from stream: '{}'", path); + File file = buildFilePath(path); createParentPath(file); @@ -121,6 +127,8 @@ public boolean saveDocumentStream(String path, InputStream documentStream) throw @Override public String readDocument(String path, Charset charset) throws IOException { + log.debug("Read document: '{}'", path); + File file = buildFilePath(path); createParentPath(file); @@ -129,6 +137,8 @@ public String readDocument(String path, Charset charset) throws IOException { @Override public InputStream readDocumentAsStream(String path) throws IOException { + log.debug("Read document as stream: '{}'", path); + File file = buildFilePath(path); return new BufferedInputStream(FileUtils.openInputStream(file)); @@ -136,6 +146,8 @@ public InputStream readDocumentAsStream(String path) throws IOException { @Override public boolean renameDocument(String currentPath, String destinationPath) throws IOException { + log.debug("Rename document: '{}' -> '{}'", currentPath, destinationPath); + File currentFile = buildFilePath(currentPath); File destinationFile = buildFilePath(destinationPath); @@ -157,6 +169,8 @@ public boolean renameDocument(String currentPath, String destinationPath) throws @Override public boolean removeDocument(String path) throws IOException { + log.debug("Remove document: '{}'", path); + if (!hasDocument(path)) { return true; } From ddd1a21a1c760a6eaf4c0affd9cd9f707726585a Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 16 Apr 2020 15:37:56 +0300 Subject: [PATCH 127/362] JCA document store provider --- core-document-store/pom.xml | 5 +- ...tandaloneDocumentStoreProviderFactory.java | 2 +- .../conf/JcaDocumentStoreConfiguration.java | 54 ++- .../WebDavDocumentStoreConfiguration.java | 60 ++- .../store/provider/DocumentStore.java | 14 +- .../provider/JcaDocumentStoreProvider.java | 349 ++++++++++++++++-- .../provider/LocalDocumentStoreProvider.java | 60 ++- .../provider/WebDavDocumentStoreProvider.java | 8 +- .../service/BaseDocumentStoreService.java | 12 +- .../manual/JcaDocumentStoreManualTest.java | 96 +++++ 10 files changed, 557 insertions(+), 103 deletions(-) create mode 100644 core-document-store/src/test/java/org/gluu/service/document/store/manual/JcaDocumentStoreManualTest.java diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index e03abf4b..da4a076a 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -65,11 +65,14 @@ javax.jcr jcr - org.apache.jackrabbit jackrabbit-core + + org.apache.jackrabbit + jackrabbit-jcr-rmi + diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java index 1e1706c5..a3116d60 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java @@ -47,7 +47,7 @@ public DocumentStoreProvider getDocumentStoreProvider(DocumentStoreConfiguration } JcaDocumentStoreProvider jcaDocumentStoreProvider = new JcaDocumentStoreProvider(); - jcaDocumentStoreProvider.configure(documentStoreConfiguration); + jcaDocumentStoreProvider.configure(documentStoreConfiguration, stringEncrypter); jcaDocumentStoreProvider.init(); documentStoreProvider = jcaDocumentStoreProvider; diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/JcaDocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/JcaDocumentStoreConfiguration.java index e24905b5..db2c910d 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/conf/JcaDocumentStoreConfiguration.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/JcaDocumentStoreConfiguration.java @@ -12,11 +12,13 @@ public class JcaDocumentStoreConfiguration implements Serializable { private static final long serialVersionUID = 3380170170265842427L; - private String serverUrl; // http://localhost:8080/ + private String serverUrl; // http://localhost:8080/rmi + private String workspaceName; + private long connectionTimeout; - private String userName; - - private String userPassowrd; + private String userId; + private String password; + private String decryptedPassword; public String getServerUrl() { return serverUrl; @@ -26,24 +28,50 @@ public void setServerUrl(String serverUrl) { this.serverUrl = serverUrl; } - public String getUserName() { - return userName; + public String getWorkspaceName() { + return workspaceName; + } + + public void setWorkspaceName(String workspaceName) { + this.workspaceName = workspaceName; + } + + public long getConnectionTimeout() { + return connectionTimeout; + } + + public void setConnectionTimeout(long connectionTimeout) { + this.connectionTimeout = connectionTimeout; } - public void setUserName(String userName) { - this.userName = userName; + public String getUserId() { + return userId; } - public String getUserPassowrd() { - return userPassowrd; + public void setUserId(String userId) { + this.userId = userId; } - public void setUserPassowrd(String userPassowrd) { - this.userPassowrd = userPassowrd; + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getDecryptedPassword() { + return decryptedPassword; + } + + public void setDecryptedPassword(String decryptedPassword) { + this.decryptedPassword = decryptedPassword; } @Override public String toString() { - return "JCAConfiguration [serverUrl=" + serverUrl + ", userName=" + userName + ", userPassowrd=" + userPassowrd + "]"; + return "JcaDocumentStoreConfiguration [serverUrl=" + serverUrl + ", workspaceName=" + workspaceName + ", connectionTimeout=" + + connectionTimeout + ", userId=" + userId + ", password=" + password + ", decryptedPassword=" + decryptedPassword + "]"; } + } diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/WebDavDocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/WebDavDocumentStoreConfiguration.java index 2ad41e23..55ef594a 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/conf/WebDavDocumentStoreConfiguration.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/WebDavDocumentStoreConfiguration.java @@ -10,15 +10,17 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class WebDavDocumentStoreConfiguration implements Serializable { - private static final long serialVersionUID = 3380170170265842538L; + private static final long serialVersionUID = 3380170170265842538L; - private String serverUrl; // http://localhost:8080/ - - private String userName; - - private String userPassowrd; + private String serverUrl; // http://localhost:8080 + private String workspaceName; + private long connectionTimeout; - public String getServerUrl() { + private String userId; + private String password; + private String decryptedPassword; + + public String getServerUrl() { return serverUrl; } @@ -26,24 +28,50 @@ public void setServerUrl(String serverUrl) { this.serverUrl = serverUrl; } - public String getUserName() { - return userName; + public String getWorkspaceName() { + return workspaceName; + } + + public void setWorkspaceName(String workspaceName) { + this.workspaceName = workspaceName; + } + + public long getConnectionTimeout() { + return connectionTimeout; + } + + public void setConnectionTimeout(long connectionTimeout) { + this.connectionTimeout = connectionTimeout; } - public void setUserName(String userName) { - this.userName = userName; + public String getUserId() { + return userId; } - public String getUserPassowrd() { - return userPassowrd; + public void setUserId(String userId) { + this.userId = userId; } - public void setUserPassowrd(String userPassowrd) { - this.userPassowrd = userPassowrd; + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getDecryptedPassword() { + return decryptedPassword; + } + + public void setDecryptedPassword(String decryptedPassword) { + this.decryptedPassword = decryptedPassword; } @Override public String toString() { - return "JCAConfiguration [serverUrl=" + serverUrl + ", userName=" + userName + ", userPassowrd=" + userPassowrd + "]"; + return "WebDavDocumentStoreConfiguration [serverUrl=" + serverUrl + ", workspaceName=" + workspaceName + ", connectionTimeout=" + + connectionTimeout + ", userId=" + userId + ", password=" + password + ", decryptedPassword=" + decryptedPassword + "]"; } + } diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStore.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStore.java index ab727cd0..259146e1 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStore.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStore.java @@ -18,35 +18,33 @@ public interface DocumentStore { /** * Save document into store - * @throws IOException */ - boolean saveDocument(String path, String documentContent, Charset charset) throws IOException; + boolean saveDocument(String path, String documentContent, Charset charset); /** * Save document stream into store - * @throws IOException */ - boolean saveDocumentStream(String path, InputStream documentStream) throws IOException; + boolean saveDocumentStream(String path, InputStream documentStream); /** * Load document from store */ - String readDocument(String path, Charset charset) throws IOException; + String readDocument(String path, Charset charset); /** * Load document from store as stream */ - public InputStream readDocumentAsStream(String path) throws IOException; + public InputStream readDocumentAsStream(String path) ; /** * Removes an object document from store */ - boolean removeDocument(String path) throws IOException; + boolean removeDocument(String path); /** * Rename an object in document store */ - boolean renameDocument(String currentPath, String destinationPath) throws IOException; + boolean renameDocument(String currentPath, String destinationPath); public abstract DocumentStoreType getProviderType(); diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java index dbd68c90..341a3f07 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java @@ -1,17 +1,44 @@ package org.gluu.service.document.store.provider; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; +import javax.jcr.AccessDeniedException; +import javax.jcr.Binary; +import javax.jcr.Node; +import javax.jcr.Property; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.SimpleCredentials; +import javax.jcr.Value; +import javax.jcr.lock.LockException; +import javax.jcr.nodetype.ConstraintViolationException; +import javax.jcr.nodetype.NodeType; +import javax.jcr.version.VersionException; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.jackrabbit.JcrConstants; +import org.apache.jackrabbit.commons.JcrUtils; +import org.apache.jackrabbit.rmi.repository.URLRemoteRepository; import org.gluu.service.document.store.conf.DocumentStoreConfiguration; import org.gluu.service.document.store.conf.DocumentStoreType; import org.gluu.service.document.store.conf.JcaDocumentStoreConfiguration; +import org.gluu.util.StringHelper; +import org.gluu.util.security.StringEncrypter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -21,80 +48,334 @@ @ApplicationScoped public class JcaDocumentStoreProvider extends DocumentStoreProvider { - @Inject - private Logger log; + @Inject + private Logger log; + + + @Inject + private DocumentStoreConfiguration documentStoreConfiguration; @Inject - private DocumentStoreConfiguration documentStoreConfiguration; + private StringEncrypter stringEncrypter; - private JcaDocumentStoreConfiguration jcaDocumentStoreConfiguration; + private JcaDocumentStoreConfiguration jcaDocumentStoreConfiguration; - public JcaDocumentStoreProvider() { - } + private URLRemoteRepository repository; + private SimpleCredentials credentials; + private String workspaceName; + private long connectionTimeout; - @PostConstruct - public void init() { - this.jcaDocumentStoreConfiguration = documentStoreConfiguration.getJcaConfiguration(); - } + public JcaDocumentStoreProvider() { + } - public void create() { - log.debug("Starting LocalDocumentStoreProvider ..."); - } + @PostConstruct + public void init() { + this.jcaDocumentStoreConfiguration = documentStoreConfiguration.getJcaConfiguration(); + } - public void configure(DocumentStoreConfiguration documentStoreConfiguration) { + public void create() { + try { + log.debug("Starting JcaDocumentStoreProvider ..."); + decryptPassword(jcaDocumentStoreConfiguration); + this.repository = new URLRemoteRepository("http://localhost:8080/rmi"); + + String password = StringUtils.isBlank(jcaDocumentStoreConfiguration.getDecryptedPassword()) ? "" : jcaDocumentStoreConfiguration.getDecryptedPassword(); + + this.credentials = new SimpleCredentials(jcaDocumentStoreConfiguration.getUserId(), + password.toCharArray()); + + this.workspaceName = jcaDocumentStoreConfiguration.getWorkspaceName(); + this.connectionTimeout = jcaDocumentStoreConfiguration.getConnectionTimeout(); + } catch (Exception ex) { + throw new IllegalStateException("Error starting JcaDocumentStoreProvider", ex); + } + } + + public void configure(DocumentStoreConfiguration documentStoreConfiguration, StringEncrypter stringEncrypter) { this.log = LoggerFactory.getLogger(DocumentStoreConfiguration.class); this.documentStoreConfiguration = documentStoreConfiguration; + this.stringEncrypter = stringEncrypter; } - @PreDestroy - public void destroy() { - log.debug("Destroying LocalDocumentStoreProvider"); + @PreDestroy + public void destroy() { + log.debug("Destroying JcaDocumentStoreProvider"); - log.debug("Destroyed LocalDocumentStoreProvider"); - } + log.debug("Destroyed JcaDocumentStoreProvider"); + } - public DocumentStoreType getProviderType() { - return DocumentStoreType.JCA; - } + public DocumentStoreType getProviderType() { + return DocumentStoreType.JCA; + } + @Override public boolean hasDocument(String path) { - // TODO Auto-generated method stub - return false; + log.debug("Has document: '{}'", path); + + if (StringHelper.isEmpty(path)) { + throw new IllegalArgumentException("Specified path should not be empty!"); + } + + Node fileNode = null; + Session session; + try { + session = getSessionWithTimeout(); + try { + fileNode = JcrUtils.getNodeIfExists(getNormalizedPath(path), session); + } finally { + closeSession(session); + } + } catch (RepositoryException ex) { + log.error("Failed to check if path '" + path + "' exists in repository", ex); + } + + return fileNode != null; } @Override public boolean saveDocument(String path, String documentContent, Charset charset) { - // TODO Auto-generated method stub + log.debug("Save document: '{}'", path); + + String normalizedPath = getNormalizedPath(path); + try { + Session session = getSessionWithTimeout(); + try { + Node contentNode = getOrCreateContentNode(normalizedPath, session); + Value value = session.getValueFactory().createValue(documentContent); + contentNode.setProperty("jcr:data", value); + + session.save(); + return true; + } finally { + closeSession(session); + } + } catch (RepositoryException ex) { + log.error("Failed to write document to file '{}'", path, ex); + } + return false; } @Override - public boolean saveDocumentStream(String path, InputStream documentStream) throws IOException { - // TODO Auto-generated method stub + public boolean saveDocumentStream(String path, InputStream documentStream) { + log.debug("Save document from stream: '{}'", path); + + String normalizedPath = getNormalizedPath(path); + try { + Session session = getSessionWithTimeout(); + try { + Node contentNode = getOrCreateContentNode(normalizedPath, session); + Binary value = session.getValueFactory().createBinary(documentStream); + contentNode.setProperty("jcr:data", value); + + session.save(); + return true; + } finally { + closeSession(session); + } + } catch (RepositoryException ex) { + log.error("Failed to write document from stream to file '{}'", path, ex); + } + return false; } + @Override - public String readDocument(String path, Charset charset) throws IOException { - // TODO Auto-generated method stub + public String readDocument(String path, Charset charset) { + log.debug("Read document: '{}'", path); + + String normalizedPath = getNormalizedPath(path); + try { + Session session = getSessionWithTimeout(); + try { + Node fileNode = JcrUtils.getNodeIfExists(normalizedPath, session); + if (fileNode == null) { + log.error("Document file '{}' isn't exist", path); + return null; + } + + Node contentNode = fileNode.getNode(JcrConstants.JCR_CONTENT); + Property property = contentNode.getProperty("jcr:data"); + try (InputStream in = property.getBinary().getStream()) { + return IOUtils.toString(in, charset); + } + } finally { + closeSession(session); + } + } catch (IOException ex) { + } catch (RepositoryException ex) { + log.error("Failed to read document from file '{}'", path, ex); + } + return null; } @Override - public InputStream readDocumentAsStream(String path) throws IOException { - // TODO Auto-generated method stub + public InputStream readDocumentAsStream(String path) { + log.debug("Read document as stream: '{}'", path); + + String normalizedPath = getNormalizedPath(path); + try { + Session session = getSessionWithTimeout(); + try { + Node fileNode = JcrUtils.getNodeIfExists(normalizedPath, session); + if (fileNode == null) { + log.error("Document file '{}' isn't exist", path); + return null; + } + + Node contentNode = fileNode.getNode(JcrConstants.JCR_CONTENT); + Property property = contentNode.getProperty("jcr:data"); + try (InputStream in = property.getBinary().getStream()) { + // Note: We can't return real input stream because we need to make sure that we close session + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + IOUtils.copy(in, bos); + + return new ByteArrayInputStream(bos.toByteArray()); + } + } finally { + closeSession(session); + } + } catch (IOException ex) { + } catch (RepositoryException ex) { + log.error("Failed to read document as stream from file '{}'", path, ex); + } + return null; } @Override - public boolean renameDocument(String currentPath, String destinationPath) throws IOException { - // TODO Auto-generated method stub + public boolean renameDocument(String currentPath, String destinationPath) { + log.debug("Rename document: '{}' -> '{}'", currentPath, destinationPath); + + String normalizedCurrentPath = getNormalizedPath(currentPath); + String normalizedDestinationPath = getNormalizedPath(destinationPath); + + try { + Session session = getSessionWithTimeout(); + try { + removeDocument(normalizedDestinationPath, session); + + createPath(normalizedDestinationPath, session); + session.move(normalizedCurrentPath, normalizedDestinationPath); + + session.save(); + return true; + } finally { + closeSession(session); + } + } catch (RepositoryException ex) { + log.error("Failed to rename to destination file '{}'", destinationPath, ex); + } + return false; } + @Override public boolean removeDocument(String path) { - // TODO Auto-generated method stub + log.debug("Remove document: '{}'", path); + + try { + Session session = getSessionWithTimeout(); + try { + removeDocument(path, session); + + session.save(); + return true; + } finally { + closeSession(session); + } + } catch (RepositoryException ex) { + log.error("Failed to remove document file '{}'", path, ex); + } + return false; } + private void removeDocument(String path, Session session) + throws RepositoryException, VersionException, LockException, ConstraintViolationException, AccessDeniedException { + Node fileNode = JcrUtils.getNodeIfExists(getNormalizedPath(path), session); + if (fileNode != null) { + fileNode.remove(); + } + } + + private void decryptPassword(JcaDocumentStoreConfiguration jcaDocumentStoreConfiguration) { + try { + String encryptedPassword = jcaDocumentStoreConfiguration.getPassword(); + if (StringUtils.isNotBlank(encryptedPassword)) { + jcaDocumentStoreConfiguration.setDecryptedPassword(stringEncrypter.decrypt(encryptedPassword)); + log.trace("Decrypted JCA password successfully."); + } + } catch (StringEncrypter.EncryptionException ex) { + log.error("Error during JCA password decryption", ex); + } + } + + private Session getSession() throws RepositoryException { + return repository.login(credentials, workspaceName); + } + + public Session getSessionWithTimeout() throws RepositoryException { + try { + CallableSession cs = new CallableSession(repository, credentials, workspaceName); + FutureTask future = new FutureTask(cs); + ExecutorService executor = Executors.newSingleThreadExecutor(); + executor.execute(future); + return future.get(connectionTimeout * 1000, TimeUnit.MILLISECONDS); + } catch (Exception ex) { + throw new RepositoryException("Failed to get session", ex); + } + } + + private void closeSession(Session session) { + if (session != null && session.isLive()) { + session.logout(); + } + } + + private String getNormalizedPath(String path) { + return path.replaceAll("\\\\", "/"); + } + + private Node getOrCreateContentNode(String path, Session session) throws RepositoryException { + Node fileNode = JcrUtils.getNodeIfExists(getNormalizedPath(path), session); + Node contentNode = null; + if (fileNode == null) { + fileNode = JcrUtils.getOrCreateByPath(path, NodeType.NT_FOLDER, NodeType.NT_FILE, session, false); + contentNode = fileNode.addNode(JcrConstants.JCR_CONTENT, NodeType.NT_RESOURCE); + } else { + contentNode = fileNode.getNode(JcrConstants.JCR_CONTENT); + } + + return contentNode; + } + + private void createPath(String path, Session session) throws RepositoryException { + File filePath = new File(path); + String folderPath = filePath.getParentFile().getPath(); + + String normalizedFolderPath = getNormalizedPath(folderPath); + JcrUtils.getOrCreateByPath(normalizedFolderPath, NodeType.NT_FOLDER, session); + } + + class CallableSession implements Callable { + + private URLRemoteRepository repository; + private SimpleCredentials credentials; + private String workspaceName; + + public CallableSession(URLRemoteRepository repository, SimpleCredentials credentials, String workspaceName) { + this.repository = repository; + this.credentials = credentials; + this.workspaceName = workspaceName; + } + + @Override + public Session call() throws Exception { + return repository.login(credentials, workspaceName); + } + } + } diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java index a3a65021..13ff776c 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java @@ -88,11 +88,13 @@ public boolean hasDocument(String path) { } @Override - public boolean saveDocument(String path, String documentContent, Charset charset) throws IOException { + public boolean saveDocument(String path, String documentContent, Charset charset) { log.debug("Save document: '{}'", path); File file = buildFilePath(path); - createParentPath(file); + if (!createParentPath(file)) { + return false; + } try (FileOutputStream os = FileUtils.openOutputStream(file)) { IOUtils.write(documentContent, os, charset); @@ -107,11 +109,13 @@ public boolean saveDocument(String path, String documentContent, Charset charset } @Override - public boolean saveDocumentStream(String path, InputStream documentStream) throws IOException { + public boolean saveDocumentStream(String path, InputStream documentStream) { log.debug("Save document from stream: '{}'", path); File file = buildFilePath(path); - createParentPath(file); + if (!createParentPath(file)) { + return false; + } try (FileOutputStream os = FileUtils.openOutputStream(file)) { IOUtils.copy(documentStream, os); @@ -119,33 +123,47 @@ public boolean saveDocumentStream(String path, InputStream documentStream) throw return true; } catch (IOException ex) { - log.error("Failed to write document stream to file '{}'", file.getAbsolutePath(), ex); + log.error("Failed to write document from stream to file '{}'", file.getAbsolutePath(), ex); } return false; } @Override - public String readDocument(String path, Charset charset) throws IOException { + public String readDocument(String path, Charset charset) { log.debug("Read document: '{}'", path); File file = buildFilePath(path); - createParentPath(file); + if (!createParentPath(file)) { + return null; + } - return FileUtils.readFileToString(file, charset); + try { + return FileUtils.readFileToString(file, charset); + } catch (IOException ex) { + log.error("Failed to read document from file '{}'", file.getAbsolutePath(), ex); + } + + return null; } @Override - public InputStream readDocumentAsStream(String path) throws IOException { + public InputStream readDocumentAsStream(String path) { log.debug("Read document as stream: '{}'", path); File file = buildFilePath(path); - return new BufferedInputStream(FileUtils.openInputStream(file)); + try { + return new BufferedInputStream(FileUtils.openInputStream(file)); + } catch (IOException ex) { + log.error("Failed to read document as stream from file '{}'", file.getAbsolutePath(), ex); + } + + return null; } @Override - public boolean renameDocument(String currentPath, String destinationPath) throws IOException { + public boolean renameDocument(String currentPath, String destinationPath) { log.debug("Rename document: '{}' -> '{}'", currentPath, destinationPath); File currentFile = buildFilePath(currentPath); @@ -155,20 +173,18 @@ public boolean renameDocument(String currentPath, String destinationPath) throws log.error("Failed to remove destination file '{}'", destinationFile.getAbsolutePath()); } - createParentPath(destinationFile); - try { currentFile.renameTo(destinationFile); + return true; } catch (Exception ex) { log.error("Failed to rename to destination file '{}'", destinationFile.getAbsolutePath(), ex); - throw new IOException("Failed to rename to destination file " + destinationFile.getAbsolutePath(), ex); } - - return true; + + return false; } @Override - public boolean removeDocument(String path) throws IOException { + public boolean removeDocument(String path) { log.debug("Remove document: '{}'", path); if (!hasDocument(path)) { @@ -176,18 +192,22 @@ public boolean removeDocument(String path) throws IOException { } File file = buildFilePath(path); - createParentPath(file); + if (!createParentPath(file)) { + return false; + } return FileUtils.deleteQuietly(file); } - private void createParentPath(File file) throws IOException { + private boolean createParentPath(File file) { try { FileUtils.forceMkdirParent(file); + return true; } catch (IOException ex) { log.error("Failed to create path to file '{}'", file.getAbsolutePath(), ex); - throw ex; } + + return false; } private File buildFilePath(String path) { diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java index c3896a23..397b44da 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java @@ -71,25 +71,25 @@ public boolean saveDocument(String path, String documentContent, Charset charset } @Override - public boolean saveDocumentStream(String path, InputStream documentStream) throws IOException { + public boolean saveDocumentStream(String path, InputStream documentStream) { // TODO Auto-generated method stub return false; } @Override - public String readDocument(String path, Charset charset) throws IOException { + public String readDocument(String path, Charset charset) { // TODO Auto-generated method stub return null; } @Override - public InputStream readDocumentAsStream(String path) throws IOException { + public InputStream readDocumentAsStream(String path) { // TODO Auto-generated method stub return null; } @Override - public boolean renameDocument(String currentPath, String destinationPath) throws IOException { + public boolean renameDocument(String currentPath, String destinationPath) { // TODO Auto-generated method stub return false; } diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/service/BaseDocumentStoreService.java b/core-document-store/src/main/java/org/gluu/service/document/store/service/BaseDocumentStoreService.java index 5275e328..3a36ee5d 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/service/BaseDocumentStoreService.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/service/BaseDocumentStoreService.java @@ -32,42 +32,42 @@ public boolean hasDocument(String path) { } @Override - public boolean saveDocument(String path, String documentContent, Charset charset) throws IOException { + public boolean saveDocument(String path, String documentContent, Charset charset) { DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); return documentStoreProvider.saveDocument(path, documentContent, charset); } @Override - public boolean saveDocumentStream(String path, InputStream documentStream) throws IOException { + public boolean saveDocumentStream(String path, InputStream documentStream) { DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); return documentStoreProvider.saveDocumentStream(path, documentStream); } @Override - public String readDocument(String path, Charset charset) throws IOException { + public String readDocument(String path, Charset charset) { DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); return documentStoreProvider.readDocument(path, charset); } @Override - public InputStream readDocumentAsStream(String path) throws IOException { + public InputStream readDocumentAsStream(String path) { DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); return documentStoreProvider.readDocumentAsStream(path); } @Override - public boolean renameDocument(String currentPath, String destinationPath) throws IOException { + public boolean renameDocument(String currentPath, String destinationPath) { DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); return documentStoreProvider.renameDocument(currentPath, destinationPath); } @Override - public boolean removeDocument(String path) throws IOException { + public boolean removeDocument(String path) { DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); return documentStoreProvider.removeDocument(path); diff --git a/core-document-store/src/test/java/org/gluu/service/document/store/manual/JcaDocumentStoreManualTest.java b/core-document-store/src/test/java/org/gluu/service/document/store/manual/JcaDocumentStoreManualTest.java new file mode 100644 index 00000000..6758d81d --- /dev/null +++ b/core-document-store/src/test/java/org/gluu/service/document/store/manual/JcaDocumentStoreManualTest.java @@ -0,0 +1,96 @@ +package org.gluu.service.document.store.manual; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import javax.jcr.RepositoryException; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.gluu.service.document.store.StandaloneDocumentStoreProviderFactory; +import org.gluu.service.document.store.conf.DocumentStoreConfiguration; +import org.gluu.service.document.store.conf.DocumentStoreType; +import org.gluu.service.document.store.conf.JcaDocumentStoreConfiguration; +import org.gluu.service.document.store.conf.LocalDocumentStoreConfiguration; +import org.gluu.service.document.store.provider.DocumentStoreProvider; +import org.gluu.util.security.StringEncrypter; +import org.gluu.util.security.StringEncrypter.EncryptionException; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class JcaDocumentStoreManualTest { + + public JcaDocumentStoreManualTest() { + + } + + public static void main(String[] args) throws RepositoryException, IOException, EncryptionException { + StringEncrypter se = new StringEncrypter(StringEncrypter.DESEDE_ENCRYPTION_SCHEME, "Zqvw62DEFdhxoL4csi9hpVI4"); + DocumentStoreConfiguration dsc = new DocumentStoreConfiguration(); + dsc.setDocumentStoreType(DocumentStoreType.JCA); + + JcaDocumentStoreConfiguration jca = new JcaDocumentStoreConfiguration(); + jca.setServerUrl("http://localhost:8080/rmi"); + jca.setWorkspaceName("default"); + jca.setUserId("admin"); + jca.setPassword(se.encrypt("admin")); + jca.setConnectionTimeout(15); + + dsc.setJcaConfiguration(jca); + + LocalDocumentStoreConfiguration lca = new LocalDocumentStoreConfiguration(); + + dsc.setLocalConfiguration(lca); + + ObjectMapper om = new ObjectMapper(); + System.out.println(om.writeValueAsString(dsc)); + + StandaloneDocumentStoreProviderFactory pf = new StandaloneDocumentStoreProviderFactory(se); + DocumentStoreProvider dsp = pf.getDocumentStoreProvider(dsc); + + String doc1 = FileUtils.readFileToString(new File("V:/authorization_code.jmx"), "UTF-8"); + byte[] doc2 = FileUtils.readFileToByteArray(new File("V:/scim_requests.zip")); + + System.out.print("Has document: " + "/test2/test2/test.jmx: "); + System.out.println(dsp.hasDocument("/test2/test2/test.jmx")); + + System.out.print("Has document: " + "/test2/test3/test3.jmx: "); + System.out.println(dsp.hasDocument("/test2/test3/test3.jmx")); + + System.out.print("Write document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.saveDocumentStream("/test2/test3/test4/test5.jmx", new ByteArrayInputStream(doc2))); + + System.out.print("Has document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.hasDocument("/test2/test3/test4/test5.jmx")); + + System.out.print("Write document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.saveDocument("/test2/test3/test4/test5.jmx", doc1, StandardCharsets.UTF_8)); + + System.out.print("Has document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.hasDocument("/test2/test3/test4/test5.jmx")); + + System.out.print("Read document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.readDocument("/test2/test3/test4/test5.jmx", StandardCharsets.UTF_8)); + + System.out.print("Read document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(IOUtils.toString(dsp.readDocumentAsStream("/test2/test3/test4/test5.jmx"), StandardCharsets.UTF_8)); + + System.out.print("Rename document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.renameDocument("/test2/test3/test4/test5.jmx", "/test2/test4/test5.jmx")); + + System.out.print("Has document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.hasDocument("/test2/test3/test4/test5.jmx")); + + System.out.print("Has document: " + "/test2/test4/test5.jmx: "); + System.out.println(dsp.hasDocument("/test2/test4/test5.jmx")); + + System.out.print("Remove document: " + "test2/test4/test5.jmx: "); + System.out.println(dsp.removeDocument("/test2/test4/test5.jmx")); + + System.out.print("Has document: " + "/test2/test4/test5.jmx: "); + System.out.println(dsp.hasDocument("/test2/test4/test5.jmx")); + } + +} From d8c789edd2b36e5a9a88f74a31d376002c1b8266 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 16 Apr 2020 16:23:02 +0300 Subject: [PATCH 128/362] Fix compilation issue --- .../main/java/org/gluu/saml/metadata/SAMLMetadataParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java index 17a9c283..defa8f2a 100644 --- a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java +++ b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java @@ -83,7 +83,7 @@ public EntityIDHandler parseMetadata(String metadataFile) { is = documentStoreService.readDocumentAsStream(metadataFile); return parseMetadata(is); - } catch (IOException ex) { + } catch (Exception ex) { log.error("Failed to read SAML metadata file: " + metadataFile, ex); return null; } finally { From 27cbcd9adc242bee7aa3b353d2c312a24efd321f Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 16 Apr 2020 17:14:37 +0300 Subject: [PATCH 129/362] Fix document store type --- .../document/store/conf/DocumentStoreConfiguration.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java index 31e48aea..c7f19636 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java @@ -15,9 +15,9 @@ public class DocumentStoreConfiguration implements Serializable { private static final long serialVersionUID = 2519892725606554887L; - private DocumentStoreType documentStoreType = DocumentStoreType.LOCAL; + private DocumentStoreType documentStoreType; - private LocalDocumentStoreConfiguration localConfiguration = new LocalDocumentStoreConfiguration(); + private LocalDocumentStoreConfiguration localConfiguration; private JcaDocumentStoreConfiguration jcaConfiguration; From 22d1f2707b84cab7e8a58ee42bbbdb2d8a34ad5e Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 17 Apr 2020 11:58:27 +0300 Subject: [PATCH 130/362] Store IDP/SP files in configurable document store oxTrust #1939 --- .../provider/JcaDocumentStoreProvider.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java index 341a3f07..15f29a75 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java @@ -101,9 +101,15 @@ public void configure(DocumentStoreConfiguration documentStoreConfiguration, Str public void destroy() { log.debug("Destroying JcaDocumentStoreProvider"); + this.repository = null; + log.debug("Destroyed JcaDocumentStoreProvider"); } + public void setJcaDocumentStoreConfiguration(JcaDocumentStoreConfiguration jcaDocumentStoreConfiguration) { + this.jcaDocumentStoreConfiguration = jcaDocumentStoreConfiguration; + } + public DocumentStoreType getProviderType() { return DocumentStoreType.JCA; } @@ -378,4 +384,23 @@ public Session call() throws Exception { } } + public boolean isConnected() { + log.debug("Check if server available"); + + Node fileNode = null; + Session session; + try { + session = getSessionWithTimeout(); + try { + fileNode = JcrUtils.getNodeIfExists(getNormalizedPath("/"), session); + } finally { + closeSession(session); + } + } catch (RepositoryException ex) { + log.error("Failed to check if server available", ex); + } + + return fileNode != null; + } + } From 4a9b6f78b9e3375885ec33999e0e359730b460c1 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 17 Apr 2020 13:39:04 +0300 Subject: [PATCH 131/362] Fix modules order --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1181060a..624f44d4 100644 --- a/pom.xml +++ b/pom.xml @@ -39,10 +39,10 @@ persistence-ldap-sample persistence-couchbase-sample oxModel - oxSaml core-cache core-document-store core-standalone + oxSaml core-java-ext core-cdi core-timer-weld From 000996b0aea972dc4f8ea83a13476a72dc7b86c5 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 17 Apr 2020 13:42:14 +0300 Subject: [PATCH 132/362] Fix modules order --- core-document-store/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index da4a076a..a6dc4b5c 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.1.1.Final + 4.2.0-SNAPSHOT From 3b224160a2f39dcf0b1eeaaab86001597c17cac5 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Fri, 17 Apr 2020 15:27:36 +0100 Subject: [PATCH 133/362] Change added to support Quarkus integration --- .../org/gluu/persist/service/PersistanceFactoryService.java | 2 +- .../org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java | 2 +- .../gluu/persist/couchbase/impl/CouchbaseFilterConverter.java | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/persistence-cdi/src/main/java/org/gluu/persist/service/PersistanceFactoryService.java b/persistence-cdi/src/main/java/org/gluu/persist/service/PersistanceFactoryService.java index 9aa51f2e..80f72ef6 100644 --- a/persistence-cdi/src/main/java/org/gluu/persist/service/PersistanceFactoryService.java +++ b/persistence-cdi/src/main/java/org/gluu/persist/service/PersistanceFactoryService.java @@ -6,6 +6,7 @@ import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Instance; +import javax.enterprise.inject.Produces; import javax.inject.Inject; import org.apache.commons.configuration.PropertiesConfiguration; @@ -229,5 +230,4 @@ public Logger getLog() { return this.log; } - } diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java index 3764a855..90813153 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java @@ -84,7 +84,7 @@ public class CouchbaseEntryManager extends BaseEntryManager implements Serializa protected CouchbaseEntryManager(CouchbaseOperationsServiceImpl operationService) { this.operationService = operationService; - this.FILTER_CONVERTER = new CouchbaseFilterConverter(this); + this.FILTER_CONVERTER = new CouchbaseFilterConverter(); subscribers = new LinkedList(); } diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java index e9dfab2e..ac1c1189 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java @@ -50,6 +50,9 @@ public CouchbaseFilterConverter(CouchbaseEntryManager couchbaseEntryManager) { this.couchbaseEntryManager = couchbaseEntryManager; } + public CouchbaseFilterConverter() { + } + public ConvertedExpression convertToCouchbaseFilter(Filter genericFilter, Map propertiesAnnotationsMap) throws SearchException { return convertToCouchbaseFilter(genericFilter, propertiesAnnotationsMap, null); } From bce9ee9fb8df53329aacc8f300e7072edf65d30f Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 17 Apr 2020 18:56:19 +0300 Subject: [PATCH 134/362] Fix server URL --- .../document/store/provider/JcaDocumentStoreProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java index 15f29a75..7ae7b4c9 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java @@ -77,7 +77,7 @@ public void create() { try { log.debug("Starting JcaDocumentStoreProvider ..."); decryptPassword(jcaDocumentStoreConfiguration); - this.repository = new URLRemoteRepository("http://localhost:8080/rmi"); + this.repository = new URLRemoteRepository(jcaDocumentStoreConfiguration.getServerUrl()); String password = StringUtils.isBlank(jcaDocumentStoreConfiguration.getDecryptedPassword()) ? "" : jcaDocumentStoreConfiguration.getDecryptedPassword(); From 6b755a1b18d1127bb6a57767f33eead6b1d7fd13 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Tue, 21 Apr 2020 20:09:05 +0100 Subject: [PATCH 135/362] Reload file based scrypt after script update --- .../org/gluu/service/custom/script/CustomScriptManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java index bd793eef..f261369b 100644 --- a/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java +++ b/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java @@ -216,8 +216,9 @@ private ReloadResult reloadCustomScriptConfigurations( CustomScriptConfiguration prevCustomScriptConfiguration = newCustomScriptConfigurations .get(newSupportedCustomScriptInum); - if ((prevCustomScriptConfiguration == null) || (prevCustomScriptConfiguration.getCustomScript() - .getRevision() != newCustomScript.getRevision())) { + boolean hasChanged = (prevCustomScriptConfiguration == null) || (prevCustomScriptConfiguration.getCustomScript() + .getRevision() != newCustomScript.getRevision()); + if (hasChanged || ScriptLocationType.FILE == newCustomScript.getLocationType()) { // Destroy old version properly before creating new one if (prevCustomScriptConfiguration != null) { destroyCustomScript(prevCustomScriptConfiguration); From 8265b7ef13963bf254a232bb03261307c52cc259 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 22 Apr 2020 12:04:08 +0300 Subject: [PATCH 136/362] Add missing scopes to beans --- .../org/gluu/service/custom/script/ExternalScriptService.java | 2 ++ .../org/gluu/service/exception/ExceptionHandlerExtension.java | 3 +++ 2 files changed, 5 insertions(+) diff --git a/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java b/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java index 203ac05c..7ccfea13 100644 --- a/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java +++ b/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.Map; +import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Observes; import javax.inject.Inject; @@ -27,6 +28,7 @@ * * @author Yuriy Movchan Date: 01/08/2015 */ +@ApplicationScoped public class ExternalScriptService implements Serializable { private static final long serialVersionUID = -1070021905117441202L; diff --git a/oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerExtension.java b/oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerExtension.java index bedf2cc7..3f6b65bf 100644 --- a/oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerExtension.java +++ b/oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerExtension.java @@ -7,6 +7,8 @@ import java.util.List; import java.util.Map; +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.context.Dependent; import javax.enterprise.event.Observes; import javax.enterprise.inject.spi.AnnotatedMethod; import javax.enterprise.inject.spi.Extension; @@ -22,6 +24,7 @@ * * @author Yuriy Movchan Date: 05/22/2017 */ +@ApplicationScoped public class ExceptionHandlerExtension implements Extension { private static final Logger log = LoggerFactory.getLogger(ExceptionHandlerExtension.class.getName()); From 6246fdaea0029fcc5f92a89f8f2f3b4c2919bdf9 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 22 Apr 2020 12:29:02 +0300 Subject: [PATCH 137/362] Remove scope from extension --- .../org/gluu/service/custom/script/ExternalScriptService.java | 3 +-- .../org/gluu/service/exception/ExceptionHandlerExtension.java | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java b/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java index 7ccfea13..57ba11c1 100644 --- a/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java +++ b/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java @@ -28,8 +28,7 @@ * * @author Yuriy Movchan Date: 01/08/2015 */ -@ApplicationScoped -public class ExternalScriptService implements Serializable { +public abstract class ExternalScriptService implements Serializable { private static final long serialVersionUID = -1070021905117441202L; diff --git a/oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerExtension.java b/oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerExtension.java index 3f6b65bf..d15e0fff 100644 --- a/oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerExtension.java +++ b/oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerExtension.java @@ -24,7 +24,6 @@ * * @author Yuriy Movchan Date: 05/22/2017 */ -@ApplicationScoped public class ExceptionHandlerExtension implements Extension { private static final Logger log = LoggerFactory.getLogger(ExceptionHandlerExtension.class.getName()); From c0f99039f7df0e5e338c9c1e44196f6591d9a9fe Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 22 Apr 2020 13:34:29 +0300 Subject: [PATCH 138/362] Move CDI extensions to separate modules --- exception-extension-cdi/pom.xml | 53 +++++++++++++++ .../service/exception/ExceptionHandler.java | 0 .../exception/ExceptionHandlerExtension.java | 0 .../exception/ExceptionHandlerMethods.java | 0 .../exception/ExceptionHandlerProducer.java | 0 .../src/main/resources/META-INF/beans.xml | 7 ++ .../javax.enterprise.inject.spi.Extension | 1 - oxJsfUtil/pom.xml | 9 ++- .../org/gluu/service/el/ConstantResolver.java | 0 .../org/gluu/service/el/ContextProducer.java | 0 .../gluu/service/el/ExpressionEvaluator.java | 0 .../service/el/ExpressionFactoryProducer.java | 0 .../gluu/service/el/ExtendedELContext.java | 0 oxService/pom.xml | 14 ++-- .../org/gluu/model/security/Identity.java | 8 +-- pom.xml | 4 +- security-extension-cdi/pom.xml | 64 +++++++++++++++++++ .../service/security/InterceptSecure.java | 0 .../org/gluu/service/security/Secure.java | 0 .../gluu/service/security/SecureVariable.java | 0 .../security/SecurityEvaluationException.java | 0 .../service/security/SecurityExtension.java | 0 .../service/security/SecurityInterceptor.java | 0 .../src/main/resources/META-INF/beans.xml | 7 ++ .../javax.enterprise.inject.spi.Extension | 1 + 25 files changed, 152 insertions(+), 16 deletions(-) create mode 100644 exception-extension-cdi/pom.xml rename {oxService => exception-extension-cdi}/src/main/java/org/gluu/service/exception/ExceptionHandler.java (100%) rename {oxService => exception-extension-cdi}/src/main/java/org/gluu/service/exception/ExceptionHandlerExtension.java (100%) rename {oxService => exception-extension-cdi}/src/main/java/org/gluu/service/exception/ExceptionHandlerMethods.java (100%) rename {oxService => exception-extension-cdi}/src/main/java/org/gluu/service/exception/ExceptionHandlerProducer.java (100%) create mode 100644 exception-extension-cdi/src/main/resources/META-INF/beans.xml rename {oxService => exception-extension-cdi}/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension (54%) rename {oxService => oxJsfUtil}/src/main/java/org/gluu/service/el/ConstantResolver.java (100%) rename {oxService => oxJsfUtil}/src/main/java/org/gluu/service/el/ContextProducer.java (100%) rename {oxService => oxJsfUtil}/src/main/java/org/gluu/service/el/ExpressionEvaluator.java (100%) rename {oxService => oxJsfUtil}/src/main/java/org/gluu/service/el/ExpressionFactoryProducer.java (100%) rename {oxService => oxJsfUtil}/src/main/java/org/gluu/service/el/ExtendedELContext.java (100%) create mode 100644 security-extension-cdi/pom.xml rename {oxService => security-extension-cdi}/src/main/java/org/gluu/service/security/InterceptSecure.java (100%) rename {oxService => security-extension-cdi}/src/main/java/org/gluu/service/security/Secure.java (100%) rename {oxService => security-extension-cdi}/src/main/java/org/gluu/service/security/SecureVariable.java (100%) rename {oxService => security-extension-cdi}/src/main/java/org/gluu/service/security/SecurityEvaluationException.java (100%) rename {oxService => security-extension-cdi}/src/main/java/org/gluu/service/security/SecurityExtension.java (100%) rename {oxService => security-extension-cdi}/src/main/java/org/gluu/service/security/SecurityInterceptor.java (100%) create mode 100644 security-extension-cdi/src/main/resources/META-INF/beans.xml create mode 100644 security-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension diff --git a/exception-extension-cdi/pom.xml b/exception-extension-cdi/pom.xml new file mode 100644 index 00000000..2eb3cdc3 --- /dev/null +++ b/exception-extension-cdi/pom.xml @@ -0,0 +1,53 @@ + + + 4.0.0 + exception-extension-cdi + Reusable CDI exception handler extension + + + org.gluu + oxcore + 4.2.0-SNAPSHOT + + + + ${maven.min-version} + + + + + + src/main/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + + + + org.slf4j + slf4j-api + provided + + + + + javax.enterprise + cdi-api + provided + + + org.jboss.weld + weld-core-impl + provided + + + + \ No newline at end of file diff --git a/oxService/src/main/java/org/gluu/service/exception/ExceptionHandler.java b/exception-extension-cdi/src/main/java/org/gluu/service/exception/ExceptionHandler.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/exception/ExceptionHandler.java rename to exception-extension-cdi/src/main/java/org/gluu/service/exception/ExceptionHandler.java diff --git a/oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerExtension.java b/exception-extension-cdi/src/main/java/org/gluu/service/exception/ExceptionHandlerExtension.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerExtension.java rename to exception-extension-cdi/src/main/java/org/gluu/service/exception/ExceptionHandlerExtension.java diff --git a/oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerMethods.java b/exception-extension-cdi/src/main/java/org/gluu/service/exception/ExceptionHandlerMethods.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerMethods.java rename to exception-extension-cdi/src/main/java/org/gluu/service/exception/ExceptionHandlerMethods.java diff --git a/oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerProducer.java b/exception-extension-cdi/src/main/java/org/gluu/service/exception/ExceptionHandlerProducer.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/exception/ExceptionHandlerProducer.java rename to exception-extension-cdi/src/main/java/org/gluu/service/exception/ExceptionHandlerProducer.java diff --git a/exception-extension-cdi/src/main/resources/META-INF/beans.xml b/exception-extension-cdi/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000..2f4f7e27 --- /dev/null +++ b/exception-extension-cdi/src/main/resources/META-INF/beans.xml @@ -0,0 +1,7 @@ + + + diff --git a/oxService/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/exception-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension similarity index 54% rename from oxService/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension rename to exception-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension index a357f26b..774c20bd 100644 --- a/oxService/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension +++ b/exception-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension @@ -1,2 +1 @@ -org.gluu.service.security.SecurityExtension org.gluu.service.exception.ExceptionHandlerExtension diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index 324a1b3e..a8833bf1 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -42,6 +42,10 @@ jsf-api provided + + org.glassfish + javax.faces + javax.servlet javax.servlet-api @@ -53,8 +57,9 @@ provided - org.glassfish - javax.faces + org.glassfish.web + el-impl + provided diff --git a/oxService/src/main/java/org/gluu/service/el/ConstantResolver.java b/oxJsfUtil/src/main/java/org/gluu/service/el/ConstantResolver.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/el/ConstantResolver.java rename to oxJsfUtil/src/main/java/org/gluu/service/el/ConstantResolver.java diff --git a/oxService/src/main/java/org/gluu/service/el/ContextProducer.java b/oxJsfUtil/src/main/java/org/gluu/service/el/ContextProducer.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/el/ContextProducer.java rename to oxJsfUtil/src/main/java/org/gluu/service/el/ContextProducer.java diff --git a/oxService/src/main/java/org/gluu/service/el/ExpressionEvaluator.java b/oxJsfUtil/src/main/java/org/gluu/service/el/ExpressionEvaluator.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/el/ExpressionEvaluator.java rename to oxJsfUtil/src/main/java/org/gluu/service/el/ExpressionEvaluator.java diff --git a/oxService/src/main/java/org/gluu/service/el/ExpressionFactoryProducer.java b/oxJsfUtil/src/main/java/org/gluu/service/el/ExpressionFactoryProducer.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/el/ExpressionFactoryProducer.java rename to oxJsfUtil/src/main/java/org/gluu/service/el/ExpressionFactoryProducer.java diff --git a/oxService/src/main/java/org/gluu/service/el/ExtendedELContext.java b/oxJsfUtil/src/main/java/org/gluu/service/el/ExtendedELContext.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/el/ExtendedELContext.java rename to oxJsfUtil/src/main/java/org/gluu/service/el/ExtendedELContext.java diff --git a/oxService/pom.xml b/oxService/pom.xml index cef0b361..ec371d07 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -69,7 +69,7 @@ oxcore-cdi - + javax.enterprise cdi-api @@ -81,11 +81,15 @@ provided - org.jboss.weld - weld-core-impl + org.jboss.spec.javax.annotation + jboss-annotations-api_1.2_spec + provided + + + org.jboss.spec.javax.interceptor + jboss-interceptors-api_1.2_spec provided - javax.inject javax.inject @@ -94,13 +98,13 @@ javax.validation validation-api - org.jboss.spec.javax.ejb jboss-ejb-api_3.2_spec provided + com.sun.faces jsf-api diff --git a/oxService/src/main/java/org/gluu/model/security/Identity.java b/oxService/src/main/java/org/gluu/model/security/Identity.java index 7ac6c153..1c1c263a 100644 --- a/oxService/src/main/java/org/gluu/model/security/Identity.java +++ b/oxService/src/main/java/org/gluu/model/security/Identity.java @@ -12,12 +12,11 @@ import javax.enterprise.inject.Alternative; import javax.inject.Inject; import javax.inject.Named; +import javax.interceptor.Interceptor; import javax.security.auth.Subject; import javax.security.auth.login.LoginException; -import javax.interceptor.Interceptor; import org.gluu.model.security.event.Authenticated; -import org.gluu.service.security.Secure; import org.slf4j.Logger; @RequestScoped @@ -229,9 +228,4 @@ public boolean hasRole(String role) { return false; } - @Secure("#{identity.loggedIn}") - public boolean checkLoggedIn() { - return isLoggedIn(); - } - } diff --git a/pom.xml b/pom.xml index 624f44d4..a650418b 100644 --- a/pom.xml +++ b/pom.xml @@ -43,12 +43,14 @@ core-document-store core-standalone oxSaml + oxJsfUtil core-java-ext core-cdi core-timer-weld + security-extension-cdi + exception-extension-cdi oxService server - oxJsfUtil oxRadius demo-cdi diff --git a/security-extension-cdi/pom.xml b/security-extension-cdi/pom.xml new file mode 100644 index 00000000..953aa85d --- /dev/null +++ b/security-extension-cdi/pom.xml @@ -0,0 +1,64 @@ + + + 4.0.0 + security-extension-cdi + Reusable CDI security extension + + + org.gluu + oxcore + 4.2.0-SNAPSHOT + + + + ${maven.min-version} + + + + + + src/main/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + + + + ${project.groupId} + oxcore-jsf-util + + + + + org.slf4j + slf4j-api + provided + + + + + javax.enterprise + cdi-api + provided + + + org.jboss.weld + weld-core-impl + provided + + + org.jboss.spec.javax.ejb + jboss-ejb-api_3.2_spec + provided + + + + \ No newline at end of file diff --git a/oxService/src/main/java/org/gluu/service/security/InterceptSecure.java b/security-extension-cdi/src/main/java/org/gluu/service/security/InterceptSecure.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/security/InterceptSecure.java rename to security-extension-cdi/src/main/java/org/gluu/service/security/InterceptSecure.java diff --git a/oxService/src/main/java/org/gluu/service/security/Secure.java b/security-extension-cdi/src/main/java/org/gluu/service/security/Secure.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/security/Secure.java rename to security-extension-cdi/src/main/java/org/gluu/service/security/Secure.java diff --git a/oxService/src/main/java/org/gluu/service/security/SecureVariable.java b/security-extension-cdi/src/main/java/org/gluu/service/security/SecureVariable.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/security/SecureVariable.java rename to security-extension-cdi/src/main/java/org/gluu/service/security/SecureVariable.java diff --git a/oxService/src/main/java/org/gluu/service/security/SecurityEvaluationException.java b/security-extension-cdi/src/main/java/org/gluu/service/security/SecurityEvaluationException.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/security/SecurityEvaluationException.java rename to security-extension-cdi/src/main/java/org/gluu/service/security/SecurityEvaluationException.java diff --git a/oxService/src/main/java/org/gluu/service/security/SecurityExtension.java b/security-extension-cdi/src/main/java/org/gluu/service/security/SecurityExtension.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/security/SecurityExtension.java rename to security-extension-cdi/src/main/java/org/gluu/service/security/SecurityExtension.java diff --git a/oxService/src/main/java/org/gluu/service/security/SecurityInterceptor.java b/security-extension-cdi/src/main/java/org/gluu/service/security/SecurityInterceptor.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/security/SecurityInterceptor.java rename to security-extension-cdi/src/main/java/org/gluu/service/security/SecurityInterceptor.java diff --git a/security-extension-cdi/src/main/resources/META-INF/beans.xml b/security-extension-cdi/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000..2f4f7e27 --- /dev/null +++ b/security-extension-cdi/src/main/resources/META-INF/beans.xml @@ -0,0 +1,7 @@ + + + diff --git a/security-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/security-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension new file mode 100644 index 00000000..4efa1a8c --- /dev/null +++ b/security-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension @@ -0,0 +1 @@ +org.gluu.service.security.SecurityExtension From b33821eae2aa854bbe2e04c26b2e4129620b4fea Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 22 Apr 2020 14:45:06 +0300 Subject: [PATCH 139/362] Move UMA secure to security CDI extension --- security-extension-cdi/pom.xml | 12 ++ .../auth/uma/annotations/UmaSecure.java | 32 ++++++ .../uma/annotations/UmaSecureInterceptor.java | 108 ++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecure.java create mode 100644 security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecureInterceptor.java diff --git a/security-extension-cdi/pom.xml b/security-extension-cdi/pom.xml index 953aa85d..3759dc36 100644 --- a/security-extension-cdi/pom.xml +++ b/security-extension-cdi/pom.xml @@ -59,6 +59,18 @@ jboss-ejb-api_3.2_spec provided + + + + javax.servlet + javax.servlet-api + provided + + + javax.ws.rs + javax.ws.rs-api + + \ No newline at end of file diff --git a/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecure.java b/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecure.java new file mode 100644 index 00000000..b9226e8d --- /dev/null +++ b/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecure.java @@ -0,0 +1,32 @@ +/* + * oxTrust is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2018, Gluu + */ +package org.gluu.oxtrust.auth.uma.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.interceptor.InterceptorBinding; + +/** + * Marks a class as a UMA scope resource. + * + * Provides service to protect Rest service endpoints with UMA scope. + * + * @author Dmitry Ognyannikov + */ +@Inherited +@InterceptorBinding +@Target(value = {ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface UmaSecure { + /** + * UMA scopes as single string + */ + String scope() default ""; +} diff --git a/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecureInterceptor.java b/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecureInterceptor.java new file mode 100644 index 00000000..271e0ba2 --- /dev/null +++ b/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecureInterceptor.java @@ -0,0 +1,108 @@ +/* + * oxTrust is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2018, Gluu + */ +package org.gluu.oxtrust.auth.uma.annotations; + +import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.Map; + +import javax.annotation.Priority; +import javax.inject.Inject; +import javax.interceptor.AroundInvoke; +import javax.interceptor.Interceptor; +import javax.interceptor.InvocationContext; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.core.Response; + +import org.gluu.service.el.ExpressionEvaluator; +import org.gluu.service.security.InterceptSecure; +import org.gluu.service.security.Secure; +import org.gluu.service.security.SecureVariable; +import org.gluu.service.security.SecurityEvaluationException; +import org.gluu.service.security.SecurityExtension; +import org.slf4j.Logger; + +/** + * Provides service to protect Rest service endpoints with UMA scope. + * + * @author Dmitry Ognyannikov + */ +@Interceptor +@UmaSecure +@Priority(Interceptor.Priority.PLATFORM_AFTER) +public class UmaSecureInterceptor { + + @Inject + private Logger log; + + @Inject + private SecurityExtension securityExtension; + + @Inject + private ExpressionEvaluator expressionEvaluator; + + @AroundInvoke + public Object invoke(InvocationContext ctx) throws Exception { + HttpServletResponse response = null; + Object[] parameters = ctx.getParameters(); + + log.trace("REST method call security check. " + ctx.getMethod().getName() + "()"); + + for (Object parameter : parameters) { + if (parameter instanceof HttpServletResponse) + response = (HttpServletResponse)parameter; + } + + InterceptSecure is = securityExtension.getInterceptSecure(ctx.getMethod()); + + // SecurityChecking restrictions + Secure[] constraints = (is == null) ? new Secure[0] : is.value(); + + // Getting the parameter values + Map secureVars = computeParameterValues(ctx); + + for (Secure constraint : constraints) { + Boolean expressionValue = expressionEvaluator.evaluateValueExpression(constraint.value(), Boolean.class, secureVars); + + if ((expressionValue == null) || !expressionValue) { + log.debug("Method: '{}' constrain '{}' evaluation is null or false!", ctx.getMethod(), constraint); + throw new SecurityEvaluationException(); + } + } + + try { + // the method call + return ctx.proceed(); + } catch (Exception e) { + log.error("Error calling ctx.proceed in UmaSecureInterceptor"); + // REST call error report + if (response != null) { + try { response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "INTERNAL SERVER ERROR"); } catch (Exception ex) {} + } else if (Response.class.isAssignableFrom(ctx.getMethod().getReturnType())) { + return Response.serverError().entity("INTERNAL SERVER ERROR").build(); + } + + return null; + } + } + + private Map computeParameterValues(InvocationContext ctx) { + Annotation[][] parametersAnnotations = ctx.getMethod().getParameterAnnotations(); + Map secureVariables = new HashMap(); + for (int i = 0; i < parametersAnnotations.length; i++) { + Annotation[] parameterAnnotations = parametersAnnotations[i]; + for (Annotation parameterAnnotation : parameterAnnotations) { + if (SecureVariable.class.isAssignableFrom(parameterAnnotation.annotationType())) { + SecureVariable secureVariable = (SecureVariable) parameterAnnotation; + Object paramValue = ctx.getParameters()[i]; + secureVariables.put(secureVariable.value(), paramValue); + } + } + } + + return secureVariables; + } +} From 9595ed4cabaa03b7b7bcf94d3e43fa9af94baa35 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 22 Apr 2020 14:57:07 +0300 Subject: [PATCH 140/362] Mark UmaSecure as deprecated --- .../java/org/gluu/oxtrust/auth/uma/annotations/UmaSecure.java | 1 + .../gluu/oxtrust/auth/uma/annotations/UmaSecureInterceptor.java | 1 + 2 files changed, 2 insertions(+) diff --git a/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecure.java b/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecure.java index b9226e8d..3501e658 100644 --- a/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecure.java +++ b/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecure.java @@ -24,6 +24,7 @@ @InterceptorBinding @Target(value = {ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) +@Deprecated public @interface UmaSecure { /** * UMA scopes as single string diff --git a/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecureInterceptor.java b/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecureInterceptor.java index 271e0ba2..29743529 100644 --- a/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecureInterceptor.java +++ b/security-extension-cdi/src/main/java/org/gluu/oxtrust/auth/uma/annotations/UmaSecureInterceptor.java @@ -33,6 +33,7 @@ @Interceptor @UmaSecure @Priority(Interceptor.Priority.PLATFORM_AFTER) +@Deprecated public class UmaSecureInterceptor { @Inject From 91775d00803f596111e65247672b4d0fc516b307 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 22 Apr 2020 15:33:03 +0300 Subject: [PATCH 141/362] Remove ApplciationScoped from CB Filter converter --- .../gluu/persist/couchbase/impl/CouchbaseEntryManager.java | 2 +- .../persist/couchbase/impl/CouchbaseFilterConverter.java | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java index 90813153..3764a855 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java @@ -84,7 +84,7 @@ public class CouchbaseEntryManager extends BaseEntryManager implements Serializa protected CouchbaseEntryManager(CouchbaseOperationsServiceImpl operationService) { this.operationService = operationService; - this.FILTER_CONVERTER = new CouchbaseFilterConverter(); + this.FILTER_CONVERTER = new CouchbaseFilterConverter(this); subscribers = new LinkedList(); } diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java index ac1c1189..45bd36dc 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java @@ -12,8 +12,6 @@ import java.util.Map; import java.util.function.Function; -import javax.enterprise.context.ApplicationScoped; - import org.gluu.persist.annotation.AttributeEnum; import org.gluu.persist.annotation.AttributeName; import org.gluu.persist.couchbase.model.ConvertedExpression; @@ -37,7 +35,6 @@ * * @author Yuriy Movchan Date: 05/15/2018 */ -@ApplicationScoped public class CouchbaseFilterConverter { private static final Logger LOG = LoggerFactory.getLogger(CouchbaseFilterConverter.class); @@ -50,9 +47,6 @@ public CouchbaseFilterConverter(CouchbaseEntryManager couchbaseEntryManager) { this.couchbaseEntryManager = couchbaseEntryManager; } - public CouchbaseFilterConverter() { - } - public ConvertedExpression convertToCouchbaseFilter(Filter genericFilter, Map propertiesAnnotationsMap) throws SearchException { return convertToCouchbaseFilter(genericFilter, propertiesAnnotationsMap, null); } From fb859afc27db0a5272f79be68b5959a9dc25f06a Mon Sep 17 00:00:00 2001 From: Milton BO Date: Thu, 23 Apr 2020 16:42:36 -0400 Subject: [PATCH 142/362] New interception script for Ciba implementation to send notification to the end user. oxAuth #1315 --- .../model/custom/script/CustomScriptType.java | 6 ++- .../ciba/DummyEndUserNotificationType.java | 44 +++++++++++++++++++ .../type/ciba/EndUserNotificationType.java | 20 +++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 oxService/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java create mode 100644 oxService/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java b/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java index ccda17d4..2cb48a66 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java @@ -13,6 +13,8 @@ import org.gluu.model.custom.script.type.auth.PersonAuthenticationType; import org.gluu.model.custom.script.type.authz.ConsentGatheringType; import org.gluu.model.custom.script.type.authz.DummyConsentGatheringType; +import org.gluu.model.custom.script.type.ciba.DummyEndUserNotificationType; +import org.gluu.model.custom.script.type.ciba.EndUserNotificationType; import org.gluu.model.custom.script.type.client.ClientRegistrationType; import org.gluu.model.custom.script.type.client.DummyClientRegistrationType; import org.gluu.model.custom.script.type.id.DummyIdGeneratorType; @@ -73,7 +75,9 @@ public enum CustomScriptType implements AttributeEnum { new DummyDynamicScopeType()), SPONTANEOUS_SCOPE("spontaneous_scope", "Spontaneous Scopes", SpontaneousScopeType.class, CustomScript.class, "SpontaneousScope", new DummySpontaneousScopeType()), END_SESSION("end_session", "End Session", EndSessionType.class, CustomScript.class, "EndSession", new DummyEndSessionType()), - SCIM("scim", "SCIM", ScimType.class, CustomScript.class, "ScimEventHandler", new DummyScimType()); + SCIM("scim", "SCIM", ScimType.class, CustomScript.class, "ScimEventHandler", new DummyScimType()), + CIBA_END_USER_NOTIFICATION("ciba_end_user_notification", "CIBA End User Notification", EndUserNotificationType.class, + CustomScript.class, "EndUserNotification", new DummyEndUserNotificationType()); private String value; private String displayName; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java new file mode 100644 index 00000000..5bd3d5e9 --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java @@ -0,0 +1,44 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.model.custom.script.type.ciba; + +import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.model.CustomScript; + +import java.util.Map; + +/** + * Dummy implementation of interface EndUserNotificationType + * + * @author Milton BO Date: 04/22/2020 + */ +public class DummyEndUserNotificationType implements EndUserNotificationType { + + @Override + public boolean init(Map configurationAttributes) { + return true; + } + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } + @Override + public boolean destroy(Map configurationAttributes) { + return true; + } + + @Override + public int getApiVersion() { + return 1; + } + + @Override + public boolean notifyEndUser(Object context) { + return false; + } + +} diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java new file mode 100644 index 00000000..dc86bfde --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java @@ -0,0 +1,20 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.model.custom.script.type.ciba; + +import org.gluu.model.custom.script.type.BaseExternalType; + +/** + * Base interface for external authentication python script + * + * @author Milton BO Date: 04/22/2020 + */ +public interface EndUserNotificationType extends BaseExternalType { + + boolean notifyEndUser(Object context); + +} From d9cd02af7369c5b81718b28d024ef3fb1edf7ea9 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 27 Apr 2020 16:21:12 +0300 Subject: [PATCH 143/362] Fix dependency on gluu-core --- oxService/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxService/pom.xml b/oxService/pom.xml index ec371d07..59c2d25d 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -112,7 +112,7 @@ com.sun.faces - jsf-impl + jsf-api provided From 4291ca8cf1a7a3fd1e31d66f50cde62b898f1f47 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 27 Apr 2020 19:22:38 +0300 Subject: [PATCH 144/362] Move Application Initalized event to core --- .../service/cdi/event/ApplicationInitializedEvent.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 oxService/src/main/java/org/gluu/service/cdi/event/ApplicationInitializedEvent.java diff --git a/oxService/src/main/java/org/gluu/service/cdi/event/ApplicationInitializedEvent.java b/oxService/src/main/java/org/gluu/service/cdi/event/ApplicationInitializedEvent.java new file mode 100644 index 00000000..18bc2b0e --- /dev/null +++ b/oxService/src/main/java/org/gluu/service/cdi/event/ApplicationInitializedEvent.java @@ -0,0 +1,8 @@ +package org.gluu.service.cdi.event; + +/** + * @author Yuriy Movchan Date: 11/27/2018 + */ +public class ApplicationInitializedEvent { + +} From 88aeb470320ef82db05aaa0cbbc1dd4923302254 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Mon, 27 Apr 2020 22:09:18 +0300 Subject: [PATCH 145/362] Use `exp` instead of `oxAuthExpiration` all over the code https://github.com/GluuFederation/oxAuth/issues/1300 --- .../gluu/model/metric/ldap/MetricEntry.java | 2 +- .../couchbase/CouchbaseSampleBatchJob.java | 26 ++++++++--------- .../gluu/couchbase/CouchbaseSampleDelete.java | 6 ++-- .../org/gluu/ldap/LdapSampleBatchJob.java | 29 +++++++++---------- .../java/org/gluu/ldap/LdapSampleDelete.java | 15 ++-------- .../persist/model/base/DeletableEntity.java | 16 ++-------- 6 files changed, 37 insertions(+), 57 deletions(-) diff --git a/oxModel/src/main/java/org/gluu/model/metric/ldap/MetricEntry.java b/oxModel/src/main/java/org/gluu/model/metric/ldap/MetricEntry.java index 822f1826..c0a140b7 100644 --- a/oxModel/src/main/java/org/gluu/model/metric/ldap/MetricEntry.java +++ b/oxModel/src/main/java/org/gluu/model/metric/ldap/MetricEntry.java @@ -44,7 +44,7 @@ public class MetricEntry { @AttributeName(name = "creationDate") private Date creationDate; - @AttributeName(name = "oxAuthExpiration") + @AttributeName(name = "exp") private Date expirationDate; @AttributeName(name = "del") private boolean deletable = true; diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleBatchJob.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleBatchJob.java index 607592e8..3d6a9c54 100644 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleBatchJob.java +++ b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleBatchJob.java @@ -1,10 +1,5 @@ package org.gluu.couchbase; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; - import org.apache.log4j.Logger; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.status.StatusLogger; @@ -21,6 +16,11 @@ import org.gluu.persist.model.base.CustomAttribute; import org.gluu.search.filter.Filter; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; + /** * Created by eugeniuparvan on 1/12/17. */ @@ -49,8 +49,8 @@ public static void main(String[] args) { public void performAction(List objects) { for (SimpleTokenCouchbase simpleTokenCouchbase : objects) { try { - CustomAttribute customAttribute = getUpdatedAttribute(couchbaseEntryManager, simpleTokenCouchbase.getDn(), "oxAuthExpiration", - simpleTokenCouchbase.getAttribute("oxAuthExpiration")); + CustomAttribute customAttribute = getUpdatedAttribute(couchbaseEntryManager, simpleTokenCouchbase.getDn(), "exp", + simpleTokenCouchbase.getAttribute("exp")); simpleTokenCouchbase.setCustomAttributes(Arrays.asList(new CustomAttribute[] {customAttribute})); couchbaseEntryManager.merge(simpleTokenCouchbase); processedCount++; @@ -63,8 +63,8 @@ public void performAction(List objects) { } }; - final Filter filter1 = Filter.createPresenceFilter("oxAuthExpiration"); - couchbaseEntryManager.findEntries("o=gluu", SimpleTokenCouchbase.class, filter1, SearchScope.SUB, new String[] {"oxAuthExpiration"}, + final Filter filter1 = Filter.createPresenceFilter("exp"); + couchbaseEntryManager.findEntries("o=gluu", SimpleTokenCouchbase.class, filter1, SearchScope.SUB, new String[] {"exp"}, tokenCouchbaseBatchOperation, 0, 0, 100); BatchOperation sessionBatchOperation = new ProcessBatchOperation() { @@ -105,9 +105,9 @@ public void performAction(List objects) { } }; - final Filter filter3 = Filter.createPresenceFilter("oxAuthExpiration"); + final Filter filter3 = Filter.createPresenceFilter("exp"); List result3 = couchbaseEntryManager.findEntries("o=gluu", SimpleClient.class, filter3, SearchScope.SUB, - new String[] {"oxAuthExpiration"}, clientBatchOperation, 0, 0, 1000); + new String[] {"exp"}, clientBatchOperation, 0, 0, 1000); LOG.info("Result count (without collecting results): " + result3.size()); @@ -124,9 +124,9 @@ public void performAction(List objects) { } }; - final Filter filter4 = Filter.createPresenceFilter("oxAuthExpiration"); + final Filter filter4 = Filter.createPresenceFilter("exp"); List result4 = couchbaseEntryManager.findEntries("o=gluu", SimpleClient.class, filter4, SearchScope.SUB, - new String[] {"oxAuthExpiration"}, clientBatchOperation2, 0, 0, 1000); + new String[] {"exp"}, clientBatchOperation2, 0, 0, 1000); LOG.info("Result count (with collecting results): " + result4.size()); } diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleDelete.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleDelete.java index a9f006dd..22cf16c1 100644 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleDelete.java +++ b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleDelete.java @@ -1,7 +1,5 @@ package org.gluu.couchbase; -import java.util.Date; - import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; import org.gluu.persist.couchbase.operation.impl.CouchbaseConnectionProvider; import org.gluu.persist.model.base.DeletableEntity; @@ -9,6 +7,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Date; + /** * @author Yuriy Movchan Date: 11/03/2016 */ @@ -29,7 +29,7 @@ public static void main(String[] args) { String baseDn = "ou=cache,o=gluu"; Filter filter = Filter.createANDFilter( Filter.createEqualityFilter("del", true), - Filter.createLessOrEqualFilter("oxAuthExpiration", couchbaseEntryManager.encodeTime(baseDn, new Date())) + Filter.createLessOrEqualFilter("exp", couchbaseEntryManager.encodeTime(baseDn, new Date())) ); int result = couchbaseEntryManager.remove(baseDn, DeletableEntity.class, filter, 100); diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleBatchJob.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleBatchJob.java index a7b56c91..e9302dac 100644 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleBatchJob.java +++ b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleBatchJob.java @@ -1,11 +1,6 @@ package org.gluu.ldap; -import java.text.ParseException; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; - +import com.unboundid.util.StaticUtils; import org.apache.log4j.Logger; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.status.StatusLogger; @@ -22,7 +17,11 @@ import org.gluu.persist.model.base.CustomAttribute; import org.gluu.search.filter.Filter; -import com.unboundid.util.StaticUtils; +import java.text.ParseException; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.List; /** * Created by eugeniuparvan on 1/12/17. @@ -52,8 +51,8 @@ public static void main(String[] args) { public void performAction(List objects) { for (SimpleTokenLdap simpleTokenLdap : objects) { try { - CustomAttribute customAttribute = getUpdatedAttribute(ldapEntryManager, simpleTokenLdap.getDn(), "oxAuthExpiration", - simpleTokenLdap.getAttribute("oxAuthExpiration")); + CustomAttribute customAttribute = getUpdatedAttribute(ldapEntryManager, simpleTokenLdap.getDn(), "exp", + simpleTokenLdap.getAttribute("exp")); simpleTokenLdap.setCustomAttributes(Arrays.asList(new CustomAttribute[] {customAttribute})); ldapEntryManager.merge(simpleTokenLdap); processedCount++; @@ -66,8 +65,8 @@ public void performAction(List objects) { } }; - final Filter filter1 = Filter.createPresenceFilter("oxAuthExpiration"); - ldapEntryManager.findEntries("o=gluu", SimpleTokenLdap.class, filter1, SearchScope.SUB, new String[] {"oxAuthExpiration"}, + final Filter filter1 = Filter.createPresenceFilter("exp"); + ldapEntryManager.findEntries("o=gluu", SimpleTokenLdap.class, filter1, SearchScope.SUB, new String[] {"exp"}, tokenLdapBatchOperation, 0, 0, 100); BatchOperation sessionBatchOperation = new ProcessBatchOperation() { @@ -108,9 +107,9 @@ public void performAction(List objects) { } }; - final Filter filter3 = Filter.createPresenceFilter("oxAuthExpiration"); + final Filter filter3 = Filter.createPresenceFilter("exp"); List result3 = ldapEntryManager.findEntries("o=gluu", SimpleClient.class, filter3, SearchScope.SUB, - new String[] {"oxAuthExpiration"}, clientBatchOperation, 0, 0, 1000); + new String[] {"exp"}, clientBatchOperation, 0, 0, 1000); LOG.info("Result count (without collecting results): " + result3.size()); @@ -127,9 +126,9 @@ public void performAction(List objects) { } }; - final Filter filter4 = Filter.createPresenceFilter("oxAuthExpiration"); + final Filter filter4 = Filter.createPresenceFilter("exp"); List result4 = ldapEntryManager.findEntries("o=gluu", SimpleClient.class, filter4, SearchScope.SUB, - new String[] {"oxAuthExpiration"}, clientBatchOperation2, 0, 0, 1000); + new String[] {"exp"}, clientBatchOperation2, 0, 0, 1000); LOG.info("Result count (with collecting results): " + result4.size()); } diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleDelete.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleDelete.java index 4e9f91cd..b8e7cf13 100644 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleDelete.java +++ b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleDelete.java @@ -1,24 +1,15 @@ package org.gluu.ldap; -import java.util.Date; -import java.util.List; - import org.apache.log4j.Logger; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.status.StatusLogger; -import org.gluu.ldap.model.SimpleAttribute; -import org.gluu.ldap.model.SimpleGrant; -import org.gluu.ldap.model.SimpleSession; -import org.gluu.ldap.model.SimpleUser; import org.gluu.log.LoggingHelper; import org.gluu.persist.ldap.impl.LdapEntryManager; -import org.gluu.persist.model.PagedResult; -import org.gluu.persist.model.SearchScope; -import org.gluu.persist.model.SortOrder; -import org.gluu.persist.model.base.CustomAttribute; import org.gluu.persist.model.base.DeletableEntity; import org.gluu.search.filter.Filter; +import java.util.Date; + /** * @author Yuriy Movchan Date: 11/03/2016 */ @@ -45,7 +36,7 @@ public static void main(String[] args) { String baseDn = "ou=cache,o=gluu"; Filter filter = Filter.createANDFilter( Filter.createEqualityFilter("del", true), - Filter.createLessOrEqualFilter("oxAuthExpiration", ldapEntryManager.encodeTime(baseDn, new Date(System.currentTimeMillis() + 2 * 24 * 60 * 60 * 1000))) + Filter.createLessOrEqualFilter("exp", ldapEntryManager.encodeTime(baseDn, new Date(System.currentTimeMillis() + 2 * 24 * 60 * 60 * 1000))) ); int result = ldapEntryManager.remove(baseDn, DeletableEntity.class, filter, 100); diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java b/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java index 472a49c5..373c014c 100644 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java +++ b/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java @@ -11,10 +11,8 @@ @DataEntry public class DeletableEntity extends BaseEntry implements Deletable { - @AttributeName(name = "oxAuthExpiration") - private Date expirationDate; @AttributeName(name = "exp") - private Date newExpirationDate; + private Date expirationDate; @AttributeName(name = "del") private Boolean deletable; @@ -35,26 +33,18 @@ public void setExpirationDate(Date expirationDate) { this.expirationDate = expirationDate; } - public Date getNewExpirationDate() { - return newExpirationDate; - } - - public void setNewExpirationDate(Date newExpirationDate) { - this.newExpirationDate = newExpirationDate; - } - public boolean canDelete() { return canDelete(new Date()); } public boolean canDelete(Date now) { - Date exp = expirationDate != null ? expirationDate : newExpirationDate; + Date exp = expirationDate != null ? expirationDate : null; return deletable != null && deletable && (exp == null || exp.before(now)); } @Override public String toString() { - Date exp = expirationDate != null ? expirationDate : newExpirationDate; + Date exp = expirationDate != null ? expirationDate : null; return "DeletableEntity{" + "expirationDate=" + exp + ", deletable=" + deletable + From 32a5d894351ed9533ae96835561d9fd60c68227b Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Mon, 27 Apr 2020 22:12:51 +0300 Subject: [PATCH 146/362] build fix https://github.com/GluuFederation/oxAuth/issues/1300 --- .../cache/NativePersistenceCacheProvider.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index 69c9e089..d30fcc01 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -1,16 +1,5 @@ package org.gluu.service.cache; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.Calendar; -import java.util.Date; - -import javax.annotation.PostConstruct; -import javax.enterprise.context.ApplicationScoped; -import javax.inject.Inject; - import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.IOUtils; @@ -21,6 +10,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Calendar; +import java.util.Date; + @ApplicationScoped public class NativePersistenceCacheProvider extends AbstractCacheProvider { @@ -116,7 +115,7 @@ public Object get(String key) { key = hashKey(key); NativePersistenceCacheEntity entity = entryManager.find(NativePersistenceCacheEntity.class, createDn(key)); if (entity != null && entity.getData() != null) { - if (isExpired(entity.getNewExpirationDate()) && entity.isDeletable()) { + if (isExpired(entity.getExpirationDate()) && entity.isDeletable()) { log.trace("Cache entity exists but expired, return null, expirationDate:" + entity.getExpirationDate() + ", key: " + key); if (deleteExpiredOnGetRequest && !skipRemoveBeforePut) { remove(key); @@ -168,7 +167,7 @@ private void putImpl(String key, Object object, Date creationDate, int expiratio entity.setId(key); entity.setDn(createDn(key)); entity.setCreationDate(creationDate); - entity.setNewExpirationDate(expirationDate.getTime()); + entity.setExpirationDate(expirationDate.getTime()); entity.setDeletable(true); if (!skipRemoveBeforePut) { From 03adba0b7461144e3128facfe5bb0e0c121247d1 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 5 May 2020 15:21:41 +0300 Subject: [PATCH 147/362] Each Person Authentication method should get configuration properties --- .../custom/script/type/auth/DummyPersonAuthenticationType.java | 2 +- .../model/custom/script/type/auth/PersonAuthenticationType.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java index 16803aff..7a481ce7 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java @@ -88,7 +88,7 @@ public int getApiVersion() { } @Override - public Map getAuthenticationMethodClaims() { + public Map getAuthenticationMethodClaims(Map configurationAttribute) { return null; } diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java index fbd285e7..f86a508a 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java @@ -41,5 +41,5 @@ String getAlternativeAuthenticationMethod(AuthenticationScriptUsageType usageTyp String getLogoutExternalUrl(Map configurationAttributes, Map requestParameters); - Map getAuthenticationMethodClaims(); + Map getAuthenticationMethodClaims(Map configurationAttributes); } From 0c5baab44ee60b272f41d667353fda0b535c9bcc Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 13 May 2020 19:49:19 +0300 Subject: [PATCH 148/362] Add Fido2 type --- oxModel/src/main/java/org/gluu/model/ApplicationType.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/oxModel/src/main/java/org/gluu/model/ApplicationType.java b/oxModel/src/main/java/org/gluu/model/ApplicationType.java index e53654ce..76fd6bdf 100644 --- a/oxModel/src/main/java/org/gluu/model/ApplicationType.java +++ b/oxModel/src/main/java/org/gluu/model/ApplicationType.java @@ -19,7 +19,8 @@ public enum ApplicationType implements AttributeEnum { OX_AUTH("oxauth", "oxAuth"), - OX_TRUST("oxtrust", "oxTrust"); + OX_TRUST("oxtrust", "oxTrust"), + FIDO2("fido2", "FIDO2"); private String value; private String displayName; From 0120f21b47920cd846c9070a74ba638dc218f0dd Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 14 May 2020 14:42:36 +0300 Subject: [PATCH 149/362] Improve render view method --- .../org/gluu/jsf2/service/FacesService.java | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/oxJsfUtil/src/main/java/org/gluu/jsf2/service/FacesService.java b/oxJsfUtil/src/main/java/org/gluu/jsf2/service/FacesService.java index 6f4abf2b..7ea9bd29 100644 --- a/oxJsfUtil/src/main/java/org/gluu/jsf2/service/FacesService.java +++ b/oxJsfUtil/src/main/java/org/gluu/jsf2/service/FacesService.java @@ -10,8 +10,10 @@ import javax.enterprise.context.RequestScoped; import javax.faces.application.NavigationHandler; import javax.faces.application.ViewHandler; +import javax.faces.component.UIViewRoot; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; +import javax.faces.context.PartialViewContext; import javax.inject.Inject; import javax.inject.Named; @@ -115,12 +117,34 @@ public String encodeParameters(String url, Map parameters) { } public void renderView(String viewId) { - final FacesContext fc = FacesContext.getCurrentInstance(); - final ViewHandler viewHandler = fc.getApplication().getViewHandler(); + final FacesContext ctx = FacesContext.getCurrentInstance(); + final ViewHandler viewHandler = ctx.getApplication().getViewHandler(); - fc.setViewRoot(viewHandler.createView(fc, viewId)); - fc.getPartialViewContext().setRenderAll(true); - fc.renderResponse(); + UIViewRoot newRoot = viewHandler.createView(ctx, viewId); + updateRenderTargets(ctx, viewId); + ctx.setViewRoot(newRoot); + clearViewMapIfNecessary(ctx, viewId); + + ctx.renderResponse(); + } + + private void updateRenderTargets(FacesContext ctx, String newId) { + if (ctx.getViewRoot() == null || !ctx.getViewRoot().getViewId().equals(newId)) { + PartialViewContext pctx = ctx.getPartialViewContext(); + if (!pctx.isRenderAll()) { + pctx.setRenderAll(true); + } + } + } + private void clearViewMapIfNecessary(FacesContext facesContext, String newId) { + UIViewRoot root = facesContext.getViewRoot(); + + if (root != null && !root.getViewId().equals(newId)) { + Map viewMap = root.getViewMap(false); + if (viewMap != null) { + viewMap.clear(); + } + } } public void navigateToView(String fromAction, String outcome, Map parameters) { From 8144c800bfb1decf20df73c1f76b32fb4557439a Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Mon, 18 May 2020 13:54:11 +0300 Subject: [PATCH 150/362] oxcore: Added Post-Authn script type. https://github.com/GluuFederation/oxAuth/issues/1129 --- .../model/custom/script/CustomScriptType.java | 3 ++ .../type/postauthn/DummyPostAuthnType.java | 41 +++++++++++++++++++ .../script/type/postauthn/PostAuthnType.java | 13 ++++++ .../custom/script/ExternalScriptService.java | 29 +++++++++---- 4 files changed, 77 insertions(+), 9 deletions(-) create mode 100644 oxService/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java create mode 100644 oxService/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java b/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java index 2cb48a66..291ff8cd 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java @@ -25,6 +25,8 @@ import org.gluu.model.custom.script.type.logout.EndSessionType; import org.gluu.model.custom.script.type.owner.DummyResourceOwnerPasswordCredentialsType; import org.gluu.model.custom.script.type.owner.ResourceOwnerPasswordCredentialsType; +import org.gluu.model.custom.script.type.postauthn.DummyPostAuthnType; +import org.gluu.model.custom.script.type.postauthn.PostAuthnType; import org.gluu.model.custom.script.type.scim.DummyScimType; import org.gluu.model.custom.script.type.scim.ScimType; import org.gluu.model.custom.script.type.scope.DummyDynamicScopeType; @@ -75,6 +77,7 @@ public enum CustomScriptType implements AttributeEnum { new DummyDynamicScopeType()), SPONTANEOUS_SCOPE("spontaneous_scope", "Spontaneous Scopes", SpontaneousScopeType.class, CustomScript.class, "SpontaneousScope", new DummySpontaneousScopeType()), END_SESSION("end_session", "End Session", EndSessionType.class, CustomScript.class, "EndSession", new DummyEndSessionType()), + POST_AUTHN("post_authn", "Post Authentication", PostAuthnType.class, CustomScript.class, "PostAuthn", new DummyPostAuthnType()), SCIM("scim", "SCIM", ScimType.class, CustomScript.class, "ScimEventHandler", new DummyScimType()), CIBA_END_USER_NOTIFICATION("ciba_end_user_notification", "CIBA End User Notification", EndUserNotificationType.class, CustomScript.class, "EndUserNotification", new DummyEndUserNotificationType()); diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java new file mode 100644 index 00000000..7186dc3b --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java @@ -0,0 +1,41 @@ +package org.gluu.model.custom.script.type.postauthn; + +import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.model.CustomScript; + +import java.util.Map; + +/** + * @author Yuriy Zabrovarnyy + */ +public class DummyPostAuthnType implements PostAuthnType { + @Override + public boolean forceReAuthentication(Object context) { + return false; + } + + @Override + public boolean forceAuthorization(Object context) { + return false; + } + + @Override + public boolean init(Map configurationAttributes) { + return true; + } + + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } + + @Override + public boolean destroy(Map configurationAttributes) { + return true; + } + + @Override + public int getApiVersion() { + return 0; + } +} diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java new file mode 100644 index 00000000..63e6efea --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java @@ -0,0 +1,13 @@ +package org.gluu.model.custom.script.type.postauthn; + +import org.gluu.model.custom.script.type.BaseExternalType; + +/** + * @author Yuriy Zabrovarnyy + */ +public interface PostAuthnType extends BaseExternalType { + + boolean forceReAuthentication(Object context); + + boolean forceAuthorization(Object context); +} diff --git a/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java b/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java index 57ba11c1..e0896ca6 100644 --- a/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java +++ b/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java @@ -6,15 +6,7 @@ package org.gluu.service.custom.script; -import java.io.Serializable; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.enterprise.context.ApplicationScoped; -import javax.enterprise.event.Observes; -import javax.inject.Inject; - +import com.google.common.collect.Lists; import org.gluu.model.custom.script.CustomScriptType; import org.gluu.model.custom.script.conf.CustomScriptConfiguration; import org.gluu.model.custom.script.model.CustomScript; @@ -23,6 +15,13 @@ import org.gluu.util.StringHelper; import org.slf4j.Logger; +import javax.enterprise.event.Observes; +import javax.inject.Inject; +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** * Provides factory methods needed to create external extension * @@ -134,4 +133,16 @@ public List getCustomScriptConfigurations() { return this.customScriptConfigurations; } + public List getCustomScriptConfigurationsByDns(List dns) { + if (dns == null || dns.isEmpty() || customScriptConfigurations == null || customScriptConfigurations.isEmpty()) { + return Lists.newArrayList(); + } + List scripts = Lists.newArrayList(); + for (CustomScriptConfiguration script : customScriptConfigurations) { + if (dns.contains(script.getCustomScript().getDn())) { + scripts.add(script); + } + } + return scripts; + } } From b87e15221cc69d0875c8376140feffce1e52e0f3 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Mon, 18 May 2020 14:00:59 +0300 Subject: [PATCH 151/362] Fixed redis sentinel provider pool exhaustion #190 --- .../service/cache/RedisSentinelProvider.java | 44 +++++++++++-------- .../service/cache/RedisShardedProvider.java | 11 +++-- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java index e5fd1f90..e1046f3e 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java @@ -71,48 +71,54 @@ public JedisSentinelPool getDelegate() { @Override public boolean hasKey(String key) { - Boolean hasKey = pool.getResource().exists(key); + try (final Jedis resource = pool.getResource()) { + Boolean hasKey = resource.exists(key); - return Boolean.TRUE.equals(hasKey); + return Boolean.TRUE.equals(hasKey); + } } @Override public Object get(String key) { - byte[] value = pool.getResource().get(key.getBytes()); - Object deserialized = null; - if (value != null && value.length > 0) { - deserialized = SerializationUtils.deserialize(value); + try (final Jedis resource = pool.getResource()) { + byte[] value = resource.get(key.getBytes()); + Object deserialized = null; + if (value != null && value.length > 0) { + deserialized = SerializationUtils.deserialize(value); + } + return deserialized; } - return deserialized; } @Override public void put(int expirationInSeconds, String key, Object object) { - String status = pool.getResource().setex(key.getBytes(), expirationInSeconds, SerializationUtils.serialize((Serializable) object)); - LOG.trace("put - key: " + key + ", status: " + status); + try (final Jedis resource = pool.getResource()) { + String status = resource.setex(key.getBytes(), expirationInSeconds, SerializationUtils.serialize((Serializable) object)); + LOG.trace("put - key: " + key + ", status: " + status); + } } @Override public void put(String key, Object object) { - String status = pool.getResource().set(key.getBytes(), SerializationUtils.serialize((Serializable) object)); - LOG.trace("put - key: " + key + ", status: " + status); + try (final Jedis resource = pool.getResource()) { + String status = resource.set(key.getBytes(), SerializationUtils.serialize((Serializable) object)); + LOG.trace("put - key: " + key + ", status: " + status); + } } @Override public void remove(String key) { - Long entriesRemoved = pool.getResource().del(key.getBytes()); - LOG.trace("remove - key: " + key + ", entriesRemoved: " + entriesRemoved); + try (final Jedis resource = pool.getResource()) { + Long entriesRemoved = resource.del(key.getBytes()); + LOG.trace("remove - key: " + key + ", entriesRemoved: " + entriesRemoved); + } } @Override public void clear() { - Jedis jedis = pool.getResource(); - - try { - jedis.flushAll(); + try (final Jedis resource = pool.getResource()) { + resource.flushAll(); LOG.trace("clear"); - } finally { - jedis.close(); } } } diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java index ab8587b3..eaa17943 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java @@ -5,10 +5,7 @@ import org.apache.http.conn.ssl.DefaultHostnameVerifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import redis.clients.jedis.JedisPoolConfig; -import redis.clients.jedis.JedisShardInfo; -import redis.clients.jedis.ShardedJedis; -import redis.clients.jedis.ShardedJedisPool; +import redis.clients.jedis.*; import javax.net.ssl.SSLParameters; import java.io.File; @@ -97,9 +94,11 @@ public ShardedJedisPool getDelegate() { @Override public boolean hasKey(String key) { - Boolean hasKey = pool.getResource().exists(key); + try (final ShardedJedis resource = pool.getResource()) { + Boolean hasKey = resource.exists(key); - return Boolean.TRUE.equals(hasKey); + return Boolean.TRUE.equals(hasKey); + } } @Override From 197f4372f68a7068afee1e7b24c06ceb6e030cac Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 20 May 2020 17:26:11 +0300 Subject: [PATCH 152/362] Add Startup extension --- pom.xml | 1 + startup-extension-cdi/pom.xml | 52 +++++++++++++++++++ .../service/startup/StartupBeanExtension.java | 32 ++++++++++++ .../src/main/resources/META-INF/beans.xml | 7 +++ .../javax.enterprise.inject.spi.Extension | 1 + 5 files changed, 93 insertions(+) create mode 100644 startup-extension-cdi/pom.xml create mode 100644 startup-extension-cdi/src/main/java/org/gluu/service/startup/StartupBeanExtension.java create mode 100644 startup-extension-cdi/src/main/resources/META-INF/beans.xml create mode 100644 startup-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension diff --git a/pom.xml b/pom.xml index a650418b..eb70436c 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,7 @@ core-timer-weld security-extension-cdi exception-extension-cdi + startup-extension-cdi oxService server oxRadius diff --git a/startup-extension-cdi/pom.xml b/startup-extension-cdi/pom.xml new file mode 100644 index 00000000..fef69478 --- /dev/null +++ b/startup-extension-cdi/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + startup-extension-cdi + Reusable CDI startup extension + + + org.gluu + oxcore + 4.2.0-SNAPSHOT + + + + ${maven.min-version} + + + + + + src/main/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + + + + javax.enterprise + cdi-api + provided + + + org.jboss.weld + weld-core-impl + provided + + + org.jboss.spec.javax.ejb + jboss-ejb-api_3.2_spec + provided + + + + + \ No newline at end of file diff --git a/startup-extension-cdi/src/main/java/org/gluu/service/startup/StartupBeanExtension.java b/startup-extension-cdi/src/main/java/org/gluu/service/startup/StartupBeanExtension.java new file mode 100644 index 00000000..2cbcf446 --- /dev/null +++ b/startup-extension-cdi/src/main/java/org/gluu/service/startup/StartupBeanExtension.java @@ -0,0 +1,32 @@ +package org.gluu.service.startup; + +import java.util.LinkedHashSet; +import java.util.Set; + +import javax.ejb.Startup; +import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.event.Observes; +import javax.enterprise.inject.spi.AfterDeploymentValidation; +import javax.enterprise.inject.spi.Bean; +import javax.enterprise.inject.spi.BeanManager; +import javax.enterprise.inject.spi.Extension; +import javax.enterprise.inject.spi.ProcessBean; + +public class StartupBeanExtension implements Extension { + + private final Set> startupBeans = new LinkedHashSet>(); + + void processBean(@Observes ProcessBean event) { + if (event.getAnnotated().isAnnotationPresent(Startup.class) && event.getAnnotated().isAnnotationPresent(ApplicationScoped.class)) { + startupBeans.add(event.getBean()); + } + } + + void afterDeploymentValidation(@Observes AfterDeploymentValidation event, BeanManager manager) { + for (Bean bean : startupBeans) { + // the call to toString() is a cheat to force the bean to be initialized + manager.getReference(bean, bean.getBeanClass(), manager.createCreationalContext(bean)).toString(); + } + } + +} \ No newline at end of file diff --git a/startup-extension-cdi/src/main/resources/META-INF/beans.xml b/startup-extension-cdi/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000..2f4f7e27 --- /dev/null +++ b/startup-extension-cdi/src/main/resources/META-INF/beans.xml @@ -0,0 +1,7 @@ + + + diff --git a/startup-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/startup-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension new file mode 100644 index 00000000..54aa6916 --- /dev/null +++ b/startup-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension @@ -0,0 +1 @@ +org.gluu.service.startup.StartupBeanExtension From 3e1a98f1b6a989d8ef4ee005aa135cda958e6bf0 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 20 May 2020 20:32:33 +0300 Subject: [PATCH 153/362] Revert "Add Startup extension" This reverts commit 197f4372f68a7068afee1e7b24c06ceb6e030cac. --- pom.xml | 1 - startup-extension-cdi/pom.xml | 52 ------------------- .../service/startup/StartupBeanExtension.java | 32 ------------ .../src/main/resources/META-INF/beans.xml | 7 --- .../javax.enterprise.inject.spi.Extension | 1 - 5 files changed, 93 deletions(-) delete mode 100644 startup-extension-cdi/pom.xml delete mode 100644 startup-extension-cdi/src/main/java/org/gluu/service/startup/StartupBeanExtension.java delete mode 100644 startup-extension-cdi/src/main/resources/META-INF/beans.xml delete mode 100644 startup-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension diff --git a/pom.xml b/pom.xml index eb70436c..a650418b 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,6 @@ core-timer-weld security-extension-cdi exception-extension-cdi - startup-extension-cdi oxService server oxRadius diff --git a/startup-extension-cdi/pom.xml b/startup-extension-cdi/pom.xml deleted file mode 100644 index fef69478..00000000 --- a/startup-extension-cdi/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - 4.0.0 - startup-extension-cdi - Reusable CDI startup extension - - - org.gluu - oxcore - 4.2.0-SNAPSHOT - - - - ${maven.min-version} - - - - - - src/main/resources - true - - **/*.xml - **/services/* - **/*.properties - - - - - - - - - javax.enterprise - cdi-api - provided - - - org.jboss.weld - weld-core-impl - provided - - - org.jboss.spec.javax.ejb - jboss-ejb-api_3.2_spec - provided - - - - - \ No newline at end of file diff --git a/startup-extension-cdi/src/main/java/org/gluu/service/startup/StartupBeanExtension.java b/startup-extension-cdi/src/main/java/org/gluu/service/startup/StartupBeanExtension.java deleted file mode 100644 index 2cbcf446..00000000 --- a/startup-extension-cdi/src/main/java/org/gluu/service/startup/StartupBeanExtension.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.gluu.service.startup; - -import java.util.LinkedHashSet; -import java.util.Set; - -import javax.ejb.Startup; -import javax.enterprise.context.ApplicationScoped; -import javax.enterprise.event.Observes; -import javax.enterprise.inject.spi.AfterDeploymentValidation; -import javax.enterprise.inject.spi.Bean; -import javax.enterprise.inject.spi.BeanManager; -import javax.enterprise.inject.spi.Extension; -import javax.enterprise.inject.spi.ProcessBean; - -public class StartupBeanExtension implements Extension { - - private final Set> startupBeans = new LinkedHashSet>(); - - void processBean(@Observes ProcessBean event) { - if (event.getAnnotated().isAnnotationPresent(Startup.class) && event.getAnnotated().isAnnotationPresent(ApplicationScoped.class)) { - startupBeans.add(event.getBean()); - } - } - - void afterDeploymentValidation(@Observes AfterDeploymentValidation event, BeanManager manager) { - for (Bean bean : startupBeans) { - // the call to toString() is a cheat to force the bean to be initialized - manager.getReference(bean, bean.getBeanClass(), manager.createCreationalContext(bean)).toString(); - } - } - -} \ No newline at end of file diff --git a/startup-extension-cdi/src/main/resources/META-INF/beans.xml b/startup-extension-cdi/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 2f4f7e27..00000000 --- a/startup-extension-cdi/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/startup-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/startup-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension deleted file mode 100644 index 54aa6916..00000000 --- a/startup-extension-cdi/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension +++ /dev/null @@ -1 +0,0 @@ -org.gluu.service.startup.StartupBeanExtension From a390b78ee6324ec0c302839e0f2f1c03944de26a Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Wed, 20 May 2020 22:08:54 +0300 Subject: [PATCH 154/362] Added utility method to select entities by data for SelectableEntity. --- .../main/java/org/gluu/model/SelectableEntity.java | 7 +++++++ .../java/org/gluu/util/SelectableEntityHelper.java | 11 ++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/oxUtil/src/main/java/org/gluu/model/SelectableEntity.java b/oxUtil/src/main/java/org/gluu/model/SelectableEntity.java index e65297a7..75a606f9 100644 --- a/oxUtil/src/main/java/org/gluu/model/SelectableEntity.java +++ b/oxUtil/src/main/java/org/gluu/model/SelectableEntity.java @@ -45,4 +45,11 @@ public void setSelected(boolean selected) { this.selected = selected; } + @Override + public String toString() { + return "SelectableEntity{" + + "entity=" + entity + + ", selected=" + selected + + '}'; + } } diff --git a/oxUtil/src/main/java/org/gluu/util/SelectableEntityHelper.java b/oxUtil/src/main/java/org/gluu/util/SelectableEntityHelper.java index b57a62a2..a25294d6 100644 --- a/oxUtil/src/main/java/org/gluu/util/SelectableEntityHelper.java +++ b/oxUtil/src/main/java/org/gluu/util/SelectableEntityHelper.java @@ -6,13 +6,13 @@ package org.gluu.util; +import org.gluu.model.SelectableEntity; + import java.util.ArrayList; import java.util.List; -import org.gluu.model.SelectableEntity; - /** - * Converts lis of entities to list of selectable entities + * Converts list of entities to list of selectable entities * * @author Yuriy Movchan Date: 04/25/2013 */ @@ -40,4 +40,9 @@ public static List convertToEntities(List> selectable return result; } + public static void select(List> selectableEntities, List entities) { + for (SelectableEntity selectable : selectableEntities) { + selectable.setSelected(entities.contains(selectable.getEntity())); + } + } } From a7b3f2082b5b7cad1b928b5845237cb7dcb047cd Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 21 May 2020 21:47:54 +0300 Subject: [PATCH 155/362] Fix NPE when there is no specified type script --- .../org/gluu/service/custom/script/CustomScriptManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java index f261369b..c40628d8 100644 --- a/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java +++ b/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java @@ -344,7 +344,9 @@ private Map> groupCustomScript CustomScriptType customScriptType = customScriptConfiguration.getCustomScript().getScriptType(); List customConfigurationsByScriptType = newCustomScriptConfigurationsByScriptType .get(customScriptType); - customConfigurationsByScriptType.add(customScriptConfiguration); + if (customConfigurationsByScriptType != null) { + customConfigurationsByScriptType.add(customScriptConfiguration); + } } return newCustomScriptConfigurationsByScriptType; From 95f46fdbf903182c777cca4977ad624a13f0a991 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 22 May 2020 21:57:05 +0300 Subject: [PATCH 156/362] Default reusable application configuration --- .../oxtrust/DbApplicationConfiguration.java | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 oxService/src/main/java/org/gluu/config/oxtrust/DbApplicationConfiguration.java diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/DbApplicationConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/DbApplicationConfiguration.java new file mode 100644 index 00000000..4173d102 --- /dev/null +++ b/oxService/src/main/java/org/gluu/config/oxtrust/DbApplicationConfiguration.java @@ -0,0 +1,63 @@ +/* + * oxTrust is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2020, Gluu + */ + +package org.gluu.config.oxtrust; + +import org.gluu.persist.annotation.AttributeName; +import org.gluu.persist.annotation.DN; +import org.gluu.persist.annotation.DataEntry; +import org.gluu.persist.annotation.JsonObject; +import org.gluu.persist.annotation.ObjectClass; + +/** + * @author Yuriy MOvchan + * @version May 12, 2020 + */ +@DataEntry +@ObjectClass(value = "gluuApplicationConfiguration") +public class DbApplicationConfiguration { + @DN + private String dn; + + @JsonObject + @AttributeName(name = "gluuConfDynamic") + private String dynamicConf; + + @AttributeName(name = "oxRevision") + private long revision; + + public DbApplicationConfiguration() { + } + + public String getDn() { + return dn; + } + + public void setDn(String p_dn) { + dn = p_dn; + } + + public String getDynamicConf() { + return dynamicConf; + } + + public void setDynamicConf(String dynamicConf) { + this.dynamicConf = dynamicConf; + } + + public long getRevision() { + return revision; + } + + public void setRevision(long revision) { + this.revision = revision; + } + + @Override + public String toString() { + return "DbApplicationConfiguration [dn=" + dn + ", dynamicConf=" + dynamicConf + ", revision=" + revision + "]"; + } +} From 9c6e0875e53bb9422766b6247da65f3672b883ff Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 25 May 2020 21:17:19 +0300 Subject: [PATCH 157/362] Add application configration reload event --- .../service/cdi/event/AppConfigurationReloadEvent.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 oxService/src/main/java/org/gluu/service/cdi/event/AppConfigurationReloadEvent.java diff --git a/oxService/src/main/java/org/gluu/service/cdi/event/AppConfigurationReloadEvent.java b/oxService/src/main/java/org/gluu/service/cdi/event/AppConfigurationReloadEvent.java new file mode 100644 index 00000000..3bd2cb15 --- /dev/null +++ b/oxService/src/main/java/org/gluu/service/cdi/event/AppConfigurationReloadEvent.java @@ -0,0 +1,7 @@ +package org.gluu.service.cdi.event; + +/** + * @author Yuriy Movchan Date: 05/25/2020 + */ +public class AppConfigurationReloadEvent { +} From ff37c37d0b167076c8454f721a058f5ca355f016 Mon Sep 17 00:00:00 2001 From: Milton BO Date: Mon, 25 May 2020 16:31:44 -0400 Subject: [PATCH 158/362] Ciba requests processor event. GluuFederation/oxAuth/issues/1361 --- .../gluu/service/cdi/event/CibaRequestsProcessorEvent.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 oxService/src/main/java/org/gluu/service/cdi/event/CibaRequestsProcessorEvent.java diff --git a/oxService/src/main/java/org/gluu/service/cdi/event/CibaRequestsProcessorEvent.java b/oxService/src/main/java/org/gluu/service/cdi/event/CibaRequestsProcessorEvent.java new file mode 100644 index 00000000..99f0216b --- /dev/null +++ b/oxService/src/main/java/org/gluu/service/cdi/event/CibaRequestsProcessorEvent.java @@ -0,0 +1,7 @@ +package org.gluu.service.cdi.event; + +/** + * @author Milton BO Date: 20/05/2020 + */ +public class CibaRequestsProcessorEvent { +} From 8defc9e2e4450ad4a67f02de6aab489139bc18df Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Tue, 26 May 2020 13:27:34 +0300 Subject: [PATCH 159/362] Deperacated CacheService.put() without expiration. --- .../main/java/org/gluu/service/BaseCacheService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/BaseCacheService.java b/oxService/src/main/java/org/gluu/service/BaseCacheService.java index 7a8b64a0..e4ad7760 100644 --- a/oxService/src/main/java/org/gluu/service/BaseCacheService.java +++ b/oxService/src/main/java/org/gluu/service/BaseCacheService.java @@ -5,16 +5,15 @@ */ package org.gluu.service; -import java.util.Date; -import java.util.function.Supplier; - -import javax.inject.Inject; - import org.gluu.service.cache.CacheInterface; import org.gluu.service.cache.CacheProvider; import org.gluu.service.cache.CacheProviderType; import org.slf4j.Logger; +import javax.inject.Inject; +import java.util.Date; +import java.util.function.Supplier; + /** * Provides operations with cache * @@ -120,6 +119,7 @@ public void cleanup(Date now) { cacheProvider.cleanup(now); } + @Deprecated public void put(String key, Object object) { put(DEFAULT_EXPIRATION, key, object); } From f9cb2d75697cee020fc86299a27ab1cf4deeb8c7 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Wed, 27 May 2020 01:37:23 +0100 Subject: [PATCH 160/362] Support hypthen in attribute name --- oxService/src/main/java/org/gluu/model/GluuAttribute.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/model/GluuAttribute.java b/oxService/src/main/java/org/gluu/model/GluuAttribute.java index fb2d1cdf..e4da922e 100644 --- a/oxService/src/main/java/org/gluu/model/GluuAttribute.java +++ b/oxService/src/main/java/org/gluu/model/GluuAttribute.java @@ -52,7 +52,7 @@ public class GluuAttribute extends Entry implements Serializable { private String nameIdType; @NotNull - @Pattern(regexp = "^[a-zA-Z0-9]+$", message = "Name should contain alphabetical and numeric characters only") + @Pattern(regexp = "^[a-zA-Z0-9_]+$", message = "Name should contain alphabetical and numeric characters only") @Size(min = 1, max = 30, message = "Length of the Name should be between 1 and 30") @AttributeName(name = "gluuAttributeName") private String name; From f1534a049522a70e27ee546076cc4f5c673b7a3f Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 27 May 2020 20:30:13 +0300 Subject: [PATCH 161/362] Don't return scripts if application not support them --- .../gluu/service/custom/script/CustomScriptManager.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java index c40628d8..e0a67ac9 100644 --- a/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java +++ b/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java @@ -150,8 +150,13 @@ private void reload() { private boolean reloadImpl() { // Load current script revisions - List customScripts = customScriptService.findCustomScripts(supportedCustomScriptTypes, - CUSTOM_SCRIPT_CHECK_ATTRIBUTES); + List customScripts; + if (supportedCustomScriptTypes.isEmpty()) { + customScripts = new ArrayList(); + } else { + customScripts = customScriptService.findCustomScripts(supportedCustomScriptTypes, + CUSTOM_SCRIPT_CHECK_ATTRIBUTES); + } // Store updated external authenticator configurations ReloadResult reloadResult = reloadCustomScriptConfigurations(this.customScriptConfigurations, customScripts); From 4a010011c9107698550f4642d5b0a2b5ecb03a63 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Fri, 29 May 2020 16:05:31 +0300 Subject: [PATCH 162/362] Removed redundant expiry field from AttributeName annotation (it's implemented via @Expiration) --- .../java/org/gluu/persist/annotation/AttributeName.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributeName.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributeName.java index d2ff245e..a3c2e3da 100644 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributeName.java +++ b/persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributeName.java @@ -48,10 +48,4 @@ * Defaults value is false. */ boolean consistency() default false; - - /** - * (Optional) Specify whether attribute contains expiration date (E.g. used by Couchbase TTL). - */ - boolean expiry () default false; - } From d117df1bc74b867dc90f65e19f2e164d8a31bf2c Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Mon, 1 Jun 2020 17:08:51 +0300 Subject: [PATCH 163/362] Added getDNs utility method. --- .../main/java/org/gluu/persist/model/base/BaseEntry.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/BaseEntry.java b/persistence-model/src/main/java/org/gluu/persist/model/base/BaseEntry.java index cf732e04..1b054964 100644 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/BaseEntry.java +++ b/persistence-model/src/main/java/org/gluu/persist/model/base/BaseEntry.java @@ -8,6 +8,10 @@ import org.gluu.persist.annotation.DN; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + /** * Provides DN attribute * @@ -47,4 +51,7 @@ public String toString() { return String.format("BaseEntry [dn=%s]", dn); } + public static List getDNs(Collection collection) { + return collection.stream().map(BaseEntry::getDn).collect(Collectors.toList()); + } } From bfbe8109d392998a6b0eaba0b76ffc07aacd5af1 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Tue, 2 Jun 2020 19:55:41 +0100 Subject: [PATCH 164/362] Fix smtp mail config issue --- oxService/src/main/java/org/gluu/service/MailService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index d77c8cba..0cc0e6e0 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -103,7 +103,7 @@ protected PasswordAuthentication getPasswordAuthentication() { } }); } else { - Session.getInstance(props, null); + session = Session.getInstance(props, null); } MimeMessage msg = new MimeMessage(session); From d0ea4106f40430402184c3289c1922fcca9035ec Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Wed, 3 Jun 2020 22:00:45 +0100 Subject: [PATCH 165/362] Add new json entry(supportedUserStatus) --- .../java/org/gluu/config/oxtrust/AppConfiguration.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index 0ef3d9cd..7d06263d 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -11,6 +11,7 @@ import javax.enterprise.inject.Vetoed; import java.io.Serializable; +import java.util.Arrays; import java.util.List; @@ -139,6 +140,7 @@ public class AppConfiguration implements Configuration, Serializable { private List clientWhiteList; private List clientBlackList; + private List supportedUserStatus= Arrays.asList("active","inactive"); private String loggingLevel; private String loggingLayout; @@ -798,6 +800,14 @@ public void setMetricReporterInterval(int metricReporterInterval) { this.metricReporterInterval = metricReporterInterval; } + public List getSupportedUserStatus() { + return supportedUserStatus; + } + + public void setSupportedUserStatus(List supportedUserStatus) { + this.supportedUserStatus = supportedUserStatus; + } + /** * @return the apiUmaClientId */ From 8f00ff3c96eba968fc30fb43082d15e695f72892 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 4 Jun 2020 20:03:53 +0300 Subject: [PATCH 166/362] Add debug logging to check why bucket ping returns false --- .../operation/impl/CouchbaseConnectionProvider.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java index ca1ddf24..8d549346 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java @@ -235,7 +235,11 @@ public boolean isConnected() { try { Bucket bucket = bucketMapping.getBucket(); if (bucket.isClosed() || !isConnected(bucketMapping)) { - LOG.error("Bucket '{}' is invalid", bucketMapping.getBucketName()); + if (bucket.isClosed()) { + LOG.debug("Bucket '{}' is closed", bucketMapping.getBucketName()); + } + + LOG.error("Bucket '{}' is in invalid state", bucketMapping.getBucketName()); isConnected = false; break; } @@ -262,6 +266,8 @@ private boolean isConnected(BucketMapping bucketMapping) { if (result) { result = queryResult.info().resultCount() == 0; + } else if (LOG.isDebugEnabled()) { + LOG.debug("There are indexes which not online"); } } @@ -269,6 +275,7 @@ private boolean isConnected(BucketMapping bucketMapping) { PingReport pingReport = bucket.ping(); for (PingServiceHealth pingServiceHealth : pingReport.services()) { if (PingState.OK != pingServiceHealth.state()) { + LOG.debug("Ping returns that service typ {} is not online", pingServiceHealth.type()); result = false; break; } From bc9e9045411c7e693c7a9d13dd64961836adf573 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 4 Jun 2020 21:43:24 +0300 Subject: [PATCH 167/362] More status checker errors --- .../operation/impl/CouchbaseConnectionProvider.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java index 8d549346..9c9ea96a 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java @@ -266,8 +266,13 @@ private boolean isConnected(BucketMapping bucketMapping) { if (result) { result = queryResult.info().resultCount() == 0; - } else if (LOG.isDebugEnabled()) { - LOG.debug("There are indexes which not online"); + if (LOG.isDebugEnabled()) { + LOG.debug("There are indexes which not online"); + } + } else { + if (LOG.isDebugEnabled()) { + LOG.debug("Faield to check indexes status"); + } } } From 67ae34bcf49c0da9c26858fb76455acd4b2380b2 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Fri, 5 Jun 2020 15:37:14 +0100 Subject: [PATCH 168/362] Add dependencies to support Java 11 --- core-cache/pom.xml | 30 +++++--- core-document-store/pom.xml | 55 +++++++------- oxModel/pom.xml | 31 ++++---- oxSaml/pom.xml | 5 ++ .../src/main/java/org/gluu/saml/Response.java | 1 - .../org/gluu/saml/SimpleNamespaceContext.java | 44 +++++++++++ oxUtil/pom.xml | 4 + .../org/gluu/xml/SimpleNamespaceContext.java | 40 ---------- persistence-couchbase/pom.xml | 74 ++++++++++--------- pom.xml | 12 ++- 10 files changed, 170 insertions(+), 126 deletions(-) create mode 100644 oxSaml/src/main/java/org/gluu/saml/SimpleNamespaceContext.java delete mode 100644 oxUtil/src/main/java/org/gluu/xml/SimpleNamespaceContext.java diff --git a/core-cache/pom.xml b/core-cache/pom.xml index 32e99cb6..5b7a4512 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -1,4 +1,5 @@ - 4.0.0 @@ -28,17 +29,17 @@ - - - src/test/resources - true - - **/*.xml - **/services/* - **/*.properties - - - + + + src/test/resources + true + + **/*.xml + **/services/* + **/*.properties + + + @@ -80,6 +81,11 @@ org.testng testng + + + javax.annotation + javax.annotation-api + \ No newline at end of file diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index a6dc4b5c..2ce305b7 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -1,4 +1,5 @@ - 4.0.0 @@ -27,17 +28,17 @@ - - - src/test/resources - true - - **/*.xml - **/services/* - **/*.properties - - - + + + src/test/resources + true + + **/*.xml + **/services/* + **/*.properties + + + @@ -60,24 +61,24 @@ javax.inject - - - javax.jcr - jcr - - - org.apache.jackrabbit - jackrabbit-core - + - org.apache.jackrabbit - jackrabbit-jcr-rmi + javax.jcr + jcr + + + org.apache.jackrabbit + jackrabbit-core + + + org.apache.jackrabbit + jackrabbit-jcr-rmi - com.fasterxml.jackson.core - jackson-annotations + com.fasterxml.jackson.core + jackson-annotations @@ -85,6 +86,10 @@ org.testng testng + + javax.annotation + javax.annotation-api + \ No newline at end of file diff --git a/oxModel/pom.xml b/oxModel/pom.xml index 7c173e80..13f00f23 100644 --- a/oxModel/pom.xml +++ b/oxModel/pom.xml @@ -1,4 +1,5 @@ - 4.0.0 @@ -27,18 +28,22 @@ validation-api - - com.fasterxml.jackson.core - jackson-annotations - - - com.fasterxml.jackson.core - jackson-core - - - com.fasterxml.jackson.core - jackson-databind - + + com.fasterxml.jackson.core + jackson-annotations + + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-databind + + + javax.annotation + javax.annotation-api + \ No newline at end of file diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index 1dafcc7c..285c98b9 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -69,5 +69,10 @@ opensaml 2.6.4 + + jakarta.xml.bind + jakarta.xml.bind-api + 2.3.3 + diff --git a/oxSaml/src/main/java/org/gluu/saml/Response.java b/oxSaml/src/main/java/org/gluu/saml/Response.java index 57800a94..f1662262 100644 --- a/oxSaml/src/main/java/org/gluu/saml/Response.java +++ b/oxSaml/src/main/java/org/gluu/saml/Response.java @@ -37,7 +37,6 @@ import javax.xml.xpath.XPathFactory; import org.apache.commons.codec.binary.Base64; -import org.gluu.xml.SimpleNamespaceContext; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; diff --git a/oxSaml/src/main/java/org/gluu/saml/SimpleNamespaceContext.java b/oxSaml/src/main/java/org/gluu/saml/SimpleNamespaceContext.java new file mode 100644 index 00000000..8b8750f6 --- /dev/null +++ b/oxSaml/src/main/java/org/gluu/saml/SimpleNamespaceContext.java @@ -0,0 +1,44 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.saml; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.xml.namespace.NamespaceContext; + +/** + * Allow to work with XML name contexts + * + * @author Yuriy Movchan Date: 04/24/2014 + */ +public class SimpleNamespaceContext implements NamespaceContext { + private final Map prefMap = new HashMap(); + + @Override + public String getNamespaceURI(String prefix) { + return prefMap.get(prefix); + } + + @Override + public String getPrefix(String namespaceURI) { + return prefMap.get(namespaceURI); + } + + @SuppressWarnings("rawtypes") + @Override + public Iterator getPrefixes(String namespaceURI) { + // TODO Auto-generated method stub + return null; + } + + public SimpleNamespaceContext(final Map prefMap) { + prefMap.putAll(prefMap); + } + +} diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index 02fef2d6..345b1a5e 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -100,6 +100,10 @@ javax.servlet javax.servlet-api + + jakarta.xml.bind + jakarta.xml.bind-api + \ No newline at end of file diff --git a/oxUtil/src/main/java/org/gluu/xml/SimpleNamespaceContext.java b/oxUtil/src/main/java/org/gluu/xml/SimpleNamespaceContext.java deleted file mode 100644 index f653b2a6..00000000 --- a/oxUtil/src/main/java/org/gluu/xml/SimpleNamespaceContext.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.xml; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import javax.xml.namespace.NamespaceContext; - -/** - * Allow to work with XML name contexts - * - * @author Yuriy Movchan Date: 04/24/2014 - */ -public class SimpleNamespaceContext implements NamespaceContext { - - private final Map prefMap = new HashMap(); - - public SimpleNamespaceContext(final Map prefMap) { - prefMap.putAll(prefMap); - } - - public String getNamespaceURI(String prefix) { - return prefMap.get(prefix); - } - - public String getPrefix(String uri) { - throw new UnsupportedOperationException(); - } - - public Iterator getPrefixes(String uri) { - throw new UnsupportedOperationException(); - } - -} diff --git a/persistence-couchbase/pom.xml b/persistence-couchbase/pom.xml index a825364f..16d738e6 100644 --- a/persistence-couchbase/pom.xml +++ b/persistence-couchbase/pom.xml @@ -1,15 +1,17 @@ - + - 4.0.0 - oxcore-persistence-couchbase - jar - persistence-couchbase - - - org.gluu - oxcore - 4.2.0-SNAPSHOT - + 4.0.0 + oxcore-persistence-couchbase + jar + persistence-couchbase + + + org.gluu + oxcore + 4.2.0-SNAPSHOT + @@ -26,27 +28,27 @@ - - - org.gluu - oxcore-util - - - org.gluu - oxcore-persistence-filter - - - org.gluu - oxcore-persistence-core - - - org.gluu - oxcore-persistence-ldap - - - org.gluu - oxcore-persistence-annotation - + + + org.gluu + oxcore-util + + + org.gluu + oxcore-persistence-filter + + + org.gluu + oxcore-persistence-core + + + org.gluu + oxcore-persistence-ldap + + + org.gluu + oxcore-persistence-annotation + com.couchbase.client @@ -63,7 +65,11 @@ javax.inject javax.inject - - + + javax.annotation + javax.annotation-api + 1.3.2 + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index a650418b..9c18bbd2 100644 --- a/pom.xml +++ b/pom.xml @@ -64,7 +64,17 @@ import pom - + + jakarta.xml.bind + jakarta.xml.bind-api + 2.3.3 + + + javax.annotation + javax.annotation-api + 1.3.2 + + From 789a3aefbf0b42bf672128343997cb31920bb4ef Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 5 Jun 2020 19:32:09 +0300 Subject: [PATCH 169/362] Add new persistence custom script #194 --- .../model/custom/script/CustomScriptType.java | 4 +- .../DummyDynamicPeristenceType.java | 64 ++++++++++++++++ .../type/persistence/PersistenceType.java | 19 +++++ .../ExternalPersistenceExtension.java | 70 ++++++++++++++++++ .../context/ExternalScriptContext.java | 73 +++++++++++++++++++ .../context/PersistenceExternalContext.java | 28 +++++++ .../extension/PersistenceExtension.java | 22 ++++++ .../gluu/persist/impl/BaseEntryManager.java | 13 ++++ .../PersistenceOperationService.java | 4 + .../couchbase/impl/CouchbaseEntryManager.java | 42 +++++------ .../impl/CouchbaseEntryManagerFactory.java | 4 +- ...ava => CouchbaseOperationServiceImpl.java} | 26 +++++-- .../HybridPersistenceOperationService.java | 8 ++ .../persist/ldap/impl/LdapEntryManager.java | 14 ++-- .../ldap/impl/LdapEntryManagerFactory.java | 4 +- ...mpl.java => LdapOperationServiceImpl.java} | 28 ++++--- 16 files changed, 374 insertions(+), 49 deletions(-) create mode 100644 oxService/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java create mode 100644 oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java create mode 100644 oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtension.java create mode 100644 oxService/src/main/java/org/gluu/service/external/context/ExternalScriptContext.java create mode 100644 oxService/src/main/java/org/gluu/service/external/context/PersistenceExternalContext.java create mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/extension/PersistenceExtension.java rename persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/{CouchbaseOperationsServiceImpl.java => CouchbaseOperationServiceImpl.java} (96%) rename persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/{LdapOperationsServiceImpl.java => LdapOperationServiceImpl.java} (98%) diff --git a/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java b/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java index 291ff8cd..af5a0e19 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java @@ -39,6 +39,7 @@ import org.gluu.model.custom.script.type.uma.UmaDummyClaimsGatheringType; import org.gluu.model.custom.script.type.uma.UmaDummyRptPolicyType; import org.gluu.model.custom.script.type.uma.UmaRptPolicyType; +import org.gluu.model.custom.script.type.persistence.*; import org.gluu.model.custom.script.type.user.*; import org.gluu.persist.annotation.AttributeEnum; @@ -80,7 +81,8 @@ public enum CustomScriptType implements AttributeEnum { POST_AUTHN("post_authn", "Post Authentication", PostAuthnType.class, CustomScript.class, "PostAuthn", new DummyPostAuthnType()), SCIM("scim", "SCIM", ScimType.class, CustomScript.class, "ScimEventHandler", new DummyScimType()), CIBA_END_USER_NOTIFICATION("ciba_end_user_notification", "CIBA End User Notification", EndUserNotificationType.class, - CustomScript.class, "EndUserNotification", new DummyEndUserNotificationType()); + CustomScript.class, "EndUserNotification", new DummyEndUserNotificationType()), + PERSISTENCE_EXTENSION("persistence_extension", "Persistence Extension", PersistenceType.class, CustomScript.class, "PersistenceExtension", new DummyDynamicPeristenceType()); private String value; private String displayName; diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java new file mode 100644 index 00000000..8365051b --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java @@ -0,0 +1,64 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2020, Gluu + */package org.gluu.model.custom.script.type.persistence; + +import java.util.Map; + +import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.model.CustomScript; +/** + * Dummy implementation of interface DynamicPeristanceType + * + * @author Yuriy Movchan Date: 06/04/2020 + */ +public class DummyDynamicPeristenceType implements PersistenceType { + + @Override + public boolean init(Map configurationAttributes) { + return true; + } + + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } + + @Override + public boolean destroy(Map configurationAttributes) { + return true; + } + + @Override + public int getApiVersion() { + return 1; + } + + @Override + public void onBeforeCreate(Object context, Map configurationAttributes) { + } + + @Override + public void onAfterCreate(Object context, Map configurationAttributes) { + } + + @Override + public void onBeforeDestroy(Object context, Map configurationAttributes) { + } + + @Override + public void onAfterDestroy(Object context, Map configurationAttributes) { + } + + @Override + public String createHashedPassword(String credential) { + return credential; + } + + @Override + public boolean compareHashedPasswords(String credential, String storedCredential) { + return false; + } + +} diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java new file mode 100644 index 00000000..a9121144 --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java @@ -0,0 +1,19 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.model.custom.script.type.persistence; + +import org.gluu.model.custom.script.type.BaseExternalType; +import org.gluu.persist.exception.extension.PersistenceExtension; + +/** + * Base interface for persistence script + * + * @author Yuriy Movchan Date: 06/04/2020 + */ +public interface PersistenceType extends BaseExternalType, PersistenceExtension { + +} diff --git a/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtension.java b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtension.java new file mode 100644 index 00000000..14d7551b --- /dev/null +++ b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtension.java @@ -0,0 +1,70 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2020, Gluu + */ + +package org.gluu.service.external; + +import java.util.Map; + +import javax.enterprise.context.ApplicationScoped; + +import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.CustomScriptType; +import org.gluu.model.custom.script.conf.CustomScriptConfiguration; +import org.gluu.model.custom.script.type.persistence.PersistenceType; +import org.gluu.service.custom.script.ExternalScriptService; +import org.gluu.service.external.context.PersistenceExternalContext; + +/** + * Provides factory methods needed to create persistence extension + * + * @author Yuriy Movchan Date: 06/04/2020 + */ +@ApplicationScoped +public class ExternalPersistenceExtension extends ExternalScriptService { + + private static final long serialVersionUID = 5466361778036208685L; + + public ExternalPersistenceExtension() { + super(CustomScriptType.PERSISTENCE_EXTENSION); + } + + public void executeExternalOnBeforeCreateMethod(CustomScriptConfiguration customScriptConfiguration, PersistenceExternalContext context) { + try { + log.debug("Executing python 'onBeforeCreate' method"); + PersistenceType persistenceType = (PersistenceType) customScriptConfiguration.getExternalType(); + Map configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); + persistenceType.onBeforeCreate(context, configurationAttributes); + } catch (Exception ex) { + log.error(ex.getMessage(), ex); + saveScriptError(customScriptConfiguration.getCustomScript(), ex); + } + } + + public void executeExternalOnAfterCreateMethod(CustomScriptConfiguration customScriptConfiguration, PersistenceExternalContext context) { + try { + log.debug("Executing python 'onAfterCreate' method"); + PersistenceType persistenceType = (PersistenceType) customScriptConfiguration.getExternalType(); + Map configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); + persistenceType.onAfterCreate(context, configurationAttributes); + } catch (Exception ex) { + log.error(ex.getMessage(), ex); + saveScriptError(customScriptConfiguration.getCustomScript(), ex); + } + } + + public void executeExternalOnBeforeDestroyMethod(CustomScriptConfiguration customScriptConfiguration, PersistenceExternalContext context) { + try { + log.debug("Executing python 'onBeforeDestroy' method"); + PersistenceType persistenceType = (PersistenceType) customScriptConfiguration.getExternalType(); + Map configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); + persistenceType.onBeforeDestroy(context, configurationAttributes); + } catch (Exception ex) { + log.error(ex.getMessage(), ex); + saveScriptError(customScriptConfiguration.getCustomScript(), ex); + } + } + +} diff --git a/oxService/src/main/java/org/gluu/service/external/context/ExternalScriptContext.java b/oxService/src/main/java/org/gluu/service/external/context/ExternalScriptContext.java new file mode 100644 index 00000000..4cdcf6eb --- /dev/null +++ b/oxService/src/main/java/org/gluu/service/external/context/ExternalScriptContext.java @@ -0,0 +1,73 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.service.external.context; + +import java.util.HashMap; +import java.util.Map; + +import javax.faces.context.ExternalContext; +import javax.faces.context.FacesContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Holds object required in custom scripts + * + * @author Yuriy Movchan Date: 07/01/2015 + */ + +public class ExternalScriptContext { + + private static final Logger log = LoggerFactory.getLogger(ExternalScriptContext.class); + + private final Map contextVariables = new HashMap<>(); + + protected HttpServletRequest httpRequest; + protected final HttpServletResponse httpResponse; + + public ExternalScriptContext(HttpServletRequest httpRequest) { + this(httpRequest, null); + } + + public ExternalScriptContext(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { + this.httpRequest = httpRequest; + this.httpResponse = httpResponse; + + if (this.httpRequest == null) { + FacesContext facesContext = FacesContext.getCurrentInstance(); + if (facesContext != null) { + ExternalContext extCtx = facesContext.getExternalContext(); + if (extCtx != null) { + this.httpRequest = (HttpServletRequest) extCtx.getRequest(); + } + } + } + } + + public Logger getLog() { + return log; + } + + public HttpServletRequest getHttpRequest() { + return httpRequest; + } + + public HttpServletResponse getHttpResponse() { + return httpResponse; + } + + public String getIpAddress() { + return httpRequest != null ? httpRequest.getRemoteAddr() : ""; + } + + public Map getContextVariables() { + return contextVariables; + } +} diff --git a/oxService/src/main/java/org/gluu/service/external/context/PersistenceExternalContext.java b/oxService/src/main/java/org/gluu/service/external/context/PersistenceExternalContext.java new file mode 100644 index 00000000..b23e772b --- /dev/null +++ b/oxService/src/main/java/org/gluu/service/external/context/PersistenceExternalContext.java @@ -0,0 +1,28 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2020, Gluu + */ + +package org.gluu.service.external.context; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Holds object required in persistence scope custom scripts + * + * @author Yuriy Movchan Date: 06/05/2020 + */ + +public class PersistenceExternalContext extends ExternalScriptContext { + + public PersistenceExternalContext(HttpServletRequest httpRequest) { + super(httpRequest, null); + } + + public PersistenceExternalContext(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { + super(httpRequest, httpResponse); + } + +} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/extension/PersistenceExtension.java b/persistence-core/src/main/java/org/gluu/persist/exception/extension/PersistenceExtension.java new file mode 100644 index 00000000..97c8dc10 --- /dev/null +++ b/persistence-core/src/main/java/org/gluu/persist/exception/extension/PersistenceExtension.java @@ -0,0 +1,22 @@ +package org.gluu.persist.exception.extension; + +import java.util.Map; + +import org.gluu.model.SimpleCustomProperty; + +/** + * Base interface for persistence script + * + * @author Yuriy Movchan Date: 06/04/2020 + */ +public interface PersistenceExtension { + + void onBeforeCreate(Object context, Map configurationAttributes); + void onAfterCreate(Object context, Map configurationAttributes); + void onBeforeDestroy(Object context, Map configurationAttributes); + void onAfterDestroy(Object context, Map configurationAttributes); + + String createHashedPassword(String credential); + boolean compareHashedPasswords(String credential, String storedCredential); + +} diff --git a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java index 948b9ed7..63549ced 100644 --- a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java @@ -37,10 +37,12 @@ import org.gluu.persist.exception.EntryPersistenceException; import org.gluu.persist.exception.InvalidArgumentException; import org.gluu.persist.exception.MappingException; +import org.gluu.persist.exception.extension.PersistenceExtension; import org.gluu.persist.model.AttributeData; import org.gluu.persist.model.AttributeDataModification; import org.gluu.persist.model.AttributeDataModification.AttributeModificationType; import org.gluu.persist.model.SearchScope; +import org.gluu.persist.operation.PersistenceOperationService; import org.gluu.persist.reflect.property.Getter; import org.gluu.persist.reflect.property.PropertyAnnotation; import org.gluu.persist.reflect.property.Setter; @@ -94,6 +96,9 @@ public abstract class BaseEntryManager implements PersistenceEntryManager { protected static final Comparator LINE_LENGHT_COMPARATOR = new LineLenghtComparator(false); protected static final int DEFAULT_PAGINATION_SIZE = 100; + + protected PersistenceOperationService operationService = null; + protected PersistenceExtension persistenceExtension = null; @Override public void persist(Object entry) { @@ -1968,6 +1973,14 @@ protected boolean isMultiValued(Class parameterType) { protected abstract String encodeTime(Date date); + public void setPersistenceExtension(PersistenceExtension persistenceExtension) { + this.persistenceExtension = persistenceExtension; + + if (this.operationService != null) { + this.operationService.setPersistenceExtension(persistenceExtension); + } + } + protected static final class PropertyComparator implements Comparator, Serializable { private static final long serialVersionUID = 574848841116711467L; diff --git a/persistence-core/src/main/java/org/gluu/persist/operation/PersistenceOperationService.java b/persistence-core/src/main/java/org/gluu/persist/operation/PersistenceOperationService.java index 749109cd..b41979de 100644 --- a/persistence-core/src/main/java/org/gluu/persist/operation/PersistenceOperationService.java +++ b/persistence-core/src/main/java/org/gluu/persist/operation/PersistenceOperationService.java @@ -6,6 +6,8 @@ package org.gluu.persist.operation; +import org.gluu.persist.exception.extension.PersistenceExtension; + /** * Base interface for Operation Service * @@ -15,4 +17,6 @@ public interface PersistenceOperationService { boolean isConnected(); + public void setPersistenceExtension(PersistenceExtension persistenceExtension); + } diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java index 3764a855..e32c911e 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java @@ -26,7 +26,6 @@ import org.gluu.persist.couchbase.model.SearchReturnDataType; import org.gluu.persist.couchbase.operation.CouchbaseOperationService; import org.gluu.persist.couchbase.operation.impl.CouchbaseConnectionProvider; -import org.gluu.persist.couchbase.operation.impl.CouchbaseOperationsServiceImpl; import org.gluu.persist.event.DeleteNotifier; import org.gluu.persist.exception.AuthenticationException; import org.gluu.persist.exception.EntryDeleteException; @@ -79,10 +78,9 @@ public class CouchbaseEntryManager extends BaseEntryManager implements Serializa private final CouchbaseFilterConverter FILTER_CONVERTER; private static final GenericKeyConverter KEY_CONVERTER = new GenericKeyConverter(); - private CouchbaseOperationsServiceImpl operationService; private List subscribers; - protected CouchbaseEntryManager(CouchbaseOperationsServiceImpl operationService) { + protected CouchbaseEntryManager(CouchbaseOperationService operationService) { this.operationService = operationService; this.FILTER_CONVERTER = new CouchbaseFilterConverter(this); subscribers = new LinkedList(); @@ -94,11 +92,11 @@ public boolean destroy() { return true; } - return this.operationService.destroy(); + return ((CouchbaseOperationService) this.operationService).destroy(); } - public CouchbaseOperationsServiceImpl getOperationService() { - return operationService; + public CouchbaseOperationService getOperationService() { + return (CouchbaseOperationService) operationService; } @Override @@ -187,7 +185,7 @@ protected void persist(String dn, List attributes, Integer expira // Process userPassword if (StringHelper.equals(CouchbaseOperationService.USER_PASSWORD, attributeName)) { - realValues = operationService.createStoragePassword(StringHelper.toStringArray(attributeValues)); + realValues = getOperationService().createStoragePassword(StringHelper.toStringArray(attributeValues)); } escapeValues(realValues); @@ -203,7 +201,7 @@ protected void persist(String dn, List attributes, Integer expira // Persist entry try { - boolean result = operationService.addEntry(toCouchbaseKey(dn).getKey(), jsonObject, expiration); + boolean result = getOperationService().addEntry(toCouchbaseKey(dn).getKey(), jsonObject, expiration); if (!result) { throw new EntryPersistenceException(String.format("Failed to persist entry: %s", dn)); } @@ -254,7 +252,7 @@ public void merge(String dn, List attributeDataModifi } if (modifications.size() > 0) { - boolean result = operationService.updateEntry(toCouchbaseKey(dn).getKey(), modifications, expirationValue); + boolean result = getOperationService().updateEntry(toCouchbaseKey(dn).getKey(), modifications, expirationValue); if (!result) { throw new EntryPersistenceException(String.format("Failed to update entry: %s", dn)); } @@ -271,7 +269,7 @@ public void remove(String dn) { for (DeleteNotifier subscriber : subscribers) { subscriber.onBeforeRemove(dn); } - operationService.delete(toCouchbaseKey(dn).getKey()); + getOperationService().delete(toCouchbaseKey(dn).getKey()); for (DeleteNotifier subscriber : subscribers) { subscriber.onAfterRemove(dn); } @@ -286,7 +284,7 @@ public void removeRecursively(String dn) { for (DeleteNotifier subscriber : subscribers) { subscriber.onBeforeRemove(dn); } - operationService.deleteRecursively(toCouchbaseKey(dn).getKey()); + getOperationService().deleteRecursively(toCouchbaseKey(dn).getKey()); for (DeleteNotifier subscriber : subscribers) { subscriber.onAfterRemove(dn); } @@ -339,7 +337,7 @@ protected int removeImpl(String dn, Class entryClass, Filter filter, int } try { - int processed = operationService.delete(keyWithInum.getKey(), getScanConsistency(convertedExpression), convertedExpression.expression(), count); + int processed = getOperationService().delete(keyWithInum.getKey(), getScanConsistency(convertedExpression), convertedExpression.expression(), count); return processed; } catch (Exception ex) { @@ -353,7 +351,7 @@ protected List find(String dn, Map pr // Load entry ParsedKey keyWithInum = toCouchbaseKey(dn); ScanConsistency scanConsistency = getScanConsistency(keyWithInum.getName(), propertiesAnnotationsMap); - JsonObject entry = operationService.lookup(keyWithInum.getKey(), scanConsistency, toInternalAttributes(ldapReturnAttributes)); + JsonObject entry = getOperationService().lookup(keyWithInum.getKey(), scanConsistency, toInternalAttributes(ldapReturnAttributes)); List result = getAttributeDataList(entry); if (result != null) { return result; @@ -520,7 +518,7 @@ protected boolean contains(String baseDN, Class entryClass, List PagedResult searchImpl(String key, ScanConsistency scanConsistency, Expression expression, SearchScope scope, String[] attributes, Sort[] orderBy, CouchbaseBatchOperationWraper batchOperationWraper, SearchReturnDataType returnDataType, int start, int count, int pageSize) throws SearchException { - return operationService.search(key, scanConsistency, expression, scope, toInternalAttributes(attributes), orderBy, batchOperationWraper, returnDataType, start, count, pageSize); + return getOperationService().search(key, scanConsistency, expression, scope, toInternalAttributes(attributes), orderBy, batchOperationWraper, returnDataType, start, count, pageSize); } protected List createEntities(String baseDN, Class entryClass, PagedResult searchResult) { @@ -541,7 +539,7 @@ protected List createEntities(Class entryClass, List boolean authenticate(String baseDN, Class entryClass, String userN @Override public boolean authenticate(String bindDn, String password) { try { - return operationService.authenticate(toCouchbaseKey(bindDn).getKey(), escapeValue(password)); + return getOperationService().authenticate(toCouchbaseKey(bindDn).getKey(), escapeValue(password)); } catch (Exception ex) { throw new AuthenticationException(String.format("Failed to authenticate DN: %s", bindDn), ex); } @@ -721,7 +719,7 @@ private MutationSpec createModification(final Mutation type, final String attrib Object[] realValues = attributeValues; if (StringHelper.equals(CouchbaseOperationService.USER_PASSWORD, realAttributeName)) { - realValues = operationService.createStoragePassword(StringHelper.toStringArray(attributeValues)); + realValues = getOperationService().createStoragePassword(StringHelper.toStringArray(attributeValues)); } escapeValues(realValues); @@ -765,7 +763,7 @@ public List exportEntry(String dn) { try { // Load entry ParsedKey keyWithInum = toCouchbaseKey(dn); - JsonObject entry = operationService.lookup(keyWithInum.getKey(), null); + JsonObject entry = getOperationService().lookup(keyWithInum.getKey(), null); List result = getAttributeDataList(entry); if (result != null) { @@ -972,7 +970,7 @@ private void unescapeValues(Object[] realValues) { public String toInternalAttribute(String attributeName) { return attributeName; -// if (operationService.isDisableAttributeMapping()) { +// if (getOperationService().isDisableAttributeMapping()) { // return attributeName; // } // @@ -981,7 +979,7 @@ public String toInternalAttribute(String attributeName) { public String[] toInternalAttributes(String[] attributeNames) { return attributeNames; -// if (operationService.isDisableAttributeMapping() || ArrayHelper.isEmpty(attributeNames)) { +// if (getOperationService().isDisableAttributeMapping() || ArrayHelper.isEmpty(attributeNames)) { // return attributeNames; // } // @@ -996,7 +994,7 @@ public String[] toInternalAttributes(String[] attributeNames) { public String fromInternalAttribute(String internalAttributeName) { return internalAttributeName; -// if (operationService.isDisableAttributeMapping()) { +// if (getOperationService().isDisableAttributeMapping()) { // return internalAttributeName; // } // @@ -1005,7 +1003,7 @@ public String fromInternalAttribute(String internalAttributeName) { public String[] fromInternalAttributes(String[] internalAttributeNames) { return internalAttributeNames; -// if (operationService.isDisableAttributeMapping() || ArrayHelper.isEmpty(internalAttributeNames)) { +// if (getOperationService().isDisableAttributeMapping() || ArrayHelper.isEmpty(internalAttributeNames)) { // return internalAttributeNames; // } // diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManagerFactory.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManagerFactory.java index bdc90cfd..64167980 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManagerFactory.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManagerFactory.java @@ -15,7 +15,7 @@ import org.gluu.persist.PersistenceEntryManagerFactory; import org.gluu.persist.couchbase.operation.impl.CouchbaseConnectionProvider; -import org.gluu.persist.couchbase.operation.impl.CouchbaseOperationsServiceImpl; +import org.gluu.persist.couchbase.operation.impl.CouchbaseOperationServiceImpl; import org.gluu.persist.exception.operation.ConfigurationException; import org.gluu.persist.service.BaseFactoryService; import org.gluu.util.PropertiesHelper; @@ -131,7 +131,7 @@ public CouchbaseEntryManager createEntryManager(Properties conf) { } LOG.debug("Created connectionProvider '{}' with code '{}'", connectionProvider, connectionProvider.getCreationResultCode()); - CouchbaseEntryManager couchbaseEntryManager = new CouchbaseEntryManager(new CouchbaseOperationsServiceImpl(entryManagerConf, connectionProvider)); + CouchbaseEntryManager couchbaseEntryManager = new CouchbaseEntryManager(new CouchbaseOperationServiceImpl(entryManagerConf, connectionProvider)); LOG.info("Created CouchbaseEntryManager: {}", couchbaseEntryManager.getOperationService()); return couchbaseEntryManager; diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationsServiceImpl.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java similarity index 96% rename from persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationsServiceImpl.java rename to persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java index 189c1f91..0e91a54c 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationsServiceImpl.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java @@ -22,6 +22,7 @@ import org.gluu.persist.couchbase.model.SearchReturnDataType; import org.gluu.persist.couchbase.operation.CouchbaseOperationService; import org.gluu.persist.couchbase.operation.watch.OperationDurationUtil; +import org.gluu.persist.exception.extension.PersistenceExtension; import org.gluu.persist.exception.operation.DeleteException; import org.gluu.persist.exception.operation.DuplicateEntryException; import org.gluu.persist.exception.operation.EntryNotFoundException; @@ -66,7 +67,7 @@ * * @author Yuriy Movchan Date: 05/10/2018 */ -public class CouchbaseOperationsServiceImpl implements CouchbaseOperationService { +public class CouchbaseOperationServiceImpl implements CouchbaseOperationService { private static final Logger LOG = LoggerFactory.getLogger(CouchbaseConnectionProvider.class); @@ -80,12 +81,14 @@ public class CouchbaseOperationsServiceImpl implements CouchbaseOperationService private boolean enableScopeSupport = false; private boolean disableAttributeMapping = false; + private PersistenceExtension persistenceExtension; + @SuppressWarnings("unused") - private CouchbaseOperationsServiceImpl() { + private CouchbaseOperationServiceImpl() { } - public CouchbaseOperationsServiceImpl(Properties props, CouchbaseConnectionProvider connectionProvider) { + public CouchbaseOperationServiceImpl(Properties props, CouchbaseConnectionProvider connectionProvider) { this.props = props; this.connectionProvider = connectionProvider; init(); @@ -145,7 +148,11 @@ private boolean authenticateImpl(final String key, final String password) throws } if (userPassword != null) { - result = PasswordEncryptionHelper.compareCredentials(password.getBytes(), userPassword.getBytes()); + if (persistenceExtension == null) { + result = PasswordEncryptionHelper.compareCredentials(password.getBytes(), userPassword.getBytes()); + } else { + result = persistenceExtension.compareHashedPasswords(password, userPassword); + } } } @@ -656,7 +663,11 @@ public String[] createStoragePassword(String[] passwords) { String[] results = new String[passwords.length]; for (int i = 0; i < passwords.length; i++) { - results[i] = PasswordEncryptionHelper.createStoragePassword(passwords[i], connectionProvider.getPasswordEncryptionMethod()); + if (persistenceExtension == null) { + results[i] = PasswordEncryptionHelper.createStoragePassword(passwords[i], connectionProvider.getPasswordEncryptionMethod()); + } else { + results[i] = persistenceExtension.createHashedPassword(passwords[i]); + } } return results; @@ -731,4 +742,9 @@ protected String getScanAttemptLogInfo(ScanConsistency scanConsistency, ScanCons return attemptInfo; } + @Override + public void setPersistenceExtension(PersistenceExtension persistenceExtension) { + this.persistenceExtension = persistenceExtension; + } + } diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridPersistenceOperationService.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridPersistenceOperationService.java index efef1c98..4578e9a4 100644 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridPersistenceOperationService.java +++ b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridPersistenceOperationService.java @@ -2,6 +2,7 @@ import java.util.List; +import org.gluu.persist.exception.extension.PersistenceExtension; import org.gluu.persist.operation.PersistenceOperationService; /** @@ -32,4 +33,11 @@ public List getPersistenceOperationServices() { return persistenceOperationServices; } + @Override + public void setPersistenceExtension(PersistenceExtension persistenceExtension) { + for(PersistenceOperationService persistenceOperationService : persistenceOperationServices) { + persistenceOperationService.setPersistenceExtension(persistenceExtension); + } + } + } diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java index 598540d4..63defcfd 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java @@ -32,7 +32,7 @@ import org.gluu.persist.exception.operation.SearchException; import org.gluu.persist.exception.operation.SearchScopeException; import org.gluu.persist.impl.BaseEntryManager; -import org.gluu.persist.ldap.operation.impl.LdapOperationsServiceImpl; +import org.gluu.persist.ldap.operation.impl.LdapOperationServiceImpl; import org.gluu.persist.model.AttributeData; import org.gluu.persist.model.AttributeDataModification; import org.gluu.persist.model.AttributeDataModification.AttributeModificationType; @@ -71,15 +71,15 @@ public class LdapEntryManager extends BaseEntryManager implements Serializable { private static final LdapFilterConverter LDAP_FILTER_CONVERTER = new LdapFilterConverter(); private static final LdapSearchScopeConverter LDAP_SEARCH_SCOPE_CONVERTER = new LdapSearchScopeConverter(); - private LdapOperationsServiceImpl operationService; + private LdapOperationServiceImpl operationService; private List subscribers; public LdapEntryManager() { } - public LdapEntryManager(LdapOperationsServiceImpl operationService) { + public LdapEntryManager(LdapOperationServiceImpl operationService) { this.operationService = operationService; - subscribers = new LinkedList(); + this.subscribers = new LinkedList(); } @Override @@ -91,7 +91,7 @@ public boolean destroy() { return this.operationService.destroy(); } - public LdapOperationsServiceImpl getOperationService() { + public LdapOperationServiceImpl getOperationService() { return operationService; } @@ -337,7 +337,7 @@ public int remove(String baseDN, Class entryClass, Filter filter, int cou LdapBatchOperationWraper batchOperationWraper = new LdapBatchOperationWraper(batchOperation, this, entryClass, propertiesAnnotations); searchResult = this.operationService.search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(SearchScope.SUB), batchOperationWraper, - 0, 100, count, null, LdapOperationsServiceImpl.DN); + 0, 100, count, null, LdapOperationServiceImpl.DN); } catch (Exception ex) { throw new EntryDeleteException(String.format("Failed to delete entries with baseDN: %s, filter: %s", baseDN, searchFilter), ex); @@ -713,7 +713,7 @@ public boolean authenticate(String baseDN, Class entryClass, String userN String[] objectClasses = getTypeObjectClasses(entryClass); // Find entries - Filter searchFilter = Filter.createEqualityFilter(LdapOperationsServiceImpl.UID, userName); + Filter searchFilter = Filter.createEqualityFilter(LdapOperationServiceImpl.UID, userName); if (objectClasses.length > 0) { searchFilter = addObjectClassFilter(searchFilter, objectClasses); } diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManagerFactory.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManagerFactory.java index 02deca03..dcb7f507 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManagerFactory.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManagerFactory.java @@ -9,7 +9,7 @@ import org.gluu.persist.exception.operation.ConfigurationException; import org.gluu.persist.ldap.operation.impl.LdapAuthConnectionProvider; import org.gluu.persist.ldap.operation.impl.LdapConnectionProvider; -import org.gluu.persist.ldap.operation.impl.LdapOperationsServiceImpl; +import org.gluu.persist.ldap.operation.impl.LdapOperationServiceImpl; import org.gluu.persist.service.BaseFactoryService; import org.gluu.util.PropertiesHelper; import org.slf4j.Logger; @@ -59,7 +59,7 @@ public LdapEntryManager createEntryManager(Properties conf) { } LOG.debug("Created bindConnectionProvider '{}' with code '{}'", bindConnectionProvider, bindConnectionProvider.getCreationResultCode()); - LdapEntryManager ldapEntryManager = new LdapEntryManager(new LdapOperationsServiceImpl(connectionProvider, bindConnectionProvider)); + LdapEntryManager ldapEntryManager = new LdapEntryManager(new LdapOperationServiceImpl(connectionProvider, bindConnectionProvider)); LOG.info("Created LdapEntryManager: {}", ldapEntryManager.getOperationService()); return ldapEntryManager; diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationsServiceImpl.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java similarity index 98% rename from persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationsServiceImpl.java rename to persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java index 09003c8a..8a5f7e6c 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationsServiceImpl.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java @@ -20,6 +20,7 @@ import org.apache.commons.lang.StringUtils; import org.gluu.persist.exception.MappingException; +import org.gluu.persist.exception.extension.PersistenceExtension; import org.gluu.persist.exception.operation.ConnectionException; import org.gluu.persist.exception.operation.DuplicateEntryException; import org.gluu.persist.exception.operation.SearchException; @@ -74,9 +75,9 @@ * @author Pankaj * @author Yuriy Movchan */ -public class LdapOperationsServiceImpl implements LdapOperationService { +public class LdapOperationServiceImpl implements LdapOperationService { - private static final Logger LOG = LoggerFactory.getLogger(LdapOperationsServiceImpl.class); + private static final Logger LOG = LoggerFactory.getLogger(LdapOperationServiceImpl.class); public static final String DN = "dn"; public static final String UID = "uid"; @@ -87,6 +88,8 @@ public class LdapOperationsServiceImpl implements LdapOperationService { private LdapConnectionProvider connectionProvider; private LdapConnectionProvider bindConnectionProvider; + private PersistenceExtension persistenceExtension; + private static Map> ATTRIBUTE_DATA_TYPES = new HashMap>(); private static final Map> OID_SYNTAX_CLASS_MAPPING; @@ -109,15 +112,15 @@ public class LdapOperationsServiceImpl implements LdapOperationService { } @SuppressWarnings("unused") - private LdapOperationsServiceImpl() { + private LdapOperationServiceImpl() { } - public LdapOperationsServiceImpl(LdapConnectionProvider connectionProvider) { + public LdapOperationServiceImpl(LdapConnectionProvider connectionProvider) { this(connectionProvider, null); populateAttributeDataTypesMapping(getSubschemaSubentry()); } - public LdapOperationsServiceImpl(LdapConnectionProvider connectionProvider, LdapConnectionProvider bindConnectionProvider) { + public LdapOperationServiceImpl(LdapConnectionProvider connectionProvider, LdapConnectionProvider bindConnectionProvider) { this.connectionProvider = connectionProvider; this.bindConnectionProvider = bindConnectionProvider; populateAttributeDataTypesMapping(getSubschemaSubentry()); @@ -717,7 +720,7 @@ public boolean addEntry(String dn, Collection attributes) throws Dupl private boolean addEntryImpl(String dn, Collection attributes) throws DuplicateEntryException { try { LDAPResult result = getConnectionPool().add(dn, attributes); - if (result.getResultCode().getName().equalsIgnoreCase(LdapOperationsServiceImpl.SUCCESS)) { + if (result.getResultCode().getName().equalsIgnoreCase(LdapOperationServiceImpl.SUCCESS)) { return true; } } catch (final LDAPException ex) { @@ -754,9 +757,9 @@ protected boolean updateEntry(String dn, Collection attrs) throws Dup for (Attribute attribute : attrs) { String attributeName = attribute.getName(); String attributeValue = attribute.getValue(); - if (attributeName.equalsIgnoreCase(LdapOperationsServiceImpl.OBJECT_CLASS) - || attributeName.equalsIgnoreCase(LdapOperationsServiceImpl.DN) - || attributeName.equalsIgnoreCase(LdapOperationsServiceImpl.USER_PASSWORD)) { + if (attributeName.equalsIgnoreCase(LdapOperationServiceImpl.OBJECT_CLASS) + || attributeName.equalsIgnoreCase(LdapOperationServiceImpl.DN) + || attributeName.equalsIgnoreCase(LdapOperationServiceImpl.USER_PASSWORD)) { continue; } else { if (attributeValue != null) { @@ -1169,7 +1172,12 @@ public int compare(T entry1, T entry2, String attributeName) { public boolean isConnected() { return connectionProvider.isConnected(); } - + + @Override + public void setPersistenceExtension(PersistenceExtension persistenceExtension) { + this.persistenceExtension = persistenceExtension; + } + private class SimplePagedResponse { private ASN1OctetString cookie; From 5d90e8b0a97b8b262dc1e6bebf273b34214d4e41 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 5 Jun 2020 19:48:56 +0300 Subject: [PATCH 170/362] Add new persistence custom script #194 --- .../script/type/persistence/PersistenceType.java | 8 ++++++++ .../external/ExternalPersistenceExtension.java | 12 ++++++++++++ .../context/PersistenceExternalContext.java | 11 ++--------- .../exception/extension/PersistenceExtension.java | 9 --------- .../operation/CouchbaseOperationService.java | 10 +++++----- .../gluu/persist/ldap/impl/LdapEntryManager.java | 5 +++-- .../ldap/operation/LdapOperationService.java | 6 ++++++ .../operation/impl/LdapOperationServiceImpl.java | 14 ++++---------- 8 files changed, 40 insertions(+), 35 deletions(-) diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java index a9121144..571d08ed 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java @@ -6,6 +6,9 @@ package org.gluu.model.custom.script.type.persistence; +import java.util.Map; + +import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.type.BaseExternalType; import org.gluu.persist.exception.extension.PersistenceExtension; @@ -16,4 +19,9 @@ */ public interface PersistenceType extends BaseExternalType, PersistenceExtension { + void onBeforeCreate(Object context, Map configurationAttributes); + void onAfterCreate(Object context, Map configurationAttributes); + void onBeforeDestroy(Object context, Map configurationAttributes); + void onAfterDestroy(Object context, Map configurationAttributes); + } diff --git a/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtension.java b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtension.java index 14d7551b..2f3b187a 100644 --- a/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtension.java +++ b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtension.java @@ -67,4 +67,16 @@ public void executeExternalOnBeforeDestroyMethod(CustomScriptConfiguration custo } } + public void executeExternalOnAfterDestroyMethod(CustomScriptConfiguration customScriptConfiguration, PersistenceExternalContext context) { + try { + log.debug("Executing python 'onAfterDestroy' method"); + PersistenceType persistenceType = (PersistenceType) customScriptConfiguration.getExternalType(); + Map configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); + persistenceType.onAfterDestroy(context, configurationAttributes); + } catch (Exception ex) { + log.error(ex.getMessage(), ex); + saveScriptError(customScriptConfiguration.getCustomScript(), ex); + } + } + } diff --git a/oxService/src/main/java/org/gluu/service/external/context/PersistenceExternalContext.java b/oxService/src/main/java/org/gluu/service/external/context/PersistenceExternalContext.java index b23e772b..2785e971 100644 --- a/oxService/src/main/java/org/gluu/service/external/context/PersistenceExternalContext.java +++ b/oxService/src/main/java/org/gluu/service/external/context/PersistenceExternalContext.java @@ -6,9 +6,6 @@ package org.gluu.service.external.context; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - /** * Holds object required in persistence scope custom scripts * @@ -17,12 +14,8 @@ public class PersistenceExternalContext extends ExternalScriptContext { - public PersistenceExternalContext(HttpServletRequest httpRequest) { - super(httpRequest, null); - } - - public PersistenceExternalContext(HttpServletRequest httpRequest, HttpServletResponse httpResponse) { - super(httpRequest, httpResponse); + public PersistenceExternalContext() { + super(null, null); } } diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/extension/PersistenceExtension.java b/persistence-core/src/main/java/org/gluu/persist/exception/extension/PersistenceExtension.java index 97c8dc10..4ee11b27 100644 --- a/persistence-core/src/main/java/org/gluu/persist/exception/extension/PersistenceExtension.java +++ b/persistence-core/src/main/java/org/gluu/persist/exception/extension/PersistenceExtension.java @@ -1,20 +1,11 @@ package org.gluu.persist.exception.extension; -import java.util.Map; - -import org.gluu.model.SimpleCustomProperty; - /** * Base interface for persistence script * * @author Yuriy Movchan Date: 06/04/2020 */ public interface PersistenceExtension { - - void onBeforeCreate(Object context, Map configurationAttributes); - void onAfterCreate(Object context, Map configurationAttributes); - void onBeforeDestroy(Object context, Map configurationAttributes); - void onAfterDestroy(Object context, Map configurationAttributes); String createHashedPassword(String credential); boolean compareHashedPasswords(String credential, String storedCredential); diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java index 64ffedb2..755ab0f8 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java @@ -35,12 +35,12 @@ */ public interface CouchbaseOperationService extends PersistenceOperationService { - String DN = "dn"; - String UID = "uid"; - String USER_PASSWORD = "userPassword"; - String OBJECT_CLASS = "objectClass"; + static String DN = "dn"; + static String UID = "uid"; + static String USER_PASSWORD = "userPassword"; + static String OBJECT_CLASS = "objectClass"; - String META_DOC_ID = "meta_doc_id"; + static String META_DOC_ID = "meta_doc_id"; CouchbaseConnectionProvider getConnectionProvider(); diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java index 63defcfd..0d0f7e41 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java @@ -32,6 +32,7 @@ import org.gluu.persist.exception.operation.SearchException; import org.gluu.persist.exception.operation.SearchScopeException; import org.gluu.persist.impl.BaseEntryManager; +import org.gluu.persist.ldap.operation.LdapOperationService; import org.gluu.persist.ldap.operation.impl.LdapOperationServiceImpl; import org.gluu.persist.model.AttributeData; import org.gluu.persist.model.AttributeDataModification; @@ -337,7 +338,7 @@ public int remove(String baseDN, Class entryClass, Filter filter, int cou LdapBatchOperationWraper batchOperationWraper = new LdapBatchOperationWraper(batchOperation, this, entryClass, propertiesAnnotations); searchResult = this.operationService.search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(SearchScope.SUB), batchOperationWraper, - 0, 100, count, null, LdapOperationServiceImpl.DN); + 0, 100, count, null, LdapOperationService.DN); } catch (Exception ex) { throw new EntryDeleteException(String.format("Failed to delete entries with baseDN: %s, filter: %s", baseDN, searchFilter), ex); @@ -713,7 +714,7 @@ public boolean authenticate(String baseDN, Class entryClass, String userN String[] objectClasses = getTypeObjectClasses(entryClass); // Find entries - Filter searchFilter = Filter.createEqualityFilter(LdapOperationServiceImpl.UID, userName); + Filter searchFilter = Filter.createEqualityFilter(LdapOperationService.UID, userName); if (objectClasses.length > 0) { searchFilter = addObjectClassFilter(searchFilter, objectClasses); } diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/LdapOperationService.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/LdapOperationService.java index 61b08b70..8449c967 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/LdapOperationService.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/LdapOperationService.java @@ -26,6 +26,12 @@ public interface LdapOperationService extends PersistenceOperationService { + static final String DN = "dn"; + static final String UID = "uid"; + static final String SUCCESS = "success"; + static final String USER_PASSWORD = "userPassword"; + static final String OBJECT_CLASS = "objectClass"; + LdapConnectionProvider getConnectionProvider(); void setConnectionProvider(LdapConnectionProvider connectionProvider); diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java index 8a5f7e6c..f06434d4 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java @@ -79,12 +79,6 @@ public class LdapOperationServiceImpl implements LdapOperationService { private static final Logger LOG = LoggerFactory.getLogger(LdapOperationServiceImpl.class); - public static final String DN = "dn"; - public static final String UID = "uid"; - public static final String SUCCESS = "success"; - public static final String USER_PASSWORD = "userPassword"; - public static final String OBJECT_CLASS = "objectClass"; - private LdapConnectionProvider connectionProvider; private LdapConnectionProvider bindConnectionProvider; @@ -720,7 +714,7 @@ public boolean addEntry(String dn, Collection attributes) throws Dupl private boolean addEntryImpl(String dn, Collection attributes) throws DuplicateEntryException { try { LDAPResult result = getConnectionPool().add(dn, attributes); - if (result.getResultCode().getName().equalsIgnoreCase(LdapOperationServiceImpl.SUCCESS)) { + if (result.getResultCode().getName().equalsIgnoreCase(SUCCESS)) { return true; } } catch (final LDAPException ex) { @@ -757,9 +751,9 @@ protected boolean updateEntry(String dn, Collection attrs) throws Dup for (Attribute attribute : attrs) { String attributeName = attribute.getName(); String attributeValue = attribute.getValue(); - if (attributeName.equalsIgnoreCase(LdapOperationServiceImpl.OBJECT_CLASS) - || attributeName.equalsIgnoreCase(LdapOperationServiceImpl.DN) - || attributeName.equalsIgnoreCase(LdapOperationServiceImpl.USER_PASSWORD)) { + if (attributeName.equalsIgnoreCase(OBJECT_CLASS) + || attributeName.equalsIgnoreCase(DN) + || attributeName.equalsIgnoreCase(USER_PASSWORD)) { continue; } else { if (attributeValue != null) { From 864be49f9f27fd182c0a4fa3097800465cd02913 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 9 Jun 2020 15:46:16 +0300 Subject: [PATCH 171/362] Add new persistence custom script oxAuth oxCore #194 --- .../DummyDynamicPeristenceType.java | 8 -- .../type/persistence/PersistenceType.java | 2 - .../custom/script/CustomScriptManager.java | 8 +- ... ExternalPersistenceExtensionService.java} | 56 +++++++++----- .../context/PersistenceExternalContext.java | 26 ++++++- .../gluu/persist/PersistenceEntryManager.java | 3 + .../impl/CouchbaseOperationServiceImpl.java | 2 +- .../persist/ldap/impl/LdapEntryManager.java | 57 +++++++------- .../impl/LdapOperationServiceImpl.java | 76 ++++++++++++++++--- 9 files changed, 163 insertions(+), 75 deletions(-) rename oxService/src/main/java/org/gluu/service/external/{ExternalPersistenceExtension.java => ExternalPersistenceExtensionService.java} (57%) diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java index 8365051b..79cab2b3 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java @@ -35,18 +35,10 @@ public int getApiVersion() { return 1; } - @Override - public void onBeforeCreate(Object context, Map configurationAttributes) { - } - @Override public void onAfterCreate(Object context, Map configurationAttributes) { } - @Override - public void onBeforeDestroy(Object context, Map configurationAttributes) { - } - @Override public void onAfterDestroy(Object context, Map configurationAttributes) { } diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java index 571d08ed..692c2239 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java @@ -19,9 +19,7 @@ */ public interface PersistenceType extends BaseExternalType, PersistenceExtension { - void onBeforeCreate(Object context, Map configurationAttributes); void onAfterCreate(Object context, Map configurationAttributes); - void onBeforeDestroy(Object context, Map configurationAttributes); void onAfterDestroy(Object context, Map configurationAttributes); } diff --git a/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java index e0a67ac9..f052a54d 100644 --- a/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java +++ b/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java @@ -508,8 +508,12 @@ public CustomScriptConfiguration getCustomScriptConfigurationByInum(String inum) public List getCustomScriptConfigurationsByScriptType( CustomScriptType customScriptType) { - return new ArrayList( - this.customScriptConfigurationsByScriptType.get(customScriptType)); + List tmpCustomScriptConfigurationsByScriptType = this.customScriptConfigurationsByScriptType + .get(customScriptType); + if (tmpCustomScriptConfigurationsByScriptType == null) { + tmpCustomScriptConfigurationsByScriptType = new ArrayList(0); + } + return new ArrayList(tmpCustomScriptConfigurationsByScriptType); } public List getCustomScriptConfigurations() { diff --git a/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtension.java b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java similarity index 57% rename from oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtension.java rename to oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java index 2f3b187a..7f02cc61 100644 --- a/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtension.java +++ b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java @@ -6,14 +6,19 @@ package org.gluu.service.external; +import java.util.Iterator; import java.util.Map; import javax.enterprise.context.ApplicationScoped; +import javax.enterprise.inject.Instance; +import javax.inject.Inject; import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.CustomScriptType; import org.gluu.model.custom.script.conf.CustomScriptConfiguration; import org.gluu.model.custom.script.type.persistence.PersistenceType; +import org.gluu.persist.PersistenceEntryManager; +import org.gluu.persist.exception.extension.PersistenceExtension; import org.gluu.service.custom.script.ExternalScriptService; import org.gluu.service.external.context.PersistenceExternalContext; @@ -23,24 +28,41 @@ * @author Yuriy Movchan Date: 06/04/2020 */ @ApplicationScoped -public class ExternalPersistenceExtension extends ExternalScriptService { +public class ExternalPersistenceExtensionService extends ExternalScriptService { private static final long serialVersionUID = 5466361778036208685L; - public ExternalPersistenceExtension() { + @Inject + private Instance persistenceMetricEntryManagerInstance; + + public ExternalPersistenceExtensionService() { super(CustomScriptType.PERSISTENCE_EXTENSION); } - public void executeExternalOnBeforeCreateMethod(CustomScriptConfiguration customScriptConfiguration, PersistenceExternalContext context) { - try { - log.debug("Executing python 'onBeforeCreate' method"); - PersistenceType persistenceType = (PersistenceType) customScriptConfiguration.getExternalType(); - Map configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); - persistenceType.onBeforeCreate(context, configurationAttributes); - } catch (Exception ex) { - log.error(ex.getMessage(), ex); - saveScriptError(customScriptConfiguration.getCustomScript(), ex); + @Override + protected void reloadExternal() { + PersistenceExtension persistenceExtension = null; + if (isEnabled()) { + persistenceExtension = (PersistenceExtension) this.defaultExternalCustomScript.getExternalType(); + } + + for (Iterator it = persistenceMetricEntryManagerInstance.iterator(); it.hasNext();) { + PersistenceEntryManager persistenceEntryManager = it.next(); + persistenceEntryManager.setPersistenceExtension(persistenceExtension); + } + } + + public void setPersistenceExtension(PersistenceEntryManager persistenceEntryManager) { + PersistenceExtension persistenceExtension = null; + if (isEnabled()) { + persistenceExtension = (PersistenceExtension) this.defaultExternalCustomScript.getExternalType(); } + + persistenceEntryManager.setPersistenceExtension(persistenceExtension); + } + + public void executeExternalOnAfterCreateMethod(PersistenceExternalContext context) { + executeExternalOnAfterCreateMethod(this.defaultExternalCustomScript, context); } public void executeExternalOnAfterCreateMethod(CustomScriptConfiguration customScriptConfiguration, PersistenceExternalContext context) { @@ -55,16 +77,8 @@ public void executeExternalOnAfterCreateMethod(CustomScriptConfiguration customS } } - public void executeExternalOnBeforeDestroyMethod(CustomScriptConfiguration customScriptConfiguration, PersistenceExternalContext context) { - try { - log.debug("Executing python 'onBeforeDestroy' method"); - PersistenceType persistenceType = (PersistenceType) customScriptConfiguration.getExternalType(); - Map configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); - persistenceType.onBeforeDestroy(context, configurationAttributes); - } catch (Exception ex) { - log.error(ex.getMessage(), ex); - saveScriptError(customScriptConfiguration.getCustomScript(), ex); - } + public void executeExternalOnAfterDestroyMethod(PersistenceExternalContext context) { + executeExternalOnAfterDestroyMethod(this.defaultExternalCustomScript, context); } public void executeExternalOnAfterDestroyMethod(CustomScriptConfiguration customScriptConfiguration, PersistenceExternalContext context) { diff --git a/oxService/src/main/java/org/gluu/service/external/context/PersistenceExternalContext.java b/oxService/src/main/java/org/gluu/service/external/context/PersistenceExternalContext.java index 2785e971..7daabaa1 100644 --- a/oxService/src/main/java/org/gluu/service/external/context/PersistenceExternalContext.java +++ b/oxService/src/main/java/org/gluu/service/external/context/PersistenceExternalContext.java @@ -6,16 +6,38 @@ package org.gluu.service.external.context; +import java.util.Properties; + +import org.gluu.persist.PersistenceEntryManager; + /** * Holds object required in persistence scope custom scripts * * @author Yuriy Movchan Date: 06/05/2020 */ - public class PersistenceExternalContext extends ExternalScriptContext { - public PersistenceExternalContext() { + private Properties connectionProperties; + private PersistenceEntryManager persistenceEntryManager; + + public PersistenceExternalContext() { super(null, null); } + public Properties getConnectionProperties() { + return connectionProperties; + } + + public void setConnectionProperties(Properties connectionProperties) { + this.connectionProperties = connectionProperties; + } + + public PersistenceEntryManager getPersistenceEntryManager() { + return persistenceEntryManager; + } + + public void setPersistenceEntryManager(PersistenceEntryManager persistenceEntryManager) { + this.persistenceEntryManager = persistenceEntryManager; + } + } diff --git a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java index 0e17be5c..2c9fa39a 100644 --- a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java @@ -17,6 +17,7 @@ import javax.persistence.Query; import org.gluu.persist.event.DeleteNotifier; +import org.gluu.persist.exception.extension.PersistenceExtension; import org.gluu.persist.model.AttributeData; import org.gluu.persist.model.BatchOperation; import org.gluu.persist.model.PagedResult; @@ -108,6 +109,8 @@ Map> groupListByProperties(Class entryClass, List entries, PersistenceOperationService getOperationService(); PersistenceEntryManager getPersistenceEntryManager(String persistenceType); + void setPersistenceExtension(PersistenceExtension persistenceExtension); + boolean destroy(); default void clear() { diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java index 0e91a54c..14bab95f 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java @@ -149,7 +149,7 @@ private boolean authenticateImpl(final String key, final String password) throws if (userPassword != null) { if (persistenceExtension == null) { - result = PasswordEncryptionHelper.compareCredentials(password.getBytes(), userPassword.getBytes()); + result = PasswordEncryptionHelper.compareCredentials(password, userPassword); } else { result = persistenceExtension.compareHashedPasswords(password, userPassword); } diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java index 0d0f7e41..dbec59ff 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java @@ -72,7 +72,6 @@ public class LdapEntryManager extends BaseEntryManager implements Serializable { private static final LdapFilterConverter LDAP_FILTER_CONVERTER = new LdapFilterConverter(); private static final LdapSearchScopeConverter LDAP_SEARCH_SCOPE_CONVERTER = new LdapSearchScopeConverter(); - private LdapOperationServiceImpl operationService; private List subscribers; public LdapEntryManager() { @@ -89,11 +88,11 @@ public boolean destroy() { return true; } - return this.operationService.destroy(); + return getOperationService().destroy(); } public LdapOperationServiceImpl getOperationService() { - return operationService; + return (LdapOperationServiceImpl) operationService; } @Override @@ -171,7 +170,7 @@ protected void persist(String dn, List attributes, Integer expira String[] attributeValues = attribute.getStringValues(); if (ArrayHelper.isNotEmpty(attributeValues) && StringHelper.isNotEmpty(attributeValues[0])) { - if (operationService.isCertificateAttribute(attributeName)) { + if (getOperationService().isCertificateAttribute(attributeName)) { byte[][] binaryValues = toBinaryValues(attributeValues); ldapAttributes.add(new Attribute(attributeName + ";binary", binaryValues)); @@ -183,7 +182,7 @@ protected void persist(String dn, List attributes, Integer expira // Persist entry try { - boolean result = this.operationService.addEntry(dn, ldapAttributes); + boolean result = getOperationService().addEntry(dn, ldapAttributes); if (!result) { throw new EntryPersistenceException(String.format("Failed to persist entry: %s", dn)); } @@ -285,7 +284,7 @@ public int compare(String o1, String o2) { } if (modifications.size() > 0) { - boolean result = this.operationService.updateEntry(dn, modifications); + boolean result = getOperationService().updateEntry(dn, modifications); if (!result) { throw new EntryPersistenceException(String.format("Failed to update entry: %s", dn)); } @@ -304,7 +303,7 @@ public void remove(String dn) { for (DeleteNotifier subscriber : subscribers) { subscriber.onBeforeRemove(dn); } - this.operationService.delete(dn); + getOperationService().delete(dn); for (DeleteNotifier subscriber : subscribers) { subscriber.onAfterRemove(dn); } @@ -337,7 +336,7 @@ public int remove(String baseDN, Class entryClass, Filter filter, int cou try { LdapBatchOperationWraper batchOperationWraper = new LdapBatchOperationWraper(batchOperation, this, entryClass, propertiesAnnotations); - searchResult = this.operationService.search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(SearchScope.SUB), batchOperationWraper, + searchResult = getOperationService().search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(SearchScope.SUB), batchOperationWraper, 0, 100, count, null, LdapOperationService.DN); } catch (Exception ex) { @@ -354,11 +353,11 @@ public int remove(String baseDN, Class entryClass, Filter filter, int cou @Override public void removeRecursively(String dn) { try { - if (this.operationService.getConnectionProvider().isSupportsSubtreeDeleteRequestControl()) { + if (getOperationService().getConnectionProvider().isSupportsSubtreeDeleteRequestControl()) { for (DeleteNotifier subscriber : subscribers) { subscriber.onBeforeRemove(dn); } - this.operationService.deleteRecursively(dn); + getOperationService().deleteRecursively(dn); for (DeleteNotifier subscriber : subscribers) { subscriber.onAfterRemove(dn); } @@ -375,7 +374,7 @@ private void removeSubtreeThroughIteration(String dn) { SearchResult searchResult = null; try { - searchResult = this.operationService.search(dn, toLdapFilter(Filter.createPresenceFilter("objectClass")), toLdapSearchScope(scope), null, 0, 0, 0, null, "dn"); + searchResult = getOperationService().search(dn, toLdapFilter(Filter.createPresenceFilter("objectClass")), toLdapSearchScope(scope), null, 0, 0, 0, null, "dn"); if (!ResultCode.SUCCESS.equals(searchResult.getResultCode())) { throw new EntryPersistenceException(String.format("Failed to find sub-entries of entry '%s' for removal", dn)); } @@ -401,7 +400,7 @@ private void removeSubtreeThroughIteration(String dn) { protected List find(String dn, Map propertiesAnnotationsMap, String... ldapReturnAttributes) { try { // Load entry - SearchResultEntry entry = this.operationService.lookup(dn, ldapReturnAttributes); + SearchResultEntry entry = getOperationService().lookup(dn, ldapReturnAttributes); List result = getAttributeDataList(entry); if (result != null) { return result; @@ -440,7 +439,7 @@ public List findEntries(String baseDN, Class entryClass, Filter filter try { LdapBatchOperationWraper batchOperationWraper = new LdapBatchOperationWraper(batchOperation, this, entryClass, propertiesAnnotations); - searchResult = this.operationService.search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(scope), batchOperationWraper, + searchResult = getOperationService().search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(scope), batchOperationWraper, start, chunkSize, count, null, currentLdapReturnAttributes); } catch (Exception ex) { throw new EntryPersistenceException(String.format("Failed to find entries with baseDN: %s, filter: %s", baseDN, searchFilter), ex); @@ -490,7 +489,7 @@ public PagedResult findPagedEntries(String baseDN, Class entryClass, F List searchResultEntries; PagedResult vlvResponse = new PagedResult(); try { - searchResultEntries = this.operationService.searchSearchResultEntryList(baseDN, toLdapFilter(searchFilter), + searchResultEntries = getOperationService().searchSearchResultEntryList(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(SearchScope.SUB), start, count, chunkSize, sortBy, sortOrder, vlvResponse, currentLdapReturnAttributes); } catch (Exception ex) { throw new EntryPersistenceException(String.format("Failed to find entries with baseDN: %s, filter: %s", baseDN, searchFilter), ex); @@ -534,7 +533,7 @@ public List findEntriesVirtualListView(String baseDN, Class entryClass SearchResult searchResult = null; try { - searchResult = this.operationService.searchVirtualListView(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(SearchScope.SUB), + searchResult = getOperationService().searchVirtualListView(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(SearchScope.SUB), start, count, sortBy, sortOrder, vlvResponse, currentLdapReturnAttributes); if (!ResultCode.SUCCESS.equals(searchResult.getResultCode())) { @@ -573,7 +572,7 @@ protected boolean contains(String baseDN, Class entryClass, List getAttributeDataList(SearchResultEntry entry) { if (LOG.isTraceEnabled()) { if (attribute.needsBase64Encoding()) { LOG.trace("Found binary attribute: " + attributeName + ". Is defined in LDAP config: " - + operationService.isBinaryAttribute(attributeName)); + + getOperationService().isBinaryAttribute(attributeName)); } } attributeValueStrings = attribute.getValues(); if (attribute.needsBase64Encoding()) { - boolean binaryAttribute = operationService.isBinaryAttribute(attributeName); - boolean certificateAttribute = operationService.isCertificateAttribute(attributeName); + boolean binaryAttribute = getOperationService().isBinaryAttribute(attributeName); + boolean certificateAttribute = getOperationService().isCertificateAttribute(attributeName); if (binaryAttribute || certificateAttribute) { byte[][] attributeValues = attribute.getValueByteArrays(); @@ -691,7 +690,7 @@ private List getAttributeDataList(SearchResultEntry entry) { } } if (certificateAttribute) { - attributeName = operationService.getCertificateAttributeName(attributeName); + attributeName = getOperationService().getCertificateAttributeName(attributeName); } } @@ -721,14 +720,14 @@ public boolean authenticate(String baseDN, Class entryClass, String userN SearchScope scope = SearchScope.SUB; try { - SearchResult searchResult = operationService.search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(scope), null, 0, 1, 1, null, (String[]) null); + SearchResult searchResult = getOperationService().search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(scope), null, 0, 1, 1, null, (String[]) null); if ((searchResult == null) || (searchResult.getEntryCount() != 1)) { return false; } String bindDn = searchResult.getSearchEntries().get(0).getDN(); - return operationService.authenticate(bindDn, password); + return getOperationService().authenticate(bindDn, password); } catch (ConnectionException ex) { throw new AuthenticationException(String.format("Failed to authenticate user: %s", userName), ex); } catch (SearchScopeException ex) { @@ -741,7 +740,7 @@ public boolean authenticate(String baseDN, Class entryClass, String userN @Override public boolean authenticate(String bindDn, String password) { try { - return operationService.authenticate(bindDn, password); + return getOperationService().authenticate(bindDn, password); } catch (ConnectionException ex) { throw new AuthenticationException(String.format("Failed to authenticate DN: %s", bindDn), ex); } @@ -791,7 +790,7 @@ public int countEntries(String baseDN, Class entryClass, Filter filter, S if (batchOperation != null) { batchOperationWraper = new LdapBatchOperationWraper(batchOperation); } - searchResult = operationService.search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(searchScope), batchOperationWraper, 0, 100, 0, null, + searchResult = getOperationService().search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(searchScope), batchOperationWraper, 0, 100, 0, null, ldapReturnAttributes); } catch (Exception ex) { throw new EntryPersistenceException( @@ -851,7 +850,7 @@ protected Date decodeTime(String date) { public boolean loadLdifFileContent(String ldifFileContent) { LDAPConnection connection = null; try { - connection = operationService.getConnection(); + connection = getOperationService().getConnection(); ResultCode result = LdifDataUtility.instance().importLdifFileContent(connection, ldifFileContent); return ResultCode.SUCCESS.equals(result); } catch (Exception ex) { @@ -859,7 +858,7 @@ public boolean loadLdifFileContent(String ldifFileContent) { return false; } finally { if (connection != null) { - operationService.releaseConnection(connection); + getOperationService().releaseConnection(connection); } } } @@ -867,7 +866,7 @@ public boolean loadLdifFileContent(String ldifFileContent) { @Override public List exportEntry(String dn) { try { - SearchResultEntry searchResultEntry = this.operationService.lookup(dn, (String[]) null); + SearchResultEntry searchResultEntry = getOperationService().lookup(dn, (String[]) null); List result = getAttributeDataList(searchResultEntry); if (result != null) { @@ -886,12 +885,12 @@ public void importEntry(String dn, List data) { } public int getSupportedLDAPVersion() { - return this.operationService.getSupportedLDAPVersion(); + return getOperationService().getSupportedLDAPVersion(); } private Modification createModification(final ModificationType modificationType, final String attributeName, final String... attributeValues) { String realAttributeName = attributeName; - if (operationService.isCertificateAttribute(realAttributeName)) { + if (getOperationService().isCertificateAttribute(realAttributeName)) { realAttributeName += ";binary"; byte[][] binaryValues = toBinaryValues(attributeValues); diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java index f06434d4..12d072c0 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java @@ -15,6 +15,7 @@ import java.util.Comparator; import java.util.Date; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -219,19 +220,24 @@ private boolean authenticateImpl(final String bindDn, final String password) thr // Try to authenticate if the password was encrypted with additional mechanism List additionalPasswordMethods = this.connectionProvider.getAdditionalPasswordMethods(); - if (!additionalPasswordMethods.isEmpty()) { - + if ((persistenceExtension != null) || !additionalPasswordMethods.isEmpty()) { SearchResultEntry searchResult = lookup(bindDn, USER_PASSWORD); if (searchResult == null) { throw new ConnectionException("Failed to find use by dn"); } - String storedUserPassword = searchResult.getAttribute(USER_PASSWORD).getValue(); - PasswordEncryptionMethod storedPasswordMethod = PasswordEncryptionHelper.findAlgorithm(storedUserPassword); - if (additionalPasswordMethods.contains(storedPasswordMethod)) { - LOG.debug("Authenticating '{}' using internal authentication mechanism '{}'", bindDn, storedPasswordMethod); - result = PasswordEncryptionHelper.compareCredentials(password, storedUserPassword); - } + String userPassword = searchResult.getAttribute(USER_PASSWORD).getValue(); + if (userPassword != null) { + if (persistenceExtension != null) { + result = persistenceExtension.compareHashedPasswords(password, userPassword); + } else { + PasswordEncryptionMethod storedPasswordMethod = PasswordEncryptionHelper.findAlgorithm(userPassword); + if (additionalPasswordMethods.contains(storedPasswordMethod)) { + LOG.debug("Authenticating '{}' using internal authentication mechanism '{}'", bindDn, storedPasswordMethod); + result = PasswordEncryptionHelper.compareCredentials(password, userPassword); + } + } + } } else { if (this.bindConnectionProvider == null) { result = authenticateConnectionPoolImpl(bindDn, password); @@ -712,7 +718,11 @@ public boolean addEntry(String dn, Collection attributes) throws Dupl } private boolean addEntryImpl(String dn, Collection attributes) throws DuplicateEntryException { - try { + if (this.persistenceExtension != null) { + updateUserPasswordAttribute(attributes); + } + + try { LDAPResult result = getConnectionPool().add(dn, attributes); if (result.getResultCode().getName().equalsIgnoreCase(SUCCESS)) { return true; @@ -784,7 +794,11 @@ public boolean updateEntry(String dn, List modifications) throws D } private boolean updateEntryImpl(String dn, List modifications) throws DuplicateEntryException { - ModifyRequest modifyRequest = new ModifyRequest(dn, modifications); + if (this.persistenceExtension != null) { + updateUserPasswordModification(modifications); + } + + ModifyRequest modifyRequest = new ModifyRequest(dn, modifications); return modifyEntry(modifyRequest); } @@ -978,6 +992,48 @@ public String getCertificateAttributeName(String attributeName) { return this.connectionProvider.getCertificateAttributeName(attributeName); } + private void updateUserPasswordAttribute(Collection attributes) { + for (Iterator it = attributes.iterator(); it.hasNext();) { + Attribute attribute = (Attribute) it.next(); + if (StringHelper.equals(LdapOperationService.USER_PASSWORD, attribute.getName())) { + it.remove(); + Attribute newAttribute = new Attribute(attribute.getName(), + createStoragePassword(attribute.getValues())); + attributes.add(newAttribute); + break; + } + } + } + + private void updateUserPasswordModification(List modifications) { + for (Iterator it = modifications.iterator(); it.hasNext();) { + Modification modification = (Modification) it.next(); + if (StringHelper.equals(LdapOperationService.USER_PASSWORD, modification.getAttributeName())) { + it.remove(); + Modification newModification = new Modification(modification.getModificationType(), + modification.getAttributeName(), + createStoragePassword(modification.getValues())); + modifications.add(newModification); + break; + } + } + } + + public String[] createStoragePassword(String[] passwords) { + if (ArrayHelper.isEmpty(passwords)) { + return passwords; + } + + String[] results = new String[passwords.length]; + for (int i = 0; i < passwords.length; i++) { + if (persistenceExtension != null) { + results[i] = persistenceExtension.createHashedPassword(passwords[i]); + } + } + + return results; + } + @Override public List sortListByAttributes(List searchResultEntries, Class cls, boolean caseSensitive, boolean ascending, String... sortByAttributes) { From 09b116f7757f830560afe4e0da9b134b91a38c56 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Tue, 9 Jun 2020 14:34:50 +0100 Subject: [PATCH 172/362] Add javax activation dependency --- oxService/pom.xml | 64 +++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/oxService/pom.xml b/oxService/pom.xml index 59c2d25d..9d55b5f1 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -25,17 +25,17 @@ - - - src/test/resources - true - - **/*.xml - **/services/* - **/*.properties - - - + + + src/test/resources + true + + **/*.xml + **/services/* + **/*.properties + + + @@ -48,14 +48,14 @@ ${project.groupId} oxcore-persistence-ldap - - ${project.groupId} - oxcore-persistence-couchbase - - - ${project.groupId} - oxcore-persistence-hybrid - + + ${project.groupId} + oxcore-persistence-couchbase + + + ${project.groupId} + oxcore-persistence-hybrid + ${project.groupId} oxcore-util @@ -81,13 +81,13 @@ provided - org.jboss.spec.javax.annotation - jboss-annotations-api_1.2_spec + org.jboss.spec.javax.annotation + jboss-annotations-api_1.2_spec provided - org.jboss.spec.javax.interceptor - jboss-interceptors-api_1.2_spec + org.jboss.spec.javax.interceptor + jboss-interceptors-api_1.2_spec provided @@ -148,10 +148,10 @@ - - com.google.guava - guava - + + com.google.guava + guava + @@ -164,6 +164,16 @@ javax.mail mail + + javax.activation + javax.activation-api + 1.2.0 + + + javax.activation + activation + 1.1.1 + \ No newline at end of file From 2d1f08e8ca8884ec7c01af42d7511e2eb6363d17 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Tue, 9 Jun 2020 14:50:42 +0100 Subject: [PATCH 173/362] Add javax activation dependency --- oxService/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/oxService/pom.xml b/oxService/pom.xml index 9d55b5f1..0d3fe02e 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -169,11 +169,6 @@ javax.activation-api 1.2.0 - - javax.activation - activation - 1.1.1 - \ No newline at end of file From 680460f134e067e3c1176bf95f2d450b12b523d5 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 9 Jun 2020 18:17:08 +0300 Subject: [PATCH 174/362] Add new persistence custom script oxCore #194 --- .../ExternalPersistenceExtensionService.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java index 7f02cc61..144bcdad 100644 --- a/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java +++ b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java @@ -7,6 +7,7 @@ package org.gluu.service.external; import java.util.Iterator; +import java.util.List; import java.util.Map; import javax.enterprise.context.ApplicationScoped; @@ -33,7 +34,10 @@ public class ExternalPersistenceExtensionService extends ExternalScriptService { private static final long serialVersionUID = 5466361778036208685L; @Inject - private Instance persistenceMetricEntryManagerInstance; + private Instance persistenceEntryManagerInstance; + + @Inject + private Instance> persistenceEntryManagerListInstance; public ExternalPersistenceExtensionService() { super(CustomScriptType.PERSISTENCE_EXTENSION); @@ -46,10 +50,17 @@ protected void reloadExternal() { persistenceExtension = (PersistenceExtension) this.defaultExternalCustomScript.getExternalType(); } - for (Iterator it = persistenceMetricEntryManagerInstance.iterator(); it.hasNext();) { + for (Iterator it = persistenceEntryManagerInstance.iterator(); it.hasNext();) { PersistenceEntryManager persistenceEntryManager = it.next(); persistenceEntryManager.setPersistenceExtension(persistenceExtension); } + + for (Iterator> it = persistenceEntryManagerListInstance.iterator(); it.hasNext();) { + List persistenceEntryManagerList = it.next(); + for (PersistenceEntryManager persistenceEntryManager: persistenceEntryManagerList) { + persistenceEntryManager.setPersistenceExtension(persistenceExtension); + } + } } public void setPersistenceExtension(PersistenceEntryManager persistenceEntryManager) { From 87de4a0d8586e4a95e525f10c48e0db856a63f85 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 10 Jun 2020 18:57:16 +0300 Subject: [PATCH 175/362] Allow to reuse after create/destroy methods in persistence script --- .../ExternalPersistenceExtensionService.java | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java index 144bcdad..ba29a53e 100644 --- a/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java +++ b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java @@ -9,6 +9,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Properties; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Instance; @@ -45,24 +46,40 @@ public ExternalPersistenceExtensionService() { @Override protected void reloadExternal() { - PersistenceExtension persistenceExtension = null; - if (isEnabled()) { - persistenceExtension = (PersistenceExtension) this.defaultExternalCustomScript.getExternalType(); - } - for (Iterator it = persistenceEntryManagerInstance.iterator(); it.hasNext();) { PersistenceEntryManager persistenceEntryManager = it.next(); - persistenceEntryManager.setPersistenceExtension(persistenceExtension); + executePersistenceExtensionAfterCreate(null, persistenceEntryManager); } for (Iterator> it = persistenceEntryManagerListInstance.iterator(); it.hasNext();) { List persistenceEntryManagerList = it.next(); - for (PersistenceEntryManager persistenceEntryManager: persistenceEntryManagerList) { - persistenceEntryManager.setPersistenceExtension(persistenceExtension); + for (PersistenceEntryManager persistenceEntryManager : persistenceEntryManagerList) { + executePersistenceExtensionAfterCreate(null, persistenceEntryManager); } } } + public void executePersistenceExtensionAfterCreate(Properties connectionProperties, PersistenceEntryManager persistenceEntryManager) { + if (isEnabled()) { + PersistenceExternalContext persistenceExternalContext = new PersistenceExternalContext(); + persistenceExternalContext.setConnectionProperties(connectionProperties); + persistenceExternalContext.setPersistenceEntryManager(persistenceEntryManager); + + executeExternalOnAfterCreateMethod(persistenceExternalContext); + + setPersistenceExtension(persistenceEntryManager); + } + } + + public void executePersistenceExtensionAfterDestroy(PersistenceEntryManager persistenceEntryManager) { + if (isEnabled()) { + PersistenceExternalContext persistenceExternalContext = new PersistenceExternalContext(); + persistenceExternalContext.setPersistenceEntryManager(persistenceEntryManager); + + executeExternalOnAfterDestroyMethod(persistenceExternalContext); + } + } + public void setPersistenceExtension(PersistenceEntryManager persistenceEntryManager) { PersistenceExtension persistenceExtension = null; if (isEnabled()) { From c66885430d0638be708fdce45f8056ea55732c5f Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 11 Jun 2020 12:34:50 +0300 Subject: [PATCH 176/362] Make it easy to support new locale without unpacking war oxAuth #1134 --- .../customization/FacesConfigPopulator.java | 237 ++++++++---------- .../FacesLocalizationConfigPopulator.java | 139 ++++++++++ .../org/gluu/jsf2/customization/Utils.java | 22 ++ 3 files changed, 264 insertions(+), 134 deletions(-) create mode 100644 oxJsfUtil/src/main/java/org/gluu/jsf2/customization/FacesLocalizationConfigPopulator.java diff --git a/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/FacesConfigPopulator.java b/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/FacesConfigPopulator.java index d169eb56..04b4a38f 100644 --- a/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/FacesConfigPopulator.java +++ b/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/FacesConfigPopulator.java @@ -1,7 +1,15 @@ package org.gluu.jsf2.customization; -import com.sun.faces.config.DbfFactory; -import com.sun.faces.util.FacesLogger; +import java.io.File; +import java.net.URL; +import java.util.Collection; +import java.util.Enumeration; +import java.util.logging.Level; + +import javax.faces.application.ApplicationConfigurationPopulator; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.DirectoryFileFilter; import org.apache.commons.io.filefilter.RegexFileFilter; @@ -11,142 +19,103 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import org.w3c.dom.ls.LSResourceResolver; -import javax.faces.application.ApplicationConfigurationPopulator; -import javax.xml.XMLConstants; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.stream.StreamSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; -import javax.xml.validation.Validator; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.net.URL; -import java.util.Collection; -import java.util.Enumeration; -import java.util.logging.Level; +import com.sun.faces.util.FacesLogger; /** * Created by eugeniuparvan on 5/1/17. */ public class FacesConfigPopulator extends ApplicationConfigurationPopulator { - /** - *

/faces-config/navigation-rule

- */ - private static final String NAVIGATION_RULE = "navigation-rule"; - private static final String FACES_2_2_XSD = "/com/sun/faces/web-facesconfig_2_2.xsd"; - private static final String FACES_CONFIG_PATTERN = ".*\\.navigation\\.xml$"; - private static final String DEFAULT_NAVIGATION_PATH = "META-INF/navigation"; - - private Logger log = LoggerFactory.getLogger(FacesConfigPopulator.class); - - @Override - public void populateApplicationConfiguration(Document toPopulate) { - log.debug("Starting configuration populator"); - - if (Utils.isCustomPagesDirExists()) { - String customPath = Utils.getCustomPagesPath(); - log.debug("Adding navigation rules from custom dir folder: {}", customPath); - try { - findAndUpdateNavigationRules(toPopulate, customPath); - } catch (Exception ex) { - FacesLogger.CONFIG.getLogger().log(Level.SEVERE, "Can't add customized navigation rules"); - } - } - - try { - log.debug("Adding navigation rules from application resurces"); - Enumeration urlEnumeration = getClass().getClassLoader().getResources(DEFAULT_NAVIGATION_PATH); - if (urlEnumeration.hasMoreElements()) { - URL url = urlEnumeration.nextElement(); - findAndUpdateNavigationRules(toPopulate, url.getPath()); - } - } catch (Exception ex) { - log.error("Failed to populate application configuraton", ex); - } - } - - /** - * Recursively finds all *.navigation.xml files located in custom pages directory, and adds navigation rules to - * navigation handler - * - * @param path to custom pages directory - * @throws Exception - */ - private void findAndUpdateNavigationRules(Document toPopulate, String path) throws Exception { - File file = new File(path); - RegexFileFilter regexFileFilter = new RegexFileFilter(FACES_CONFIG_PATTERN); - Collection facesConfigFiles = FileUtils.listFiles(file, regexFileFilter, DirectoryFileFilter.DIRECTORY); - log.debug("Found '{}' navigation rules files", facesConfigFiles.size()); - - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - DocumentBuilder builder = factory.newDocumentBuilder(); - - for (File files : facesConfigFiles) { - String faceConfig = files.getAbsolutePath(); - updateDocument(toPopulate, builder, faceConfig); - log.debug("Added navigation rules from {}", faceConfig); - } - } - - /** - * Validates *.faces-config.xml file and creates DocumentInfo class - * - * @param docBuilder - * @param faceConfig - * @return - */ - private void updateDocument(Document toPopulate, DocumentBuilder docBuilder, String faceConfig) { - try { - InputStream xml = new FileInputStream(faceConfig); -// try { -// if (!isValidFacesConfig(xml)) { -// return; -// } -// } finally { -// xml.close(); -// } - Document document = docBuilder.parse(new File(faceConfig)); - Element root = toPopulate.getDocumentElement(); - NodeList navigationRules = getNavigationRules(document); - for (int i = 0; i < navigationRules.getLength(); ++i) { - Node importedNode = toPopulate.importNode(navigationRules.item(i), true); - root.appendChild(importedNode); - } - } catch (Exception ex) { - log.error("Failed to update navigation rules", ex); - } - } - - /** - * Validates *.faces-config.xml file - * - * @param xml - * @return - */ - private boolean isValidFacesConfig(InputStream xml) { - try { - SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - factory.setResourceResolver((LSResourceResolver) DbfFactory.FACES_ENTITY_RESOLVER); - - InputStream xsd = this.getClass().getResourceAsStream(FACES_2_2_XSD); - Schema schema = factory.newSchema(new StreamSource(xsd)); - - Validator validator = schema.newValidator(); - validator.validate(new StreamSource(xml)); - return true; - } catch (Exception ex) { - return false; - } - } - - private NodeList getNavigationRules(Document document) { - String namespace = document.getDocumentElement() - .getNamespaceURI(); - return document.getDocumentElement().getElementsByTagNameNS(namespace, NAVIGATION_RULE); - } + /** + *

+ * /faces-config/navigation-rule + *

+ */ + private static final String NAVIGATION_RULE = "navigation-rule"; + private static final String FACES_CONFIG_PATTERN = ".*\\.navigation\\.xml$"; + private static final String DEFAULT_NAVIGATION_PATH = "META-INF/navigation"; + + private Logger log = LoggerFactory.getLogger(FacesConfigPopulator.class); + + @Override + public void populateApplicationConfiguration(Document toPopulate) { + populateNavigationRules(toPopulate); + } + + // Navigation Rules + protected void populateNavigationRules(Document toPopulate) { + log.debug("Starting configuration populator"); + + if (Utils.isCustomPagesDirExists()) { + String customPath = Utils.getCustomPagesPath(); + log.debug("Adding navigation rules from custom dir folder: {}", customPath); + try { + findAndUpdateNavigationRules(toPopulate, customPath); + } catch (Exception ex) { + FacesLogger.CONFIG.getLogger().log(Level.SEVERE, "Can't add customized navigation rules"); + } + } + + try { + log.debug("Adding navigation rules from application resurces"); + Enumeration urlEnumeration = getClass().getClassLoader().getResources(DEFAULT_NAVIGATION_PATH); + if (urlEnumeration.hasMoreElements()) { + URL url = urlEnumeration.nextElement(); + findAndUpdateNavigationRules(toPopulate, url.getPath()); + } + } catch (Exception ex) { + log.error("Failed to populate application configuraton", ex); + } + } + + /** + * Recursively finds all *.navigation.xml files located in custom pages + * directory, and adds navigation rules to navigation handler + * + * @param path to custom pages directory + * @throws Exception + */ + private void findAndUpdateNavigationRules(Document toPopulate, String path) throws Exception { + File file = new File(path); + RegexFileFilter regexFileFilter = new RegexFileFilter(FACES_CONFIG_PATTERN); + Collection facesConfigFiles = FileUtils.listFiles(file, regexFileFilter, DirectoryFileFilter.DIRECTORY); + log.debug("Found '{}' navigation rules files", facesConfigFiles.size()); + + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + DocumentBuilder builder = factory.newDocumentBuilder(); + + for (File files : facesConfigFiles) { + String faceConfig = files.getAbsolutePath(); + updateDocument(toPopulate, builder, faceConfig); + log.debug("Added navigation rules from {}", faceConfig); + } + } + + /** + * Validates *.faces-config.xml file and creates DocumentInfo class + * + * @param docBuilder + * @param faceConfig + * @return + */ + private void updateDocument(Document toPopulate, DocumentBuilder docBuilder, String faceConfig) { + try { + Document document = docBuilder.parse(new File(faceConfig)); + Element root = toPopulate.getDocumentElement(); + NodeList navigationRules = getNavigationRules(document); + for (int i = 0; i < navigationRules.getLength(); ++i) { + Node importedNode = toPopulate.importNode(navigationRules.item(i), true); + root.appendChild(importedNode); + } + } catch (Exception ex) { + log.error("Failed to update navigation rules", ex); + } + } + + private NodeList getNavigationRules(Document document) { + String namespace = document.getDocumentElement().getNamespaceURI(); + return document.getDocumentElement().getElementsByTagNameNS(namespace, NAVIGATION_RULE); + } + } diff --git a/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/FacesLocalizationConfigPopulator.java b/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/FacesLocalizationConfigPopulator.java new file mode 100644 index 00000000..a809fecb --- /dev/null +++ b/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/FacesLocalizationConfigPopulator.java @@ -0,0 +1,139 @@ +package org.gluu.jsf2.customization; + +import java.io.File; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.logging.Level; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.faces.application.ApplicationConfigurationPopulator; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.filefilter.DirectoryFileFilter; +import org.apache.commons.io.filefilter.RegexFileFilter; +import org.gluu.util.StringHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import com.sun.faces.util.FacesLogger; + +/** + * @author Yuriy Movchan + * @version 06/11/2020 + */ +public abstract class FacesLocalizationConfigPopulator extends ApplicationConfigurationPopulator { + + private static final String DEFAULT_LANGUAGE_PATH = "/classes/"; + + private Logger log = LoggerFactory.getLogger(FacesLocalizationConfigPopulator.class); + + @Override + public void populateApplicationConfiguration(Document toPopulate) { + populateLocalizations(toPopulate); + } + + private void populateLocalizations(Document toPopulate) { + log.debug("Starting localization configuration populator"); + + if (Utils.isCustomLocalizationDirExists()) { + String customLocalizationPath = Utils.getCustomLocalizationPath(); + log.debug("Adding localizations from custom dir folder: {}", customLocalizationPath); + try { + findAndAddLocalizations(toPopulate, customLocalizationPath); + } catch (Exception ex) { + FacesLogger.CONFIG.getLogger().log(Level.SEVERE, "Can't add localizations from custom dir"); + } + } + + try { + log.debug("Adding localizations from application resurces"); + URL[] ulrs = ((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs(); + for (URL url : ulrs) { + if (url.getFile().endsWith(DEFAULT_LANGUAGE_PATH)) { + int count = findAndAddLocalizations(toPopulate, url.getFile()); + if (count > 0) { + log.debug("Added {} application localizations from war folder: {}", count, url.getFile()); + } + } + } + } catch (Exception ex) { + log.error("Failed to populate application localizations", ex); + } + } + + private int findAndAddLocalizations(Document toPopulate, String path) throws Exception { + String languageFilePattern = getLanguageFilePattern(); + RegexFileFilter regexFileFilter = new RegexFileFilter(languageFilePattern); + Pattern regexFilePatern = Pattern.compile(languageFilePattern); + + File file = new File(path); + Collection languageFiles = FileUtils.listFiles(file, regexFileFilter, DirectoryFileFilter.DIRECTORY); + + if (languageFiles.size() == 0) { + return 0; + } + log.debug("Found '{}' language files", languageFiles.size()); + + List localeNames = new ArrayList(); + for (File languageFile : languageFiles) { + Matcher matcher = regexFilePatern.matcher(languageFile.getName()); + + if (matcher.matches()) { + String localeName = matcher.group(1); + + localeNames.add(localeName); + } + } + log.debug("Adding languages '{}' from dir folder: {}", localeNames, path); + + updateDocument(toPopulate, localeNames); + + return localeNames.size(); + } + + private void updateDocument(Document toPopulate, List localeNames) { + String ns = toPopulate.getDocumentElement().getNamespaceURI(); + Element rootElement = toPopulate.getDocumentElement(); + + // Add application + Node applicationNode = getChildOrCreate(toPopulate, ns, rootElement, "application"); + + // Add locale-config + Node localeConfigNode = getChildOrCreate(toPopulate, ns, applicationNode, "locale-config"); + + for (String localeName : localeNames) { + // Add supported-locale + Element supportedLocaleElement = toPopulate.createElementNS(ns, "supported-locale"); + Node supportedLocaleNode = localeConfigNode.appendChild(supportedLocaleElement); + + supportedLocaleNode.appendChild(toPopulate.createTextNode(localeName)); + } + } + + protected Node getChildOrCreate(Document toPopulate, String ns, Node rootElement, String childNodeName) { + if (rootElement.hasChildNodes()) { + NodeList nodeList = rootElement.getChildNodes(); + for (int i = 0; i < nodeList.getLength(); i++) { + if (StringHelper.equals(nodeList.item(i).getNodeName(), childNodeName)) { + return nodeList.item(i); + } + } + } + + Element applicationElement = toPopulate.createElementNS(ns, childNodeName); + Node applicationNode = rootElement.appendChild(applicationElement); + + return applicationNode; + } + + public abstract String getLanguageFilePattern(); + +} diff --git a/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/Utils.java b/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/Utils.java index 03b6b54b..1ea303a9 100644 --- a/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/Utils.java +++ b/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/Utils.java @@ -10,6 +10,7 @@ public final class Utils { private static final String SERVER_BASE_PATH = "server.base"; private static final String CUSTOM_PAGES_PATH = "/custom/pages"; + private static final String CUSTOM_LOCALIZATION_PATH = "/custom/i18n"; private Utils() { } @@ -25,6 +26,18 @@ public static boolean isCustomPagesDirExists() { } } + public static boolean isCustomLocalizationDirExists() { + String externalResourceBase = getCustomLocalizationPath(); + if (StringHelper.isNotEmpty(externalResourceBase)) { + File folder = new File(externalResourceBase); + boolean result = folder.exists() && folder.isDirectory(); + + return result; + } else { + return false; + } + } + public static String getCustomPagesPath() { String externalResourceBase = System.getProperty(SERVER_BASE_PATH); if (StringHelper.isNotEmpty(externalResourceBase)) { @@ -34,4 +47,13 @@ public static String getCustomPagesPath() { return externalResourceBase; } + public static String getCustomLocalizationPath() { + String externalResourceBase = System.getProperty(SERVER_BASE_PATH); + if (StringHelper.isNotEmpty(externalResourceBase)) { + externalResourceBase += CUSTOM_LOCALIZATION_PATH; + } + + return externalResourceBase; + } + } From 964ed55740efa8d06064f5124abde55380a504ca Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 11 Jun 2020 13:02:53 +0300 Subject: [PATCH 177/362] Show log info about adding custom localization --- .../jsf2/customization/FacesLocalizationConfigPopulator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/FacesLocalizationConfigPopulator.java b/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/FacesLocalizationConfigPopulator.java index a809fecb..3d517444 100644 --- a/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/FacesLocalizationConfigPopulator.java +++ b/oxJsfUtil/src/main/java/org/gluu/jsf2/customization/FacesLocalizationConfigPopulator.java @@ -92,7 +92,7 @@ private int findAndAddLocalizations(Document toPopulate, String path) throws Exc localeNames.add(localeName); } } - log.debug("Adding languages '{}' from dir folder: {}", localeNames, path); + log.info("Adding languages '{}' from dir folder: {}", localeNames, path); updateDocument(toPopulate, localeNames); From 2a283d2a225807268edb511b54dbf808668dbfb7 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Fri, 12 Jun 2020 12:52:48 +0300 Subject: [PATCH 178/362] Added new onEvent() method to application session interception script. https://github.com/GluuFederation/oxAuth/issues/1353 --- .../custom/script/type/session/ApplicationSessionType.java | 6 ++++-- .../script/type/session/DummyApplicationSessionType.java | 7 +++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java index 796c71ce..4ed6b636 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java @@ -5,11 +5,11 @@ */ package org.gluu.model.custom.script.type.session; -import java.util.Map; - import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.type.BaseExternalType; +import java.util.Map; + /** * Base interface for external application session python script * @@ -18,6 +18,8 @@ public interface ApplicationSessionType extends BaseExternalType { boolean startSession(Object httpRequest, Object sessionState, Map configurationAttributes); + boolean endSession(Object httpRequest, Object sessionState, Map configurationAttributes); + void onEvent(Object event); } diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java index 6994eb47..6019ea9b 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java @@ -4,10 +4,10 @@ * Copyright (c) 2014, Gluu */ package org.gluu.model.custom.script.type.session; +import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.model.CustomScript; -import java.util.Map; -import org.gluu.model.SimpleCustomProperty; +import java.util.Map; /** * Dummy implementation of interface ApplicationSessionType @@ -44,4 +44,7 @@ public boolean endSession(Object httpRequest, Object authorizationGrant, Map Date: Fri, 12 Jun 2020 16:06:30 +0300 Subject: [PATCH 179/362] Don't attempt to load global scripts if application not supports them --- .../org/gluu/service/custom/script/CustomScriptManager.java | 4 ++++ .../org/gluu/service/custom/script/ExternalScriptService.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java index f052a54d..5c3649b9 100644 --- a/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java +++ b/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java @@ -524,4 +524,8 @@ public List getSupportedCustomScriptTypes() { return supportedCustomScriptTypes; } + public boolean isSupportedType(CustomScriptType customScriptType) { + return supportedCustomScriptTypes.contains(customScriptType); + } + } diff --git a/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java b/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java index e0896ca6..6ec4ac9e 100644 --- a/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java +++ b/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java @@ -48,6 +48,10 @@ public ExternalScriptService(CustomScriptType customScriptType) { } public void reload(@Observes @ReloadScript String event) { + // Skip reload if global script is not enabled for this application + if (!customScriptManager.isSupportedType(customScriptType)) { + return; + } // Get actual list of external configurations List newCustomScriptConfigurations = customScriptManager .getCustomScriptConfigurationsByScriptType(customScriptType); From d0623449c5930abc97881870fc4a5fc0855ed007 Mon Sep 17 00:00:00 2001 From: Jose Date: Fri, 12 Jun 2020 10:59:02 -0500 Subject: [PATCH 180/362] Add missing methods https://github.com/GluuFederation/oxTrust/issues/885 --- .../script/type/scim/DummyScimType.java | 19 +++++++++++++------ .../custom/script/type/scim/ScimType.java | 11 +++++------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java index 96c25ef6..47465d4e 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java @@ -1,8 +1,3 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ package org.gluu.model.custom.script.type.scim; import java.util.Map; @@ -11,7 +6,7 @@ import org.gluu.model.custom.script.model.CustomScript; /** - * @author Val Pecaoco + * @author jgomer2001 */ public class DummyScimType implements ScimType { @@ -19,10 +14,12 @@ public class DummyScimType implements ScimType { public boolean init(Map configurationAttributes) { return true; } + @Override public boolean init(CustomScript customScript, Map configurationAttributes) { return true; } + @Override public boolean destroy(Map configurationAttributes) { return true; @@ -102,5 +99,15 @@ public boolean getUser(Object user, Map configurat public boolean getGroup(Object group, Map configurationAttributes) { return false; } + + @Override + public boolean postSearchUsers(Object user, Map configurationAttributes) { + return false; + } + + @Override + public boolean postSearchGroups(Object group, Map configurationAttributes) { + return false; + } } diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java index 11443913..1d0d3a51 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java @@ -1,8 +1,3 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ package org.gluu.model.custom.script.type.scim; import org.gluu.model.SimpleCustomProperty; @@ -11,7 +6,7 @@ import java.util.Map; /** - * @author Val Pecaoco + * @author jgomer2001 */ public interface ScimType extends BaseExternalType { @@ -43,4 +38,8 @@ public interface ScimType extends BaseExternalType { boolean getGroup(Object group, Map configurationAttributes); + boolean postSearchUsers(Object user, Map configurationAttributes); + + boolean postSearchGroups(Object group, Map configurationAttributes); + } From 266f5619597fe643d440cc8a814befacd9034a65 Mon Sep 17 00:00:00 2001 From: Jose Date: Fri, 12 Jun 2020 11:23:16 -0500 Subject: [PATCH 181/362] Use proper argument names https://github.com/GluuFederation/oxTrust/issues/885 --- .../org/gluu/model/custom/script/type/scim/DummyScimType.java | 4 ++-- .../java/org/gluu/model/custom/script/type/scim/ScimType.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java index 47465d4e..56499ff7 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java @@ -101,12 +101,12 @@ public boolean getGroup(Object group, Map configur } @Override - public boolean postSearchUsers(Object user, Map configurationAttributes) { + public boolean postSearchUsers(Object results, Map configurationAttributes) { return false; } @Override - public boolean postSearchGroups(Object group, Map configurationAttributes) { + public boolean postSearchGroups(Object results, Map configurationAttributes) { return false; } diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java index 1d0d3a51..5d3c1ffd 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java +++ b/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java @@ -38,8 +38,8 @@ public interface ScimType extends BaseExternalType { boolean getGroup(Object group, Map configurationAttributes); - boolean postSearchUsers(Object user, Map configurationAttributes); + boolean postSearchUsers(Object results, Map configurationAttributes); - boolean postSearchGroups(Object group, Map configurationAttributes); + boolean postSearchGroups(Object results, Map configurationAttributes); } From 1bb969a471752bc96407f2b2770145c9fdb8842c Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 15 Jun 2020 23:13:24 +0300 Subject: [PATCH 182/362] Smtp mail configuration not working after migration to Java 11 oxTrust #1972 --- oxService/pom.xml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/oxService/pom.xml b/oxService/pom.xml index 0d3fe02e..db0976b1 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -163,11 +163,12 @@ javax.mail mail - - - javax.activation - javax.activation-api - 1.2.0 + + + javax.activation + activation + + From b8f39a085f2af5280871bc539002297cf8e66185 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 18 Jun 2020 13:22:34 +0300 Subject: [PATCH 183/362] Dynamic SAML Attribute Interception Script oxShibboleth #71 --- .../gluu/service/cdi/async/Asynchronous.java | 0 .../org/gluu/service/cdi/event/Scheduled.java | 0 core-script-manager/pom.xml | 86 +++++++++++++++++++ .../org/gluu/exception/PythonException.java | 0 .../model/custom/script/CustomScriptType.java | 16 ++-- .../conf/CustomScriptConfiguration.java | 0 .../custom/script/model/CustomScript.java | 2 +- .../custom/script/model/ScriptError.java | 0 .../custom/script/model/ScriptTemplate.java | 0 .../auth/AuthenticationCustomScript.java | 0 .../script/model/bind/BindCredentials.java | 0 .../custom/script/type/BaseExternalType.java | 0 .../auth/DummyPersonAuthenticationType.java | 0 .../type/auth/PersonAuthenticationType.java | 6 +- .../type/authz/ConsentGatheringType.java | 0 .../type/authz/DummyConsentGatheringType.java | 0 .../ciba/DummyEndUserNotificationType.java | 4 +- .../type/ciba/EndUserNotificationType.java | 0 .../type/client/ClientRegistrationType.java | 0 .../client/DummyClientRegistrationType.java | 0 .../script/type/id/DummyIdGeneratorType.java | 0 .../script/type/id/IdGeneratorType.java | 0 .../introspection/DummyIntrospectionType.java | 0 .../type/introspection/IntrospectionType.java | 0 .../type/logout/DummyEndSessionType.java | 4 +- .../script/type/logout/EndSessionType.java | 0 ...yResourceOwnerPasswordCredentialsType.java | 0 .../ResourceOwnerPasswordCredentialsType.java | 0 .../DummyDynamicPeristenceType.java | 0 .../type/persistence/PersistenceType.java | 0 .../type/postauthn/DummyPostAuthnType.java | 4 +- .../script/type/postauthn/PostAuthnType.java | 0 .../script/type/scim/DummyScimType.java | 0 .../custom/script/type/scim/ScimType.java | 4 +- .../type/scope/DummyDynamicScopeType.java | 0 .../script/type/scope/DynamicScopeType.java | 0 .../type/session/ApplicationSessionType.java | 4 +- .../session/DummyApplicationSessionType.java | 4 +- .../DummySpontaneousScopeType.java | 4 +- .../spontaneous/SpontaneousScopeType.java | 0 .../type/uma/UmaClaimsGatheringType.java | 0 .../type/uma/UmaDummyClaimsGatheringType.java | 0 .../type/uma/UmaDummyRptPolicyType.java | 2 +- .../script/type/uma/UmaRptPolicyType.java | 0 .../script/type/user/CacheRefreshType.java | 0 .../type/user/DummyCacheRefreshType.java | 2 +- .../script/type/user/DummyUpdateUserType.java | 0 .../type/user/DummyUserRegistrationType.java | 0 .../script/type/user/UpdateUserType.java | 0 .../type/user/UserRegistrationType.java | 0 .../java/org/gluu/service/PythonService.java | 2 - .../service/cdi/event/UpdateScriptEvent.java | 0 .../service/custom/inject/ReloadScript.java | 0 .../script/AbstractCustomScriptService.java | 3 +- .../custom/script/CustomScriptManager.java | 0 .../custom/script/ExternalScriptService.java | 16 ++-- .../src/main/resources/META-INF/beans.xml | 7 ++ oxService/pom.xml | 10 +-- .../AuthenticationProtectionService.java | 3 +- pom.xml | 1 + 60 files changed, 141 insertions(+), 43 deletions(-) rename {oxService => core-cdi}/src/main/java/org/gluu/service/cdi/async/Asynchronous.java (100%) rename {oxService => core-cdi}/src/main/java/org/gluu/service/cdi/event/Scheduled.java (100%) create mode 100644 core-script-manager/pom.xml rename {oxService => core-script-manager}/src/main/java/org/gluu/exception/PythonException.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/CustomScriptType.java (93%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/conf/CustomScriptConfiguration.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/model/CustomScript.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/model/ScriptError.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/model/auth/AuthenticationCustomScript.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/model/bind/BindCredentials.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java (97%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/authz/ConsentGatheringType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java (95%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/id/IdGeneratorType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/introspection/IntrospectionType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/owner/ResourceOwnerPasswordCredentialsType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/scope/DynamicScopeType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/uma/UmaClaimsGatheringType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptPolicyType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/user/UpdateUserType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/model/custom/script/type/user/UserRegistrationType.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/service/PythonService.java (99%) rename {oxService => core-script-manager}/src/main/java/org/gluu/service/cdi/event/UpdateScriptEvent.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/service/custom/inject/ReloadScript.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java (99%) rename {oxService => core-script-manager}/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java (100%) rename {oxService => core-script-manager}/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java (99%) create mode 100644 core-script-manager/src/main/resources/META-INF/beans.xml diff --git a/oxService/src/main/java/org/gluu/service/cdi/async/Asynchronous.java b/core-cdi/src/main/java/org/gluu/service/cdi/async/Asynchronous.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cdi/async/Asynchronous.java rename to core-cdi/src/main/java/org/gluu/service/cdi/async/Asynchronous.java diff --git a/oxService/src/main/java/org/gluu/service/cdi/event/Scheduled.java b/core-cdi/src/main/java/org/gluu/service/cdi/event/Scheduled.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cdi/event/Scheduled.java rename to core-cdi/src/main/java/org/gluu/service/cdi/event/Scheduled.java diff --git a/core-script-manager/pom.xml b/core-script-manager/pom.xml new file mode 100644 index 00000000..77002e25 --- /dev/null +++ b/core-script-manager/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + oxcore-script-manager + Reusable CDI Script manager implementation + + + org.gluu + oxcore + 4.2.0-SNAPSHOT + + + + ${maven.min-version} + + + + + + src/main/resources + true + + **/*.xml + **/services/* + **/*.properties + + + + + + + + + ${project.groupId} + oxcore-cdi + + + ${project.groupId} + oxcore-persistence-core + + + ${project.groupId} + oxcore-persistence-model + + + ${project.groupId} + oxcore-model + + + ${project.groupId} + oxcore-util + + + + + org.python + jython-standalone + + + + + javax.enterprise + cdi-api + provided + + + javax.validation + validation-api + provided + + + javax.servlet + javax.servlet-api + provided + + + + + org.slf4j + slf4j-api + provided + + + + \ No newline at end of file diff --git a/oxService/src/main/java/org/gluu/exception/PythonException.java b/core-script-manager/src/main/java/org/gluu/exception/PythonException.java similarity index 100% rename from oxService/src/main/java/org/gluu/exception/PythonException.java rename to core-script-manager/src/main/java/org/gluu/exception/PythonException.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/CustomScriptType.java similarity index 93% rename from oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/CustomScriptType.java index af5a0e19..dce6ce53 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/CustomScriptType.java +++ b/core-script-manager/src/main/java/org/gluu/model/custom/script/CustomScriptType.java @@ -6,6 +6,9 @@ package org.gluu.model.custom.script; +import java.util.HashMap; +import java.util.Map; + import org.gluu.model.custom.script.model.CustomScript; import org.gluu.model.custom.script.model.auth.AuthenticationCustomScript; import org.gluu.model.custom.script.type.BaseExternalType; @@ -25,6 +28,8 @@ import org.gluu.model.custom.script.type.logout.EndSessionType; import org.gluu.model.custom.script.type.owner.DummyResourceOwnerPasswordCredentialsType; import org.gluu.model.custom.script.type.owner.ResourceOwnerPasswordCredentialsType; +import org.gluu.model.custom.script.type.persistence.DummyDynamicPeristenceType; +import org.gluu.model.custom.script.type.persistence.PersistenceType; import org.gluu.model.custom.script.type.postauthn.DummyPostAuthnType; import org.gluu.model.custom.script.type.postauthn.PostAuthnType; import org.gluu.model.custom.script.type.scim.DummyScimType; @@ -39,13 +44,14 @@ import org.gluu.model.custom.script.type.uma.UmaDummyClaimsGatheringType; import org.gluu.model.custom.script.type.uma.UmaDummyRptPolicyType; import org.gluu.model.custom.script.type.uma.UmaRptPolicyType; -import org.gluu.model.custom.script.type.persistence.*; -import org.gluu.model.custom.script.type.user.*; +import org.gluu.model.custom.script.type.user.CacheRefreshType; +import org.gluu.model.custom.script.type.user.DummyCacheRefreshType; +import org.gluu.model.custom.script.type.user.DummyUpdateUserType; +import org.gluu.model.custom.script.type.user.DummyUserRegistrationType; +import org.gluu.model.custom.script.type.user.UpdateUserType; +import org.gluu.model.custom.script.type.user.UserRegistrationType; import org.gluu.persist.annotation.AttributeEnum; -import java.util.HashMap; -import java.util.Map; - /** * List of supported custom scripts * diff --git a/oxService/src/main/java/org/gluu/model/custom/script/conf/CustomScriptConfiguration.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/conf/CustomScriptConfiguration.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/conf/CustomScriptConfiguration.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/conf/CustomScriptConfiguration.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/model/CustomScript.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/model/CustomScript.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/model/CustomScript.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/model/CustomScript.java index 9a72654e..a00ca64f 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/model/CustomScript.java +++ b/core-script-manager/src/main/java/org/gluu/model/custom/script/model/CustomScript.java @@ -17,11 +17,11 @@ import org.gluu.model.SimpleCustomProperty; import org.gluu.model.SimpleExtendedCustomProperty; import org.gluu.model.custom.script.CustomScriptType; -import org.gluu.persist.model.base.BaseEntry; import org.gluu.persist.annotation.AttributeName; import org.gluu.persist.annotation.DataEntry; import org.gluu.persist.annotation.JsonObject; import org.gluu.persist.annotation.ObjectClass; +import org.gluu.persist.model.base.BaseEntry; import org.gluu.util.StringHelper; /** diff --git a/oxService/src/main/java/org/gluu/model/custom/script/model/ScriptError.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/model/ScriptError.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/model/ScriptError.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/model/ScriptError.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/model/auth/AuthenticationCustomScript.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/model/auth/AuthenticationCustomScript.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/model/auth/AuthenticationCustomScript.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/model/auth/AuthenticationCustomScript.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/model/bind/BindCredentials.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/model/bind/BindCredentials.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/model/bind/BindCredentials.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/model/bind/BindCredentials.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java similarity index 97% rename from oxService/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java index f86a508a..fcb478ac 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java +++ b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java @@ -6,13 +6,13 @@ package org.gluu.model.custom.script.type.auth; +import java.util.List; +import java.util.Map; + import org.gluu.model.AuthenticationScriptUsageType; import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.type.BaseExternalType; -import java.util.List; -import java.util.Map; - /** * Base interface for external authentication python script * diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/authz/ConsentGatheringType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/authz/ConsentGatheringType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/authz/ConsentGatheringType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/authz/ConsentGatheringType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java similarity index 95% rename from oxService/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java index 5bd3d5e9..d496a97c 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java +++ b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java @@ -6,11 +6,11 @@ package org.gluu.model.custom.script.type.ciba; +import java.util.Map; + import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.model.CustomScript; -import java.util.Map; - /** * Dummy implementation of interface EndUserNotificationType * diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/id/IdGeneratorType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/id/IdGeneratorType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/id/IdGeneratorType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/id/IdGeneratorType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/introspection/IntrospectionType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/introspection/IntrospectionType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/introspection/IntrospectionType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/introspection/IntrospectionType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java index 35f6f5ca..d8efad8c 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java +++ b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java @@ -1,8 +1,8 @@ package org.gluu.model.custom.script.type.logout; -import org.gluu.model.SimpleCustomProperty; - import java.util.Map; + +import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.model.CustomScript; /** diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/owner/ResourceOwnerPasswordCredentialsType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/owner/ResourceOwnerPasswordCredentialsType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/owner/ResourceOwnerPasswordCredentialsType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/owner/ResourceOwnerPasswordCredentialsType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java index 7186dc3b..d94fcde6 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java +++ b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java @@ -1,10 +1,10 @@ package org.gluu.model.custom.script.type.postauthn; +import java.util.Map; + import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.model.CustomScript; -import java.util.Map; - /** * @author Yuriy Zabrovarnyy */ diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java index 5d3c1ffd..9802f33e 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java +++ b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java @@ -1,10 +1,10 @@ package org.gluu.model.custom.script.type.scim; +import java.util.Map; + import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.type.BaseExternalType; -import java.util.Map; - /** * @author jgomer2001 */ diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/scope/DynamicScopeType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/scope/DynamicScopeType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/scope/DynamicScopeType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/scope/DynamicScopeType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java index 4ed6b636..e5c303bf 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java +++ b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java @@ -5,11 +5,11 @@ */ package org.gluu.model.custom.script.type.session; +import java.util.Map; + import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.type.BaseExternalType; -import java.util.Map; - /** * Base interface for external application session python script * diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java index 6019ea9b..b9849307 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java +++ b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java @@ -4,11 +4,11 @@ * Copyright (c) 2014, Gluu */ package org.gluu.model.custom.script.type.session; +import java.util.Map; + import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.model.CustomScript; -import java.util.Map; - /** * Dummy implementation of interface ApplicationSessionType * diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java index 60887ca3..6b7f676c 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java +++ b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java @@ -1,8 +1,8 @@ package org.gluu.model.custom.script.type.spontaneous; -import org.gluu.model.SimpleCustomProperty; - import java.util.Map; + +import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.model.CustomScript; public class DummySpontaneousScopeType implements SpontaneousScopeType { diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaClaimsGatheringType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaClaimsGatheringType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaClaimsGatheringType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaClaimsGatheringType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java index ad020527..debabd0d 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java +++ b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java @@ -5,8 +5,8 @@ import java.util.Map; import org.gluu.model.SimpleCustomProperty; -import org.gluu.model.uma.ClaimDefinition; import org.gluu.model.custom.script.model.CustomScript; +import org.gluu.model.uma.ClaimDefinition; /** * @author yuriyz on 05/30/2017. */ diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptPolicyType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptPolicyType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptPolicyType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptPolicyType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java index 3ddb65c3..bb8c70da 100644 --- a/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java +++ b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java @@ -8,8 +8,8 @@ import java.util.Map; import org.gluu.model.SimpleCustomProperty; -import org.gluu.model.custom.script.model.bind.BindCredentials; import org.gluu.model.custom.script.model.CustomScript; +import org.gluu.model.custom.script.model.bind.BindCredentials; /** * Dummy implementation of interface CacheRefreshType * diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/user/UpdateUserType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/UpdateUserType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/user/UpdateUserType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/UpdateUserType.java diff --git a/oxService/src/main/java/org/gluu/model/custom/script/type/user/UserRegistrationType.java b/core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/UserRegistrationType.java similarity index 100% rename from oxService/src/main/java/org/gluu/model/custom/script/type/user/UserRegistrationType.java rename to core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/UserRegistrationType.java diff --git a/oxService/src/main/java/org/gluu/service/PythonService.java b/core-script-manager/src/main/java/org/gluu/service/PythonService.java similarity index 99% rename from oxService/src/main/java/org/gluu/service/PythonService.java rename to core-script-manager/src/main/java/org/gluu/service/PythonService.java index 90823470..d3486a25 100644 --- a/oxService/src/main/java/org/gluu/service/PythonService.java +++ b/core-script-manager/src/main/java/org/gluu/service/PythonService.java @@ -19,7 +19,6 @@ import javax.annotation.PreDestroy; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; -import javax.inject.Named; import org.gluu.exception.PythonException; import org.gluu.persist.reflect.util.ReflectHelper; @@ -35,7 +34,6 @@ * @author Yuriy Movchan Date: 08.21.2012 */ @ApplicationScoped -@Named public class PythonService implements Serializable { private static final long serialVersionUID = 3398422090669045605L; diff --git a/oxService/src/main/java/org/gluu/service/cdi/event/UpdateScriptEvent.java b/core-script-manager/src/main/java/org/gluu/service/cdi/event/UpdateScriptEvent.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/cdi/event/UpdateScriptEvent.java rename to core-script-manager/src/main/java/org/gluu/service/cdi/event/UpdateScriptEvent.java diff --git a/oxService/src/main/java/org/gluu/service/custom/inject/ReloadScript.java b/core-script-manager/src/main/java/org/gluu/service/custom/inject/ReloadScript.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/custom/inject/ReloadScript.java rename to core-script-manager/src/main/java/org/gluu/service/custom/inject/ReloadScript.java diff --git a/oxService/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java b/core-script-manager/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java similarity index 99% rename from oxService/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java rename to core-script-manager/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java index 7db1ac36..0b9e9c8a 100644 --- a/oxService/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java +++ b/core-script-manager/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java @@ -14,9 +14,10 @@ import org.gluu.model.custom.script.model.CustomScript; import org.gluu.persist.PersistenceEntryManager; import org.gluu.search.filter.Filter; -import com.google.common.base.Optional; import org.slf4j.Logger; +import com.google.common.base.Optional; + /** * Operations with custom scripts * diff --git a/oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/core-script-manager/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java rename to core-script-manager/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java diff --git a/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java b/core-script-manager/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java similarity index 99% rename from oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java rename to core-script-manager/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java index 6ec4ac9e..d2bb5110 100644 --- a/oxService/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java +++ b/core-script-manager/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java @@ -6,7 +6,14 @@ package org.gluu.service.custom.script; -import com.google.common.collect.Lists; +import java.io.Serializable; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.enterprise.event.Observes; +import javax.inject.Inject; + import org.gluu.model.custom.script.CustomScriptType; import org.gluu.model.custom.script.conf.CustomScriptConfiguration; import org.gluu.model.custom.script.model.CustomScript; @@ -15,12 +22,7 @@ import org.gluu.util.StringHelper; import org.slf4j.Logger; -import javax.enterprise.event.Observes; -import javax.inject.Inject; -import java.io.Serializable; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import com.google.common.collect.Lists; /** * Provides factory methods needed to create external extension diff --git a/core-script-manager/src/main/resources/META-INF/beans.xml b/core-script-manager/src/main/resources/META-INF/beans.xml new file mode 100644 index 00000000..2f4f7e27 --- /dev/null +++ b/core-script-manager/src/main/resources/META-INF/beans.xml @@ -0,0 +1,7 @@ + + + diff --git a/oxService/pom.xml b/oxService/pom.xml index db0976b1..26ef3602 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -64,6 +64,10 @@ ${project.groupId} oxcore-cache + + ${project.groupId} + oxcore-script-manager + ${project.groupId} oxcore-cdi @@ -121,12 +125,6 @@ provided - - - org.python - jython-standalone - - net.spy diff --git a/oxService/src/main/java/org/gluu/service/security/protect/AuthenticationProtectionService.java b/oxService/src/main/java/org/gluu/service/security/protect/AuthenticationProtectionService.java index c71809d5..945a7c08 100644 --- a/oxService/src/main/java/org/gluu/service/security/protect/AuthenticationProtectionService.java +++ b/oxService/src/main/java/org/gluu/service/security/protect/AuthenticationProtectionService.java @@ -8,7 +8,6 @@ import org.gluu.model.security.protect.AuthenticationAttempt; import org.gluu.model.security.protect.AuthenticationAttemptList; import org.gluu.service.CacheService; -import org.python.jline.internal.Log; import org.slf4j.Logger; /** @@ -105,7 +104,7 @@ public void doDelayIfNeeded(String key) { log.debug("Current login attempt requires delay: '{}' seconds", delayTime); Thread.sleep(delayTime * 1000); } catch (InterruptedException ex) { - Log.error("Failed to process authentication delay"); + log.error("Failed to process authentication delay"); } } diff --git a/pom.xml b/pom.xml index 9c18bbd2..6a69d377 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,7 @@ core-timer-weld security-extension-cdi exception-extension-cdi + core-script-manager oxService server oxRadius From 3ba9a4de07d7b7024c6c51a82373905317531e46 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 18 Jun 2020 13:22:56 +0300 Subject: [PATCH 184/362] Move cache services to cache library --- .../src/main/java/org/gluu/service/BaseCacheService.java | 0 .../src/main/java/org/gluu/service/CacheService.java | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {oxService => core-cache}/src/main/java/org/gluu/service/BaseCacheService.java (100%) rename {oxService => core-cache}/src/main/java/org/gluu/service/CacheService.java (100%) diff --git a/oxService/src/main/java/org/gluu/service/BaseCacheService.java b/core-cache/src/main/java/org/gluu/service/BaseCacheService.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/BaseCacheService.java rename to core-cache/src/main/java/org/gluu/service/BaseCacheService.java diff --git a/oxService/src/main/java/org/gluu/service/CacheService.java b/core-cache/src/main/java/org/gluu/service/CacheService.java similarity index 100% rename from oxService/src/main/java/org/gluu/service/CacheService.java rename to core-cache/src/main/java/org/gluu/service/CacheService.java From 6b12fc75da1a09a53d82777e3c7ed5074ece0f4e Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 18 Jun 2020 13:39:06 +0300 Subject: [PATCH 185/362] Rename library script-manager to script --- {core-script-manager => core-script}/pom.xml | 2 +- .../src/main/java/org/gluu/exception/PythonException.java | 0 .../java/org/gluu/model/custom/script/CustomScriptType.java | 0 .../model/custom/script/conf/CustomScriptConfiguration.java | 0 .../java/org/gluu/model/custom/script/model/CustomScript.java | 0 .../java/org/gluu/model/custom/script/model/ScriptError.java | 0 .../java/org/gluu/model/custom/script/model/ScriptTemplate.java | 0 .../custom/script/model/auth/AuthenticationCustomScript.java | 0 .../gluu/model/custom/script/model/bind/BindCredentials.java | 0 .../org/gluu/model/custom/script/type/BaseExternalType.java | 0 .../custom/script/type/auth/DummyPersonAuthenticationType.java | 0 .../model/custom/script/type/auth/PersonAuthenticationType.java | 0 .../model/custom/script/type/authz/ConsentGatheringType.java | 0 .../custom/script/type/authz/DummyConsentGatheringType.java | 0 .../custom/script/type/ciba/DummyEndUserNotificationType.java | 0 .../model/custom/script/type/ciba/EndUserNotificationType.java | 0 .../model/custom/script/type/client/ClientRegistrationType.java | 0 .../custom/script/type/client/DummyClientRegistrationType.java | 0 .../gluu/model/custom/script/type/id/DummyIdGeneratorType.java | 0 .../org/gluu/model/custom/script/type/id/IdGeneratorType.java | 0 .../script/type/introspection/DummyIntrospectionType.java | 0 .../custom/script/type/introspection/IntrospectionType.java | 0 .../model/custom/script/type/logout/DummyEndSessionType.java | 0 .../gluu/model/custom/script/type/logout/EndSessionType.java | 0 .../type/owner/DummyResourceOwnerPasswordCredentialsType.java | 0 .../script/type/owner/ResourceOwnerPasswordCredentialsType.java | 0 .../script/type/persistence/DummyDynamicPeristenceType.java | 0 .../model/custom/script/type/persistence/PersistenceType.java | 0 .../model/custom/script/type/postauthn/DummyPostAuthnType.java | 0 .../gluu/model/custom/script/type/postauthn/PostAuthnType.java | 0 .../org/gluu/model/custom/script/type/scim/DummyScimType.java | 0 .../java/org/gluu/model/custom/script/type/scim/ScimType.java | 0 .../model/custom/script/type/scope/DummyDynamicScopeType.java | 0 .../gluu/model/custom/script/type/scope/DynamicScopeType.java | 0 .../custom/script/type/session/ApplicationSessionType.java | 0 .../custom/script/type/session/DummyApplicationSessionType.java | 0 .../script/type/spontaneous/DummySpontaneousScopeType.java | 0 .../custom/script/type/spontaneous/SpontaneousScopeType.java | 0 .../model/custom/script/type/uma/UmaClaimsGatheringType.java | 0 .../custom/script/type/uma/UmaDummyClaimsGatheringType.java | 0 .../model/custom/script/type/uma/UmaDummyRptPolicyType.java | 0 .../org/gluu/model/custom/script/type/uma/UmaRptPolicyType.java | 0 .../gluu/model/custom/script/type/user/CacheRefreshType.java | 0 .../model/custom/script/type/user/DummyCacheRefreshType.java | 0 .../gluu/model/custom/script/type/user/DummyUpdateUserType.java | 0 .../custom/script/type/user/DummyUserRegistrationType.java | 0 .../org/gluu/model/custom/script/type/user/UpdateUserType.java | 0 .../model/custom/script/type/user/UserRegistrationType.java | 0 .../src/main/java/org/gluu/service/PythonService.java | 0 .../main/java/org/gluu/service/cdi/event/UpdateScriptEvent.java | 0 .../main/java/org/gluu/service/custom/inject/ReloadScript.java | 0 .../gluu/service/custom/script/AbstractCustomScriptService.java | 0 .../org/gluu/service/custom/script/CustomScriptManager.java | 0 .../org/gluu/service/custom/script/ExternalScriptService.java | 0 .../src/main/resources/META-INF/beans.xml | 0 pom.xml | 2 +- 56 files changed, 2 insertions(+), 2 deletions(-) rename {core-script-manager => core-script}/pom.xml (97%) rename {core-script-manager => core-script}/src/main/java/org/gluu/exception/PythonException.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/CustomScriptType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/conf/CustomScriptConfiguration.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/model/CustomScript.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/model/ScriptError.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/model/auth/AuthenticationCustomScript.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/model/bind/BindCredentials.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/authz/ConsentGatheringType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/id/IdGeneratorType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/introspection/IntrospectionType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/owner/ResourceOwnerPasswordCredentialsType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/scope/DynamicScopeType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/uma/UmaClaimsGatheringType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptPolicyType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/user/UpdateUserType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/model/custom/script/type/user/UserRegistrationType.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/service/PythonService.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/service/cdi/event/UpdateScriptEvent.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/service/custom/inject/ReloadScript.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java (100%) rename {core-script-manager => core-script}/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java (100%) rename {core-script-manager => core-script}/src/main/resources/META-INF/beans.xml (100%) diff --git a/core-script-manager/pom.xml b/core-script/pom.xml similarity index 97% rename from core-script-manager/pom.xml rename to core-script/pom.xml index 77002e25..b97afa5f 100644 --- a/core-script-manager/pom.xml +++ b/core-script/pom.xml @@ -2,7 +2,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - oxcore-script-manager + oxcore-script Reusable CDI Script manager implementation diff --git a/core-script-manager/src/main/java/org/gluu/exception/PythonException.java b/core-script/src/main/java/org/gluu/exception/PythonException.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/exception/PythonException.java rename to core-script/src/main/java/org/gluu/exception/PythonException.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/CustomScriptType.java b/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/CustomScriptType.java rename to core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/conf/CustomScriptConfiguration.java b/core-script/src/main/java/org/gluu/model/custom/script/conf/CustomScriptConfiguration.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/conf/CustomScriptConfiguration.java rename to core-script/src/main/java/org/gluu/model/custom/script/conf/CustomScriptConfiguration.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/model/CustomScript.java b/core-script/src/main/java/org/gluu/model/custom/script/model/CustomScript.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/model/CustomScript.java rename to core-script/src/main/java/org/gluu/model/custom/script/model/CustomScript.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/model/ScriptError.java b/core-script/src/main/java/org/gluu/model/custom/script/model/ScriptError.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/model/ScriptError.java rename to core-script/src/main/java/org/gluu/model/custom/script/model/ScriptError.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java b/core-script/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java rename to core-script/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/model/auth/AuthenticationCustomScript.java b/core-script/src/main/java/org/gluu/model/custom/script/model/auth/AuthenticationCustomScript.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/model/auth/AuthenticationCustomScript.java rename to core-script/src/main/java/org/gluu/model/custom/script/model/auth/AuthenticationCustomScript.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/model/bind/BindCredentials.java b/core-script/src/main/java/org/gluu/model/custom/script/model/bind/BindCredentials.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/model/bind/BindCredentials.java rename to core-script/src/main/java/org/gluu/model/custom/script/model/bind/BindCredentials.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/BaseExternalType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/auth/DummyPersonAuthenticationType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/auth/PersonAuthenticationType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/authz/ConsentGatheringType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/authz/ConsentGatheringType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/authz/ConsentGatheringType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/authz/ConsentGatheringType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/authz/DummyConsentGatheringType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/ciba/DummyEndUserNotificationType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/ciba/EndUserNotificationType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/id/DummyIdGeneratorType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/id/IdGeneratorType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/id/IdGeneratorType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/id/IdGeneratorType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/id/IdGeneratorType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/introspection/DummyIntrospectionType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/introspection/IntrospectionType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/introspection/IntrospectionType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/introspection/IntrospectionType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/introspection/IntrospectionType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/logout/DummyEndSessionType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/logout/EndSessionType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/owner/DummyResourceOwnerPasswordCredentialsType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/owner/ResourceOwnerPasswordCredentialsType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/owner/ResourceOwnerPasswordCredentialsType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/owner/ResourceOwnerPasswordCredentialsType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/owner/ResourceOwnerPasswordCredentialsType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/postauthn/DummyPostAuthnType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/postauthn/PostAuthnType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/scope/DummyDynamicScopeType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/scope/DynamicScopeType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/scope/DynamicScopeType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/scope/DynamicScopeType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/scope/DynamicScopeType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/session/ApplicationSessionType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/session/DummyApplicationSessionType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/spontaneous/DummySpontaneousScopeType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/spontaneous/SpontaneousScopeType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaClaimsGatheringType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaClaimsGatheringType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaClaimsGatheringType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaClaimsGatheringType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyClaimsGatheringType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptPolicyType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptPolicyType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptPolicyType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptPolicyType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptPolicyType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/user/DummyUpdateUserType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/user/DummyUserRegistrationType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/UpdateUserType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/user/UpdateUserType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/UpdateUserType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/user/UpdateUserType.java diff --git a/core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/UserRegistrationType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/user/UserRegistrationType.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/model/custom/script/type/user/UserRegistrationType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/user/UserRegistrationType.java diff --git a/core-script-manager/src/main/java/org/gluu/service/PythonService.java b/core-script/src/main/java/org/gluu/service/PythonService.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/service/PythonService.java rename to core-script/src/main/java/org/gluu/service/PythonService.java diff --git a/core-script-manager/src/main/java/org/gluu/service/cdi/event/UpdateScriptEvent.java b/core-script/src/main/java/org/gluu/service/cdi/event/UpdateScriptEvent.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/service/cdi/event/UpdateScriptEvent.java rename to core-script/src/main/java/org/gluu/service/cdi/event/UpdateScriptEvent.java diff --git a/core-script-manager/src/main/java/org/gluu/service/custom/inject/ReloadScript.java b/core-script/src/main/java/org/gluu/service/custom/inject/ReloadScript.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/service/custom/inject/ReloadScript.java rename to core-script/src/main/java/org/gluu/service/custom/inject/ReloadScript.java diff --git a/core-script-manager/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java b/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java rename to core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java diff --git a/core-script-manager/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java rename to core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java diff --git a/core-script-manager/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java b/core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java similarity index 100% rename from core-script-manager/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java rename to core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java diff --git a/core-script-manager/src/main/resources/META-INF/beans.xml b/core-script/src/main/resources/META-INF/beans.xml similarity index 100% rename from core-script-manager/src/main/resources/META-INF/beans.xml rename to core-script/src/main/resources/META-INF/beans.xml diff --git a/pom.xml b/pom.xml index 6a69d377..4f2498cd 100644 --- a/pom.xml +++ b/pom.xml @@ -49,7 +49,7 @@ core-timer-weld security-extension-cdi exception-extension-cdi - core-script-manager + core-script oxService server oxRadius From dc1b4bb55e54672acc18461709e82d5bc9865e2e Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 18 Jun 2020 13:53:38 +0300 Subject: [PATCH 186/362] Fix library name --- oxService/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxService/pom.xml b/oxService/pom.xml index 26ef3602..05f5ee09 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -66,7 +66,7 @@ ${project.groupId} - oxcore-script-manager + oxcore-script ${project.groupId} From 2009023e18e02522e03ea07d2a2b2f095f97499d Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 18 Jun 2020 14:11:12 +0300 Subject: [PATCH 187/362] Add Idp custom script type --- .../model/custom/script/CustomScriptType.java | 7 ++- .../custom/script/type/idp/DummyIdpType.java | 43 +++++++++++++++++++ .../model/custom/script/type/idp/IdpType.java | 23 ++++++++++ ...enceType.java => DummyPeristenceType.java} | 2 +- 4 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 core-script/src/main/java/org/gluu/model/custom/script/type/idp/DummyIdpType.java create mode 100644 core-script/src/main/java/org/gluu/model/custom/script/type/idp/IdpType.java rename core-script/src/main/java/org/gluu/model/custom/script/type/persistence/{DummyDynamicPeristenceType.java => DummyPeristenceType.java} (94%) diff --git a/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java b/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java index dce6ce53..9c997885 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java @@ -22,13 +22,15 @@ import org.gluu.model.custom.script.type.client.DummyClientRegistrationType; import org.gluu.model.custom.script.type.id.DummyIdGeneratorType; import org.gluu.model.custom.script.type.id.IdGeneratorType; +import org.gluu.model.custom.script.type.idp.DummyIdpType; +import org.gluu.model.custom.script.type.idp.IdpType; import org.gluu.model.custom.script.type.introspection.DummyIntrospectionType; import org.gluu.model.custom.script.type.introspection.IntrospectionType; import org.gluu.model.custom.script.type.logout.DummyEndSessionType; import org.gluu.model.custom.script.type.logout.EndSessionType; import org.gluu.model.custom.script.type.owner.DummyResourceOwnerPasswordCredentialsType; import org.gluu.model.custom.script.type.owner.ResourceOwnerPasswordCredentialsType; -import org.gluu.model.custom.script.type.persistence.DummyDynamicPeristenceType; +import org.gluu.model.custom.script.type.persistence.DummyPeristenceType; import org.gluu.model.custom.script.type.persistence.PersistenceType; import org.gluu.model.custom.script.type.postauthn.DummyPostAuthnType; import org.gluu.model.custom.script.type.postauthn.PostAuthnType; @@ -88,7 +90,8 @@ public enum CustomScriptType implements AttributeEnum { SCIM("scim", "SCIM", ScimType.class, CustomScript.class, "ScimEventHandler", new DummyScimType()), CIBA_END_USER_NOTIFICATION("ciba_end_user_notification", "CIBA End User Notification", EndUserNotificationType.class, CustomScript.class, "EndUserNotification", new DummyEndUserNotificationType()), - PERSISTENCE_EXTENSION("persistence_extension", "Persistence Extension", PersistenceType.class, CustomScript.class, "PersistenceExtension", new DummyDynamicPeristenceType()); + PERSISTENCE_EXTENSION("persistence_extension", "Persistence Extension", PersistenceType.class, CustomScript.class, "PersistenceExtension", new DummyPeristenceType()), + IDP("idp", "Idp Extension", IdpType.class, CustomScript.class, "IdpExtension", new DummyIdpType()); private String value; private String displayName; diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/idp/DummyIdpType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/idp/DummyIdpType.java new file mode 100644 index 00000000..cbf662ca --- /dev/null +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/idp/DummyIdpType.java @@ -0,0 +1,43 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2020, Gluu + */package org.gluu.model.custom.script.type.idp; + +import java.util.Map; + +import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.model.CustomScript; +/** + * Dummy implementation of interface IdpType + * + * @author Yuriy Movchan Date: 06/18/2020 + */ +public class DummyIdpType implements IdpType { + + @Override + public boolean init(Map configurationAttributes) { + return true; + } + + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } + + @Override + public boolean destroy(Map configurationAttributes) { + return true; + } + + @Override + public int getApiVersion() { + return 1; + } + + @Override + public boolean updateAttributes(Object context, Map configurationAttributes) { + return false; + } + +} diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/idp/IdpType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/idp/IdpType.java new file mode 100644 index 00000000..14d23d8e --- /dev/null +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/idp/IdpType.java @@ -0,0 +1,23 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.model.custom.script.type.idp; + +import java.util.Map; + +import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.type.BaseExternalType; + +/** + * Base interface for IDP script + * + * @author Yuriy Movchan Date: 06/18/2020 + */ +public interface IdpType extends BaseExternalType { + + boolean updateAttributes(Object context, Map configurationAttributes); + +} diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/persistence/DummyPeristenceType.java similarity index 94% rename from core-script/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java rename to core-script/src/main/java/org/gluu/model/custom/script/type/persistence/DummyPeristenceType.java index 79cab2b3..ff18e9ec 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/persistence/DummyDynamicPeristenceType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/persistence/DummyPeristenceType.java @@ -13,7 +13,7 @@ * * @author Yuriy Movchan Date: 06/04/2020 */ -public class DummyDynamicPeristenceType implements PersistenceType { +public class DummyPeristenceType implements PersistenceType { @Override public boolean init(Map configurationAttributes) { From 619f3eb1ae09e89745fb152d76888fdd54da890f Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 18 Jun 2020 15:23:44 +0300 Subject: [PATCH 188/362] Fix jsf-api dependecy --- core-script/pom.xml | 2 +- oxService/pom.xml | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/core-script/pom.xml b/core-script/pom.xml index b97afa5f..ae607a62 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -3,7 +3,7 @@ 4.0.0 oxcore-script - Reusable CDI Script manager implementation + Reusable CDI Script implementation org.gluu diff --git a/oxService/pom.xml b/oxService/pom.xml index 05f5ee09..574f8929 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -114,11 +114,6 @@ jsf-api provided - - com.sun.faces - jsf-api - provided - org.glassfish.web el-impl From 3a3989f5f6b4e0aa4ac018604ff661fafa766d9b Mon Sep 17 00:00:00 2001 From: Jose Date: Thu, 18 Jun 2020 11:52:03 -0500 Subject: [PATCH 189/362] Fixes https://github.com/GluuFederation/scim/issues/2 --- .../src/main/java/org/gluu/persist/impl/BaseEntryManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java index 63549ced..ebe201c5 100644 --- a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java @@ -390,7 +390,7 @@ protected List collectAttributeModifications( } else { if (!attributeFromLdap.equals(attributeToPersist)) { if (isEmptyAttributeValues(attributeToPersist) - && !ldapAttributeConfiguration.updateOnly()) { + && (ldapAttributeConfiguration == null || !ldapAttributeConfiguration.updateOnly())) { attributeDataModifications.add(new AttributeDataModification( AttributeModificationType.REMOVE, null, attributeFromLdap)); } else { From 463fe927bfc3294977d1f090c9457a98c6b21f9a Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 19 Jun 2020 20:04:10 +0300 Subject: [PATCH 190/362] Add standalone custom script manager implementation --- core-script/pom.xml | 7 ++ .../java/org/gluu/service/PythonService.java | 5 ++ .../script/AbstractCustomScriptService.java | 4 +- .../custom/script/CustomScriptManager.java | 16 +++- .../custom/script/ExternalScriptService.java | 14 +++ .../script/StandaloneCustomScriptManager.java | 66 ++++++++++++++ .../script/StandaloneCustomScriptService.java | 28 ++++++ .../test/SampleIdpExternalScriptService.java | 53 +++++++++++ .../StandaloneCustomScriptManagerTest.java | 87 +++++++++++++++++++ 9 files changed, 274 insertions(+), 6 deletions(-) create mode 100644 core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptManager.java create mode 100644 core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptService.java create mode 100644 core-script/src/test/java/org/gluu/service/custom/script/test/SampleIdpExternalScriptService.java create mode 100644 core-script/src/test/java/org/gluu/service/custom/script/test/StandaloneCustomScriptManagerTest.java diff --git a/core-script/pom.xml b/core-script/pom.xml index ae607a62..30fc7612 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -81,6 +81,13 @@ slf4j-api provided + + + + ${project.groupId} + oxcore-persistence-ldap + test + \ No newline at end of file diff --git a/core-script/src/main/java/org/gluu/service/PythonService.java b/core-script/src/main/java/org/gluu/service/PythonService.java index d3486a25..e452455b 100644 --- a/core-script/src/main/java/org/gluu/service/PythonService.java +++ b/core-script/src/main/java/org/gluu/service/PythonService.java @@ -27,6 +27,7 @@ import org.python.core.PyObject; import org.python.util.PythonInterpreter; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Provides operations with python module @@ -56,6 +57,10 @@ public void init() { } } + public void configure() { + this.log = LoggerFactory.getLogger(PythonService.class); + } + /* * Initialize singleton instance during startup */ diff --git a/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java b/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java index 0b9e9c8a..cf37690a 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java @@ -28,10 +28,10 @@ public abstract class AbstractCustomScriptService implements Serializable { private static final long serialVersionUID = -6187179012715072064L; @Inject - private Logger log; + protected Logger log; @Inject - private PersistenceEntryManager persistenceEntryManager; + protected PersistenceEntryManager persistenceEntryManager; public void add(CustomScript customScript) { persistenceEntryManager.persist(customScript); diff --git a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java index 5c3649b9..67731539 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java @@ -74,7 +74,7 @@ public class CustomScriptManager implements Serializable { private Event timerEvent; @Inject - private PythonService pythonService; + protected PythonService pythonService; @Inject protected AbstractCustomScriptService customScriptService; @@ -95,8 +95,7 @@ public class CustomScriptManager implements Serializable { public void initTimer(List supportedCustomScriptTypes) { this.supportedCustomScriptTypes = supportedCustomScriptTypes; - this.isActive = new AtomicBoolean(false); - this.lastFinishedTime = System.currentTimeMillis(); + configure(); final int delay = 30; final int interval = DEFAULT_INTERVAL; @@ -107,6 +106,11 @@ public void initTimer(List supportedCustomScriptTypes) { Scheduled.Literal.INSTANCE)); } + protected void configure() { + this.isActive = new AtomicBoolean(false); + this.lastFinishedTime = System.currentTimeMillis(); + } + public void reloadTimerEvent(@Observes @Scheduled UpdateScriptEvent updateScriptEvent) { if (this.isActive.get()) { return; @@ -144,10 +148,14 @@ private void reload() { boolean modified = reloadImpl(); if (modified) { - event.fire(CUSTOM_SCRIPT_MODIFIED_EVENT_TYPE); + updateScriptServices(); } } + protected void updateScriptServices() { + event.fire(CUSTOM_SCRIPT_MODIFIED_EVENT_TYPE); + } + private boolean reloadImpl() { // Load current script revisions List customScripts; diff --git a/core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java b/core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java index d2bb5110..97069570 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java @@ -21,6 +21,7 @@ import org.gluu.service.custom.inject.ReloadScript; import org.gluu.util.StringHelper; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.collect.Lists; @@ -49,6 +50,14 @@ public ExternalScriptService(CustomScriptType customScriptType) { this.customScriptType = customScriptType; } + /** + * Method for standalone usage + */ + public void configure(StandaloneCustomScriptManager customScriptManager) { + this.customScriptManager = customScriptManager; + this.log = LoggerFactory.getLogger(ExternalScriptService.class); + } + public void reload(@Observes @ReloadScript String event) { // Skip reload if global script is not enabled for this application if (!customScriptManager.isSupportedType(customScriptType)) { @@ -151,4 +160,9 @@ public List getCustomScriptConfigurationsByDns(List externalScriptServices = new ArrayList(); + + public StandaloneCustomScriptManager(PersistenceEntryManager entryManager, String scriptsBaseDn, String pythonModulesDir) { + // Configure python service + PythonService pythonService = new PythonService(); + pythonService.configure(); + pythonService.init(); + // Initialize python interpreter + pythonService.initPythonInterpreter(pythonModulesDir); + + // Configure custom script service + StandaloneCustomScriptService standaloneCustomScriptService = new StandaloneCustomScriptService(); + standaloneCustomScriptService.configure(entryManager, scriptsBaseDn); + + this.log = LoggerFactory.getLogger(StandaloneCustomScriptManager.class); + this.supportedCustomScriptTypes = new ArrayList(); + this.pythonService = pythonService; + this.customScriptService = standaloneCustomScriptService; + } + + public void init() { + configure(); + reloadTimerEvent(null); + } + + public void destory() { + super.destroy(null); + } + + public void reload() { + reloadTimerEvent(null); + } + + public void registerExternalScriptService(ExternalScriptService externalScriptService) { + externalScriptService.configure(this); + externalScriptServices.add(externalScriptService); + supportedCustomScriptTypes.add(externalScriptService.getCustomScriptType()); + } + + @Override + public void updateScriptServices() { + for (ExternalScriptService externalScriptService : externalScriptServices) { + externalScriptService.reload(null); + } + } + +} diff --git a/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptService.java b/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptService.java new file mode 100644 index 00000000..ce11ee1d --- /dev/null +++ b/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptService.java @@ -0,0 +1,28 @@ +package org.gluu.service.custom.script; + +import org.gluu.persist.PersistenceEntryManager; +import org.gluu.service.PythonService; +import org.slf4j.LoggerFactory; + +/** + * Operations with custom scripts + * + * @author Yuriy Movchan Date: 06/19/2020 + */ +public class StandaloneCustomScriptService extends AbstractCustomScriptService { + + private static final long serialVersionUID = -5283102477313448031L; + + private String scriptsBaseDn; + + public void configure(PersistenceEntryManager entryManager, String scriptsBaseDn) { + this.scriptsBaseDn = scriptsBaseDn; + this.log = LoggerFactory.getLogger(PythonService.class); + this.persistenceEntryManager = entryManager; + } + + public String baseDn() { + return scriptsBaseDn; + } + +} diff --git a/core-script/src/test/java/org/gluu/service/custom/script/test/SampleIdpExternalScriptService.java b/core-script/src/test/java/org/gluu/service/custom/script/test/SampleIdpExternalScriptService.java new file mode 100644 index 00000000..c2f543da --- /dev/null +++ b/core-script/src/test/java/org/gluu/service/custom/script/test/SampleIdpExternalScriptService.java @@ -0,0 +1,53 @@ +package org.gluu.service.custom.script.test; + +import java.util.Map; + +import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.CustomScriptType; +import org.gluu.model.custom.script.conf.CustomScriptConfiguration; +import org.gluu.model.custom.script.type.idp.IdpType; +import org.gluu.service.custom.script.ExternalScriptService; + +/** + * External IDP script service + * + * @author Yuriy Movchan + * @version 0.1, 06/18/2020 + */ +public class SampleIdpExternalScriptService extends ExternalScriptService { + + private static final long serialVersionUID = -1316361273036208685L; + + public SampleIdpExternalScriptService() { + super(CustomScriptType.IDP); + } + + public boolean executeExternalUpdateAttributesMethod(Object context, CustomScriptConfiguration customScriptConfiguration) { + try { + log.debug("Executing python 'updateAttributes' method"); + IdpType idpType = (IdpType) customScriptConfiguration.getExternalType(); + Map configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); + return idpType.updateAttributes(context, configurationAttributes); + } catch (Exception ex) { + log.error(ex.getMessage(), ex); + saveScriptError(customScriptConfiguration.getCustomScript(), ex); + } + + return false; + } + + public boolean executeExternalUpdateAttributesMethods(Object context) { + boolean result = true; + for (CustomScriptConfiguration customScriptConfiguration : this.customScriptConfigurations) { + if (customScriptConfiguration.getExternalType().getApiVersion() > 1) { + result &= executeExternalUpdateAttributesMethod(context, customScriptConfiguration); + if (!result) { + return result; + } + } + } + + return result; + } + +} diff --git a/core-script/src/test/java/org/gluu/service/custom/script/test/StandaloneCustomScriptManagerTest.java b/core-script/src/test/java/org/gluu/service/custom/script/test/StandaloneCustomScriptManagerTest.java new file mode 100644 index 00000000..54b84ccf --- /dev/null +++ b/core-script/src/test/java/org/gluu/service/custom/script/test/StandaloneCustomScriptManagerTest.java @@ -0,0 +1,87 @@ +package org.gluu.service.custom.script.test; + +import java.util.Properties; + +import org.apache.log4j.Logger; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.status.StatusLogger; +import org.gluu.log.LoggingHelper; +import org.gluu.persist.PersistenceEntryManager; +import org.gluu.persist.ldap.impl.LdapEntryManager; +import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; +import org.gluu.service.custom.script.StandaloneCustomScriptManager; + +public class StandaloneCustomScriptManagerTest { + + private static final Logger LOG = Logger.getLogger(StandaloneCustomScriptManagerTest.class); + + static { + StatusLogger.getLogger().setLevel(Level.OFF); + LoggingHelper.configureConsoleAppender(); + } + + private static Properties getSampleConnectionProperties() { + Properties connectionProperties = new Properties(); + + connectionProperties.put("ldap.bindDN", "cn=Directory Manager"); + connectionProperties.put("ldap.bindPassword", "Secret1!"); +// connectionProperties.put("ldap.bindPassword", "test"); + connectionProperties.put("ldap.servers", "localhost:1636"); + connectionProperties.put("ldap.useSSL", "true"); + connectionProperties.put("ldap.maxconnections", "3"); + + return connectionProperties; + } + + public static LdapEntryManager createLdapEntryManager() { + LdapEntryManagerFactory ldapEntryManagerFactory = new LdapEntryManagerFactory(); + Properties connectionProperties = getSampleConnectionProperties(); + + LdapEntryManager ldapEntryManager = ldapEntryManagerFactory.createEntryManager(connectionProperties); + LOG.debug("Created LdapEntryManager: " + ldapEntryManager); + + return ldapEntryManager; + } + + public static void main(String[] args) { + if (System.getenv("PYTHON_HOME") == null) { + System.err.println("PYTHON_HOME environment variable is not defined"); + System.exit(-1); + } + + PersistenceEntryManager persistenceEntryManager = createLdapEntryManager(); + StandaloneCustomScriptManager customScriptManager = new StandaloneCustomScriptManager(persistenceEntryManager, "ou=scripts,o=gluu", "/opt/gluu/python/libs"); + + // Register required external scripts + SampleIdpExternalScriptService sampleIdpExternalScriptService = new SampleIdpExternalScriptService(); + customScriptManager.registerExternalScriptService(sampleIdpExternalScriptService); + + // Init script manager and load scripts + customScriptManager.init(); + + // Call script + Object context = new SampleContext(System.currentTimeMillis()); + sampleIdpExternalScriptService.executeExternalUpdateAttributesMethods(context); + + // Reload script if needed + customScriptManager.init(); + + // Call script + Object context2 = new SampleContext(System.currentTimeMillis()); + sampleIdpExternalScriptService.executeExternalUpdateAttributesMethods(context2); + + // Destroy custom script manager and scripts + customScriptManager.destory(); + } + + private static class SampleContext { + + long time; + + public SampleContext(long time) { + super(); + this.time = time; + } + } + +} From f1ebc761bd5f7fe58df54e65669420b2d78a4b03 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 19 Jun 2020 20:48:13 +0300 Subject: [PATCH 191/362] Allow to get base configuration --- .../main/java/org/gluu/conf/service/ConfigurationFactory.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java b/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java index b9229a20..a8931d90 100644 --- a/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java +++ b/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java @@ -281,6 +281,10 @@ public FileConfiguration getPersistenceConfiguration() { return this.persistenceConfiguration.getConfiguration(); } + public FileConfiguration getBaseConfiguration() { + return baseConfiguration; + } + public String getCryptoConfigurationSalt() { return cryptoConfigurationSalt; } From f76352225284c9125d716ffbb307d37b6adf7df2 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 22 Jun 2020 16:38:15 +0300 Subject: [PATCH 192/362] Add @Vetoed to StandaloneCustomScriptService --- .../service/custom/script/StandaloneCustomScriptService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptService.java b/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptService.java index ce11ee1d..4b8c266f 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptService.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptService.java @@ -1,5 +1,7 @@ package org.gluu.service.custom.script; +import javax.enterprise.inject.Vetoed; + import org.gluu.persist.PersistenceEntryManager; import org.gluu.service.PythonService; import org.slf4j.LoggerFactory; @@ -9,6 +11,7 @@ * * @author Yuriy Movchan Date: 06/19/2020 */ +@Vetoed public class StandaloneCustomScriptService extends AbstractCustomScriptService { private static final long serialVersionUID = -5283102477313448031L; From bbc6224c16b5df0c346b60b9add7ad346d5e76c7 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 22 Jun 2020 16:54:10 +0300 Subject: [PATCH 193/362] Add vetoed to StandaloneCustomScriptManager --- .../service/custom/script/StandaloneCustomScriptManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptManager.java b/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptManager.java index 85bbc56f..46563f40 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptManager.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptManager.java @@ -3,6 +3,8 @@ import java.util.ArrayList; import java.util.List; +import javax.enterprise.inject.Vetoed; + import org.gluu.model.custom.script.CustomScriptType; import org.gluu.persist.PersistenceEntryManager; import org.gluu.service.PythonService; @@ -13,6 +15,7 @@ * * @author Yuriy Movchan Date: 06/19/2020 */ +@Vetoed public class StandaloneCustomScriptManager extends CustomScriptManager { private static final long serialVersionUID = -7212146007659551839L; From cf341fcf7bfc1972073a48104aaa80623cf9334f Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 23 Jun 2020 16:48:58 +0300 Subject: [PATCH 194/362] Fix scripts reload in sample --- .../custom/script/test/StandaloneCustomScriptManagerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-script/src/test/java/org/gluu/service/custom/script/test/StandaloneCustomScriptManagerTest.java b/core-script/src/test/java/org/gluu/service/custom/script/test/StandaloneCustomScriptManagerTest.java index 54b84ccf..1275bd00 100644 --- a/core-script/src/test/java/org/gluu/service/custom/script/test/StandaloneCustomScriptManagerTest.java +++ b/core-script/src/test/java/org/gluu/service/custom/script/test/StandaloneCustomScriptManagerTest.java @@ -55,7 +55,7 @@ public static void main(String[] args) { // Register required external scripts SampleIdpExternalScriptService sampleIdpExternalScriptService = new SampleIdpExternalScriptService(); customScriptManager.registerExternalScriptService(sampleIdpExternalScriptService); - + // Init script manager and load scripts customScriptManager.init(); @@ -64,7 +64,7 @@ public static void main(String[] args) { sampleIdpExternalScriptService.executeExternalUpdateAttributesMethods(context); // Reload script if needed - customScriptManager.init(); + customScriptManager.reload(); // Call script Object context2 = new SampleContext(System.currentTimeMillis()); From f687fd584a262785730d3f717570f3f60c6e01cb Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 24 Jun 2020 12:44:38 +0300 Subject: [PATCH 195/362] Add translate attributes method to IDP script --- .../custom/script/type/idp/DummyIdpType.java | 5 + .../model/custom/script/type/idp/IdpType.java | 2 + .../test/SampleIdpExternalScriptService.java | 98 ++++++++++++------- 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/idp/DummyIdpType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/idp/DummyIdpType.java index cbf662ca..f8efb778 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/idp/DummyIdpType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/idp/DummyIdpType.java @@ -35,6 +35,11 @@ public int getApiVersion() { return 1; } + @Override + public boolean translateAttributes(Object context, Map configurationAttributes) { + return false; + } + @Override public boolean updateAttributes(Object context, Map configurationAttributes) { return false; diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/idp/IdpType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/idp/IdpType.java index 14d23d8e..4b9de9f6 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/idp/IdpType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/idp/IdpType.java @@ -18,6 +18,8 @@ */ public interface IdpType extends BaseExternalType { + boolean translateAttributes(Object context, Map configurationAttributes); + boolean updateAttributes(Object context, Map configurationAttributes); } diff --git a/core-script/src/test/java/org/gluu/service/custom/script/test/SampleIdpExternalScriptService.java b/core-script/src/test/java/org/gluu/service/custom/script/test/SampleIdpExternalScriptService.java index c2f543da..b206c21c 100644 --- a/core-script/src/test/java/org/gluu/service/custom/script/test/SampleIdpExternalScriptService.java +++ b/core-script/src/test/java/org/gluu/service/custom/script/test/SampleIdpExternalScriptService.java @@ -16,38 +16,70 @@ */ public class SampleIdpExternalScriptService extends ExternalScriptService { - private static final long serialVersionUID = -1316361273036208685L; - - public SampleIdpExternalScriptService() { - super(CustomScriptType.IDP); - } - - public boolean executeExternalUpdateAttributesMethod(Object context, CustomScriptConfiguration customScriptConfiguration) { - try { - log.debug("Executing python 'updateAttributes' method"); - IdpType idpType = (IdpType) customScriptConfiguration.getExternalType(); - Map configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); - return idpType.updateAttributes(context, configurationAttributes); - } catch (Exception ex) { - log.error(ex.getMessage(), ex); - saveScriptError(customScriptConfiguration.getCustomScript(), ex); - } - - return false; - } - - public boolean executeExternalUpdateAttributesMethods(Object context) { - boolean result = true; - for (CustomScriptConfiguration customScriptConfiguration : this.customScriptConfigurations) { - if (customScriptConfiguration.getExternalType().getApiVersion() > 1) { - result &= executeExternalUpdateAttributesMethod(context, customScriptConfiguration); - if (!result) { - return result; - } - } - } - - return result; - } + private static final long serialVersionUID = -1316361273036208685L; + + public SampleIdpExternalScriptService() { + super(CustomScriptType.IDP); + } + + // boolean translateAttributes(Object context, Map configurationAttributes); + + public boolean executeExternalTranslateAttributesMethod(Object context, CustomScriptConfiguration customScriptConfiguration) { + try { + log.debug("Executing python 'translateAttributes' method"); + IdpType idpType = (IdpType) customScriptConfiguration.getExternalType(); + Map configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); + return idpType.translateAttributes(context, configurationAttributes); + } catch (Exception ex) { + log.error(ex.getMessage(), ex); + saveScriptError(customScriptConfiguration.getCustomScript(), ex); + } + + return false; + } + + public boolean executeExternalTranslateAttributesMethod(Object context) { + boolean result = true; + for (CustomScriptConfiguration customScriptConfiguration : this.customScriptConfigurations) { + if (customScriptConfiguration.getExternalType().getApiVersion() > 1) { + result &= executeExternalTranslateAttributesMethod(context, customScriptConfiguration); + if (!result) { + return result; + } + } + } + + return result; + } + + // boolean updateAttributes(Object context, Map configurationAttributes); + + public boolean executeExternalUpdateAttributesMethod(Object context, CustomScriptConfiguration customScriptConfiguration) { + try { + log.debug("Executing python 'updateAttributes' method"); + IdpType idpType = (IdpType) customScriptConfiguration.getExternalType(); + Map configurationAttributes = customScriptConfiguration.getConfigurationAttributes(); + return idpType.updateAttributes(context, configurationAttributes); + } catch (Exception ex) { + log.error(ex.getMessage(), ex); + saveScriptError(customScriptConfiguration.getCustomScript(), ex); + } + + return false; + } + + public boolean executeExternalUpdateAttributesMethods(Object context) { + boolean result = true; + for (CustomScriptConfiguration customScriptConfiguration : this.customScriptConfigurations) { + if (customScriptConfiguration.getExternalType().getApiVersion() > 1) { + result &= executeExternalUpdateAttributesMethod(context, customScriptConfiguration); + if (!result) { + return result; + } + } + } + + return result; + } } From 04d770dc0ff482ee51397809b95036e1d65585e2 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 24 Jun 2020 12:58:56 +0300 Subject: [PATCH 196/362] Allow to reuse script manager constants --- .../org/gluu/service/custom/script/CustomScriptManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java index 67731539..4c281659 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java @@ -62,7 +62,7 @@ public class CustomScriptManager implements Serializable { private static final long serialVersionUID = -4225890597520443390L; public static final String CUSTOM_SCRIPT_MODIFIED_EVENT_TYPE = "customScriptModifiedEvent"; - private static final int DEFAULT_INTERVAL = 30; // 30 seconds + public static final int DEFAULT_INTERVAL = 30; // 30 seconds public static final String[] CUSTOM_SCRIPT_CHECK_ATTRIBUTES = { "dn", "inum", "oxRevision", "oxScriptType", "oxModuleProperty", "oxEnabled" }; From 87005675ee1e600102d5a5a04fc1273dc2fe9d80 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 24 Jun 2020 18:03:34 +0300 Subject: [PATCH 197/362] Fix typo --- .../service/custom/script/AbstractCustomScriptService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java b/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java index cf37690a..23f01c1f 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java @@ -2,7 +2,8 @@ * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. * * Copyright (c) 2014, Gluu - */package org.gluu.service.custom.script; + */ +package org.gluu.service.custom.script; import java.io.Serializable; import java.util.ArrayList; From 0af0be343f678683dd6642e4e48f62f38ca1e993 Mon Sep 17 00:00:00 2001 From: Yuriy Zabrovarnyy Date: Thu, 25 Jun 2020 15:41:13 +0300 Subject: [PATCH 198/362] Added definition of UMA RPT Claims script. https://github.com/GluuFederation/oxAuth/issues/1397 --- .../model/custom/script/CustomScriptType.java | 19 +++------- .../type/uma/UmaDummyRptClaimsType.java | 37 +++++++++++++++++++ .../script/type/uma/UmaRptClaimsType.java | 11 ++++++ 3 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptClaimsType.java create mode 100644 core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptClaimsType.java diff --git a/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java b/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java index 9c997885..1f931515 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java @@ -6,9 +6,6 @@ package org.gluu.model.custom.script; -import java.util.HashMap; -import java.util.Map; - import org.gluu.model.custom.script.model.CustomScript; import org.gluu.model.custom.script.model.auth.AuthenticationCustomScript; import org.gluu.model.custom.script.type.BaseExternalType; @@ -42,18 +39,13 @@ import org.gluu.model.custom.script.type.session.DummyApplicationSessionType; import org.gluu.model.custom.script.type.spontaneous.DummySpontaneousScopeType; import org.gluu.model.custom.script.type.spontaneous.SpontaneousScopeType; -import org.gluu.model.custom.script.type.uma.UmaClaimsGatheringType; -import org.gluu.model.custom.script.type.uma.UmaDummyClaimsGatheringType; -import org.gluu.model.custom.script.type.uma.UmaDummyRptPolicyType; -import org.gluu.model.custom.script.type.uma.UmaRptPolicyType; -import org.gluu.model.custom.script.type.user.CacheRefreshType; -import org.gluu.model.custom.script.type.user.DummyCacheRefreshType; -import org.gluu.model.custom.script.type.user.DummyUpdateUserType; -import org.gluu.model.custom.script.type.user.DummyUserRegistrationType; -import org.gluu.model.custom.script.type.user.UpdateUserType; -import org.gluu.model.custom.script.type.user.UserRegistrationType; +import org.gluu.model.custom.script.type.uma.*; +import org.gluu.model.custom.script.type.user.*; import org.gluu.persist.annotation.AttributeEnum; +import java.util.HashMap; +import java.util.Map; + /** * List of supported custom scripts * @@ -78,6 +70,7 @@ public enum CustomScriptType implements AttributeEnum { new DummyIdGeneratorType()), UMA_RPT_POLICY("uma_rpt_policy", "UMA RPT Policies", UmaRptPolicyType.class, CustomScript.class, "UmaRptPolicy", new UmaDummyRptPolicyType()), + UMA_RPT_CLAIMS("uma_rpt_claims", "UMA RPT Claims", UmaRptClaimsType.class, CustomScript.class, "UmaRptClaims", new UmaDummyRptClaimsType()), UMA_CLAIMS_GATHERING("uma_claims_gathering", "UMA Claims Gathering", UmaClaimsGatheringType.class, CustomScript.class, "UmaClaimsGathering", new UmaDummyClaimsGatheringType()), CONSENT_GATHERING("consent_gathering", "Consent Gathering", ConsentGatheringType.class, CustomScript.class, "ConsentGathering", diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptClaimsType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptClaimsType.java new file mode 100644 index 00000000..42ed90b3 --- /dev/null +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaDummyRptClaimsType.java @@ -0,0 +1,37 @@ +package org.gluu.model.custom.script.type.uma; + +import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.model.CustomScript; + +import java.util.Map; + +/** + * @author Yuriy Zabrovarnyy + */ +public class UmaDummyRptClaimsType implements UmaRptClaimsType { + + @Override + public boolean modify(Object rptAsJsonObject, Object context) { + return false; + } + + @Override + public boolean init(Map configurationAttributes) { + return true; + } + + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } + + @Override + public boolean destroy(Map configurationAttributes) { + return true; + } + + @Override + public int getApiVersion() { + return 1; + } +} diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptClaimsType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptClaimsType.java new file mode 100644 index 00000000..0ff56ca7 --- /dev/null +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/uma/UmaRptClaimsType.java @@ -0,0 +1,11 @@ +package org.gluu.model.custom.script.type.uma; + +import org.gluu.model.custom.script.type.BaseExternalType; + +/** + * @author Yuriy Zabrovarnyy + */ +public interface UmaRptClaimsType extends BaseExternalType { + + boolean modify(Object rptAsJsonObject, Object context); +} From 40e63a545785a09d278c4516b21b4c6cea317793 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 26 Jun 2020 19:48:13 +0300 Subject: [PATCH 199/362] Fix password in sample class --- .../custom/script/test/StandaloneCustomScriptManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-script/src/test/java/org/gluu/service/custom/script/test/StandaloneCustomScriptManagerTest.java b/core-script/src/test/java/org/gluu/service/custom/script/test/StandaloneCustomScriptManagerTest.java index 1275bd00..2a4b54a5 100644 --- a/core-script/src/test/java/org/gluu/service/custom/script/test/StandaloneCustomScriptManagerTest.java +++ b/core-script/src/test/java/org/gluu/service/custom/script/test/StandaloneCustomScriptManagerTest.java @@ -24,7 +24,7 @@ private static Properties getSampleConnectionProperties() { Properties connectionProperties = new Properties(); connectionProperties.put("ldap.bindDN", "cn=Directory Manager"); - connectionProperties.put("ldap.bindPassword", "Secret1!"); + connectionProperties.put("ldap.bindPassword", "secret"); // connectionProperties.put("ldap.bindPassword", "test"); connectionProperties.put("ldap.servers", "localhost:1636"); connectionProperties.put("ldap.useSSL", "true"); From fd24bd009885855fbc29a3151da81e029abfa4da Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Mon, 6 Jul 2020 14:41:51 +0100 Subject: [PATCH 200/362] Add more information for redis provider creation error --- .../src/main/java/org/gluu/service/cache/RedisProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java index 86cccac2..b9402d8f 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java @@ -52,6 +52,7 @@ public void create() { log.debug("RedisProvider started."); } catch (Exception e) { log.error("Failed to start RedisProvider."); + log.error("Log Error",e); throw new IllegalStateException("Error starting RedisProvider", e); } } From 0b4780a35dab82b88967b5c4b41a74bcb599ad5a Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 6 Jul 2020 21:39:28 +0300 Subject: [PATCH 201/362] Generated CB query not returning results #195 --- .../impl/CouchbaseFilterConverter.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java index 45bd36dc..66ab825d 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java @@ -28,6 +28,7 @@ import com.couchbase.client.java.document.json.JsonArray; import com.couchbase.client.java.query.dsl.Expression; +import com.couchbase.client.java.query.dsl.functions.Collections; import com.couchbase.client.java.query.dsl.functions.StringFunctions; /** @@ -180,11 +181,23 @@ public ConvertedExpression convertToCouchbaseFilter(Filter genericFilter, Map Date: Tue, 7 Jul 2020 21:45:13 +0300 Subject: [PATCH 202/362] Support multivalued in presence and partial match --- .../impl/CouchbaseFilterConverter.java | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java index 66ab825d..d9dfafe8 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java @@ -181,27 +181,30 @@ public ConvertedExpression convertToCouchbaseFilter(Filter genericFilter, Map propertiesAnnotationsMap) { + Boolean isMultiValuedDetected = determineMultiValuedByType(currentGenericFilter.getAttributeName(), propertiesAnnotationsMap); + if (Boolean.TRUE.equals(currentGenericFilter.getMultiValued()) || Boolean.TRUE.equals(isMultiValuedDetected)) { + return true; + } + + return false; + } + private String toInternalAttribute(Filter filter) { if (ArrayHelper.isNotEmpty(filter.getFilters())) { From 2f60adce9566bc69ad6b6e8cf5393e78c7d8dafd Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 13 Jul 2020 19:21:45 +0300 Subject: [PATCH 203/362] Lowercase filter for multivalued attribute produces wrong query in CB #197 --- .../impl/CouchbaseFilterConverter.java | 32 +++++++++++++++---- .../java/org/gluu/search/filter/Filter.java | 16 ++++++++++ 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java index d9dfafe8..17316593 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java @@ -153,8 +153,18 @@ public ConvertedExpression convertToCouchbaseFilter(Filter genericFilter, Map Date: Mon, 13 Jul 2020 21:24:20 +0300 Subject: [PATCH 204/362] Branch for version 4.3 --- core-cache/pom.xml | 2 +- core-cdi/pom.xml | 2 +- core-document-store/pom.xml | 2 +- core-java-ext/pom.xml | 2 +- core-script/pom.xml | 2 +- core-standalone/pom.xml | 2 +- core-timer-weld/pom.xml | 2 +- demo-cdi/pom.xml | 2 +- exception-extension-cdi/pom.xml | 2 +- oxJsfUtil/pom.xml | 2 +- oxModel/pom.xml | 2 +- oxRadius/pom.xml | 2 +- oxSaml/pom.xml | 2 +- oxService/pom.xml | 2 +- oxUtil/pom.xml | 2 +- persistence-annotation/pom.xml | 2 +- persistence-cdi/pom.xml | 2 +- persistence-core/pom.xml | 2 +- persistence-couchbase-sample/pom.xml | 2 +- persistence-couchbase/pom.xml | 2 +- persistence-filter/pom.xml | 2 +- persistence-hybrid/pom.xml | 2 +- persistence-ldap-sample/pom.xml | 2 +- persistence-ldap/pom.xml | 2 +- persistence-model/pom.xml | 2 +- persistence-standalone/pom.xml | 2 +- pom.xml | 4 ++-- security-extension-cdi/pom.xml | 2 +- server/pom.xml | 2 +- 29 files changed, 30 insertions(+), 30 deletions(-) diff --git a/core-cache/pom.xml b/core-cache/pom.xml index 5b7a4512..d1a6909f 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/core-cdi/pom.xml b/core-cdi/pom.xml index 116a3fab..cfe2e779 100644 --- a/core-cdi/pom.xml +++ b/core-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index 2ce305b7..cc0d2d5e 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/core-java-ext/pom.xml b/core-java-ext/pom.xml index b3fce2b7..9dc502a4 100644 --- a/core-java-ext/pom.xml +++ b/core-java-ext/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/core-script/pom.xml b/core-script/pom.xml index 30fc7612..90b5423b 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/core-standalone/pom.xml b/core-standalone/pom.xml index 10a8956b..df4731ff 100644 --- a/core-standalone/pom.xml +++ b/core-standalone/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/core-timer-weld/pom.xml b/core-timer-weld/pom.xml index 8c6f32e4..794e2690 100644 --- a/core-timer-weld/pom.xml +++ b/core-timer-weld/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index 54f94194..ca5cd7d7 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/exception-extension-cdi/pom.xml b/exception-extension-cdi/pom.xml index 2eb3cdc3..c6dfd74e 100644 --- a/exception-extension-cdi/pom.xml +++ b/exception-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index a8833bf1..aa265185 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/oxModel/pom.xml b/oxModel/pom.xml index 13f00f23..44585493 100644 --- a/oxModel/pom.xml +++ b/oxModel/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/oxRadius/pom.xml b/oxRadius/pom.xml index 2935d29f..5a4841c2 100644 --- a/oxRadius/pom.xml +++ b/oxRadius/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index 285c98b9..2a49fea6 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/oxService/pom.xml b/oxService/pom.xml index 574f8929..9c6659d7 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index 345b1a5e..be05d19c 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/persistence-annotation/pom.xml b/persistence-annotation/pom.xml index 0b5608c5..7b4d203e 100644 --- a/persistence-annotation/pom.xml +++ b/persistence-annotation/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT \ No newline at end of file diff --git a/persistence-cdi/pom.xml b/persistence-cdi/pom.xml index 4242fe05..2a296f03 100644 --- a/persistence-cdi/pom.xml +++ b/persistence-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/persistence-core/pom.xml b/persistence-core/pom.xml index 03d38837..d97841b4 100644 --- a/persistence-core/pom.xml +++ b/persistence-core/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/persistence-couchbase-sample/pom.xml b/persistence-couchbase-sample/pom.xml index 69199d07..cff90901 100644 --- a/persistence-couchbase-sample/pom.xml +++ b/persistence-couchbase-sample/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/persistence-couchbase/pom.xml b/persistence-couchbase/pom.xml index 16d738e6..88ee4d6c 100644 --- a/persistence-couchbase/pom.xml +++ b/persistence-couchbase/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/persistence-filter/pom.xml b/persistence-filter/pom.xml index a3d147aa..0d00b7e1 100644 --- a/persistence-filter/pom.xml +++ b/persistence-filter/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/persistence-hybrid/pom.xml b/persistence-hybrid/pom.xml index 1ca7d8cf..d53ba0ef 100644 --- a/persistence-hybrid/pom.xml +++ b/persistence-hybrid/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/persistence-ldap-sample/pom.xml b/persistence-ldap-sample/pom.xml index d253de04..d9b80aca 100644 --- a/persistence-ldap-sample/pom.xml +++ b/persistence-ldap-sample/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/persistence-ldap/pom.xml b/persistence-ldap/pom.xml index 7756d577..05c900da 100644 --- a/persistence-ldap/pom.xml +++ b/persistence-ldap/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/persistence-model/pom.xml b/persistence-model/pom.xml index 2ed419d0..084bd7d3 100644 --- a/persistence-model/pom.xml +++ b/persistence-model/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/persistence-standalone/pom.xml b/persistence-standalone/pom.xml index f4968c4f..ea65fc14 100644 --- a/persistence-standalone/pom.xml +++ b/persistence-standalone/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/pom.xml b/pom.xml index 4f2498cd..20f6acf8 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.gluu oxcore pom - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT oxCore http://ox.gluu.org @@ -61,7 +61,7 @@ org.gluu gluu-core-bom - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT import pom diff --git a/security-extension-cdi/pom.xml b/security-extension-cdi/pom.xml index 3759dc36..329955c4 100644 --- a/security-extension-cdi/pom.xml +++ b/security-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT diff --git a/server/pom.xml b/server/pom.xml index 9f7dd01a..c87143e6 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.2.0-SNAPSHOT + 4.3.0-SNAPSHOT From c2662cf16b0c6056bf4eceae11888619fa7ac7bb Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 14 Jul 2020 17:13:55 +0300 Subject: [PATCH 205/362] Branch for version 5.0 --- core-cache/pom.xml | 2 +- core-cdi/pom.xml | 2 +- core-document-store/pom.xml | 2 +- core-java-ext/pom.xml | 2 +- core-script/pom.xml | 2 +- core-standalone/pom.xml | 2 +- core-timer-weld/pom.xml | 2 +- demo-cdi/pom.xml | 2 +- exception-extension-cdi/pom.xml | 2 +- oxJsfUtil/pom.xml | 2 +- oxModel/pom.xml | 2 +- oxRadius/pom.xml | 2 +- oxSaml/pom.xml | 2 +- oxService/pom.xml | 2 +- oxUtil/pom.xml | 2 +- persistence-annotation/pom.xml | 2 +- persistence-cdi/pom.xml | 2 +- persistence-core/pom.xml | 2 +- persistence-couchbase-sample/pom.xml | 2 +- persistence-couchbase/pom.xml | 2 +- persistence-filter/pom.xml | 2 +- persistence-hybrid/pom.xml | 2 +- persistence-ldap-sample/pom.xml | 2 +- persistence-ldap/pom.xml | 2 +- persistence-model/pom.xml | 2 +- persistence-standalone/pom.xml | 2 +- pom.xml | 4 ++-- security-extension-cdi/pom.xml | 2 +- server/pom.xml | 2 +- 29 files changed, 30 insertions(+), 30 deletions(-) diff --git a/core-cache/pom.xml b/core-cache/pom.xml index d1a6909f..81bc0af4 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/core-cdi/pom.xml b/core-cdi/pom.xml index cfe2e779..6c882d2a 100644 --- a/core-cdi/pom.xml +++ b/core-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index cc0d2d5e..cc3e761f 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/core-java-ext/pom.xml b/core-java-ext/pom.xml index 9dc502a4..236ae38c 100644 --- a/core-java-ext/pom.xml +++ b/core-java-ext/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/core-script/pom.xml b/core-script/pom.xml index 90b5423b..c6c275f4 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/core-standalone/pom.xml b/core-standalone/pom.xml index df4731ff..a172c459 100644 --- a/core-standalone/pom.xml +++ b/core-standalone/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/core-timer-weld/pom.xml b/core-timer-weld/pom.xml index 794e2690..1a52f89f 100644 --- a/core-timer-weld/pom.xml +++ b/core-timer-weld/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index ca5cd7d7..81eccd51 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/exception-extension-cdi/pom.xml b/exception-extension-cdi/pom.xml index c6dfd74e..da6c79ad 100644 --- a/exception-extension-cdi/pom.xml +++ b/exception-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index aa265185..0211eb0b 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/oxModel/pom.xml b/oxModel/pom.xml index 44585493..1d50925a 100644 --- a/oxModel/pom.xml +++ b/oxModel/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/oxRadius/pom.xml b/oxRadius/pom.xml index 5a4841c2..8a39e359 100644 --- a/oxRadius/pom.xml +++ b/oxRadius/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index 2a49fea6..744add4d 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/oxService/pom.xml b/oxService/pom.xml index 9c6659d7..191ce500 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index be05d19c..900e25ba 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/persistence-annotation/pom.xml b/persistence-annotation/pom.xml index 7b4d203e..6187e81e 100644 --- a/persistence-annotation/pom.xml +++ b/persistence-annotation/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT \ No newline at end of file diff --git a/persistence-cdi/pom.xml b/persistence-cdi/pom.xml index 2a296f03..013e121d 100644 --- a/persistence-cdi/pom.xml +++ b/persistence-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/persistence-core/pom.xml b/persistence-core/pom.xml index d97841b4..21b28398 100644 --- a/persistence-core/pom.xml +++ b/persistence-core/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/persistence-couchbase-sample/pom.xml b/persistence-couchbase-sample/pom.xml index cff90901..6b55696f 100644 --- a/persistence-couchbase-sample/pom.xml +++ b/persistence-couchbase-sample/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/persistence-couchbase/pom.xml b/persistence-couchbase/pom.xml index 88ee4d6c..c4ac6726 100644 --- a/persistence-couchbase/pom.xml +++ b/persistence-couchbase/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/persistence-filter/pom.xml b/persistence-filter/pom.xml index 0d00b7e1..e186942b 100644 --- a/persistence-filter/pom.xml +++ b/persistence-filter/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/persistence-hybrid/pom.xml b/persistence-hybrid/pom.xml index d53ba0ef..7f4cea83 100644 --- a/persistence-hybrid/pom.xml +++ b/persistence-hybrid/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/persistence-ldap-sample/pom.xml b/persistence-ldap-sample/pom.xml index d9b80aca..cda15b64 100644 --- a/persistence-ldap-sample/pom.xml +++ b/persistence-ldap-sample/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/persistence-ldap/pom.xml b/persistence-ldap/pom.xml index 05c900da..55bbc150 100644 --- a/persistence-ldap/pom.xml +++ b/persistence-ldap/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/persistence-model/pom.xml b/persistence-model/pom.xml index 084bd7d3..af57a1bf 100644 --- a/persistence-model/pom.xml +++ b/persistence-model/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/persistence-standalone/pom.xml b/persistence-standalone/pom.xml index ea65fc14..ea880666 100644 --- a/persistence-standalone/pom.xml +++ b/persistence-standalone/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/pom.xml b/pom.xml index 20f6acf8..70906e7f 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.gluu oxcore pom - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT oxCore http://ox.gluu.org @@ -61,7 +61,7 @@ org.gluu gluu-core-bom - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT import pom diff --git a/security-extension-cdi/pom.xml b/security-extension-cdi/pom.xml index 329955c4..f12563ac 100644 --- a/security-extension-cdi/pom.xml +++ b/security-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT diff --git a/server/pom.xml b/server/pom.xml index c87143e6..593c8051 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT From 429815a789464ca1783dbc74f67f141d2d52b682 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Fri, 17 Jul 2020 21:59:57 +0100 Subject: [PATCH 206/362] Remove uncrypter redis password --- .../org/gluu/service/cache/RedisClusterProvider.java | 3 +-- .../org/gluu/service/cache/RedisConfiguration.java | 10 ---------- .../java/org/gluu/service/cache/RedisProvider.java | 5 +---- .../gluu/service/cache/RedisSentinelProvider.java | 4 +--- .../gluu/service/cache/RedisStandaloneProvider.java | 12 +++++------- 5 files changed, 8 insertions(+), 26 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java index ffb57c8c..f70064dc 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java @@ -7,7 +7,6 @@ import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPoolConfig; - import java.io.IOException; import java.io.Serializable; import java.util.HashSet; @@ -33,7 +32,7 @@ public void create() { LOG.debug("Starting RedisClusterProvider ... configuration:" + getRedisConfiguration()); JedisPoolConfig poolConfig = createPoolConfig(); - String password = StringUtils.isBlank(redisConfiguration.getDecryptedPassword()) ? null : redisConfiguration.getDecryptedPassword(); + String password = redisConfiguration.getPassword(); pool = new JedisCluster(hosts(getRedisConfiguration().getServers()), redisConfiguration.getConnectionTimeout(), redisConfiguration.getSoTimeout(), redisConfiguration.getMaxRetryAttempts(), password, poolConfig); testConnection(); diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java b/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java index e9280d0f..4d5c8f98 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java @@ -23,8 +23,6 @@ public class RedisConfiguration implements Serializable { private String password; - private String decryptedPassword; - private Boolean useSSL = false; private String sslTrustStoreFilePath = ""; @@ -142,14 +140,6 @@ public void setSslTrustStoreFilePath(String sslTrustStoreFilePath) { this.sslTrustStoreFilePath = sslTrustStoreFilePath; } - public String getDecryptedPassword() { - return decryptedPassword; - } - - public void setDecryptedPassword(String decryptedPassword) { - this.decryptedPassword = decryptedPassword; - } - public String getSentinelMasterGroupName() { return sentinelMasterGroupName; } diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java index b9402d8f..eb43cc6e 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisProvider.java @@ -42,13 +42,10 @@ public void create() { RedisConfiguration redisConfiguration = cacheConfiguration.getRedisConfiguration(); decryptPassword(redisConfiguration); log.debug("Starting RedisProvider ... configuration:" + redisConfiguration); - defaultPutExpiration = redisConfiguration.getDefaultPutExpiration() > 0 ? redisConfiguration.getDefaultPutExpiration() : DEFAULT_PUT_EXPIRATION_IN_SECONDS; - redisProvider = RedisProviderFactory.create(cacheConfiguration.getRedisConfiguration()); redisProvider.create(); - log.debug("RedisProvider started."); } catch (Exception e) { log.error("Failed to start RedisProvider."); @@ -71,7 +68,7 @@ private void decryptPassword(RedisConfiguration redisConfiguration) { try { String encryptedPassword = redisConfiguration.getPassword(); if (StringUtils.isNotBlank(encryptedPassword)) { - redisConfiguration.setDecryptedPassword(stringEncrypter.decrypt(encryptedPassword)); + redisConfiguration.setPassword(stringEncrypter.decrypt(encryptedPassword)); log.trace("Decrypted redis password successfully."); } } catch (StringEncrypter.EncryptionException e) { diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java index e1046f3e..2a7fb4e6 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java @@ -32,8 +32,7 @@ public void create() { LOG.debug("Starting RedisSentinelProvider ... configuration:" + getRedisConfiguration()); JedisPoolConfig poolConfig = createPoolConfig(); - String password = StringUtils.isBlank(redisConfiguration.getDecryptedPassword()) ? null : redisConfiguration.getDecryptedPassword(); - + String password = redisConfiguration.getPassword(); pool = new JedisSentinelPool( getRedisConfiguration().getSentinelMasterGroupName(), Sets.newHashSet(StringUtils.split(getRedisConfiguration().getServers().trim(), ",")), @@ -42,7 +41,6 @@ public void create() { redisConfiguration.getSoTimeout(), password, Protocol.DEFAULT_DATABASE); - testConnection(); LOG.debug("RedisSentinelProvider started."); } catch (Exception e) { diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java index 1a91243b..1448019c 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java @@ -22,7 +22,6 @@ public class RedisStandaloneProvider extends AbstractRedisProvider { private static final Logger LOG = LoggerFactory.getLogger(RedisStandaloneProvider.class); private JedisPool pool; - public RedisStandaloneProvider(RedisConfiguration redisConfiguratio) { super(redisConfiguratio); } @@ -34,22 +33,21 @@ public void create() { JedisPoolConfig poolConfig = createPoolConfig(); HostAndPort hostAndPort = RedisClusterProvider.hosts(redisConfiguration.getServers()).iterator().next(); - String password = StringUtils.isBlank(redisConfiguration.getDecryptedPassword()) ? null : redisConfiguration.getDecryptedPassword(); - + String password = redisConfiguration.getPassword(); if (redisConfiguration.getUseSSL()) { if (StringUtils.isNotBlank(redisConfiguration.getSslTrustStoreFilePath())) { - if (StringUtils.isBlank(redisConfiguration.getDecryptedPassword())) { + if (StringUtils.isBlank(password)) { pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), true, RedisProviderFactory.createTrustStoreSslSocketFactory(new File(redisConfiguration.getSslTrustStoreFilePath())), new SSLParameters(), new DefaultHostnameVerifier()); } else { - pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), redisConfiguration.getConnectionTimeout(), redisConfiguration.getDecryptedPassword(), true, + pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), redisConfiguration.getConnectionTimeout(), password, true, RedisProviderFactory.createTrustStoreSslSocketFactory(new File(redisConfiguration.getSslTrustStoreFilePath())), new SSLParameters(), new DefaultHostnameVerifier()); } } else { - if (StringUtils.isBlank(redisConfiguration.getDecryptedPassword())) { + if (StringUtils.isBlank(password)) { pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), true); } else { - pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), redisConfiguration.getConnectionTimeout(), redisConfiguration.getDecryptedPassword(), true); + pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), redisConfiguration.getConnectionTimeout(), password, true); } } } else { From 40276663a999ee94bf8f7757f46d313c4cadaa61 Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Mon, 20 Jul 2020 12:17:07 +0300 Subject: [PATCH 207/362] Simple test to check session ttl. --- .../test/ManualCouchbaseEntryManagerTest.java | 66 +++++++++++++++++-- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java index d2089938..fbd3dbf1 100644 --- a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java +++ b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java @@ -1,15 +1,17 @@ package org.gluu.couchbase.test; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.Properties; - +import com.couchbase.client.java.document.JsonDocument; import org.gluu.couchbase.model.SimpleClient; import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; import org.gluu.persist.couchbase.impl.CouchbaseEntryManagerFactory; +import org.gluu.persist.exception.operation.SearchException; +import org.gluu.util.Pair; import org.testng.annotations.Test; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; + /** * @author Yuriy Zabrovarnyy */ @@ -27,12 +29,62 @@ public void sample() throws IOException { } } + @Test(enabled = true) // manual + public void sampleSessionId() throws IOException, SearchException { + CouchbaseEntryManager manager = createCouchbaseEntryManager(); + + try { + SessionId sessionId = createSessionId(); + manager.persist(sessionId); + + final String key = "sessions_" + sessionId.getId(); + System.out.println("Key: " + key + ", ttl:" + sessionId.getTtl()); + + final JsonDocument lookup = manager.getOperationService().getConnectionProvider().getBucketMapping("sessions").getBucket().get(key); + System.out.println("expiry: " + lookup.expiry()); + + updateSession(sessionId); + manager.merge(sessionId); + + final JsonDocument lookup2 = manager.getOperationService().getConnectionProvider().getBucketMapping("sessions").getBucket().get(key); + System.out.println("expiry after udpate: " + lookup2.expiry()); + + } finally { + manager.destroy(); + } + } + + private SessionId createSessionId() { + SessionId sessionId = new SessionId(); + sessionId.setId(UUID.randomUUID().toString()); + sessionId.setDn(String.format("oxId=%s,%s", sessionId.getId(), "ou=sessions,o=gluu")); + sessionId.setCreationDate(new Date()); + + updateSession(sessionId); + return sessionId; + } + + private void updateSession(SessionId sessionId) { + final Pair expiration = expirationDate(sessionId.getCreationDate()); + sessionId.setLastUsedAt(new Date()); + sessionId.setExpirationDate(expiration.getFirst()); + sessionId.setTtl(expiration.getSecond()); + } + + private Pair expirationDate(Date creationDate) { + int expirationInSeconds = 120; + Calendar calendar = Calendar.getInstance(); + calendar.setTime(creationDate); + calendar.add(Calendar.SECOND, expirationInSeconds); + return new Pair<>(calendar.getTime(), expirationInSeconds); + } + // MODIFY ACCORDING TO YOUR SERVER public static Properties loadProperties() throws IOException { Properties properties = new Properties(); - properties.put("couchbase.auth.userPassword", ""); + properties.put("couchbase.auth.userPassword", "1234.Gluu"); - try (InputStream is = ManualCouchbaseEntryManagerTest.class.getResourceAsStream("c1.gluu.org.properties")) { + try (InputStream is = ManualCouchbaseEntryManagerTest.class.getResourceAsStream("cb-bench-backend.gluu.org.properties")) { properties.load(is); return properties; } From 59bedca457e1e50c8002de79acdd3bd49e3757d1 Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Mon, 20 Jul 2020 12:21:57 +0300 Subject: [PATCH 208/362] Simple test to check session ttl. --- .../org/gluu/couchbase/test/SessionId.java | 260 ++++++++++++++++++ .../gluu/couchbase/test/SessionIdState.java | 46 ++++ 2 files changed, 306 insertions(+) create mode 100644 persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionId.java create mode 100644 persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionIdState.java diff --git a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionId.java b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionId.java new file mode 100644 index 00000000..1310c4e1 --- /dev/null +++ b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionId.java @@ -0,0 +1,260 @@ +package org.gluu.couchbase.test; + +/* + * oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +import com.couchbase.client.java.cluster.User; +import com.google.common.collect.Maps; +import org.gluu.persist.annotation.*; +import org.gluu.persist.model.base.Deletable; + +import javax.inject.Named; +import javax.persistence.Transient; +import java.io.Serializable; +import java.util.Date; +import java.util.Map; + +/** + * @author Yuriy Zabrovarnyy + * @author Javier Rojas Blum + * @version December 8, 2018 + */ +@Named("sessionUser") +@DataEntry +@ObjectClass(value = "oxAuthSessionId") +public class SessionId implements Deletable, Serializable { + + private static final long serialVersionUID = -237476411915686378L; + + @DN + private String dn; + + @AttributeName(name = "oxId") + private String id; + + @AttributeName(name = "oxLastAccessTime") + private Date lastUsedAt; + + @AttributeName(name = "oxAuthUserDN") + private String userDn; + + @AttributeName(name = "authnTime") + private Date authenticationTime; + + @AttributeName(name = "oxState") + private SessionIdState state; + + @AttributeName(name = "oxSessionState") + private String sessionState; + + @AttributeName(name = "oxAuthPermissionGranted") + private Boolean permissionGranted; + + @AttributeName(name = "oxAsJwt") + private Boolean isJwt = false; + + @AttributeName(name = "oxJwt") + private String jwt; + + @JsonObject + @AttributeName(name = "oxAuthSessionAttribute") + private Map sessionAttributes; + + @AttributeName(name = "exp") + private Date expirationDate; + + @AttributeName(name = "del") + private Boolean deletable = true; + + @AttributeName(name = "creationDate") + private Date creationDate = new Date(); + + @Transient + private transient boolean persisted; + + @Transient + private User user; + + @Expiration + private int ttl; + + public SessionId() { + } + + public int getTtl() { + return ttl; + } + + public void setTtl(int ttl) { + this.ttl = ttl; + } + + public String getDn() { + return dn; + } + + public void setDn(String p_dn) { + dn = p_dn; + } + + public String getJwt() { + return jwt; + } + + public void setJwt(String jwt) { + this.jwt = jwt; + } + + public Boolean getIsJwt() { + return isJwt; + } + + public void setIsJwt(Boolean isJwt) { + this.isJwt = isJwt; + } + + public SessionIdState getState() { + return state; + } + + public void setState(SessionIdState state) { + this.state = state; + } + + public String getSessionState() { + return sessionState; + } + + public void setSessionState(String sessionState) { + this.sessionState = sessionState; + } + + public String getId() { + return id; + } + + public void setId(String p_id) { + id = p_id; + } + + public Date getLastUsedAt() { + return lastUsedAt; + } + + public void setLastUsedAt(Date p_lastUsedAt) { + lastUsedAt = p_lastUsedAt; + } + + public String getUserDn() { + return userDn; + } + + public void setUserDn(String p_userDn) { + userDn = p_userDn != null ? p_userDn : ""; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public Date getAuthenticationTime() { + return authenticationTime; + } + + public void setAuthenticationTime(Date authenticationTime) { + this.authenticationTime = authenticationTime; + } + + public Boolean getPermissionGranted() { + return permissionGranted; + } + + public void setPermissionGranted(Boolean permissionGranted) { + this.permissionGranted = permissionGranted; + } + + public Map getSessionAttributes() { + if (sessionAttributes == null) { + sessionAttributes = Maps.newHashMap(); + } + return sessionAttributes; + } + + public void setSessionAttributes(Map sessionAttributes) { + this.sessionAttributes = sessionAttributes; + } + + public boolean isPersisted() { + return persisted; + } + + public void setPersisted(boolean persisted) { + this.persisted = persisted; + } + + public Date getExpirationDate() { + return expirationDate; + } + + public void setExpirationDate(Date expirationDate) { + this.expirationDate = expirationDate; + } + + public Boolean isDeletable() { + return deletable != null ? deletable : true; + } + + public void setDeletable(Boolean deletable) { + this.deletable = deletable; + } + + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + SessionId id1 = (SessionId) o; + + return !(id != null ? !id.equals(id1.id) : id1.id != null); + } + + @Override + public int hashCode() { + return id != null ? id.hashCode() : 0; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(); + sb.append("SessionIdTest {"); + sb.append("dn='").append(dn).append('\''); + sb.append(", id='").append(id).append('\''); + sb.append(", lastUsedAt=").append(lastUsedAt); + sb.append(", userDn='").append(userDn).append('\''); + sb.append(", authenticationTime=").append(authenticationTime); + sb.append(", state=").append(state); + sb.append(", sessionState='").append(sessionState).append('\''); + sb.append(", permissionGranted=").append(permissionGranted); + sb.append(", isJwt=").append(isJwt); + sb.append(", jwt=").append(jwt); + sb.append(", sessionAttributes=").append(sessionAttributes); + sb.append(", persisted=").append(persisted); + sb.append("}"); + return sb.toString(); + } +} diff --git a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionIdState.java b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionIdState.java new file mode 100644 index 00000000..c6c8d6eb --- /dev/null +++ b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionIdState.java @@ -0,0 +1,46 @@ +package org.gluu.couchbase.test; + +import org.gluu.persist.annotation.AttributeEnum; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Yuriy Zabrovarnyy + */ +public enum SessionIdState implements AttributeEnum { + + UNAUTHENTICATED("unauthenticated"), AUTHENTICATED("authenticated"); + + private final String value; + + private static Map mapByValues = new HashMap(); + + static { + for (SessionIdState enumType : values()) { + mapByValues.put(enumType.getValue(), enumType); + } + } + + private SessionIdState(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public static SessionIdState getByValue(String value) { + return mapByValues.get(value); + } + + public Enum resolveByValue(String value) { + return getByValue(value); + } + + @Override + public String toString() { + return value; + } + +} From 956a06f7a3a7f16b3125d57e8581845ecfc54013 Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Mon, 20 Jul 2020 12:34:03 +0300 Subject: [PATCH 209/362] During CB entry update make sure TTL is updated too. https://github.com/GluuFederation/oxCore/issues/199 --- .../test/ManualCouchbaseEntryManagerTest.java | 2 +- .../impl/CouchbaseOperationServiceImpl.java | 60 +++++++------------ 2 files changed, 21 insertions(+), 41 deletions(-) diff --git a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java index fbd3dbf1..9b6f30d5 100644 --- a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java +++ b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java @@ -47,7 +47,7 @@ public void sampleSessionId() throws IOException, SearchException { manager.merge(sessionId); final JsonDocument lookup2 = manager.getOperationService().getConnectionProvider().getBucketMapping("sessions").getBucket().get(key); - System.out.println("expiry after udpate: " + lookup2.expiry()); + System.out.println("expiry after update: " + lookup2.expiry()); } finally { manager.destroy(); diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java index 14bab95f..994f32f0 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java @@ -6,28 +6,27 @@ package org.gluu.persist.couchbase.operation.impl; -import java.time.Duration; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.Set; - +import com.couchbase.client.core.CouchbaseException; +import com.couchbase.client.core.message.kv.subdoc.multi.Mutation; +import com.couchbase.client.java.Bucket; +import com.couchbase.client.java.document.JsonDocument; +import com.couchbase.client.java.document.json.JsonArray; +import com.couchbase.client.java.document.json.JsonObject; +import com.couchbase.client.java.query.*; +import com.couchbase.client.java.query.consistency.ScanConsistency; +import com.couchbase.client.java.query.dsl.Expression; +import com.couchbase.client.java.query.dsl.Sort; +import com.couchbase.client.java.query.dsl.path.*; +import com.couchbase.client.java.subdoc.DocumentFragment; +import com.couchbase.client.java.subdoc.MutateInBuilder; +import com.couchbase.client.java.subdoc.MutationSpec; import org.gluu.persist.couchbase.impl.CouchbaseBatchOperationWraper; import org.gluu.persist.couchbase.model.BucketMapping; import org.gluu.persist.couchbase.model.SearchReturnDataType; import org.gluu.persist.couchbase.operation.CouchbaseOperationService; import org.gluu.persist.couchbase.operation.watch.OperationDurationUtil; import org.gluu.persist.exception.extension.PersistenceExtension; -import org.gluu.persist.exception.operation.DeleteException; -import org.gluu.persist.exception.operation.DuplicateEntryException; -import org.gluu.persist.exception.operation.EntryNotFoundException; -import org.gluu.persist.exception.operation.PersistenceException; -import org.gluu.persist.exception.operation.SearchException; +import org.gluu.persist.exception.operation.*; import org.gluu.persist.model.BatchOperation; import org.gluu.persist.model.PagedResult; import org.gluu.persist.model.SearchScope; @@ -37,30 +36,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.couchbase.client.core.CouchbaseException; -import com.couchbase.client.core.message.kv.subdoc.multi.Mutation; -import com.couchbase.client.java.Bucket; -import com.couchbase.client.java.document.JsonDocument; -import com.couchbase.client.java.document.json.JsonArray; -import com.couchbase.client.java.document.json.JsonObject; -import com.couchbase.client.java.query.Delete; -import com.couchbase.client.java.query.N1qlParams; -import com.couchbase.client.java.query.N1qlQuery; -import com.couchbase.client.java.query.N1qlQueryResult; -import com.couchbase.client.java.query.N1qlQueryRow; -import com.couchbase.client.java.query.Select; -import com.couchbase.client.java.query.Statement; -import com.couchbase.client.java.query.consistency.ScanConsistency; -import com.couchbase.client.java.query.dsl.Expression; -import com.couchbase.client.java.query.dsl.Sort; -import com.couchbase.client.java.query.dsl.path.GroupByPath; -import com.couchbase.client.java.query.dsl.path.LimitPath; -import com.couchbase.client.java.query.dsl.path.MutateLimitPath; -import com.couchbase.client.java.query.dsl.path.OffsetPath; -import com.couchbase.client.java.query.dsl.path.ReturningPath; -import com.couchbase.client.java.subdoc.DocumentFragment; -import com.couchbase.client.java.subdoc.MutateInBuilder; -import com.couchbase.client.java.subdoc.MutationSpec; +import java.time.Duration; +import java.time.Instant; +import java.util.*; +import java.util.Map.Entry; /** * Base service which performs all supported Couchbase operations @@ -241,6 +220,7 @@ private boolean updateEntryImpl(BucketMapping bucketMapping, String key, List Date: Mon, 20 Jul 2020 17:08:04 +0300 Subject: [PATCH 210/362] Add sample to get documetn ttl --- .../test/ManualCouchbaseEntryManagerTest.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java index 9b6f30d5..ce137384 100644 --- a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java +++ b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java @@ -1,6 +1,11 @@ package org.gluu.couchbase.test; +import com.couchbase.client.core.message.kv.subdoc.multi.Lookup; +import com.couchbase.client.java.Bucket; import com.couchbase.client.java.document.JsonDocument; +import com.couchbase.client.java.subdoc.DocumentFragment; +import com.couchbase.client.java.subdoc.SubdocOptionsBuilder; + import org.gluu.couchbase.model.SimpleClient; import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; import org.gluu.persist.couchbase.impl.CouchbaseEntryManagerFactory; @@ -40,9 +45,14 @@ public void sampleSessionId() throws IOException, SearchException { final String key = "sessions_" + sessionId.getId(); System.out.println("Key: " + key + ", ttl:" + sessionId.getTtl()); - final JsonDocument lookup = manager.getOperationService().getConnectionProvider().getBucketMapping("sessions").getBucket().get(key); + Bucket sessionBucket = manager.getOperationService().getConnectionProvider().getBucketMapping("sessions").getBucket(); + final JsonDocument lookup = sessionBucket.get(key); + System.out.println("cas: " + lookup.cas()); System.out.println("expiry: " + lookup.expiry()); + DocumentFragment ttl = sessionBucket.lookupIn(key).get("$document.exptime", new SubdocOptionsBuilder().xattr(true)).execute(); + System.out.println("ttl: " + ttl.content("$document.exptime")); + updateSession(sessionId); manager.merge(sessionId); From ae73a3a5dc373ec1b0911853e8cce4bcf1d9a778 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 20 Jul 2020 17:08:17 +0300 Subject: [PATCH 211/362] Add sample to get ttl --- .../org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java index ce137384..e67c92f2 100644 --- a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java +++ b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java @@ -47,7 +47,6 @@ public void sampleSessionId() throws IOException, SearchException { Bucket sessionBucket = manager.getOperationService().getConnectionProvider().getBucketMapping("sessions").getBucket(); final JsonDocument lookup = sessionBucket.get(key); - System.out.println("cas: " + lookup.cas()); System.out.println("expiry: " + lookup.expiry()); DocumentFragment ttl = sessionBucket.lookupIn(key).get("$document.exptime", new SubdocOptionsBuilder().xattr(true)).execute(); From b6ca1929c91d937f1b5ff681551fbae4a46f832c Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 30 Jul 2020 15:57:09 +0300 Subject: [PATCH 212/362] Don't load entry from DB afte merge #200 --- .../main/java/org/gluu/persist/PersistenceEntryManager.java | 2 +- .../src/main/java/org/gluu/persist/impl/BaseEntryManager.java | 4 ++-- .../gluu/persist/couchbase/impl/CouchbaseEntryManager.java | 2 +- .../java/org/gluu/persist/hybrid/impl/HybridEntryManager.java | 2 +- .../java/org/gluu/persist/ldap/impl/LdapEntryManager.java | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java index 2c9fa39a..0584f78a 100644 --- a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java @@ -38,7 +38,7 @@ public interface PersistenceEntryManager extends EntityManager { void persist(Object entry); - T merge(T entry); + Void merge(Object entry); @Deprecated boolean contains(Object entity); diff --git a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java index ebe201c5..a95361b2 100644 --- a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java +++ b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java @@ -201,7 +201,7 @@ public int countEntries(Object entry) { } @SuppressWarnings("unchecked") - protected T merge(T entry, boolean isSchemaUpdate, boolean isConfigurationUpdate, AttributeModificationType schemaModificationType) { + protected Void merge(Object entry, boolean isSchemaUpdate, boolean isConfigurationUpdate, AttributeModificationType schemaModificationType) { if (entry == null) { throw new MappingException("Entry to persist is null"); } @@ -247,7 +247,7 @@ protected T merge(T entry, boolean isSchemaUpdate, boolean isConfigurationUp merge(dnValue.toString(), attributeDataModifications, expirationValue); - return (T) find(entryClass, dnValue.toString(), null, propertiesAnnotations, propertiesAnnotationsMap); + return null; } protected abstract void updateMergeChanges(String baseDn, T entry, boolean isConfigurationUpdate, Class entryClass, diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java index e32c911e..1d66c4cf 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java @@ -110,7 +110,7 @@ public void removeDeleteSubscriber(DeleteNotifier subscriber) { } @Override - public T merge(T entry) { + public Void merge(Object entry) { Class entryClass = entry.getClass(); checkEntryClass(entryClass, true); if (isSchemaEntry(entryClass)) { diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java index 9f3c84b0..bda530d1 100644 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java +++ b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java @@ -343,7 +343,7 @@ public HybridPersistenceOperationService getOperationService() { } @Override - public T merge(T entry) { + public Void merge(Object entry) { Class entryClass = entry.getClass(); Object dnValue = getDNValue(entry, entryClass); diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java index dbec59ff..b42915dc 100644 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java +++ b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java @@ -106,7 +106,7 @@ public void removeDeleteSubscriber(DeleteNotifier subscriber) { } @Override - public T merge(T entry) { + public Void merge(Object entry) { Class entryClass = entry.getClass(); checkEntryClass(entryClass, true); if (isSchemaEntry(entryClass)) { From 8a34d5bded3e3857c6bd4e027bfad90dee525488 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 5 Aug 2020 18:21:49 +0300 Subject: [PATCH 213/362] Store issued tokens count metrics #1436 --- .../main/java/org/gluu/model/metric/MetricType.java | 13 ++++++++++++- .../java/org/gluu/service/metric/MetricService.java | 2 ++ .../java/org/gluu/service/net/NetworkService.java | 6 ++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/oxModel/src/main/java/org/gluu/model/metric/MetricType.java b/oxModel/src/main/java/org/gluu/model/metric/MetricType.java index 21336148..674d14f5 100644 --- a/oxModel/src/main/java/org/gluu/model/metric/MetricType.java +++ b/oxModel/src/main/java/org/gluu/model/metric/MetricType.java @@ -30,7 +30,18 @@ public enum MetricType implements AttributeEnum { OXAUTH_USER_AUTHENTICATION_RATE("user_authentication_rate", "User authentication rate", TimerMetricData.class, TimerMetricEntry.class), DYNAMIC_CLIENT_REGISTRATION_RATE("dynamic_client_registration_rate", - "Dynamic client registration rate", TimerMetricData.class, TimerMetricEntry.class); + "Dynamic client registration rate", TimerMetricData.class, TimerMetricEntry.class), + + OXAUTH_TOKEN_AUTHORIZATION_CODE_COUNT("tkn_authorization_code_count", + "Count successfull issued oxAuth authorization code tokens", CounterMetricData.class, CounterMetricEntry.class), + OXAUTH_TOKEN_ACCESS_TOKEN_COUNT("tkn_access_token_count", + "Count successfull issued oxAuth access tokens", CounterMetricData.class, CounterMetricEntry.class), + OXAUTH_TOKEN_ID_TOKEN_COUNT("tkn_id_token_count", + "Count successfull issued oxAuth id tokens", CounterMetricData.class, CounterMetricEntry.class), + OXAUTH_TOKEN_REFRESH_TOKEN_COUNT("tkn_refresh_token_count", + "Count successfull issued oxAuth refresh tokens", CounterMetricData.class, CounterMetricEntry.class), + OXAUTH_TOKEN_LONG_LIVED_ACCESS_TOKEN_COUNT("tkn_long_lived_access_token_count", + "Count successfull issued oxAuth long lived access tokens", CounterMetricData.class, CounterMetricEntry.class); private String value; private String displayName; diff --git a/oxService/src/main/java/org/gluu/service/metric/MetricService.java b/oxService/src/main/java/org/gluu/service/metric/MetricService.java index 537a5f7e..4ddcb77a 100644 --- a/oxService/src/main/java/org/gluu/service/metric/MetricService.java +++ b/oxService/src/main/java/org/gluu/service/metric/MetricService.java @@ -390,5 +390,7 @@ public Set getRegisteredMetricTypes() { public abstract ApplicationType getApplicationType(); + public abstract String getNodeIndetifier(); + public abstract PersistenceEntryManager getEntryManager(); } diff --git a/oxService/src/main/java/org/gluu/service/net/NetworkService.java b/oxService/src/main/java/org/gluu/service/net/NetworkService.java index 563555ee..c04be83c 100644 --- a/oxService/src/main/java/org/gluu/service/net/NetworkService.java +++ b/oxService/src/main/java/org/gluu/service/net/NetworkService.java @@ -5,6 +5,7 @@ */ package org.gluu.service.net; +import org.gluu.net.InetAddressUtility; import org.gluu.util.StringHelper; import org.slf4j.Logger; @@ -65,4 +66,9 @@ public String getHost(String serverUri) { return serverUri; } + + public String getMacAdress() { + return InetAddressUtility.getMACAddressOrNull(); + } + } From 43351d6650e0066c7a49dff44b9ccaa16b1e011d Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 6 Aug 2020 13:55:21 +0300 Subject: [PATCH 214/362] Turn off metric reported by default if there is no configuration --- .../src/main/java/org/gluu/config/oxtrust/AppConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index 7d06263d..63ad01df 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -154,7 +154,7 @@ public class AppConfiguration implements Configuration, Serializable { private int metricReporterInterval; private int metricReporterKeepDataDays; - private Boolean metricReporterEnabled = true; + private Boolean metricReporterEnabled; private Boolean disableJdkLogger = true; @JsonProperty("ScimProperties") From e749dc20a3d8e3ea95313a580772527cf3309351 Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Mon, 10 Aug 2020 19:40:00 +0300 Subject: [PATCH 215/362] disabled manual test --- .../gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java index e67c92f2..343e21b9 100644 --- a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java +++ b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java @@ -34,7 +34,7 @@ public void sample() throws IOException { } } - @Test(enabled = true) // manual + @Test(enabled = false) // manual public void sampleSessionId() throws IOException, SearchException { CouchbaseEntryManager manager = createCouchbaseEntryManager(); From 4d7fd6c6c033e063a8b26893af7a8d87409b0bcb Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 11 Aug 2020 22:30:51 +0300 Subject: [PATCH 216/362] Add uniq identifier for each metric entry to allow find whcih node addded this record oxAuth #1438 --- .../gluu/model/metric/ldap/MetricEntry.java | 32 ++++++++++--------- .../service/metric/LdapEntryReporter.java | 10 ++++-- .../gluu/service/metric/MetricService.java | 2 +- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/oxModel/src/main/java/org/gluu/model/metric/ldap/MetricEntry.java b/oxModel/src/main/java/org/gluu/model/metric/ldap/MetricEntry.java index c0a140b7..4e4d4a81 100644 --- a/oxModel/src/main/java/org/gluu/model/metric/ldap/MetricEntry.java +++ b/oxModel/src/main/java/org/gluu/model/metric/ldap/MetricEntry.java @@ -44,6 +44,9 @@ public class MetricEntry { @AttributeName(name = "creationDate") private Date creationDate; + @AttributeName(name = "oxHost") + private String nodeIndetifier; + @AttributeName(name = "exp") private Date expirationDate; @AttributeName(name = "del") @@ -114,7 +117,15 @@ public void setCreationDate(Date creationDate) { this.creationDate = creationDate; } - public Date getExpirationDate() { + public String getNodeIndetifier() { + return nodeIndetifier; + } + + public void setNodeIndetifier(String nodeIndetifier) { + this.nodeIndetifier = nodeIndetifier; + } + + public Date getExpirationDate() { return expirationDate; } @@ -130,19 +141,10 @@ public void setDeletable(boolean deletable) { this.deletable = deletable; } - @Override - public String toString() { - return "MetricEntry{" + - "dn='" + dn + '\'' + - ", id='" + id + '\'' + - ", startDate=" + startDate + - ", endDate=" + endDate + - ", applicationType=" + applicationType + - ", metricType=" + metricType + - ", creationDate=" + creationDate + - ", expirationDate=" + expirationDate + - ", deletable=" + deletable + - '}'; - } + public String toString() { + return "MetricEntry [dn=" + dn + ", id=" + id + ", startDate=" + startDate + ", endDate=" + endDate + ", applicationType=" + + applicationType + ", metricType=" + metricType + ", creationDate=" + creationDate + ", nodeIndetifier=" + nodeIndetifier + + ", expirationDate=" + expirationDate + ", deletable=" + deletable + "]"; + } } diff --git a/oxService/src/main/java/org/gluu/service/metric/LdapEntryReporter.java b/oxService/src/main/java/org/gluu/service/metric/LdapEntryReporter.java index 6cf0beb8..ca227682 100644 --- a/oxService/src/main/java/org/gluu/service/metric/LdapEntryReporter.java +++ b/oxService/src/main/java/org/gluu/service/metric/LdapEntryReporter.java @@ -226,14 +226,18 @@ private List builTimerEntries(SortedMap timers, Set< private void addMandatoryAttributes(MetricService metricService, Date startTime, Date endTime, List metricEntries, Date creationTime) { + String nodeIndetifier = metricService.getNodeIndetifier(); + ApplicationType applicationType = metricService.getApplicationType(); + for (MetricEntry metricEntry : metricEntries) { - String id = metricService.getuUiqueIdentifier(); - String dn = metricService.buildDn(id, creationTime, ApplicationType.OX_AUTH); + String id = metricService.getUiqueIdentifier(); + String dn = metricService.buildDn(id, creationTime, applicationType); metricEntry.setId(id); metricEntry.setDn(dn); - metricEntry.setApplicationType(ApplicationType.OX_AUTH); + metricEntry.setApplicationType(applicationType); + metricEntry.setNodeIndetifier(nodeIndetifier); metricEntry.setStartDate(startTime); metricEntry.setEndDate(endTime); diff --git a/oxService/src/main/java/org/gluu/service/metric/MetricService.java b/oxService/src/main/java/org/gluu/service/metric/MetricService.java index 4ddcb77a..fe504669 100644 --- a/oxService/src/main/java/org/gluu/service/metric/MetricService.java +++ b/oxService/src/main/java/org/gluu/service/metric/MetricService.java @@ -331,7 +331,7 @@ private Set getBaseDnForPeriod(ApplicationType applicationType, Date sta return metricDns; } - public String getuUiqueIdentifier() { + public String getUiqueIdentifier() { return UUID.randomUUID().toString(); } From 7db6cd2d2d72208b5eab836b28dd117db5c7a7b6 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 12 Aug 2020 20:27:32 +0300 Subject: [PATCH 217/362] Change javax.faces with jakarta.faces --- oxJsfUtil/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index 0211eb0b..82fdd2c7 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -44,7 +44,7 @@ org.glassfish - javax.faces + jakarta.faces javax.servlet From 61fff6b578c01728d97eaa3cadaa873d37e4ba33 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 12 Aug 2020 20:53:37 +0300 Subject: [PATCH 218/362] Injection: Cross-Site Scripting oxTrust #2012 --- .../src/main/java/org/gluu/jsf2/message/FacesMessages.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/oxJsfUtil/src/main/java/org/gluu/jsf2/message/FacesMessages.java b/oxJsfUtil/src/main/java/org/gluu/jsf2/message/FacesMessages.java index df6dbc0c..2d910a32 100644 --- a/oxJsfUtil/src/main/java/org/gluu/jsf2/message/FacesMessages.java +++ b/oxJsfUtil/src/main/java/org/gluu/jsf2/message/FacesMessages.java @@ -16,6 +16,7 @@ import javax.faces.context.FacesContext; import javax.inject.Inject; +import org.apache.commons.text.StringEscapeUtils; import org.gluu.service.el.ExpressionEvaluator; /** @@ -53,7 +54,8 @@ public void add(String clientId, Severity severity, String message) { } String evaluatedMessage = evalAsString(message); - FacesMessage facesMessage = new FacesMessage(severity, evaluatedMessage, evaluatedMessage); + String encodedMessage = StringEscapeUtils.escapeHtml4(evaluatedMessage); + FacesMessage facesMessage = new FacesMessage(severity, encodedMessage, encodedMessage); facesContext.addMessage(clientId, facesMessage); messages.put(clientId, facesMessage); From 7f3e98e7e28a6d772ec78611f2a0b9059adfac43 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Thu, 13 Aug 2020 14:17:58 +0100 Subject: [PATCH 219/362] Move some log from DEBUG to TRACE #201 --- .../org/gluu/service/custom/script/ExternalScriptService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java b/core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java index 97069570..44d0dd1a 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java @@ -109,7 +109,7 @@ public CustomScriptConfiguration determineDefaultCustomScriptConfiguration(List< public int executeExternalGetApiVersion(CustomScriptConfiguration customScriptConfiguration) { try { - log.debug("Executing python 'getApiVersion' authenticator method"); + log.trace("Executing python 'getApiVersion' authenticator method"); BaseExternalType externalAuthenticator = (BaseExternalType) customScriptConfiguration.getExternalType(); return externalAuthenticator.getApiVersion(); } catch (Exception ex) { From f4682656a4f0391c553cce99ca99eb5b5e8966d6 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 13 Aug 2020 17:04:07 +0300 Subject: [PATCH 220/362] Update methods to store oxExternalUid as multivalued by default oxAuth #1442 --- .../gluu/persist/model/base/CustomAttribute.java | 16 +++++++++++++++- .../model/base/CustomObjectAttribute.java | 4 +++- .../org/gluu/persist/model/base/SimpleUser.java | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/CustomAttribute.java b/persistence-model/src/main/java/org/gluu/persist/model/base/CustomAttribute.java index a066bd4c..3966acd7 100644 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/CustomAttribute.java +++ b/persistence-model/src/main/java/org/gluu/persist/model/base/CustomAttribute.java @@ -19,6 +19,7 @@ public class CustomAttribute implements Serializable, Comparable values; public CustomAttribute() { @@ -31,6 +32,7 @@ public CustomAttribute(String name) { public CustomAttribute(String name, String value) { this.name = name; setValue(value); + this.multiValued = false; } public CustomAttribute(String name, List values) { @@ -53,6 +55,7 @@ public String getValue() { public void setValue(String value) { this.values = new ArrayList(); this.values.add(value); + this.multiValued = false; } public List getValues() { @@ -61,6 +64,7 @@ public List getValues() { public void setValues(List values) { this.values = values; + this.multiValued = (values != null) && (values.size() > 1); } public final String getName() { @@ -71,6 +75,16 @@ public final void setName(String name) { this.name = name; } + public boolean isMultiValued() { + return multiValued; + } + + public CustomAttribute setMultiValued(boolean multiValued) { + this.multiValued = multiValued; + + return this; + } + public String getDisplayValue() { if (values == null) { return ""; @@ -113,7 +127,7 @@ public int hashCode() { @Override public String toString() { - return String.format("Attribute [name=%s, values=%s]", name, values); + return String.format("Attribute [name=%s, multiValued=%s, value=%s]", name, multiValued, values); } public int compareTo(CustomAttribute o) { diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/CustomObjectAttribute.java b/persistence-model/src/main/java/org/gluu/persist/model/base/CustomObjectAttribute.java index e7b39b33..cfb04c9b 100644 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/CustomObjectAttribute.java +++ b/persistence-model/src/main/java/org/gluu/persist/model/base/CustomObjectAttribute.java @@ -78,8 +78,10 @@ public boolean isMultiValued() { return multiValued; } - public void setMultiValued(boolean multiValued) { + public CustomObjectAttribute setMultiValued(boolean multiValued) { this.multiValued = multiValued; + + return this; } public String getDisplayValue() { diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java index e6d4aaf3..fef1b519 100644 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java +++ b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java @@ -43,7 +43,7 @@ public class SimpleUser implements Serializable { @AttributeName(name = "oxAuthPersistentJWT") private String[] oxAuthPersistentJwt; - @AttributesList(name = "name", value = "values", sortByName = true) + @AttributesList(name = "name", value = "values", multiValued = "multiValued", sortByName = true) protected List customAttributes = new ArrayList(); @CustomObjectClass From cf97f2e56b88ecc03bb422ae2faae185a6dcd5d7 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 13 Aug 2020 20:56:27 +0300 Subject: [PATCH 221/362] Update sample to add user with oxExternalUid and search by this attribute --- ...CouchbaseCustomStringAttributesSample.java | 23 +++++++++++-------- .../model/SimpleCustomStringUser.java | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomStringAttributesSample.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomStringAttributesSample.java index 988fc03d..71564e5a 100644 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomStringAttributesSample.java +++ b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomStringAttributesSample.java @@ -1,15 +1,14 @@ package org.gluu.couchbase; import java.util.Arrays; -import java.util.Date; +import java.util.List; import org.gluu.couchbase.model.SimpleCustomStringUser; -import org.gluu.couchbase.model.SimpleUser; import org.gluu.couchbase.model.UserRole; import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; import org.gluu.persist.couchbase.operation.impl.CouchbaseConnectionProvider; import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.persist.model.base.CustomObjectAttribute; +import org.gluu.search.filter.Filter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,16 +29,15 @@ public static void main(String[] args) { // Create Couchbase entry manager CouchbaseEntryManager couchbaseEntryManager = couchbaseSampleEntryManager.createCouchbaseEntryManager(); + String randomExternalUid = "otp:" + System.currentTimeMillis(); + // Add dummy user - SimpleUser newUser = new SimpleUser(); + SimpleCustomStringUser newUser = new SimpleCustomStringUser(); newUser.setDn(String.format("inum=%s,ou=people,o=gluu", System.currentTimeMillis())); newUser.setUserId("sample_user_" + System.currentTimeMillis()); newUser.setUserPassword("test"); - newUser.getCustomAttributes().add(new CustomObjectAttribute("streetAddress", Arrays.asList("London", "Texas", "Kiev"))); - newUser.getCustomAttributes().add(new CustomObjectAttribute("test", "test_value")); - newUser.getCustomAttributes().add(new CustomObjectAttribute("birthdate", new Date())); - newUser.getCustomAttributes().add(new CustomObjectAttribute("enabled", false)); - newUser.getCustomAttributes().add(new CustomObjectAttribute("age", 18)); + newUser.getCustomAttributes().add(new CustomAttribute("streetAddress", Arrays.asList("London", "Texas", "Kiev"))); + newUser.getCustomAttributes().add((new CustomAttribute("oxExternalUid", randomExternalUid)).setMultiValued(true)); newUser.setUserRole(UserRole.ADMIN); newUser.setNotes(Arrays.asList("note 1", "note 2", "note 3")); @@ -56,6 +54,13 @@ public static void main(String[] args) { for (CustomAttribute customAttribute : foundUser.getCustomAttributes()) { LOG.info("Found custom attribute '{}' with value '{}'", customAttribute.getName(), customAttribute.getValue()); } + + // Find by oxExternalUid + Filter oxExternalUidFilter = Filter.createEqualityFilter("oxExternalUid", randomExternalUid).multiValued(); + List foundUsers = couchbaseEntryManager.findEntries("ou=people,o=gluu", SimpleCustomStringUser.class, oxExternalUidFilter); + for (SimpleCustomStringUser foundUser2 : foundUsers) { + LOG.info("Found User '{}' by oxExternalUid with uid '{}' and key '{}'", foundUser2, foundUser2.getUserId(), foundUser2.getDn()); + } } } diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleCustomStringUser.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleCustomStringUser.java index 38100f04..c191aad6 100644 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleCustomStringUser.java +++ b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleCustomStringUser.java @@ -44,7 +44,7 @@ public class SimpleCustomStringUser implements Serializable { @AttributeName(name = "notes") private List notes; - @AttributesList(name = "name", value = "values", sortByName = true) + @AttributesList(name = "name", value = "values", multiValued = "multiValued", sortByName = true) private List customAttributes = new ArrayList(); @CustomObjectClass From 6ffe37dd6385309945f2e388f505a5c48d74aa7e Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Fri, 14 Aug 2020 10:47:27 +0300 Subject: [PATCH 222/362] (5.0) Added new methods related to software_statement validation. https://github.com/GluuFederation/oxAuth/issues/1444 --- .../script/type/client/ClientRegistrationType.java | 8 ++++++-- .../type/client/DummyClientRegistrationType.java | 13 +++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java index ab9bd366..81e94507 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java @@ -6,11 +6,11 @@ package org.gluu.model.custom.script.type.client; -import java.util.Map; - import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.type.BaseExternalType; +import java.util.Map; + /** * Base interface for external custom client registration python script * @@ -22,4 +22,8 @@ public interface ClientRegistrationType extends BaseExternalType { public boolean updateClient(Object registerRequest, Object client, Map configurationAttributes); + String getHmacSecret(Object context); + + String getJwks(Object context); + } diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java index ecab4bb1..e9e27730 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java @@ -4,10 +4,10 @@ * Copyright (c) 2014, Gluu */package org.gluu.model.custom.script.type.client; -import java.util.Map; - import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.model.CustomScript; + +import java.util.Map; /** * Dummy implementation of interface ClientRegistrationType * @@ -43,4 +43,13 @@ public boolean updateClient(Object registerRequest, Object client, Map Date: Fri, 14 Aug 2020 11:20:52 +0300 Subject: [PATCH 223/362] (5.0) Renamed new methods related to software_statement validation. https://github.com/GluuFederation/oxAuth/issues/1444 --- .../custom/script/type/client/ClientRegistrationType.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java index 81e94507..06f80267 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/client/ClientRegistrationType.java @@ -22,8 +22,8 @@ public interface ClientRegistrationType extends BaseExternalType { public boolean updateClient(Object registerRequest, Object client, Map configurationAttributes); - String getHmacSecret(Object context); + String getSoftwareStatementHmacSecret(Object context); - String getJwks(Object context); + String getSoftwareStatementJwks(Object context); } From 88bf7b88241bed1a39eb29772ebd708564c242d7 Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Fri, 14 Aug 2020 11:28:00 +0300 Subject: [PATCH 224/362] (5.0) Corrected DummyClientRegistrationType. https://github.com/GluuFederation/oxAuth/issues/1444 --- .../script/type/client/DummyClientRegistrationType.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java index e9e27730..cbf77668 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/client/DummyClientRegistrationType.java @@ -44,12 +44,12 @@ public boolean updateClient(Object registerRequest, Object client, Map Date: Fri, 14 Aug 2020 13:09:16 +0300 Subject: [PATCH 225/362] Fix variable name spelling --- .../reflect/property/BasicPropertyAnnotationResolver.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/persistence-core/src/main/java/org/gluu/persist/reflect/property/BasicPropertyAnnotationResolver.java b/persistence-core/src/main/java/org/gluu/persist/reflect/property/BasicPropertyAnnotationResolver.java index d2f2c489..3e295b32 100644 --- a/persistence-core/src/main/java/org/gluu/persist/reflect/property/BasicPropertyAnnotationResolver.java +++ b/persistence-core/src/main/java/org/gluu/persist/reflect/property/BasicPropertyAnnotationResolver.java @@ -61,14 +61,14 @@ public Map> getPropertiesAnnotations(Class theClass, Class thisClass = theClass; while (ReflectHelper.isNotPrimitiveClass(thisClass)) { - Field[] fileds = thisClass.getDeclaredFields(); - for (Field filed : fileds) { - List annotations = getOnlyAllowedAnntotations(filed.getAnnotations(), allowedAnnotations); + Field[] fields = thisClass.getDeclaredFields(); + for (Field field : fields) { + List annotations = getOnlyAllowedAnntotations(field.getAnnotations(), allowedAnnotations); if ((annotations == null) || (annotations.size() == 0)) { continue; } - result.put(filed.getName(), annotations); + result.put(field.getName(), annotations); } thisClass = thisClass.getSuperclass(); } From baa00ccdc536122a110d1324cf5d482eab434c76 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 14 Aug 2020 13:09:30 +0300 Subject: [PATCH 226/362] Use CustomObjectAttribute instead of CustomAttribute in user services to use JSON data types #1445 --- .../gluu/persist/model/base/SimpleUser.java | 46 +++++++++++++------ 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java index fef1b519..28881712 100644 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java +++ b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java @@ -44,7 +44,7 @@ public class SimpleUser implements Serializable { private String[] oxAuthPersistentJwt; @AttributesList(name = "name", value = "values", multiValued = "multiValued", sortByName = true) - protected List customAttributes = new ArrayList(); + protected List customAttributes = new ArrayList(); @CustomObjectClass private String[] customObjectClasses; @@ -89,19 +89,25 @@ public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; } - public List getCustomAttributes() { + public List getCustomAttributes() { return customAttributes; } - public void setCustomAttributes(List customAttributes) { + public void setCustomAttributes(List customAttributes) { this.customAttributes = customAttributes; } - public String getAttribute(String ldapAttribute) { - String attribute = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(ldapAttribute)) { + public String getAttribute(String attributeName) { + Object objectAttribute = getObjectAttribute(attributeName); + + return StringHelper.toString(objectAttribute); + } + + public Object getObjectAttribute(String attributeName) { + Object attribute = null; + if (attributeName != null && !attributeName.isEmpty()) { + for (CustomObjectAttribute customAttribute : customAttributes) { + if (customAttribute.getName().equals(attributeName)) { attribute = customAttribute.getValue(); break; } @@ -111,11 +117,25 @@ public String getAttribute(String ldapAttribute) { return attribute; } - public List getAttributeValues(String ldapAttribute) { - List values = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), ldapAttribute)) { + public List getAttributeValues(String attributeName) { + List objectValues = getAttributeObjectValues(attributeName); + if (objectValues == null) { + return null; + } + + List values = new ArrayList(objectValues.size()); + for (Object objectValue : objectValues) { + values.add(StringHelper.toString(objectValue)); + } + + return values; + } + + public List getAttributeObjectValues(String attributeName) { + List values = null; + if (attributeName != null && !attributeName.isEmpty()) { + for (CustomObjectAttribute customAttribute : customAttributes) { + if (StringHelper.equalsIgnoreCase(customAttribute.getName(), attributeName)) { values = customAttribute.getValues(); break; } From 0db89c5b50d33124c09507bd7f8777f8ac37487f Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 14 Aug 2020 16:20:44 +0300 Subject: [PATCH 227/362] Rename method to get value as object --- .../src/main/java/org/gluu/persist/model/base/SimpleUser.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java index 28881712..59a99fcb 100644 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java +++ b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java @@ -98,12 +98,12 @@ public void setCustomAttributes(List customAttributes) { } public String getAttribute(String attributeName) { - Object objectAttribute = getObjectAttribute(attributeName); + Object objectAttribute = getAttributeObject(attributeName); return StringHelper.toString(objectAttribute); } - public Object getObjectAttribute(String attributeName) { + public Object getAttributeObject(String attributeName) { Object attribute = null; if (attributeName != null && !attributeName.isEmpty()) { for (CustomObjectAttribute customAttribute : customAttributes) { From 6437019a886224e9583d30cfd4552c44ae29e6d5 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 26 Aug 2020 22:53:06 +0300 Subject: [PATCH 228/362] JAXB-API implementation error oxTrust #2005 --- .../java/org/gluu/service/XmlService.java | 126 +----------------- .../java/org/gluu/model/TrustContact.java | 3 - 2 files changed, 1 insertion(+), 128 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/XmlService.java b/oxService/src/main/java/org/gluu/service/XmlService.java index 6433fa51..9d051a79 100644 --- a/oxService/src/main/java/org/gluu/service/XmlService.java +++ b/oxService/src/main/java/org/gluu/service/XmlService.java @@ -5,19 +5,13 @@ */package org.gluu.service; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; -import javax.annotation.PostConstruct; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import javax.inject.Named; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; -import javax.xml.bind.Unmarshaller; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; @@ -27,8 +21,6 @@ import javax.xml.xpath.XPathFactory; import org.apache.commons.io.IOUtils; -import org.gluu.model.GluuImage; -import org.gluu.model.TrustContact; import org.gluu.util.StringHelper; import org.slf4j.Logger; import org.w3c.dom.Document; @@ -42,129 +34,13 @@ * @author Yuriy Movchan Date: 01.11.2011 */ @ApplicationScoped -@Named -public class XmlService implements Serializable { +public class XmlService { private static final long serialVersionUID = -4805285557592935972L; @Inject private Logger log; - private JAXBContext jaxbContext; - private Marshaller jaxbMarshaller; - private Unmarshaller jaxbUnmarshaller; - - @PostConstruct - public void init() { - try { - this.jaxbContext = JAXBContext.newInstance(GluuImage.class, TrustContact.class); - this.jaxbMarshaller = this.jaxbContext.createMarshaller(); - this.jaxbUnmarshaller = this.jaxbContext.createUnmarshaller(); - } catch (JAXBException ex) { - log.error("Failed to create JAXB marshaller and unmarshaller", ex); - } - } - - public String getXMLFromGluuImage(GluuImage photo) { - if (photo == null) { - return null; - } - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - try { - this.jaxbMarshaller.marshal(photo, bos); - return new String(bos.toByteArray(), "UTF-8"); - } catch (Exception ex) { - log.error("Failed to convert GluuImage {} to XML", ex, photo); - } - - return null; - } - - public GluuImage getGluuImageFromXML(String xml) { - if (xml == null) { - return null; - } - - try { - ByteArrayInputStream bis = new ByteArrayInputStream(xml.getBytes("UTF-8")); - return (GluuImage) this.jaxbUnmarshaller.unmarshal(bis); - } catch (Exception ex) { - log.error("Failed to create GluuImage from XML {}", ex, xml); - } - - return null; - } - - public TrustContact getTrustContactFromXML(String xml) { - if (xml == null) { - return null; - } - - try { - ByteArrayInputStream bis = new ByteArrayInputStream(xml.getBytes("UTF-8")); - return (TrustContact) this.jaxbUnmarshaller.unmarshal(bis); - } catch (Exception ex) { - log.error("Failed to create TrustContact from XML {}", ex, xml); - } - - return null; - } - - // public String - // getXMLFromDeconstructedTrustRelationship(DeconstructedTrustRelationship - // deconstructedTR) { - // if (deconstructedTR == null) { - // return null; - // } - // - // ByteArrayOutputStream bos = new ByteArrayOutputStream(); - // try { - // this.jaxbMarshaller.marshal(deconstructedTR, bos); - // return new String(bos.toByteArray(), "UTF-8"); - // } catch (Exception ex) { - // log.error("Failed to convert DeconstructedTrustRelationship {} to XML", - // ex, deconstructedTR); - // } - // - // return null; - // } - // - // public DeconstructedTrustRelationship - // getDeconstructedTrustRelationshipFromXML(String xml) { - // if (xml == null) { - // return null; - // } - // - // try { - // ByteArrayInputStream bis = new - // ByteArrayInputStream(xml.getBytes("UTF-8")); - // return (DeconstructedTrustRelationship) - // this.jaxbUnmarshaller.unmarshal(bis); - // } catch (Exception ex) { - // log.error("Failed to create DeconstructedTrustRelationship from XML {}", - // ex, xml); - // } - // - // return null; - // } - - public String getXMLFromTrustContact(TrustContact contact) { - if (contact == null) { - return null; - } - - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - try { - this.jaxbMarshaller.marshal(contact, bos); - return new String(bos.toByteArray(), "UTF-8"); - } catch (Exception ex) { - log.error("Failed to convert TrustContact {} to XML", ex, contact); - } - - return null; - } - public Document getXmlDocument(byte[] xmlDocumentBytes) throws SAXException, IOException, ParserConfigurationException { return getXmlDocument(xmlDocumentBytes, false); } diff --git a/oxUtil/src/main/java/org/gluu/model/TrustContact.java b/oxUtil/src/main/java/org/gluu/model/TrustContact.java index e4b33e63..790c588c 100644 --- a/oxUtil/src/main/java/org/gluu/model/TrustContact.java +++ b/oxUtil/src/main/java/org/gluu/model/TrustContact.java @@ -6,9 +6,6 @@ package org.gluu.model; -import javax.xml.bind.annotation.XmlRootElement; - -@XmlRootElement public class TrustContact implements java.io.Serializable { private static final long serialVersionUID = -3268590744030750954L; From dd3acd5227db9bd3f7b5f95e00105ad23cb84b44 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 27 Aug 2020 13:35:38 +0300 Subject: [PATCH 229/362] Add new utility methods to xml service --- .../java/org/gluu/service/XmlService.java | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/XmlService.java b/oxService/src/main/java/org/gluu/service/XmlService.java index 9d051a79..e25ca7d4 100644 --- a/oxService/src/main/java/org/gluu/service/XmlService.java +++ b/oxService/src/main/java/org/gluu/service/XmlService.java @@ -7,11 +7,10 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.Serializable; +import java.nio.charset.Charset; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; -import javax.inject.Named; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; @@ -41,6 +40,21 @@ public class XmlService { @Inject private Logger log; + public Document getXmlDocument(String xmlDocument) throws SAXException, IOException, ParserConfigurationException { + return getXmlDocument(xmlDocument, false); + } + + public Document getXmlDocument(String xmlDocument, boolean skipValidation) throws SAXException, IOException, ParserConfigurationException { + InputStream is = IOUtils.toInputStream(xmlDocument, Charset.forName("utf-8")); + try { + DocumentBuilderFactory fty = createDocumentBuilderFactory(skipValidation); + + return fty.newDocumentBuilder().parse(is); + } finally { + IOUtils.closeQuietly(is); + } + } + public Document getXmlDocument(byte[] xmlDocumentBytes) throws SAXException, IOException, ParserConfigurationException { return getXmlDocument(xmlDocumentBytes, false); } @@ -68,7 +82,7 @@ public Document getXmlDocument(InputSource is) throws SAXException, IOException, return fty.newDocumentBuilder().parse(is); } - public Document getXmlDocument(String uri) throws SAXException, IOException, ParserConfigurationException { + public Document getXmlDocumentFromUri(String uri) throws SAXException, IOException, ParserConfigurationException { DocumentBuilderFactory fty = createDocumentBuilderFactory(); return fty.newDocumentBuilder().parse(uri); @@ -114,6 +128,12 @@ public String getNodeValue(Document xmlDocument, String xPathExpression, String Node attributeNode = node.getAttributes().getNamedItem(attributeName); if (attributeNode == null) { + if (node.getChildNodes().getLength() == 1) { + node = node.getFirstChild(); + if (node.getNodeType() == Node.TEXT_NODE) { + return node.getNodeValue(); + } + } return null; } From bee3cf00c3ccf6e1c6e6f687757baf4836ea551c Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Thu, 3 Sep 2020 14:01:46 +0100 Subject: [PATCH 230/362] Add ScriptService in oxCore --- .../java/org/gluu/service/ScriptService.java | 126 ++++++++++++++++++ .../main/java/org/gluu/util/OxConstants.java | 37 ++--- 2 files changed, 145 insertions(+), 18 deletions(-) create mode 100644 oxService/src/main/java/org/gluu/service/ScriptService.java diff --git a/oxService/src/main/java/org/gluu/service/ScriptService.java b/oxService/src/main/java/org/gluu/service/ScriptService.java new file mode 100644 index 00000000..9258f078 --- /dev/null +++ b/oxService/src/main/java/org/gluu/service/ScriptService.java @@ -0,0 +1,126 @@ +/** + * + */ +package org.gluu.service; + +import java.util.List; + +import javax.inject.Inject; + +import org.gluu.model.custom.script.CustomScriptType; +import org.gluu.model.custom.script.model.CustomScript; +import org.gluu.persist.PersistenceEntryManager; +import org.gluu.search.filter.Filter; +import org.gluu.service.custom.script.AbstractCustomScriptService; +import org.gluu.util.OxConstants; +import org.gluu.util.StringHelper; + +/** + * @author Mougang T.Gasmyr + * + */ +public class ScriptService extends AbstractCustomScriptService { + + @Inject + private OrganizationService organizationService; + + @Inject + private PersistenceEntryManager persistenceEntryManager; + + private static final long serialVersionUID = -5283102477313448031L; + + public CustomScript getScriptByInum(String inum) { + CustomScript result = null; + try { + result = persistenceEntryManager.find(CustomScript.class, buildDn(inum)); + } catch (Exception ex) { + } + return result; + } + + public List findCustomAuthScripts(String pattern, int sizeLimit) { + String[] targetArray = new String[] { pattern }; + Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); + Filter scriptTypeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, + CustomScriptType.PERSON_AUTHENTICATION); + Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); + Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, + Filter.createANDFilter(searchFilter, scriptTypeFilter), sizeLimit); + } + + public List findCustomAuthScripts(int sizeLimit) { + Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, + CustomScriptType.PERSON_AUTHENTICATION.getValue()); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, searchFilter, + sizeLimit); + } + + public List findOtherCustomScripts(String pattern, int sizeLimit) { + String[] targetArray = new String[] { pattern }; + Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); + Filter scriptTypeFilter = Filter.createNOTFilter( + Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, CustomScriptType.PERSON_AUTHENTICATION)); + Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); + Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, + Filter.createANDFilter(searchFilter, scriptTypeFilter), sizeLimit); + } + + public List findScriptByType(CustomScriptType type, int sizeLimit) { + Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, searchFilter, + sizeLimit); + } + + public List findScriptByType(CustomScriptType type) { + Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, searchFilter, null); + } + + public List findScriptByPatternAndType(String pattern, CustomScriptType type, int sizeLimit) { + String[] targetArray = new String[] { pattern }; + Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); + Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); + Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + Filter typeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, + Filter.createANDFilter(searchFilter, typeFilter), sizeLimit); + } + + public List findScriptByPatternAndType(String pattern, CustomScriptType type) { + String[] targetArray = new String[] { pattern }; + Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); + Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); + Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + Filter typeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, + Filter.createANDFilter(searchFilter, typeFilter), null); + } + + public List findOtherCustomScripts(int sizeLimit) { + Filter searchFilter = Filter.createNOTFilter( + Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, CustomScriptType.PERSON_AUTHENTICATION)); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, searchFilter, + sizeLimit); + } + + public String getDnForCustomScript(String inum) { + String orgDn = organizationService.getDnForOrganization(null); + if (StringHelper.isEmpty(inum)) { + return String.format("ou=scripts,%s", orgDn); + } + return String.format("inum=%s,ou=scripts,%s", inum, orgDn); + } + + /* + * (non-Javadoc) + * + * @see org.gluu.service.custom.script.AbstractCustomScriptService#baseDn() + */ + @Override + public String baseDn() { + return String.format("ou=scripts,%s", organizationService.getDnForOrganization(null)); + } + +} diff --git a/oxService/src/main/java/org/gluu/util/OxConstants.java b/oxService/src/main/java/org/gluu/util/OxConstants.java index 56eb6cb8..1e5da00c 100644 --- a/oxService/src/main/java/org/gluu/util/OxConstants.java +++ b/oxService/src/main/java/org/gluu/util/OxConstants.java @@ -12,27 +12,28 @@ */ public class OxConstants { - public static final String UID = "uid"; - public static final String OBJECT_CLASS = "objectClass"; + public static final String UID = "uid"; + public static final String OBJECT_CLASS = "objectClass"; - public static final String INUM = "inum"; - public static final String INAME = "iname"; - public static final String DISPLAY_NAME = "displayName"; - public static final String DESCRIPTION = "description"; - public static final String ORIGIN = "gluuAttributeOrigin"; - public static final String MAIL = "mail"; + public static final String INUM = "inum"; + public static final String INAME = "iname"; + public static final String DISPLAY_NAME = "displayName"; + public static final String SCRIPT_TYPE = "oxScriptType"; + public static final String DESCRIPTION = "description"; + public static final String ORIGIN = "gluuAttributeOrigin"; + public static final String MAIL = "mail"; - public static final String CACHE_ORGANIZATION_KEY = "organization"; - public static final String CACHE_METRICS_KEY = "metrics"; - public static final String CACHE_APPLICATION_NAME = "ApplicationCache"; - public static final String CACHE_ATTRIBUTE_NAME = "AttributeCache"; - public static final String CACHE_LOOKUP_NAME = "LookupCache"; - public static final String CACHE_METRICS_NAME = "metricsCache"; + public static final String CACHE_ORGANIZATION_KEY = "organization"; + public static final String CACHE_METRICS_KEY = "metrics"; + public static final String CACHE_APPLICATION_NAME = "ApplicationCache"; + public static final String CACHE_ATTRIBUTE_NAME = "AttributeCache"; + public static final String CACHE_LOOKUP_NAME = "LookupCache"; + public static final String CACHE_METRICS_NAME = "metricsCache"; - public static final String CACHE_ATTRIBUTE_KEY_LIST = "attributeList"; - public static final String CACHE_ACTIVE_ATTRIBUTE_KEY_LIST = "activeAttributeList"; - public static final String CACHE_ACTIVE_ATTRIBUTE_NAME = "ActiveAttributeCache"; + public static final String CACHE_ATTRIBUTE_KEY_LIST = "attributeList"; + public static final String CACHE_ACTIVE_ATTRIBUTE_KEY_LIST = "activeAttributeList"; + public static final String CACHE_ACTIVE_ATTRIBUTE_NAME = "ActiveAttributeCache"; - public static final String SCRIPT_TYPE_INTERNAL_RESERVED_NAME = "simple_password_auth"; + public static final String SCRIPT_TYPE_INTERNAL_RESERVED_NAME = "simple_password_auth"; } From e699f00ab1c587e973b6b5da8b777bd6c45a22d3 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Thu, 3 Sep 2020 16:55:03 +0100 Subject: [PATCH 231/362] Add scope to ScriptService --- .../java/org/gluu/service/LookupService.java | 265 +++++++++--------- .../service/ObjectSerializationService.java | 132 ++++----- .../java/org/gluu/service/SchemaService.java | 8 - .../java/org/gluu/service/ScriptService.java | 4 + 4 files changed, 196 insertions(+), 213 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/LookupService.java b/oxService/src/main/java/org/gluu/service/LookupService.java index 1ab209e4..e80ffe09 100644 --- a/oxService/src/main/java/org/gluu/service/LookupService.java +++ b/oxService/src/main/java/org/gluu/service/LookupService.java @@ -20,7 +20,6 @@ import org.gluu.persist.model.base.Entry; import org.gluu.search.filter.Filter; import org.gluu.util.OxConstants; -import org.slf4j.Logger; /** * Provides operations with DisplayNameEntry @@ -31,138 +30,136 @@ @Named public class LookupService implements Serializable { - private static final long serialVersionUID = -3707238475653913313L; - - @Inject - private Logger log; - - @Inject - private PersistenceEntryManager persistenceEntryManager; - - @Inject - private CacheService cacheService; - - /** - * Returns DisplayNameEntry based on display name - * - * @param dn - * display name - * @return DisplayNameEntry object - */ - public DisplayNameEntry getDisplayNameEntry(String dn) throws Exception { - String key = "l_" + dn; - DisplayNameEntry entry = (DisplayNameEntry) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); - if (entry == null) { - entry = persistenceEntryManager.find(dn, DisplayNameEntry.class, null); - - cacheService.put(OxConstants.CACHE_LOOKUP_NAME, key, entry); - } - - return entry; - } - - /** - * Returns list of DisplayNameEntry objects - * - * @param baseDn - * base DN - * @param dns - * list of display names to find - * @return list of DisplayNameEntry objects - */ - @SuppressWarnings("unchecked") - public List getDisplayNameEntries(String baseDn, List dns) { - List inums = getInumsFromDns(dns); - if (inums.size() == 0) { - return null; - } - - String key = getCompoundKey(inums); - List entries = (List) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); - if (entries == null) { - Filter searchFilter = buildInumFilter(inums); - entries = persistenceEntryManager.findEntries(baseDn, DisplayNameEntry.class, searchFilter); - cacheService.put(OxConstants.CACHE_LOOKUP_NAME, key, entries); - } - return entries; - } - - public Filter buildInumFilter(List inums) { - List inumFilters = new ArrayList(inums.size()); - for (String inum : inums) { - inumFilters.add(Filter.createEqualityFilter(OxConstants.INUM, inum).multiValued(false)); - } - return Filter.createORFilter(inumFilters); - } - - public List getInumsFromDns(List dns) { - List inums = new ArrayList(); - - if (dns == null) { - return inums; - } - - for (String dn : dns) { - String inum = getInumFromDn(dn); - if (inum != null) { - inums.add(inum); - } - } - - Collections.sort(inums); - - return inums; - } - - private String getCompoundKey(List inums) { - StringBuilder compoundKey = new StringBuilder(); - for (String inum : inums) { - if (compoundKey.length() > 0) { - compoundKey.append("_"); - } else { - compoundKey.append("l_"); - } - compoundKey.append(inum); - } - - return compoundKey.toString(); - } - - public List getDisplayNameEntriesByEntries(String baseDn, List entries) throws Exception { - if (entries == null) { - return null; - } - - List dns = new ArrayList(entries.size()); - for (Entry entry : entries) { - dns.add(entry.getDn()); - } - - return getDisplayNameEntries(baseDn, dns); - } - - /** - * Get inum from DN - * - * @param dn - * DN - * @return Inum - */ - public String getInumFromDn(String dn) { - if (dn == null) { - return null; - } - - if (!dn.startsWith("inum=")) { - return null; - } - - int idx = dn.indexOf(",", 5); - if (idx == -1) { - return null; - } - - return dn.substring(5, idx); - } + private static final long serialVersionUID = -3707238475653913313L; + + @Inject + private PersistenceEntryManager persistenceEntryManager; + + @Inject + private CacheService cacheService; + + /** + * Returns DisplayNameEntry based on display name + * + * @param dn + * display name + * @return DisplayNameEntry object + */ + public DisplayNameEntry getDisplayNameEntry(String dn) throws Exception { + String key = "l_" + dn; + DisplayNameEntry entry = (DisplayNameEntry) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); + if (entry == null) { + entry = persistenceEntryManager.find(dn, DisplayNameEntry.class, null); + + cacheService.put(OxConstants.CACHE_LOOKUP_NAME, key, entry); + } + + return entry; + } + + /** + * Returns list of DisplayNameEntry objects + * + * @param baseDn + * base DN + * @param dns + * list of display names to find + * @return list of DisplayNameEntry objects + */ + @SuppressWarnings("unchecked") + public List getDisplayNameEntries(String baseDn, List dns) { + List inums = getInumsFromDns(dns); + if (inums.size() == 0) { + return null; + } + + String key = getCompoundKey(inums); + List entries = (List) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); + if (entries == null) { + Filter searchFilter = buildInumFilter(inums); + entries = persistenceEntryManager.findEntries(baseDn, DisplayNameEntry.class, searchFilter); + cacheService.put(OxConstants.CACHE_LOOKUP_NAME, key, entries); + } + return entries; + } + + public Filter buildInumFilter(List inums) { + List inumFilters = new ArrayList(inums.size()); + for (String inum : inums) { + inumFilters.add(Filter.createEqualityFilter(OxConstants.INUM, inum).multiValued(false)); + } + return Filter.createORFilter(inumFilters); + } + + public List getInumsFromDns(List dns) { + List inums = new ArrayList(); + + if (dns == null) { + return inums; + } + + for (String dn : dns) { + String inum = getInumFromDn(dn); + if (inum != null) { + inums.add(inum); + } + } + + Collections.sort(inums); + + return inums; + } + + private String getCompoundKey(List inums) { + StringBuilder compoundKey = new StringBuilder(); + for (String inum : inums) { + if (compoundKey.length() > 0) { + compoundKey.append("_"); + } else { + compoundKey.append("l_"); + } + compoundKey.append(inum); + } + + return compoundKey.toString(); + } + + public List getDisplayNameEntriesByEntries(String baseDn, List entries) + throws Exception { + if (entries == null) { + return null; + } + + List dns = new ArrayList(entries.size()); + for (Entry entry : entries) { + dns.add(entry.getDn()); + } + + return getDisplayNameEntries(baseDn, dns); + } + + /** + * Get inum from DN + * + * @param dn + * DN + * @return Inum + */ + public String getInumFromDn(String dn) { + if (dn == null) { + return null; + } + + if (!dn.startsWith("inum=")) { + return null; + } + + int idx = dn.indexOf(",", 5); + if (idx == -1) { + return null; + } + + return dn.substring(5, idx); + } } diff --git a/oxService/src/main/java/org/gluu/service/ObjectSerializationService.java b/oxService/src/main/java/org/gluu/service/ObjectSerializationService.java index 27e377bc..c0343aa3 100644 --- a/oxService/src/main/java/org/gluu/service/ObjectSerializationService.java +++ b/oxService/src/main/java/org/gluu/service/ObjectSerializationService.java @@ -20,7 +20,6 @@ import javax.inject.Named; import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang.SerializationUtils; import org.slf4j.Logger; @@ -33,75 +32,66 @@ @Named public class ObjectSerializationService { - @Inject - private Logger log; - - public boolean saveObject(String path, Serializable obj, boolean append) { - File file = new File(path); - FileOutputStream fos; - try { - fos = new FileOutputStream(file, append); - } catch (FileNotFoundException ex) { - log.error("Faield to serialize to file: '{}'. Error: ", path, ex); - - return false; - } - - BufferedOutputStream bos = new BufferedOutputStream(fos); - try { - GZIPOutputStream gos = new GZIPOutputStream(bos); - SerializationUtils.serialize(obj, gos); - gos.flush(); - IOUtils.closeQuietly(gos); - } catch (IOException ex) { - log.error("Faield to serialize to file: '{}'. Error: ", path, ex); - IOUtils.closeQuietly(bos); - - return false; - } - - return true; - } - - public boolean saveObject(String path, Serializable obj) { - return saveObject(path, obj, false); - } - - public Object loadObject(String path) { - File file = new File(path); - if (!file.exists()) { - log.trace("File '{}' is not exist", path); - return null; - } - - FileInputStream fis; - try { - fis = new FileInputStream(file); - } catch (FileNotFoundException ex) { - log.error("Faield to deserialize from file: '{}'. Error: ", path, ex); - - return null; - } - - BufferedInputStream bis = new BufferedInputStream(fis); - Object obj = null; - try { - GZIPInputStream gis = new GZIPInputStream(bis); - obj = SerializationUtils.deserialize(gis); - IOUtils.closeQuietly(gis); - } catch (IOException ex) { - log.error("Faield to deserialize from file: '{}'. Error: ", path, ex); - IOUtils.closeQuietly(bis); - - return null; - } - - return obj; - } - - public void cleanup(String path) { - File file = new File(path); - FileUtils.deleteQuietly(file); - } + @Inject + private Logger log; + + public boolean saveObject(String path, Serializable obj, boolean append) { + File file = new File(path); + FileOutputStream fos; + try { + fos = new FileOutputStream(file, append); + } catch (FileNotFoundException ex) { + log.error("Faield to serialize to file: '{}'. Error: ", path, ex); + + return false; + } + + ; + try (GZIPOutputStream gos = new GZIPOutputStream(new BufferedOutputStream(fos))) { + SerializationUtils.serialize(obj, gos); + gos.flush(); + } catch (IOException ex) { + log.error("Faield to serialize to file: '{}'. Error: ", path, ex); + return false; + } + + return true; + } + + public boolean saveObject(String path, Serializable obj) { + return saveObject(path, obj, false); + } + + public Object loadObject(String path) { + File file = new File(path); + if (!file.exists()) { + log.trace("File '{}' is not exist", path); + return null; + } + + FileInputStream fis; + try { + fis = new FileInputStream(file); + } catch (FileNotFoundException ex) { + log.error("Faield to deserialize from file: '{}'. Error: ", path, ex); + + return null; + } + + Object obj = null; + try (GZIPInputStream gis = new GZIPInputStream(new BufferedInputStream(fis))) { + ; + obj = SerializationUtils.deserialize(gis); + } catch (IOException ex) { + log.error("Faield to deserialize from file: '{}'. Error: ", path, ex); + return null; + } + return obj; + } + + public void cleanup(String path) { + File file = new File(path); + FileUtils.deleteQuietly(file); + } } diff --git a/oxService/src/main/java/org/gluu/service/SchemaService.java b/oxService/src/main/java/org/gluu/service/SchemaService.java index 5b111d0a..fa33aecc 100644 --- a/oxService/src/main/java/org/gluu/service/SchemaService.java +++ b/oxService/src/main/java/org/gluu/service/SchemaService.java @@ -15,20 +15,14 @@ import java.util.Set; import javax.enterprise.context.ApplicationScoped; -import javax.enterprise.inject.Instance; import javax.inject.Inject; import javax.inject.Named; import org.gluu.model.SchemaEntry; import org.gluu.persist.PersistenceEntryManager; -import org.gluu.persist.hybrid.impl.HybridEntryManager; import org.gluu.persist.hybrid.impl.HybridEntryManagerFactory; -import org.gluu.persist.hybrid.impl.HybridPersistenceOperationService; -import org.gluu.persist.ldap.impl.LdapEntryManager; import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; import org.gluu.persist.ldap.operation.LdapOperationService; -import org.gluu.persist.operation.PersistenceOperationService; -import org.gluu.service.cdi.util.CdiUtil; import org.gluu.util.StringHelper; import org.gluu.util.exception.InvalidSchemaUpdateException; import org.slf4j.Logger; @@ -51,8 +45,6 @@ public class SchemaService { @Inject private PersistenceEntryManager persistenceEntryManager; - @Inject - private Instance hybridEntryManagerInstance; @Inject private DataSourceTypeService dataSourceTypeService; diff --git a/oxService/src/main/java/org/gluu/service/ScriptService.java b/oxService/src/main/java/org/gluu/service/ScriptService.java index 9258f078..46de2c56 100644 --- a/oxService/src/main/java/org/gluu/service/ScriptService.java +++ b/oxService/src/main/java/org/gluu/service/ScriptService.java @@ -5,7 +5,9 @@ import java.util.List; +import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; +import javax.inject.Named; import org.gluu.model.custom.script.CustomScriptType; import org.gluu.model.custom.script.model.CustomScript; @@ -19,6 +21,8 @@ * @author Mougang T.Gasmyr * */ +@ApplicationScoped +@Named public class ScriptService extends AbstractCustomScriptService { @Inject From 00ecbfb5853903295caacc4e114cbbaafc2f7746 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Thu, 3 Sep 2020 17:42:41 +0100 Subject: [PATCH 232/362] Add methods --- oxService/src/main/java/org/gluu/service/ScriptService.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/ScriptService.java b/oxService/src/main/java/org/gluu/service/ScriptService.java index 46de2c56..d5d52760 100644 --- a/oxService/src/main/java/org/gluu/service/ScriptService.java +++ b/oxService/src/main/java/org/gluu/service/ScriptService.java @@ -117,11 +117,6 @@ public String getDnForCustomScript(String inum) { return String.format("inum=%s,ou=scripts,%s", inum, orgDn); } - /* - * (non-Javadoc) - * - * @see org.gluu.service.custom.script.AbstractCustomScriptService#baseDn() - */ @Override public String baseDn() { return String.format("ou=scripts,%s", organizationService.getDnForOrganization(null)); From 7c7a2d0f786bbd1e6c84865a9ae590dc0e5559a6 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 7 Sep 2020 12:53:49 +0300 Subject: [PATCH 233/362] Fix dependecies issue --- .../java/org/gluu/service/ScriptService.java | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/ScriptService.java b/oxService/src/main/java/org/gluu/service/ScriptService.java index 9258f078..a7fc7ec0 100644 --- a/oxService/src/main/java/org/gluu/service/ScriptService.java +++ b/oxService/src/main/java/org/gluu/service/ScriptService.java @@ -14,12 +14,13 @@ import org.gluu.service.custom.script.AbstractCustomScriptService; import org.gluu.util.OxConstants; import org.gluu.util.StringHelper; +import org.python.jline.internal.Log; /** * @author Mougang T.Gasmyr * */ -public class ScriptService extends AbstractCustomScriptService { +public class ScriptService { @Inject private OrganizationService organizationService; @@ -27,14 +28,17 @@ public class ScriptService extends AbstractCustomScriptService { @Inject private PersistenceEntryManager persistenceEntryManager; - private static final long serialVersionUID = -5283102477313448031L; + @Inject + protected AbstractCustomScriptService customScriptService; public CustomScript getScriptByInum(String inum) { CustomScript result = null; try { - result = persistenceEntryManager.find(CustomScript.class, buildDn(inum)); + result = persistenceEntryManager.find(CustomScript.class, customScriptService.buildDn(inum)); } catch (Exception ex) { + Log.error("Failed to find script by inum {}", inum, ex); } + return result; } @@ -45,6 +49,7 @@ public List findCustomAuthScripts(String pattern, int sizeLimit) { CustomScriptType.PERSON_AUTHENTICATION); Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, Filter.createANDFilter(searchFilter, scriptTypeFilter), sizeLimit); } @@ -52,6 +57,7 @@ public List findCustomAuthScripts(String pattern, int sizeLimit) { public List findCustomAuthScripts(int sizeLimit) { Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, CustomScriptType.PERSON_AUTHENTICATION.getValue()); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, searchFilter, sizeLimit); } @@ -63,18 +69,21 @@ public List findOtherCustomScripts(String pattern, int sizeLimit) Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, CustomScriptType.PERSON_AUTHENTICATION)); Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, Filter.createANDFilter(searchFilter, scriptTypeFilter), sizeLimit); } public List findScriptByType(CustomScriptType type, int sizeLimit) { Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, searchFilter, sizeLimit); } public List findScriptByType(CustomScriptType type) { Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, searchFilter, null); } @@ -84,6 +93,7 @@ public List findScriptByPatternAndType(String pattern, CustomScrip Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); Filter typeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, Filter.createANDFilter(searchFilter, typeFilter), sizeLimit); } @@ -94,6 +104,7 @@ public List findScriptByPatternAndType(String pattern, CustomScrip Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); Filter typeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, Filter.createANDFilter(searchFilter, typeFilter), null); } @@ -101,6 +112,7 @@ public List findScriptByPatternAndType(String pattern, CustomScrip public List findOtherCustomScripts(int sizeLimit) { Filter searchFilter = Filter.createNOTFilter( Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, CustomScriptType.PERSON_AUTHENTICATION)); + return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, searchFilter, sizeLimit); } @@ -113,12 +125,6 @@ public String getDnForCustomScript(String inum) { return String.format("inum=%s,ou=scripts,%s", inum, orgDn); } - /* - * (non-Javadoc) - * - * @see org.gluu.service.custom.script.AbstractCustomScriptService#baseDn() - */ - @Override public String baseDn() { return String.format("ou=scripts,%s", organizationService.getDnForOrganization(null)); } From 2d4db4f1bbd46630d9b532ad3f5f8fdfeaa10220 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 7 Sep 2020 12:55:56 +0300 Subject: [PATCH 234/362] Named is not needed for services --- oxService/src/main/java/org/gluu/service/ScriptService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/service/ScriptService.java b/oxService/src/main/java/org/gluu/service/ScriptService.java index 44d23903..3bb60078 100644 --- a/oxService/src/main/java/org/gluu/service/ScriptService.java +++ b/oxService/src/main/java/org/gluu/service/ScriptService.java @@ -26,7 +26,6 @@ * */ @ApplicationScoped -@Named public class ScriptService { @Inject From 935c3dab1aa86e5f3745788bb13f816cff80a685 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 7 Sep 2020 20:03:08 +0300 Subject: [PATCH 235/362] Merge ScriptService into AbstractCustomScriptService --- .../script/AbstractCustomScriptService.java | 82 ++++++++++++++++++- .../main/java/org/gluu/util/OxConstants.java | 0 2 files changed, 81 insertions(+), 1 deletion(-) rename {oxService => oxUtil}/src/main/java/org/gluu/util/OxConstants.java (100%) diff --git a/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java b/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java index 23f01c1f..688319e1 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java @@ -15,6 +15,7 @@ import org.gluu.model.custom.script.model.CustomScript; import org.gluu.persist.PersistenceEntryManager; import org.gluu.search.filter.Filter; +import org.gluu.util.OxConstants; import org.slf4j.Logger; import com.google.common.base.Optional; @@ -102,7 +103,86 @@ public List findCustomScripts(List customScriptT return result; } - public String buildDn(String customScriptId) { + public CustomScript getScriptByInum(String inum) { + return persistenceEntryManager.find(CustomScript.class, buildDn(inum)); + } + + public List findCustomAuthScripts(String pattern, int sizeLimit) { + String[] targetArray = new String[] { pattern }; + Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); + Filter scriptTypeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, + CustomScriptType.PERSON_AUTHENTICATION); + Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); + Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, + Filter.createANDFilter(searchFilter, scriptTypeFilter), sizeLimit); + } + + public List findCustomAuthScripts(int sizeLimit) { + Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, + CustomScriptType.PERSON_AUTHENTICATION.getValue()); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, searchFilter, + sizeLimit); + } + + public List findOtherCustomScripts(String pattern, int sizeLimit) { + String[] targetArray = new String[] { pattern }; + Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); + Filter scriptTypeFilter = Filter.createNOTFilter( + Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, CustomScriptType.PERSON_AUTHENTICATION)); + Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); + Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, + Filter.createANDFilter(searchFilter, scriptTypeFilter), sizeLimit); + } + + public List findScriptByType(CustomScriptType type, int sizeLimit) { + Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, searchFilter, + sizeLimit); + } + + public List findScriptByType(CustomScriptType type) { + Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, searchFilter, null); + } + + public List findScriptByPatternAndType(String pattern, CustomScriptType type, int sizeLimit) { + String[] targetArray = new String[] { pattern }; + Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); + Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); + Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + Filter typeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, + Filter.createANDFilter(searchFilter, typeFilter), sizeLimit); + } + + public List findScriptByPatternAndType(String pattern, CustomScriptType type) { + String[] targetArray = new String[] { pattern }; + Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); + Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); + Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + Filter typeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, + Filter.createANDFilter(searchFilter, typeFilter), null); + } + + public List findOtherCustomScripts(int sizeLimit) { + Filter searchFilter = Filter.createNOTFilter( + Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, CustomScriptType.PERSON_AUTHENTICATION)); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, searchFilter, + sizeLimit); + } + + public String buildDn(String customScriptId) { final StringBuilder dn = new StringBuilder(); dn.append(String.format("inum=%s,", customScriptId)); dn.append(baseDn()); diff --git a/oxService/src/main/java/org/gluu/util/OxConstants.java b/oxUtil/src/main/java/org/gluu/util/OxConstants.java similarity index 100% rename from oxService/src/main/java/org/gluu/util/OxConstants.java rename to oxUtil/src/main/java/org/gluu/util/OxConstants.java From 3724a1663186c9332abd6eba03d7ca841b29dfa9 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 7 Sep 2020 20:26:53 +0300 Subject: [PATCH 236/362] Merge ScriptService into AbstractCustomScriptService --- .../java/org/gluu/service/ScriptService.java | 138 ------------------ 1 file changed, 138 deletions(-) delete mode 100644 oxService/src/main/java/org/gluu/service/ScriptService.java diff --git a/oxService/src/main/java/org/gluu/service/ScriptService.java b/oxService/src/main/java/org/gluu/service/ScriptService.java deleted file mode 100644 index 3bb60078..00000000 --- a/oxService/src/main/java/org/gluu/service/ScriptService.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.service; - -import java.util.List; - -import javax.enterprise.context.ApplicationScoped; -import javax.inject.Inject; -import javax.inject.Named; - -import org.gluu.model.custom.script.CustomScriptType; -import org.gluu.model.custom.script.model.CustomScript; -import org.gluu.persist.PersistenceEntryManager; -import org.gluu.search.filter.Filter; -import org.gluu.service.custom.script.AbstractCustomScriptService; -import org.gluu.util.OxConstants; -import org.gluu.util.StringHelper; -import org.python.jline.internal.Log; - -/** - * @author Mougang T.Gasmyr - * - */ -@ApplicationScoped -public class ScriptService { - - @Inject - private OrganizationService organizationService; - - @Inject - private PersistenceEntryManager persistenceEntryManager; - - @Inject - protected AbstractCustomScriptService customScriptService; - - public CustomScript getScriptByInum(String inum) { - CustomScript result = null; - try { - result = persistenceEntryManager.find(CustomScript.class, customScriptService.buildDn(inum)); - } catch (Exception ex) { - Log.error("Failed to find script by inum {}", inum, ex); - } - - return result; - } - - public List findCustomAuthScripts(String pattern, int sizeLimit) { - String[] targetArray = new String[] { pattern }; - Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); - Filter scriptTypeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, - CustomScriptType.PERSON_AUTHENTICATION); - Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); - Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); - - return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, - Filter.createANDFilter(searchFilter, scriptTypeFilter), sizeLimit); - } - - public List findCustomAuthScripts(int sizeLimit) { - Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, - CustomScriptType.PERSON_AUTHENTICATION.getValue()); - - return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, searchFilter, - sizeLimit); - } - - public List findOtherCustomScripts(String pattern, int sizeLimit) { - String[] targetArray = new String[] { pattern }; - Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); - Filter scriptTypeFilter = Filter.createNOTFilter( - Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, CustomScriptType.PERSON_AUTHENTICATION)); - Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); - Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); - - return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, - Filter.createANDFilter(searchFilter, scriptTypeFilter), sizeLimit); - } - - public List findScriptByType(CustomScriptType type, int sizeLimit) { - Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); - - return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, searchFilter, - sizeLimit); - } - - public List findScriptByType(CustomScriptType type) { - Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); - - return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, searchFilter, null); - } - - public List findScriptByPatternAndType(String pattern, CustomScriptType type, int sizeLimit) { - String[] targetArray = new String[] { pattern }; - Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); - Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); - Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); - Filter typeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); - - return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, - Filter.createANDFilter(searchFilter, typeFilter), sizeLimit); - } - - public List findScriptByPatternAndType(String pattern, CustomScriptType type) { - String[] targetArray = new String[] { pattern }; - Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); - Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); - Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); - Filter typeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); - - return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, - Filter.createANDFilter(searchFilter, typeFilter), null); - } - - public List findOtherCustomScripts(int sizeLimit) { - Filter searchFilter = Filter.createNOTFilter( - Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, CustomScriptType.PERSON_AUTHENTICATION)); - - return persistenceEntryManager.findEntries(getDnForCustomScript(null), CustomScript.class, searchFilter, - sizeLimit); - } - - public String getDnForCustomScript(String inum) { - String orgDn = organizationService.getDnForOrganization(null); - if (StringHelper.isEmpty(inum)) { - return String.format("ou=scripts,%s", orgDn); - } - return String.format("inum=%s,ou=scripts,%s", inum, orgDn); - } - - public String baseDn() { - return String.format("ou=scripts,%s", organizationService.getDnForOrganization(null)); - } - -} From 3fb93bbbe12baf795f6d36edf37b7467831c2bd1 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 7 Sep 2020 20:38:28 +0300 Subject: [PATCH 237/362] Merge ScriptService into AbstractCustomScriptService --- .../gluu/service/custom/script/AbstractCustomScriptService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java b/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java index 688319e1..7cbdd036 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java @@ -24,6 +24,7 @@ * Operations with custom scripts * * @author Yuriy Movchan Date: 12/03/2014 + * @author Mougang T.Gasmyr */ public abstract class AbstractCustomScriptService implements Serializable { From 9252432c467efdc0a9eaafd24390ae821b710b42 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 7 Sep 2020 21:22:43 +0300 Subject: [PATCH 238/362] Default custom ScriptService --- .../service/custom/CustomScriptService.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 oxService/src/main/java/org/gluu/service/custom/CustomScriptService.java diff --git a/oxService/src/main/java/org/gluu/service/custom/CustomScriptService.java b/oxService/src/main/java/org/gluu/service/custom/CustomScriptService.java new file mode 100644 index 00000000..405181c9 --- /dev/null +++ b/oxService/src/main/java/org/gluu/service/custom/CustomScriptService.java @@ -0,0 +1,26 @@ +package org.gluu.service.custom; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; + +import org.gluu.service.OrganizationService; +import org.gluu.service.custom.script.AbstractCustomScriptService; + +/** + * Operations with custom scripts + * + * @author Yuriy Movchan Date: 09/07/2020 + */ +@ApplicationScoped +public class CustomScriptService extends AbstractCustomScriptService { + + private static final long serialVersionUID = -7670016078535552193L; + + @Inject + private OrganizationService organizationService; + + public String baseDn() { + return String.format("ou=scripts,%s", organizationService.getDnForOrganization(null)); + } + +} From 10da3d0a06794b9e60a63dda65daea5e72a56acf Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 15 Sep 2020 19:41:57 +0300 Subject: [PATCH 239/362] Load scripts during startup instead of send async even to load them after startup oxCore #202 --- .../custom/script/CustomScriptManager.java | 24 ++++++++++++++----- .../script/StandaloneCustomScriptManager.java | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java index 4c281659..2e0b56dc 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java @@ -24,6 +24,7 @@ import javax.enterprise.context.BeforeDestroyed; import javax.enterprise.event.Event; import javax.enterprise.event.Observes; +import javax.enterprise.inject.Instance; import javax.inject.Inject; import javax.servlet.ServletContext; @@ -83,6 +84,9 @@ public class CustomScriptManager implements Serializable { @ReloadScript private Event event; + @Inject + private Instance externalScriptServiceInstance; + protected List supportedCustomScriptTypes; private Map customScriptConfigurations; @@ -100,7 +104,7 @@ public void initTimer(List supportedCustomScriptTypes) { final int delay = 30; final int interval = DEFAULT_INTERVAL; - reload(); + reload(true); timerEvent.fire(new TimerEvent(new TimerSchedule(delay, interval), new UpdateScriptEvent(), Scheduled.Literal.INSTANCE)); @@ -121,7 +125,7 @@ public void reloadTimerEvent(@Observes @Scheduled UpdateScriptEvent updateScript } try { - reload(); + reload(false); } catch (Throwable ex) { log.error("Exception happened while reloading custom scripts configuration", ex); } finally { @@ -144,16 +148,24 @@ public void destroy(@BeforeDestroyed(ApplicationScoped.class) ServletContext ini } } - private void reload() { + private void reload(boolean syncUpdate) { boolean modified = reloadImpl(); if (modified) { - updateScriptServices(); + updateScriptServices(syncUpdate); } } - protected void updateScriptServices() { - event.fire(CUSTOM_SCRIPT_MODIFIED_EVENT_TYPE); + protected void updateScriptServices(boolean syncUpdate) { + if (syncUpdate) { + for (ExternalScriptService externalScriptService : externalScriptServiceInstance) { + if (supportedCustomScriptTypes.contains(externalScriptService.getCustomScriptType())) { + externalScriptService.reload(CUSTOM_SCRIPT_MODIFIED_EVENT_TYPE); + } + } + } else { + event.fire(CUSTOM_SCRIPT_MODIFIED_EVENT_TYPE); + } } private boolean reloadImpl() { diff --git a/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptManager.java b/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptManager.java index 46563f40..399accee 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptManager.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/StandaloneCustomScriptManager.java @@ -60,7 +60,7 @@ public void registerExternalScriptService(ExternalScriptService externalScriptSe } @Override - public void updateScriptServices() { + public void updateScriptServices(boolean syncUpdate) { for (ExternalScriptService externalScriptService : externalScriptServices) { externalScriptService.reload(null); } From 9c10bbe53f4b32160ead2d9b05aedbcda3cc0491 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 16 Sep 2020 16:19:18 +0300 Subject: [PATCH 240/362] Add property to specify when exernal service is loaded --- .../custom/script/ExternalScriptService.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java b/core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java index 44d0dd1a..7d7dd39d 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/ExternalScriptService.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.Map; +import javax.annotation.PostConstruct; import javax.enterprise.event.Observes; import javax.inject.Inject; @@ -41,11 +42,18 @@ public abstract class ExternalScriptService implements Serializable { protected CustomScriptManager customScriptManager; protected CustomScriptType customScriptType; + + protected boolean loaded; protected Map customScriptConfigurationsNameMap; protected List customScriptConfigurations; protected CustomScriptConfiguration defaultExternalCustomScript; + @PostConstruct + public void init() { + this.loaded = false; + } + public ExternalScriptService(CustomScriptType customScriptType) { this.customScriptType = customScriptType; } @@ -76,6 +84,8 @@ public void reload(@Observes @ReloadScript String event) { // Allow to execute additional logic reloadExternal(); + + loaded = true; } protected void addExternalConfigurations(List newCustomScriptConfigurations) { @@ -165,4 +175,8 @@ public CustomScriptType getCustomScriptType() { return customScriptType; } + public boolean isLoaded() { + return loaded; + } + } From 32a49846a7f20558587e03163989566bc642419f Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 18 Sep 2020 11:12:49 +0300 Subject: [PATCH 241/362] Override default timeout in bucket infor request --- .../operation/impl/CouchbaseConnectionProvider.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java index 9c9ea96a..9460c821 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java @@ -10,6 +10,8 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Properties; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import org.gluu.persist.couchbase.model.BucketMapping; import org.gluu.persist.couchbase.model.ResultCode; @@ -243,7 +245,7 @@ public boolean isConnected() { isConnected = false; break; } - } catch (CouchbaseException ex) { + } catch (CouchbaseException | TimeoutException ex) { LOG.error("Failed to check bucket", ex); } } @@ -251,11 +253,11 @@ public boolean isConnected() { return isConnected; } - private boolean isConnected(BucketMapping bucketMapping) { + private boolean isConnected(BucketMapping bucketMapping) throws TimeoutException { Bucket bucket = bucketMapping.getBucket(); BucketManager bucketManager = bucket.bucketManager(); - BucketInfo bucketInfo = bucketManager.info(); + BucketInfo bucketInfo = bucketManager.info(30, TimeUnit.SECONDS); boolean result = true; if (com.couchbase.client.java.bucket.BucketType.COUCHBASE == bucketInfo.type()) { From d1113e74e267dcf4e8ae85aed348a5b6545ecf56 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 18 Sep 2020 11:39:18 +0300 Subject: [PATCH 242/362] Fail isConnected method check if at least one bucket is not online --- .../operation/impl/CouchbaseConnectionProvider.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java index 9460c821..8d719255 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java @@ -233,8 +233,8 @@ public boolean isConnected() { } boolean isConnected = true; - for (BucketMapping bucketMapping : bucketToBaseNameMapping.values()) { - try { + try { + for (BucketMapping bucketMapping : bucketToBaseNameMapping.values()) { Bucket bucket = bucketMapping.getBucket(); if (bucket.isClosed() || !isConnected(bucketMapping)) { if (bucket.isClosed()) { @@ -245,15 +245,16 @@ public boolean isConnected() { isConnected = false; break; } - } catch (CouchbaseException | TimeoutException ex) { - LOG.error("Failed to check bucket", ex); - } + } + } catch (RuntimeException ex) { + LOG.error("Failed to check bucket", ex); + isConnected = false; } return isConnected; } - private boolean isConnected(BucketMapping bucketMapping) throws TimeoutException { + private boolean isConnected(BucketMapping bucketMapping) { Bucket bucket = bucketMapping.getBucket(); BucketManager bucketManager = bucket.bucketManager(); From 5b336058a86c129e3edf9fc014bacdb8f5304b41 Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Mon, 21 Sep 2020 13:39:24 +0300 Subject: [PATCH 243/362] Added CouchbaseConnectionConfiguration (config api) https://github.com/GluuFederation/oxauth-config/issues/136 --- .../CouchbaseConnectionConfiguration.java | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/CouchbaseConnectionConfiguration.java diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/CouchbaseConnectionConfiguration.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/CouchbaseConnectionConfiguration.java new file mode 100644 index 00000000..e3bd7c59 --- /dev/null +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/CouchbaseConnectionConfiguration.java @@ -0,0 +1,157 @@ +package org.gluu.persist.couchbase.model; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +/** + * @author Yuriy Zabrovarnyy + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class CouchbaseConnectionConfiguration { + + private String userName; + private String userPassword; + private List servers; + private String defaultBucket; + private List buckets; + private String passwordEncryptionMethod; + private Boolean operationTracingEnabled; + private Boolean mutationTokensEnabled; + private int connectTimeout; + private int computationPoolSize; + private Boolean useSSL; + private String sslTrustStoreFile; + private String sslTrustStorePin; + private String sslTrustStoreFormat; + private List binaryAttributes; + private List certificateAttributes; + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getUserPassword() { + return userPassword; + } + + public void setUserPassword(String userPassword) { + this.userPassword = userPassword; + } + + public List getServers() { + return servers; + } + + public void setServers(List servers) { + this.servers = servers; + } + + public String getDefaultBucket() { + return defaultBucket; + } + + public void setDefaultBucket(String defaultBucket) { + this.defaultBucket = defaultBucket; + } + + public List getBuckets() { + return buckets; + } + + public void setBuckets(List buckets) { + this.buckets = buckets; + } + + public String getPasswordEncryptionMethod() { + return passwordEncryptionMethod; + } + + public void setPasswordEncryptionMethod(String passwordEncryptionMethod) { + this.passwordEncryptionMethod = passwordEncryptionMethod; + } + + public Boolean getOperationTracingEnabled() { + return operationTracingEnabled; + } + + public void setOperationTracingEnabled(Boolean operationTracingEnabled) { + this.operationTracingEnabled = operationTracingEnabled; + } + + public Boolean getMutationTokensEnabled() { + return mutationTokensEnabled; + } + + public void setMutationTokensEnabled(Boolean mutationTokensEnabled) { + this.mutationTokensEnabled = mutationTokensEnabled; + } + + public int getConnectTimeout() { + return connectTimeout; + } + + public void setConnectTimeout(int connectTimeout) { + this.connectTimeout = connectTimeout; + } + + public int getComputationPoolSize() { + return computationPoolSize; + } + + public void setComputationPoolSize(int computationPoolSize) { + this.computationPoolSize = computationPoolSize; + } + + public Boolean getUseSSL() { + return useSSL; + } + + public void setUseSSL(Boolean useSSL) { + this.useSSL = useSSL; + } + + public String getSslTrustStoreFile() { + return sslTrustStoreFile; + } + + public void setSslTrustStoreFile(String sslTrustStoreFile) { + this.sslTrustStoreFile = sslTrustStoreFile; + } + + public String getSslTrustStorePin() { + return sslTrustStorePin; + } + + public void setSslTrustStorePin(String sslTrustStorePin) { + this.sslTrustStorePin = sslTrustStorePin; + } + + public String getSslTrustStoreFormat() { + return sslTrustStoreFormat; + } + + public void setSslTrustStoreFormat(String sslTrustStoreFormat) { + this.sslTrustStoreFormat = sslTrustStoreFormat; + } + + public List getBinaryAttributes() { + return binaryAttributes; + } + + public void setBinaryAttributes(List binaryAttributes) { + this.binaryAttributes = binaryAttributes; + } + + public List getCertificateAttributes() { + return certificateAttributes; + } + + public void setCertificateAttributes(List certificateAttributes) { + this.certificateAttributes = certificateAttributes; + } +} From 9f16e957a5cfc7b4ceddce1b4e9d05fd10639ae2 Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Mon, 21 Sep 2020 14:12:58 +0300 Subject: [PATCH 244/362] Added config id https://github.com/GluuFederation/oxauth-config/issues/136 --- .../model/CouchbaseConnectionConfiguration.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/CouchbaseConnectionConfiguration.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/CouchbaseConnectionConfiguration.java index e3bd7c59..501011aa 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/CouchbaseConnectionConfiguration.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/CouchbaseConnectionConfiguration.java @@ -10,6 +10,7 @@ @JsonIgnoreProperties(ignoreUnknown = true) public class CouchbaseConnectionConfiguration { + private String configId; private String userName; private String userPassword; private List servers; @@ -27,6 +28,14 @@ public class CouchbaseConnectionConfiguration { private List binaryAttributes; private List certificateAttributes; + public String getConfigId() { + return configId; + } + + public void setConfigId(String configId) { + this.configId = configId; + } + public String getUserName() { return userName; } From 72bce70b2f2fd52385c0991fbd60a4cd02434269 Mon Sep 17 00:00:00 2001 From: Gasmyr Date: Tue, 29 Sep 2020 18:25:50 +0100 Subject: [PATCH 245/362] Add additional methods --- .../script/AbstractCustomScriptService.java | 192 ++++++++++-------- 1 file changed, 104 insertions(+), 88 deletions(-) diff --git a/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java b/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java index 7cbdd036..47a8d7c5 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/AbstractCustomScriptService.java @@ -5,12 +5,7 @@ */ package org.gluu.service.custom.script; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import javax.inject.Inject; - +import com.google.common.base.Optional; import org.gluu.model.custom.script.CustomScriptType; import org.gluu.model.custom.script.model.CustomScript; import org.gluu.persist.PersistenceEntryManager; @@ -18,7 +13,10 @@ import org.gluu.util.OxConstants; import org.slf4j.Logger; -import com.google.common.base.Optional; +import javax.inject.Inject; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; /** * Operations with custom scripts @@ -69,7 +67,7 @@ public Optional getCustomScriptByINum(String baseDn, String inum, if (result.isEmpty()) { - return Optional.absent(); + return Optional.absent(); } return Optional.of(result.get(0)); @@ -104,86 +102,104 @@ public List findCustomScripts(List customScriptT return result; } - public CustomScript getScriptByInum(String inum) { - return persistenceEntryManager.find(CustomScript.class, buildDn(inum)); - } - - public List findCustomAuthScripts(String pattern, int sizeLimit) { - String[] targetArray = new String[] { pattern }; - Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); - Filter scriptTypeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, - CustomScriptType.PERSON_AUTHENTICATION); - Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); - Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); - - return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, - Filter.createANDFilter(searchFilter, scriptTypeFilter), sizeLimit); - } - - public List findCustomAuthScripts(int sizeLimit) { - Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, - CustomScriptType.PERSON_AUTHENTICATION.getValue()); - - return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, searchFilter, - sizeLimit); - } - - public List findOtherCustomScripts(String pattern, int sizeLimit) { - String[] targetArray = new String[] { pattern }; - Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); - Filter scriptTypeFilter = Filter.createNOTFilter( - Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, CustomScriptType.PERSON_AUTHENTICATION)); - Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); - Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); - - return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, - Filter.createANDFilter(searchFilter, scriptTypeFilter), sizeLimit); - } - - public List findScriptByType(CustomScriptType type, int sizeLimit) { - Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); - - return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, searchFilter, - sizeLimit); - } - - public List findScriptByType(CustomScriptType type) { - Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); - - return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, searchFilter, null); - } - - public List findScriptByPatternAndType(String pattern, CustomScriptType type, int sizeLimit) { - String[] targetArray = new String[] { pattern }; - Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); - Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); - Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); - Filter typeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); - - return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, - Filter.createANDFilter(searchFilter, typeFilter), sizeLimit); - } - - public List findScriptByPatternAndType(String pattern, CustomScriptType type) { - String[] targetArray = new String[] { pattern }; - Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); - Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); - Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); - Filter typeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); - - return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, - Filter.createANDFilter(searchFilter, typeFilter), null); - } - - public List findOtherCustomScripts(int sizeLimit) { - Filter searchFilter = Filter.createNOTFilter( - Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, CustomScriptType.PERSON_AUTHENTICATION)); - - return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, searchFilter, - sizeLimit); - } - - public String buildDn(String customScriptId) { + public CustomScript getScriptByInum(String inum) { + return persistenceEntryManager.find(CustomScript.class, buildDn(inum)); + } + + public List findCustomAuthScripts(String pattern, int sizeLimit) { + String[] targetArray = new String[]{pattern}; + Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); + Filter scriptTypeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, + CustomScriptType.PERSON_AUTHENTICATION); + Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); + Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, + Filter.createANDFilter(searchFilter, scriptTypeFilter), sizeLimit); + } + + public List findCustomAuthScripts(int sizeLimit) { + Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, + CustomScriptType.PERSON_AUTHENTICATION.getValue()); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, searchFilter, + sizeLimit); + } + + + public CustomScript getScriptByDisplayName(String name) { + Filter searchFilter = Filter.createEqualityFilter("displayName", + name); + List result=persistenceEntryManager.findEntries(baseDn(), CustomScript.class, searchFilter, + 1); + if(result!=null && !result.isEmpty()){ + return result.get(0); + } + return null; + } + public int getScriptLevel(CustomScript customScript) { + if(customScript!=null){ + return customScript.getLevel(); + } + return -2; + } + + public List findOtherCustomScripts(String pattern, int sizeLimit) { + String[] targetArray = new String[]{pattern}; + Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); + Filter scriptTypeFilter = Filter.createNOTFilter( + Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, CustomScriptType.PERSON_AUTHENTICATION)); + Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); + Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, + Filter.createANDFilter(searchFilter, scriptTypeFilter), sizeLimit); + } + + public List findScriptByType(CustomScriptType type, int sizeLimit) { + Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, searchFilter, + sizeLimit); + } + + public List findScriptByType(CustomScriptType type) { + Filter searchFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, searchFilter, null); + } + + public List findScriptByPatternAndType(String pattern, CustomScriptType type, int sizeLimit) { + String[] targetArray = new String[]{pattern}; + Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); + Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); + Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + Filter typeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, + Filter.createANDFilter(searchFilter, typeFilter), sizeLimit); + } + + public List findScriptByPatternAndType(String pattern, CustomScriptType type) { + String[] targetArray = new String[]{pattern}; + Filter descriptionFilter = Filter.createSubstringFilter(OxConstants.DESCRIPTION, null, targetArray, null); + Filter displayNameFilter = Filter.createSubstringFilter(OxConstants.DISPLAY_NAME, null, targetArray, null); + Filter searchFilter = Filter.createORFilter(descriptionFilter, displayNameFilter); + Filter typeFilter = Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, type); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, + Filter.createANDFilter(searchFilter, typeFilter), null); + } + + public List findOtherCustomScripts(int sizeLimit) { + Filter searchFilter = Filter.createNOTFilter( + Filter.createEqualityFilter(OxConstants.SCRIPT_TYPE, CustomScriptType.PERSON_AUTHENTICATION)); + + return persistenceEntryManager.findEntries(baseDn(), CustomScript.class, searchFilter, + sizeLimit); + } + + public String buildDn(String customScriptId) { final StringBuilder dn = new StringBuilder(); dn.append(String.format("inum=%s,", customScriptId)); dn.append(baseDn()); From b7a98bf32985eac39056ce832f5d8ae4f919dee9 Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Wed, 30 Sep 2020 14:19:39 +0300 Subject: [PATCH 246/362] CB : removed redundant touch during entry update. https://github.com/GluuFederation/oxCore/issues/199 --- .../couchbase/operation/impl/CouchbaseOperationServiceImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java index 994f32f0..fc5ad563 100644 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java +++ b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java @@ -219,7 +219,6 @@ private boolean updateEntryImpl(BucketMapping bucketMapping, String key, List Date: Tue, 15 Dec 2020 17:33:40 +0300 Subject: [PATCH 247/362] Don't fail in javadocs error --- pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pom.xml b/pom.xml index 70906e7f..a1ff6685 100644 --- a/pom.xml +++ b/pom.xml @@ -169,6 +169,13 @@ false + + org.apache.maven.plugins + maven-javadoc-plugin + + false + + From 3e3c9b83c18704a3cc5ff1836eac7b545ee7a665 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Tue, 5 Oct 2021 12:02:44 +0300 Subject: [PATCH 248/362] Merge from 4.3.0 (#219) * Version 4.2.0.Final * Version 4.2.1.Final * Remove uncrypter redis password * Simple test to check session ttl. (cherry picked from commit 40276663a999ee94bf8f7757f46d313c4cadaa61) * Simple test to check session ttl. (cherry picked from commit 59bedca457e1e50c8002de79acdd3bd49e3757d1) * (4.2.1) During CB entry update make sure TTL is updated too. https://github.com/GluuFederation/oxCore/issues/199 (cherry picked from commit 956a06f7a3a7f16b3125d57e8581845ecfc54013) * Update to conform Couchbase 6.5 * Don't load entry from DB afte merge #200 * Sample for session replacement * Store issued tokens count metrics #1436 * disabled manual tests * Add uniq identifier for each metric entry to allow find whcih node addded this record oxAuth #1438 * Change javax.faces with jakarta.faces * Injection: Cross-Site Scripting oxTrust #2012 * Move some log from DEBUG to TRACE #201 * Update methods to store oxExternalUid as multivalued by default oxAuth #1442 * Update sample to add user with oxExternalUid and search by this attribute * Added new methods related to software_statement validation. https://github.com/GluuFederation/oxAuth/issues/1444 * Renamed new methods related to software_statement validation. https://github.com/GluuFederation/oxAuth/issues/1444 * Corrected DummyClientRegistrationType. https://github.com/GluuFederation/oxAuth/issues/1444 * Fix variable name spelling * Use CustomObjectAttribute instead of CustomAttribute in user services to use JSON data types #1445 * Rename method to get value as object * JAXB-API implementation error oxTrust #2005 * Add new utility methods to xml service * Add ScriptService in oxCore * Add scope to ScriptService * Add methods * Fix dependecy issue * Merge ScriptService into AbstractCustomScriptService * Merge ScriptService into AbstractCustomScriptService * Default custom ScriptService * Version 4.2.1.Final * Load scripts during startup instead of send async even to load them after startup oxCore #202 * Add property to specify when exernal service is loaded * Override default timeout in bucket infor request * Fail isConnected method check if at least one bucket is not online * Version 4.2.2-SNAPSHOT * Add additional methods * Added CouchbaseConnectionConfiguration (config api) https://github.com/GluuFederation/oxauth-config/issues/136 * Added config id https://github.com/GluuFederation/oxauth-config/issues/136 * During CB entry update make sure TTL is updated too. #199 * Turn off metric reported by default if there is no configuration * Simple test to check session ttl. * disabled manual test * Simple test to check session ttl. * Revert " During CB entry update make sure TTL is updated too. #199" This reverts commit d2f8041c * Moving noisy log lines to trace * oxAuth reloads custom scripts (file method) * (4.2.2) Avoid race condition during saving grant object in cache https://github.com/GluuFederation/oxAuth/issues/1478 * (4.2.2) oxcore : added revoke token custom script https://github.com/GluuFederation/oxAuth/issues/1502 * Destroy CouchbaseEnvironment object on container restart #207 * Destroy CouchbaseEnvironment object on container restart #207 * Fix typo in method name * Metric Service clean all entries when DB is Couchbase #206 * Metric Service clean all entries when DB is Couchbase #206 * Fix method to update log level #204 * Don't fail in javadocs error * Add boolean switcher for id token in logout uri #2046 * Persistence extension script still running after disabled oxAuth #1514 * Version 4.2.2.Final * Version 4.2.3-SNAPSHOT * (4.2.2) oxcore : removed printing password from JcaDocumentStoreConfiguration and WebDavDocumentStoreConfiguration * Use UTF-8 encodeing during convertion base64 to XML * Fix XML doc reading and signature validation * Commented updateAppendersAndLogLevel() method which cause memory leak https://github.com/GluuFederation/oxCore/issues/204 * Temporary enabled back old solution. https://github.com/GluuFederation/oxCore/issues/204 * Version 4.2.3.Final * Version 4.3.0.Final * New interceptions script to modify id_token oxAuth #1523 * Add license * Convert decrypted data to UTF-8 string * Add keepAliveInterval CB SDK support * (4.2.3) ORM : allow to ignore TTL update on merging. https://github.com/GluuFederation/oxAuth/issues/1528 * Revert "(4.2.3) ORM : allow to ignore TTL update on merging." This reverts commit 478a71bd * Allow to skip TTL set on Couchbase document update Jans ORM #6 * Don't update ttl on docuemnt update by default * (4.2.3) Avoid NPE in BaseEntryManager.getExpirationValue() https://github.com/GluuFederation/oxAuth/issues/1528 * Revert "Don't update ttl on docuemnt update by default" This reverts commit 8707a195 * fix: issue #216 * feat: move ORM to oxOrm * feat: move ORM to oxOrm * feat: move ORM to oxOrm * feat: move ORM to oxOrm * feat: move ORM to oxOrm * feat: move ORM to oxOrm * feat: move ORM to oxOrm * feat: move ORM to oxOrm * feat: merge ORM from Jans * fix: skip metrics clean up because we do this in oxAuth * fix: merge cache changes from Jans * fix: add application type * Remove unused attributes * feat: add method to determine if DB is Spanner * fix: #217 * feat: allow to use unecrypted password in JCA config * feat: decryptedPassword should be ignored * fix: fix annotation type in JCA config * fix: add removed from JDK 11 group interface * feat: upgrade libs * feat: upgrade libs * feat: update libs * feat: update libs * feat: Add methods, see https://github.com/GluuFederation/scim/issues/18 * feat: augment scim protection modes https://github.com/GluuFederation/scim/issues/20 * feat: simplify interface https://github.com/GluuFederation/scim/issues/18 * feat: add field for https://github.com/GluuFederation/scim/issues/22 * feat: add class to check if proxy specified * feat: add method to lookup typed entry * feat: check if OC is null * feat: add no-protection scim mode https://github.com/GluuFederation/scim/issues/26 * Version 4.3.0.Final * Merge with 4.3.0 Co-authored-by: Gasmyr Co-authored-by: YuriyZ Co-authored-by: Jose --- core-cache/pom.xml | 34 +- .../cache/NativePersistenceCacheProvider.java | 60 +- core-cdi/pom.xml | 2 +- core-document-store/pom.xml | 10 +- ...tandaloneDocumentStoreProviderFactory.java | 2 +- .../conf/JcaDocumentStoreConfiguration.java | 15 +- .../WebDavDocumentStoreConfiguration.java | 12 +- .../provider/JcaDocumentStoreProvider.java | 5 +- .../provider/WebDavDocumentStoreProvider.java | 218 +- .../manual/WebDavDocumentStoreManualTest.java | 97 + core-java-ext/pom.xml | 2 +- core-script/pom.xml | 14 +- .../model/custom/script/CustomScriptType.java | 7 +- .../custom/script/model/CustomScript.java | 2 +- .../custom/script/model/ScriptTemplate.java | 6 +- .../type/revoke/DummyRevokeTokenType.java | 36 + .../script/type/revoke/RevokeTokenType.java | 11 + .../script/type/scim/DummyScimType.java | 12 + .../custom/script/type/scim/ScimType.java | 6 + .../type/token/DummyUpdateTokenType.java | 44 + .../script/type/token/UpdateTokenType.java | 17 + .../custom/script/CustomScriptManager.java | 5 +- core-standalone/pom.xml | 9 +- .../conf/service/ConfigurationFactory.java | 2 +- core-timer-weld/pom.xml | 7 +- .../java/org/gluu/service/timer/TimerJob.java | 4 +- demo-cdi/pom.xml | 2 +- exception-extension-cdi/pom.xml | 2 +- oxJsfUtil/pom.xml | 2 +- oxModel/pom.xml | 14 +- .../org/gluu/model/attribute/Attribute.java | 2 +- .../gluu/model/metric/ldap/MetricEntry.java | 17 +- oxRadius/pom.xml | 6 +- oxSaml/pom.xml | 11 +- .../src/main/java/org/gluu/saml/Response.java | 30 +- oxService/pom.xml | 36 +- .../gluu/config/oxtrust/AppConfiguration.java | 18 +- .../org/gluu/config/oxtrust/ScimMode.java | 3 + .../gluu/config/oxtrust/ScimProperties.java | 22 +- .../java/org/gluu/model/DisplayNameEntry.java | 2 +- .../java/org/gluu/model/GluuAttribute.java | 26 +- .../java/org/gluu/model/security/Group.java | 62 + .../org/gluu/model/security/Identity.java | 1 - .../org/gluu/model/security/SimpleGroup.java | 1 - .../gluu/service/DataSourceTypeService.java | 14 +- .../java/org/gluu/service/LookupService.java | 26 + .../java/org/gluu/service/MailService.java | 3 +- .../org/gluu/service/OrganizationService.java | 5 + .../java/org/gluu/service/SchemaService.java | 2 +- .../ExternalPersistenceExtensionService.java | 4 +- .../gluu/service/logger/LoggerService.java | 551 +++-- .../service/metric/LdapEntryReporter.java | 3 + .../gluu/service/metric/MetricService.java | 66 +- .../CouchbaseNativeBenchmarkCacheTest.java | 4 +- .../cache/CouchbaseNativeCacheTest.java | 4 +- oxUtil/pom.xml | 4 +- .../src/main/java/org/gluu/net/ProxyUtil.java | 17 + .../org/gluu/util/init/Initializable.java | 3 + .../gluu/util/security/StringEncrypter.java | 10 +- persistence-annotation/pom.xml | 15 - .../persist/annotation/AttributeEnum.java | 20 - .../persist/annotation/AttributeName.java | 51 - .../persist/annotation/AttributesList.java | 49 - .../persist/annotation/CustomObjectClass.java | 22 - .../java/org/gluu/persist/annotation/DN.java | 23 - .../gluu/persist/annotation/DataEntry.java | 33 - .../gluu/persist/annotation/Expiration.java | 23 - .../gluu/persist/annotation/JsonObject.java | 22 - .../gluu/persist/annotation/ObjectClass.java | 27 - .../org/gluu/persist/annotation/Password.java | 22 - .../gluu/persist/annotation/SchemaEntry.java | 22 - persistence-cdi/pom.xml | 58 - .../service/PersistanceFactoryService.java | 233 -- .../src/main/resources/META-INF/beans.xml | 7 - .../org/gluu/persist/service/test/.gitignore | 1 - .../docs/LDAP to Couchbase data mapping.png | Bin 320788 -> 0 bytes .../docs/Persistent layer design.png | Bin 59183 -> 0 bytes .../src/LDAP to Couchbase data mapping.dia | Bin 4642 -> 0 bytes persistence-core/docs/src/ldap_tree.png | Bin 71733 -> 0 bytes persistence-core/pom.xml | 64 - .../gluu/persist/PersistenceEntryManager.java | 184 -- .../PersistenceEntryManagerFactory.java | 29 - .../gluu/persist/event/DeleteNotifier.java | 15 - .../exception/AuthenticationException.java | 30 - .../exception/BasePersistenceException.java | 28 - .../exception/EntryDeleteException.java | 30 - .../exception/EntryPersistenceException.java | 30 - .../exception/InvalidArgumentException.java | 28 - .../exception/KeyConversionException.java | 22 - .../persist/exception/MappingException.java | 28 - .../exception/PropertyAccessException.java | 47 - .../exception/PropertyNotFoundException.java | 21 - .../UnsupportedOperationException.java | 30 - .../extension/PersistenceExtension.java | 13 - .../operation/ConfigurationException.java | 34 - .../operation/ConnectionException.java | 34 - .../exception/operation/DeleteException.java | 38 - .../operation/DuplicateEntryException.java | 36 - .../operation/EntryNotFoundException.java | 47 - .../operation/PersistenceException.java | 101 - .../exception/operation/SearchException.java | 38 - .../operation/SearchScopeException.java | 22 - .../gluu/persist/impl/BaseEntryManager.java | 2074 ----------------- .../persist/key/impl/GenericKeyConverter.java | 62 - .../gluu/persist/key/impl/KeyShortcuter.java | 126 - .../persist/key/impl/KeyShortcuterConf.java | 52 - .../persist/key/impl/model/ParsedKey.java | 37 - .../org/gluu/persist/model/AttributeData.java | 118 - .../model/AttributeDataModification.java | 98 - .../gluu/persist/model/BatchOperation.java | 22 - .../persist/model/DefaultBatchOperation.java | 18 - .../org/gluu/persist/model/PagedResult.java | 59 - .../model/PersistenceConfiguration.java | 44 - .../persist/model/ProcessBatchOperation.java | 18 - .../org/gluu/persist/model/SearchScope.java | 36 - .../org/gluu/persist/model/SortOrder.java | 49 - .../PersistenceOperationService.java | 22 - .../operation/auth/PasswordDetails.java | 47 - .../auth/PasswordEncryptionHelper.java | 482 ---- .../auth/PasswordEncryptionMethod.java | 188 -- .../property/BasicPropertyAccessor.java | 269 --- .../BasicPropertyAnnotationResolver.java | 96 - .../property/DirectPropertyAccessor.java | 150 -- .../gluu/persist/reflect/property/Getter.java | 42 - .../reflect/property/PropertyAccessor.java | 25 - .../reflect/property/PropertyAnnotation.java | 92 - .../property/PropertyAnnotationResolver.java | 38 - .../gluu/persist/reflect/property/Setter.java | 38 - .../persist/reflect/util/ReflectHelper.java | 574 ----- .../persist/service/BaseFactoryService.java | 22 - .../org/gluu/persist/watch/DurationUtil.java | 33 - .../main/resources/key-shortcuter-rules.json | 54 - .../persist/key/impl/KeyShortcuterTest.java | 87 - .../key/impl/dev/KeyShortcuterManualTest.java | 42 - persistence-couchbase-sample/pom.xml | 71 - ...CouchbaseCustomMultiValuedTypesSample.java | 77 - ...CouchbaseCustomObjectAttributesSample.java | 78 - ...CouchbaseCustomStringAttributesSample.java | 66 - .../org/gluu/couchbase/CouchbaseSample.java | 118 - .../couchbase/CouchbaseSampleBatchJob.java | 150 -- .../gluu/couchbase/CouchbaseSampleDelete.java | 39 - .../CouchbaseSampleEntryManager.java | 46 - .../CouchbaseSampleSimpleSessionSample.java | 92 - .../CouchbaseSampleUserSearchSample.java | 112 - .../gluu/couchbase/model/SimpleAttribute.java | 92 - .../gluu/couchbase/model/SimpleClient.java | 92 - .../model/SimpleCustomStringUser.java | 161 -- .../org/gluu/couchbase/model/SimpleGrant.java | 92 - .../gluu/couchbase/model/SimpleSession.java | 92 - .../couchbase/model/SimpleSessionState.java | 183 -- .../couchbase/model/SimpleTokenCouchbase.java | 81 - .../org/gluu/couchbase/model/SimpleUser.java | 161 -- .../org/gluu/couchbase/model/UserRole.java | 90 - .../test/ManualCouchbaseEntryManagerTest.java | 111 - .../org/gluu/couchbase/test/SessionId.java | 260 --- .../gluu/couchbase/test/SessionIdState.java | 46 - .../couchbase/test/c1.gluu.org.properties | 6 - persistence-couchbase/LICENSE | 25 - persistence-couchbase/pom.xml | 75 - .../impl/CouchbaseBatchOperationWraper.java | 63 - .../couchbase/impl/CouchbaseEntryManager.java | 1019 -------- .../impl/CouchbaseEntryManagerFactory.java | 160 -- .../impl/CouchbaseFilterConverter.java | 339 --- .../couchbase/model/BucketMapping.java | 32 - .../couchbase/model/ConvertedExpression.java | 45 - .../CouchbaseConnectionConfiguration.java | 166 -- .../persist/couchbase/model/ResultCode.java | 38 - .../couchbase/model/SearchReturnDataType.java | 51 - .../operation/CouchbaseOperationService.java | 71 - .../impl/CouchbaseConnectionProvider.java | 364 --- .../impl/CouchbaseOperationServiceImpl.java | 729 ------ .../watch/OperationDurationUtil.java | 24 - .../src/main/resources/META-INF/beans.xml | 7 - .../src/test/java/org/gluu/test/.gitignore | 1 - .../test/java/org/gluu/test/dev/.gitignore | 1 - persistence-filter/pom.xml | 21 - .../java/org/gluu/search/filter/Filter.java | 286 --- .../org/gluu/search/filter/FilterType.java | 23 - persistence-hybrid/pom.xml | 56 - .../hybrid/impl/HybridEntryManager.java | 441 ---- .../impl/HybridEntryManagerFactory.java | 141 -- .../HybridPersistenceOperationService.java | 43 - .../src/main/resources/META-INF/beans.xml | 7 - persistence-ldap-sample/pom.xml | 30 - .../main/java/org/gluu/ldap/LdapSample.java | 82 - .../org/gluu/ldap/LdapSampleBatchJob.java | 152 -- .../java/org/gluu/ldap/LdapSampleDelete.java | 46 - .../org/gluu/ldap/LdapSampleEntryManager.java | 39 - .../ldap/LdapSampleSimpleSessionSample.java | 93 - .../MailUniquenessConfigurationSample.java | 56 - .../model/MailUniquenessConfiguration.java | 48 - .../org/gluu/ldap/model/SimpleAttribute.java | 92 - .../org/gluu/ldap/model/SimpleClient.java | 92 - .../java/org/gluu/ldap/model/SimpleGrant.java | 92 - .../org/gluu/ldap/model/SimpleSession.java | 92 - .../gluu/ldap/model/SimpleSessionState.java | 183 -- .../org/gluu/ldap/model/SimpleTokenLdap.java | 79 - .../java/org/gluu/ldap/model/SimpleUser.java | 104 - persistence-ldap/pom.xml | 65 - .../InvalidSimplePageControlException.java | 38 - .../ldap/impl/LdapBatchOperationWraper.java | 51 - .../persist/ldap/impl/LdapEntryManager.java | 1008 -------- .../ldap/impl/LdapEntryManagerFactory.java | 71 - .../ldap/impl/LdapFilterConverter.java | 147 -- .../ldap/impl/LdapSearchScopeConverter.java | 27 - .../persist/ldap/impl/LdifDataUtility.java | 346 --- .../ldap/operation/LdapOperationService.java | 132 -- .../impl/LdapAuthConnectionProvider.java | 37 - .../impl/LdapConnectionProvider.java | 551 ----- .../impl/LdapOperationServiceImpl.java | 1252 ---------- .../watch/OperationDurationUtil.java | 24 - .../src/main/resources/META-INF/beans.xml | 7 - persistence-model/pom.xml | 25 - .../gluu/persist/model/base/BaseEntry.java | 57 - .../persist/model/base/CustomAttribute.java | 136 -- .../gluu/persist/model/base/CustomEntry.java | 63 - .../model/base/CustomObjectAttribute.java | 159 -- .../gluu/persist/model/base/Deletable.java | 8 - .../persist/model/base/DeletableEntity.java | 53 - .../gluu/persist/model/base/DummyEntry.java | 23 - .../org/gluu/persist/model/base/Entry.java | 85 - .../gluu/persist/model/base/GluuBoolean.java | 69 - .../persist/model/base/GluuDummyEntry.java | 23 - .../gluu/persist/model/base/InumEntry.java | 45 - .../gluu/persist/model/base/SimpleBranch.java | 54 - .../gluu/persist/model/base/SimpleUser.java | 156 -- persistence-standalone/pom.xml | 51 - .../StandalonePersistanceFactoryService.java | 87 - .../org/gluu/persist/service/test/.gitignore | 1 - pom.xml | 15 +- security-extension-cdi/pom.xml | 7 +- .../security/SecurityEvaluationException.java | 3 - server/pom.xml | 2 +- 233 files changed, 1158 insertions(+), 19847 deletions(-) create mode 100644 core-document-store/src/test/java/org/gluu/service/document/store/manual/WebDavDocumentStoreManualTest.java create mode 100644 core-script/src/main/java/org/gluu/model/custom/script/type/revoke/DummyRevokeTokenType.java create mode 100644 core-script/src/main/java/org/gluu/model/custom/script/type/revoke/RevokeTokenType.java create mode 100644 core-script/src/main/java/org/gluu/model/custom/script/type/token/DummyUpdateTokenType.java create mode 100644 core-script/src/main/java/org/gluu/model/custom/script/type/token/UpdateTokenType.java create mode 100644 oxService/src/main/java/org/gluu/config/oxtrust/ScimMode.java create mode 100644 oxService/src/main/java/org/gluu/model/security/Group.java create mode 100644 oxUtil/src/main/java/org/gluu/net/ProxyUtil.java delete mode 100644 persistence-annotation/pom.xml delete mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributeEnum.java delete mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributeName.java delete mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributesList.java delete mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/CustomObjectClass.java delete mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/DN.java delete mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/DataEntry.java delete mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/Expiration.java delete mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/JsonObject.java delete mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/ObjectClass.java delete mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/Password.java delete mode 100644 persistence-annotation/src/main/java/org/gluu/persist/annotation/SchemaEntry.java delete mode 100644 persistence-cdi/pom.xml delete mode 100644 persistence-cdi/src/main/java/org/gluu/persist/service/PersistanceFactoryService.java delete mode 100644 persistence-cdi/src/main/resources/META-INF/beans.xml delete mode 100644 persistence-cdi/src/test/java/org/gluu/persist/service/test/.gitignore delete mode 100644 persistence-core/docs/LDAP to Couchbase data mapping.png delete mode 100644 persistence-core/docs/Persistent layer design.png delete mode 100644 persistence-core/docs/src/LDAP to Couchbase data mapping.dia delete mode 100644 persistence-core/docs/src/ldap_tree.png delete mode 100644 persistence-core/pom.xml delete mode 100644 persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManagerFactory.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/event/DeleteNotifier.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/AuthenticationException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/BasePersistenceException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/EntryDeleteException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/EntryPersistenceException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/InvalidArgumentException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/KeyConversionException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/MappingException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/PropertyAccessException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/PropertyNotFoundException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/UnsupportedOperationException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/extension/PersistenceExtension.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/operation/ConfigurationException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/operation/ConnectionException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/operation/DeleteException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/operation/DuplicateEntryException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/operation/EntryNotFoundException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/operation/PersistenceException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/operation/SearchException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/exception/operation/SearchScopeException.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/key/impl/GenericKeyConverter.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/key/impl/KeyShortcuter.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/key/impl/KeyShortcuterConf.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/key/impl/model/ParsedKey.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/model/AttributeData.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/model/AttributeDataModification.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/model/BatchOperation.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/model/DefaultBatchOperation.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/model/PagedResult.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/model/PersistenceConfiguration.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/model/ProcessBatchOperation.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/model/SearchScope.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/model/SortOrder.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/operation/PersistenceOperationService.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/operation/auth/PasswordDetails.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/operation/auth/PasswordEncryptionHelper.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/operation/auth/PasswordEncryptionMethod.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/reflect/property/BasicPropertyAccessor.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/reflect/property/BasicPropertyAnnotationResolver.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/reflect/property/DirectPropertyAccessor.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/reflect/property/Getter.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/reflect/property/PropertyAccessor.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/reflect/property/PropertyAnnotation.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/reflect/property/PropertyAnnotationResolver.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/reflect/property/Setter.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/reflect/util/ReflectHelper.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/service/BaseFactoryService.java delete mode 100644 persistence-core/src/main/java/org/gluu/persist/watch/DurationUtil.java delete mode 100644 persistence-core/src/main/resources/key-shortcuter-rules.json delete mode 100644 persistence-core/src/test/java/org/gluu/persist/key/impl/KeyShortcuterTest.java delete mode 100644 persistence-core/src/test/java/org/gluu/persist/key/impl/dev/KeyShortcuterManualTest.java delete mode 100644 persistence-couchbase-sample/pom.xml delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomMultiValuedTypesSample.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomObjectAttributesSample.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomStringAttributesSample.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSample.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleBatchJob.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleDelete.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleEntryManager.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleSimpleSessionSample.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleUserSearchSample.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleAttribute.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleClient.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleCustomStringUser.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleGrant.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleSession.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleSessionState.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleTokenCouchbase.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleUser.java delete mode 100644 persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/UserRole.java delete mode 100644 persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java delete mode 100644 persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionId.java delete mode 100644 persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionIdState.java delete mode 100644 persistence-couchbase-sample/src/test/resources/org/gluu/couchbase/test/c1.gluu.org.properties delete mode 100644 persistence-couchbase/LICENSE delete mode 100644 persistence-couchbase/pom.xml delete mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseBatchOperationWraper.java delete mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java delete mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManagerFactory.java delete mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java delete mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/BucketMapping.java delete mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/ConvertedExpression.java delete mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/CouchbaseConnectionConfiguration.java delete mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/ResultCode.java delete mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/SearchReturnDataType.java delete mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java delete mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java delete mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java delete mode 100644 persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/watch/OperationDurationUtil.java delete mode 100644 persistence-couchbase/src/main/resources/META-INF/beans.xml delete mode 100644 persistence-couchbase/src/test/java/org/gluu/test/.gitignore delete mode 100644 persistence-couchbase/src/test/java/org/gluu/test/dev/.gitignore delete mode 100644 persistence-filter/pom.xml delete mode 100644 persistence-filter/src/main/java/org/gluu/search/filter/Filter.java delete mode 100644 persistence-filter/src/main/java/org/gluu/search/filter/FilterType.java delete mode 100644 persistence-hybrid/pom.xml delete mode 100644 persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java delete mode 100644 persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManagerFactory.java delete mode 100644 persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridPersistenceOperationService.java delete mode 100644 persistence-hybrid/src/main/resources/META-INF/beans.xml delete mode 100644 persistence-ldap-sample/pom.xml delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSample.java delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleBatchJob.java delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleDelete.java delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleEntryManager.java delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleSimpleSessionSample.java delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/MailUniquenessConfigurationSample.java delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/model/MailUniquenessConfiguration.java delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleAttribute.java delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleClient.java delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleGrant.java delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleSession.java delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleSessionState.java delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleTokenLdap.java delete mode 100644 persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleUser.java delete mode 100644 persistence-ldap/pom.xml delete mode 100644 persistence-ldap/src/main/java/org/gluu/persist/ldap/exception/InvalidSimplePageControlException.java delete mode 100644 persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapBatchOperationWraper.java delete mode 100644 persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java delete mode 100644 persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManagerFactory.java delete mode 100644 persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapFilterConverter.java delete mode 100644 persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapSearchScopeConverter.java delete mode 100644 persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdifDataUtility.java delete mode 100644 persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/LdapOperationService.java delete mode 100644 persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapAuthConnectionProvider.java delete mode 100644 persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapConnectionProvider.java delete mode 100644 persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java delete mode 100644 persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/watch/OperationDurationUtil.java delete mode 100644 persistence-ldap/src/main/resources/META-INF/beans.xml delete mode 100644 persistence-model/pom.xml delete mode 100644 persistence-model/src/main/java/org/gluu/persist/model/base/BaseEntry.java delete mode 100644 persistence-model/src/main/java/org/gluu/persist/model/base/CustomAttribute.java delete mode 100644 persistence-model/src/main/java/org/gluu/persist/model/base/CustomEntry.java delete mode 100644 persistence-model/src/main/java/org/gluu/persist/model/base/CustomObjectAttribute.java delete mode 100644 persistence-model/src/main/java/org/gluu/persist/model/base/Deletable.java delete mode 100644 persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java delete mode 100644 persistence-model/src/main/java/org/gluu/persist/model/base/DummyEntry.java delete mode 100644 persistence-model/src/main/java/org/gluu/persist/model/base/Entry.java delete mode 100644 persistence-model/src/main/java/org/gluu/persist/model/base/GluuBoolean.java delete mode 100644 persistence-model/src/main/java/org/gluu/persist/model/base/GluuDummyEntry.java delete mode 100644 persistence-model/src/main/java/org/gluu/persist/model/base/InumEntry.java delete mode 100644 persistence-model/src/main/java/org/gluu/persist/model/base/SimpleBranch.java delete mode 100644 persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java delete mode 100644 persistence-standalone/pom.xml delete mode 100644 persistence-standalone/src/main/java/org/gluu/persist/service/StandalonePersistanceFactoryService.java delete mode 100644 persistence-standalone/src/test/java/org/gluu/persist/service/test/.gitignore diff --git a/core-cache/pom.xml b/core-cache/pom.xml index 81bc0af4..56d99693 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final @@ -46,8 +46,11 @@ ${project.groupId} - oxcore-persistence-core - ${project.version} + gluu-orm-core + + + ${project.groupId} + oxcore-util @@ -75,6 +78,31 @@ net.jodah expiringmap + + commons-io + commons-io + + + commons-httpclient + commons-httpclient + + + org.apache.httpcomponents + httpcore + + + org.apache.httpcomponents + httpclient + + + + jakarta.xml.bind + jakarta.xml.bind-api + + + javax.annotation + javax.annotation-api + diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java index d30fcc01..79478564 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheProvider.java @@ -5,6 +5,8 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.gluu.persist.PersistenceEntryManager; +import org.gluu.persist.exception.EntryPersistenceException; +import org.gluu.persist.exception.operation.DuplicateEntryException; import org.gluu.persist.model.base.SimpleBranch; import org.gluu.search.filter.Filter; import org.slf4j.Logger; @@ -38,6 +40,8 @@ public class NativePersistenceCacheProvider extends AbstractCacheProvider org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index cc3e761f..9543ca57 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final @@ -74,6 +74,14 @@ org.apache.jackrabbit jackrabbit-jcr-rmi + + org.apache.jackrabbit + jackrabbit-webdav + + + com.github.lookfirst + sardine + diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java index a3116d60..72d0b022 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java @@ -58,7 +58,7 @@ public DocumentStoreProvider getDocumentStoreProvider(DocumentStoreConfiguration } WebDavDocumentStoreProvider webDavDocumentStoreProvider = new WebDavDocumentStoreProvider(); - webDavDocumentStoreProvider.configure(documentStoreConfiguration); + webDavDocumentStoreProvider.configure(documentStoreConfiguration, stringEncrypter); webDavDocumentStoreProvider.init(); documentStoreProvider = webDavDocumentStoreProvider; diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/JcaDocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/JcaDocumentStoreConfiguration.java index db2c910d..65da3a34 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/conf/JcaDocumentStoreConfiguration.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/JcaDocumentStoreConfiguration.java @@ -1,9 +1,10 @@ package org.gluu.service.document.store.conf; -import java.io.Serializable; - +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.io.Serializable; + /** * @author Yuriy Movchan on 04/10/2020 */ @@ -14,10 +15,12 @@ public class JcaDocumentStoreConfiguration implements Serializable { private String serverUrl; // http://localhost:8080/rmi private String workspaceName; - private long connectionTimeout; + private int connectionTimeout; private String userId; private String password; + + @JsonIgnore private String decryptedPassword; public String getServerUrl() { @@ -36,11 +39,11 @@ public void setWorkspaceName(String workspaceName) { this.workspaceName = workspaceName; } - public long getConnectionTimeout() { + public int getConnectionTimeout() { return connectionTimeout; } - public void setConnectionTimeout(long connectionTimeout) { + public void setConnectionTimeout(int connectionTimeout) { this.connectionTimeout = connectionTimeout; } @@ -71,7 +74,7 @@ public void setDecryptedPassword(String decryptedPassword) { @Override public String toString() { return "JcaDocumentStoreConfiguration [serverUrl=" + serverUrl + ", workspaceName=" + workspaceName + ", connectionTimeout=" - + connectionTimeout + ", userId=" + userId + ", password=" + password + ", decryptedPassword=" + decryptedPassword + "]"; + + connectionTimeout + ", userId=" + userId + "]"; } } diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/WebDavDocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/WebDavDocumentStoreConfiguration.java index 55ef594a..81b22fd5 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/conf/WebDavDocumentStoreConfiguration.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/WebDavDocumentStoreConfiguration.java @@ -1,9 +1,9 @@ package org.gluu.service.document.store.conf; -import java.io.Serializable; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.io.Serializable; + /** * @author Yuriy Movchan on 04/10/2020 */ @@ -14,7 +14,7 @@ public class WebDavDocumentStoreConfiguration implements Serializable { private String serverUrl; // http://localhost:8080 private String workspaceName; - private long connectionTimeout; + private int connectionTimeout; private String userId; private String password; @@ -36,11 +36,11 @@ public void setWorkspaceName(String workspaceName) { this.workspaceName = workspaceName; } - public long getConnectionTimeout() { + public int getConnectionTimeout() { return connectionTimeout; } - public void setConnectionTimeout(long connectionTimeout) { + public void setConnectionTimeout(int connectionTimeout) { this.connectionTimeout = connectionTimeout; } @@ -71,7 +71,7 @@ public void setDecryptedPassword(String decryptedPassword) { @Override public String toString() { return "WebDavDocumentStoreConfiguration [serverUrl=" + serverUrl + ", workspaceName=" + workspaceName + ", connectionTimeout=" - + connectionTimeout + ", userId=" + userId + ", password=" + password + ", decryptedPassword=" + decryptedPassword + "]"; + + connectionTimeout + ", userId=" + userId + "]"; } } diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java index 7ae7b4c9..c9ad1345 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java @@ -309,12 +309,13 @@ private void removeDocument(String path, Session session) private void decryptPassword(JcaDocumentStoreConfiguration jcaDocumentStoreConfiguration) { try { - String encryptedPassword = jcaDocumentStoreConfiguration.getPassword(); + String encryptedPassword = jcaDocumentStoreConfiguration.getPassword(); if (StringUtils.isNotBlank(encryptedPassword)) { jcaDocumentStoreConfiguration.setDecryptedPassword(stringEncrypter.decrypt(encryptedPassword)); log.trace("Decrypted JCA password successfully."); } } catch (StringEncrypter.EncryptionException ex) { + jcaDocumentStoreConfiguration.setDecryptedPassword(jcaDocumentStoreConfiguration.getPassword()); log.error("Error during JCA password decryption", ex); } } @@ -342,7 +343,7 @@ private void closeSession(Session session) { } private String getNormalizedPath(String path) { - return path.replaceAll("\\\\", "/"); + return path.replace("\\", "/").replace(" ", ""); } private Node getOrCreateContentNode(String path, Session session) throws RepositoryException { diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java index 397b44da..ac7f498b 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java @@ -8,26 +8,75 @@ import javax.annotation.PreDestroy; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; +import javax.jcr.RepositoryException; +import org.apache.commons.lang.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.AuthSchemes; +import org.apache.http.client.config.CookieSpecs; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.conn.SchemePortResolver; +import org.apache.http.conn.UnsupportedSchemeException; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.InputStreamEntity; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.DefaultSchemePortResolver; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.protocol.BasicHttpContext; +import org.apache.http.protocol.HttpContext; +import org.apache.http.util.Args; +import org.apache.jackrabbit.webdav.client.methods.HttpMkcol; +import org.apache.tika.io.IOUtils; import org.gluu.service.document.store.conf.DocumentStoreConfiguration; import org.gluu.service.document.store.conf.DocumentStoreType; import org.gluu.service.document.store.conf.WebDavDocumentStoreConfiguration; +import org.gluu.util.security.StringEncrypter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.github.sardine.Sardine; +import com.github.sardine.SardineFactory; + /** * @author Yuriy Movchan on 04/10/2020 */ @ApplicationScoped public class WebDavDocumentStoreProvider extends DocumentStoreProvider { - @Inject + @Inject private Logger log; @Inject private DocumentStoreConfiguration documentStoreConfiguration; + @Inject + private StringEncrypter stringEncrypter; + + /** + * Local context with authentication cache. Make sure the same context is used to execute + * logically related requests. + */ + protected HttpClientContext context = HttpClientContext.create(); + private WebDavDocumentStoreConfiguration webDavDocumentStoreConfiguration; + + private Sardine client; + private HttpClient httpClient; + private String baseServerUrl; + private int connectionTimeout; public WebDavDocumentStoreProvider() { } @@ -37,20 +86,45 @@ public void init() { this.webDavDocumentStoreConfiguration = documentStoreConfiguration.getWebDavConfiguration(); } - public void create() { - log.debug("Starting LocalDocumentStoreProvider ..."); - } + public void create() { + try { + log.debug("Starting WebDavDocumentStoreProvider ..."); + decryptPassword(webDavDocumentStoreConfiguration); + + String password = StringUtils.isBlank(webDavDocumentStoreConfiguration.getDecryptedPassword()) ? "" : webDavDocumentStoreConfiguration.getDecryptedPassword(); + + UsernamePasswordCredentials credentials = new UsernamePasswordCredentials( + webDavDocumentStoreConfiguration.getUserId(), password); - public void configure(DocumentStoreConfiguration documentStoreConfiguration) { - this.log = LoggerFactory.getLogger(DocumentStoreConfiguration.class); + this.connectionTimeout = webDavDocumentStoreConfiguration.getConnectionTimeout(); + + this.httpClient = createHttpClient(credentials, connectionTimeout * 1000); + + this.baseServerUrl = webDavDocumentStoreConfiguration.getServerUrl() + "/" + + webDavDocumentStoreConfiguration.getWorkspaceName(); +/* + * Sardine +*/ + + this.client = SardineFactory.begin(webDavDocumentStoreConfiguration.getUserId(), password); + } catch (Exception ex) { + throw new IllegalStateException("Error starting JcaDocumentStoreProvider", ex); + } + } + + public void configure(DocumentStoreConfiguration documentStoreConfiguration, StringEncrypter stringEncrypter) { + this.log = LoggerFactory.getLogger(WebDavDocumentStoreProvider.class); this.documentStoreConfiguration = documentStoreConfiguration; + this.stringEncrypter = stringEncrypter; } @PreDestroy public void destroy() { - log.debug("Destroying LocalDocumentStoreProvider"); + log.debug("Destroying WebDavDocumentStoreProvider"); + + this.client = null; - log.debug("Destroyed LocalDocumentStoreProvider"); + log.debug("Destroyed WebDavDocumentStoreProvider"); } @Override @@ -66,13 +140,60 @@ public boolean hasDocument(String path) { @Override public boolean saveDocument(String path, String documentContent, Charset charset) { - // TODO Auto-generated method stub + if (true) { + log.debug("Save document: '{}'", path); + + String normalizedPath = getNormalizedPath(path); + try { + HttpPut method = new HttpPut(baseServerUrl + "/" + normalizedPath); + HttpEntity entity = new StringEntity(documentContent, charset); + method.setEntity(entity); + + HttpContext requestLocalContext = new BasicHttpContext(context); + HttpResponse response = httpClient.execute(method, requestLocalContext); + + int statusCode = response.getStatusLine().getStatusCode(); + return statusCode == HttpStatus.SC_CREATED || statusCode == HttpStatus.SC_NO_CONTENT; + } catch (IOException ex) { + log.error("Failed to write document to file '{}'", path, ex); + } + + return false; + } else { + + log.debug("Save document: '{}'", path); + + String normalizedPath = getNormalizedPath(path); + try { + String url = baseServerUrl + "/" + normalizedPath; + client.put(url, IOUtils.toInputStream(documentContent)); + + return true; + } catch (IOException ex) { + log.error("Failed to write document to file '{}'", path, ex); + } + return false; + } } @Override public boolean saveDocumentStream(String path, InputStream documentStream) { - // TODO Auto-generated method stub + log.debug("Save document from stream: '{}'", path); + String normalizedPath = getNormalizedPath(path); + try { + HttpPut method = new HttpPut(baseServerUrl + "/" + normalizedPath); + HttpEntity entity = new InputStreamEntity(documentStream); + method.setEntity(entity); + + HttpContext requestLocalContext = new BasicHttpContext(context); + HttpResponse response = httpClient.execute(method, requestLocalContext); + + return response.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED; + } catch (IOException ex) { + log.error("Failed to write document from stream to file '{}'", path, ex); + } + return false; } @@ -100,4 +221,81 @@ public boolean removeDocument(String path) { return false; } + private void createPath(String path) throws RepositoryException { +/* + HttpMkcol mkcol = new HttpMkcol(""); + this.client.executeMethod(mkcol, ) + + File filePath = new File(path); + String folderPath = filePath.getParentFile().getPath(); + + String normalizedFolderPath = getNormalizedPath(folderPath); + JcrUtils.getOrCreateByPath(normalizedFolderPath, NodeType.NT_FOLDER, session); +*/ + } + private HttpClient createHttpClient(UsernamePasswordCredentials credentials, int timeoutInMillis) { + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); +// credentialsProvider.setCredentials(AuthScope.ANY, credentials); + credentialsProvider.setCredentials( + new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM, AuthSchemes.BASIC), + credentials); + + SchemePortResolver portResolver = new DefaultSchemePortResolver() { + @Override + public int resolve(final HttpHost host) throws UnsupportedSchemeException { + Args.notNull(host, "HTTP host"); + final int port = host.getPort(); + if (port > 0) { + return port; + } + final String name = host.getSchemeName(); + if (name.equalsIgnoreCase("http")) { + return 8080; + } else if (name.equalsIgnoreCase("https")) { + return 8443; + } + + return super.resolve(host); + } + }; + + PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); + CloseableHttpClient httpClient = HttpClients.custom() + .setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD) + .setSocketTimeout(timeoutInMillis).setExpectContinueEnabled(false).build()) + .setDefaultCredentialsProvider(credentialsProvider) + .setConnectionManager(cm) +/* .setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))*/ +/* .setSchemePortResolver(portResolver)*/ + + .build(); + cm.setMaxTotal(50); // Increase max total connection to 50 + cm.setDefaultMaxPerRoute(10); // Increase default max connection per route to 10 + + context.setCredentialsProvider(credentialsProvider); + + return httpClient; + } + + private void decryptPassword(WebDavDocumentStoreConfiguration webDocumentStoreConfiguration) { + try { + String encryptedPassword = webDocumentStoreConfiguration.getPassword(); + if (StringUtils.isNotBlank(encryptedPassword)) { + webDocumentStoreConfiguration.setDecryptedPassword(stringEncrypter.decrypt(encryptedPassword)); + log.trace("Decrypted WebDAV password successfully."); + } + } catch (StringEncrypter.EncryptionException ex) { + log.error("Error during WebDAV password decryption", ex); + } + } + + private String getNormalizedPath(String path) { + String resultPath = path.replace("\\", "/").replace(" ", ""); + if (resultPath.startsWith("/")) { + resultPath = resultPath.substring(1); + } + + return resultPath; + } + } diff --git a/core-document-store/src/test/java/org/gluu/service/document/store/manual/WebDavDocumentStoreManualTest.java b/core-document-store/src/test/java/org/gluu/service/document/store/manual/WebDavDocumentStoreManualTest.java new file mode 100644 index 00000000..eaf09b59 --- /dev/null +++ b/core-document-store/src/test/java/org/gluu/service/document/store/manual/WebDavDocumentStoreManualTest.java @@ -0,0 +1,97 @@ +package org.gluu.service.document.store.manual; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import javax.jcr.RepositoryException; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; +import org.gluu.service.document.store.StandaloneDocumentStoreProviderFactory; +import org.gluu.service.document.store.conf.DocumentStoreConfiguration; +import org.gluu.service.document.store.conf.DocumentStoreType; +import org.gluu.service.document.store.conf.WebDavDocumentStoreConfiguration; +import org.gluu.service.document.store.conf.LocalDocumentStoreConfiguration; +import org.gluu.service.document.store.provider.DocumentStoreProvider; +import org.gluu.util.security.StringEncrypter; +import org.gluu.util.security.StringEncrypter.EncryptionException; + +import com.fasterxml.jackson.databind.ObjectMapper; + +public class WebDavDocumentStoreManualTest { + + public WebDavDocumentStoreManualTest() { + + } + + public static void main(String[] args) throws RepositoryException, IOException, EncryptionException { + StringEncrypter se = new StringEncrypter(StringEncrypter.DESEDE_ENCRYPTION_SCHEME, "Zqvw62DEFdhxoL4csi9hpVI4"); + DocumentStoreConfiguration dsc = new DocumentStoreConfiguration(); + dsc.setDocumentStoreType(DocumentStoreType.WEB_DAV); + + WebDavDocumentStoreConfiguration jca = new WebDavDocumentStoreConfiguration(); + jca.setServerUrl("http://localhost:8080/repository"); + jca.setWorkspaceName("default"); + jca.setUserId("admin"); + jca.setPassword(se.encrypt("admin")); + jca.setConnectionTimeout(15); + + dsc.setWebDavConfiguration(jca); + + LocalDocumentStoreConfiguration lca = new LocalDocumentStoreConfiguration(); + + dsc.setLocalConfiguration(lca); + + ObjectMapper om = new ObjectMapper(); + System.out.println(om.writeValueAsString(dsc)); + + StandaloneDocumentStoreProviderFactory pf = new StandaloneDocumentStoreProviderFactory(se); + DocumentStoreProvider dsp = pf.getDocumentStoreProvider(dsc); + + String doc1 = FileUtils.readFileToString(new File("V:/test.log"), "UTF-8"); + byte[] doc2 = FileUtils.readFileToByteArray(new File("V:/test.zip")); +/* + System.out.print("Has document: " + "/test2/test2/test.jmx: "); + System.out.println(dsp.hasDocument("/test2/test2/test.jmx")); +*/ + System.out.print("Has document: " + "/test2/test3/test3.jmx: "); + System.out.println(dsp.hasDocument("/test2/test3/test3.jmx")); + + System.out.print("Write document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.saveDocumentStream("/test-1.jmx", new ByteArrayInputStream(doc2))); +/* + System.out.print("Has document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.hasDocument("/test2/test3/test4/test5.jmx")); +*/ + System.out.print("Write document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.saveDocument("/test7.jmx", doc1, StandardCharsets.UTF_8)); +/* + System.out.print("Has document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.hasDocument("/test2/test3/test4/test5.jmx")); + + System.out.print("Read document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.readDocument("/test2/test3/test4/test5.jmx", StandardCharsets.UTF_8)); + + System.out.print("Read document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(IOUtils.toString(dsp.readDocumentAsStream("/test2/test3/test4/test5.jmx"), StandardCharsets.UTF_8)); + + System.out.print("Rename document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.renameDocument("/test2/test3/test4/test5.jmx", "/test2/test4/test5.jmx")); + + System.out.print("Has document: " + "/test2/test3/test4/test5.jmx: "); + System.out.println(dsp.hasDocument("/test2/test3/test4/test5.jmx")); + + System.out.print("Has document: " + "/test2/test4/test5.jmx: "); + System.out.println(dsp.hasDocument("/test2/test4/test5.jmx")); + + System.out.print("Remove document: " + "test2/test4/test5.jmx: "); + System.out.println(dsp.removeDocument("/test2/test4/test5.jmx")); + + System.out.print("Has document: " + "/test2/test4/test5.jmx: "); + System.out.println(dsp.hasDocument("/test2/test4/test5.jmx")); +*/ + } + +} diff --git a/core-java-ext/pom.xml b/core-java-ext/pom.xml index 236ae38c..2f313b48 100644 --- a/core-java-ext/pom.xml +++ b/core-java-ext/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final diff --git a/core-script/pom.xml b/core-script/pom.xml index c6c275f4..54382e9b 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final @@ -37,11 +37,11 @@ ${project.groupId} - oxcore-persistence-core + gluu-orm-core ${project.groupId} - oxcore-persistence-model + gluu-orm-model ${project.groupId} @@ -82,10 +82,16 @@ provided + + javax.ws.rs + javax.ws.rs-api + provided + + ${project.groupId} - oxcore-persistence-ldap + gluu-orm-ldap test diff --git a/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java b/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java index 1f931515..d2b32ae7 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java @@ -31,6 +31,8 @@ import org.gluu.model.custom.script.type.persistence.PersistenceType; import org.gluu.model.custom.script.type.postauthn.DummyPostAuthnType; import org.gluu.model.custom.script.type.postauthn.PostAuthnType; +import org.gluu.model.custom.script.type.revoke.DummyRevokeTokenType; +import org.gluu.model.custom.script.type.revoke.RevokeTokenType; import org.gluu.model.custom.script.type.scim.DummyScimType; import org.gluu.model.custom.script.type.scim.ScimType; import org.gluu.model.custom.script.type.scope.DummyDynamicScopeType; @@ -41,6 +43,7 @@ import org.gluu.model.custom.script.type.spontaneous.SpontaneousScopeType; import org.gluu.model.custom.script.type.uma.*; import org.gluu.model.custom.script.type.user.*; +import org.gluu.model.custom.script.type.token.*; import org.gluu.persist.annotation.AttributeEnum; import java.util.HashMap; @@ -83,8 +86,10 @@ public enum CustomScriptType implements AttributeEnum { SCIM("scim", "SCIM", ScimType.class, CustomScript.class, "ScimEventHandler", new DummyScimType()), CIBA_END_USER_NOTIFICATION("ciba_end_user_notification", "CIBA End User Notification", EndUserNotificationType.class, CustomScript.class, "EndUserNotification", new DummyEndUserNotificationType()), + REVOKE_TOKEN("revoke_token", "Revoke Token", RevokeTokenType.class, CustomScript.class, "RevokeToken", new DummyRevokeTokenType()), PERSISTENCE_EXTENSION("persistence_extension", "Persistence Extension", PersistenceType.class, CustomScript.class, "PersistenceExtension", new DummyPeristenceType()), - IDP("idp", "Idp Extension", IdpType.class, CustomScript.class, "IdpExtension", new DummyIdpType()); + IDP("idp", "Idp Extension", IdpType.class, CustomScript.class, "IdpExtension", new DummyIdpType()), + UPDATE_TOKEN("update_token", "Update Token", UpdateTokenType.class, CustomScript.class, "UpdateToken", new DummyUpdateTokenType()); private String value; private String displayName; diff --git a/core-script/src/main/java/org/gluu/model/custom/script/model/CustomScript.java b/core-script/src/main/java/org/gluu/model/custom/script/model/CustomScript.java index a00ca64f..3060404e 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/model/CustomScript.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/model/CustomScript.java @@ -29,7 +29,7 @@ * * @author Yuriy Movchan Date: 12/03/2014 */ -@DataEntry(sortBy = "level") +@DataEntry(sortBy = "level", sortByName = "oxLevel") @ObjectClass("oxCustomScript") public class CustomScript extends BaseEntry { diff --git a/core-script/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java b/core-script/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java index c41af06f..06aa3920 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/model/ScriptTemplate.java @@ -7,9 +7,9 @@ public enum ScriptTemplate { "\n" + "import java\n" + "\n" + - "class SamplePersonScript(PersonAuthenticationType):\n" + + "class PersonAuthentication(PersonAuthenticationType):\n" + " def __init__(self, currentTimeMillis):\n" + - " \n" + + " self.currentTimeMillis = currentTimeMillis\n" + "\n" + " def init(self, configurationAttributes):\n" + " return True \n" + @@ -30,7 +30,7 @@ public enum ScriptTemplate { " return True\n" + "\n" + " def prepareForStep(self, configurationAttributes, requestParameters, step):\n" + - " \n" + + " return True\n" + "\n" + " def getExtraParametersForStep(self, configurationAttributes, step):\n" + " return None\n" + diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/revoke/DummyRevokeTokenType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/revoke/DummyRevokeTokenType.java new file mode 100644 index 00000000..4aba8086 --- /dev/null +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/revoke/DummyRevokeTokenType.java @@ -0,0 +1,36 @@ +package org.gluu.model.custom.script.type.revoke; + +import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.model.CustomScript; + +import java.util.Map; + +/** + * @author Yuriy Zabrovarnyy + */ +public class DummyRevokeTokenType implements RevokeTokenType { + @Override + public boolean init(Map configurationAttributes) { + return true; + } + + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } + + @Override + public boolean destroy(Map configurationAttributes) { + return true; + } + + @Override + public int getApiVersion() { + return 1; + } + + @Override + public boolean revoke(Object context) { + return true; + } +} diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/revoke/RevokeTokenType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/revoke/RevokeTokenType.java new file mode 100644 index 00000000..7be84f19 --- /dev/null +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/revoke/RevokeTokenType.java @@ -0,0 +1,11 @@ +package org.gluu.model.custom.script.type.revoke; + +import org.gluu.model.custom.script.type.BaseExternalType; + +/** + * @author Yuriy Zabrovarnyy + */ +public interface RevokeTokenType extends BaseExternalType { + + boolean revoke(Object context); +} diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java index 56499ff7..60d157c1 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/scim/DummyScimType.java @@ -5,6 +5,8 @@ import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.model.CustomScript; +import javax.ws.rs.core.Response; + /** * @author jgomer2001 */ @@ -110,4 +112,14 @@ public boolean postSearchGroups(Object results, Map configurationAttributes) { + return null; + } + + @Override + public Response manageSearchOperation(Object context, Object searchRequest, Map configurationAttributes) { + return null; + } + } diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java index 9802f33e..8d6f35c2 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/scim/ScimType.java @@ -5,6 +5,8 @@ import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.type.BaseExternalType; +import javax.ws.rs.core.Response; + /** * @author jgomer2001 */ @@ -42,4 +44,8 @@ public interface ScimType extends BaseExternalType { boolean postSearchGroups(Object results, Map configurationAttributes); + Response manageResourceOperation(Object context, Object entity, Object payload, Map configurationAttributes); + + Response manageSearchOperation(Object context, Object searchRequest, Map configurationAttributes); + } diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/token/DummyUpdateTokenType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/token/DummyUpdateTokenType.java new file mode 100644 index 00000000..a17864ca --- /dev/null +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/token/DummyUpdateTokenType.java @@ -0,0 +1,44 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2020, Gluu + */ + +package org.gluu.model.custom.script.type.token; + +import java.util.Map; + +import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.model.CustomScript; + +/** + * @author Yuriy Movchan + */ +public class DummyUpdateTokenType implements UpdateTokenType { + + @Override + public boolean init(Map configurationAttributes) { + return true; + } + + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } + + @Override + public boolean destroy(Map configurationAttributes) { + return true; + } + + @Override + public int getApiVersion() { + return 1; + } + + @Override + public boolean modifyIdToken(Object jwr, Object tokenContext) { + return false; + } + +} diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/token/UpdateTokenType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/token/UpdateTokenType.java new file mode 100644 index 00000000..907d1812 --- /dev/null +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/token/UpdateTokenType.java @@ -0,0 +1,17 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2020, Gluu + */ + +package org.gluu.model.custom.script.type.token; + +import org.gluu.model.custom.script.type.BaseExternalType; + +/** + * @author Yuriy Movchan + */ +public interface UpdateTokenType extends BaseExternalType { + + boolean modifyIdToken(Object jsonWebResponse, Object tokenContext); +} diff --git a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java index 2e0b56dc..409aec07 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java @@ -241,9 +241,8 @@ private ReloadResult reloadCustomScriptConfigurations( CustomScriptConfiguration prevCustomScriptConfiguration = newCustomScriptConfigurations .get(newSupportedCustomScriptInum); - boolean hasChanged = (prevCustomScriptConfiguration == null) || (prevCustomScriptConfiguration.getCustomScript() - .getRevision() != newCustomScript.getRevision()); - if (hasChanged || ScriptLocationType.FILE == newCustomScript.getLocationType()) { + if (prevCustomScriptConfiguration == null || prevCustomScriptConfiguration.getCustomScript() + .getRevision() != newCustomScript.getRevision()) { // Destroy old version properly before creating new one if (prevCustomScriptConfiguration != null) { destroyCustomScript(prevCustomScriptConfiguration); diff --git a/core-standalone/pom.xml b/core-standalone/pom.xml index a172c459..b4a189ce 100644 --- a/core-standalone/pom.xml +++ b/core-standalone/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final @@ -44,18 +44,15 @@ org.gluu - oxcore-persistence-cdi - ${project.version} + gluu-orm-cdi org.gluu oxcore-cache - ${project.version} org.gluu - oxcore-persistence-standalone - ${project.version} + gluu-orm-standalone diff --git a/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java b/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java index a8931d90..f1e75507 100644 --- a/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java +++ b/core-standalone/src/main/java/org/gluu/conf/service/ConfigurationFactory.java @@ -24,7 +24,7 @@ import org.gluu.service.cache.InMemoryConfiguration; import org.gluu.util.StringHelper; import org.gluu.util.exception.ConfigurationException; -import org.gluu.util.properties.FileConfiguration; +import org.gluu.orm.util.properties.FileConfiguration; import org.gluu.util.security.PropertiesDecrypter; import org.gluu.util.security.StringEncrypter; import org.gluu.util.security.StringEncrypter.EncryptionException; diff --git a/core-timer-weld/pom.xml b/core-timer-weld/pom.xml index 1a52f89f..3b9ec6e1 100644 --- a/core-timer-weld/pom.xml +++ b/core-timer-weld/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final @@ -53,6 +53,11 @@ cdi-api provided + + org.jboss.spec.javax.annotation + jboss-annotations-api_1.2_spec + provided + diff --git a/core-timer-weld/src/main/java/org/gluu/service/timer/TimerJob.java b/core-timer-weld/src/main/java/org/gluu/service/timer/TimerJob.java index db7ba9ee..2f6b8464 100644 --- a/core-timer-weld/src/main/java/org/gluu/service/timer/TimerJob.java +++ b/core-timer-weld/src/main/java/org/gluu/service/timer/TimerJob.java @@ -32,10 +32,8 @@ public void execute(JobExecutionContext context) throws JobExecutionException { if (timerEvent == null) { return; } - - log.debug("Fire timer event [{}] with qualifiers {} from instance {}", timerEvent.getTargetEvent().getClass().getName(), + log.trace("Fire timer event [{}] with qualifiers {} from instance {}", timerEvent.getTargetEvent().getClass().getName(), timerEvent.getQualifiers(), System.identityHashCode(this)); - beanManager.fireEvent(timerEvent.getTargetEvent(), timerEvent.getQualifiers()); } catch (Exception ex) { throw new JobExecutionException(ex); diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index 81eccd51..f0a958b9 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final diff --git a/exception-extension-cdi/pom.xml b/exception-extension-cdi/pom.xml index da6c79ad..7dd63717 100644 --- a/exception-extension-cdi/pom.xml +++ b/exception-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index 82fdd2c7..dd3017ee 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final diff --git a/oxModel/pom.xml b/oxModel/pom.xml index 1d50925a..b367f9de 100644 --- a/oxModel/pom.xml +++ b/oxModel/pom.xml @@ -10,17 +10,17 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final org.gluu - oxcore-persistence-annotation + gluu-orm-annotation org.gluu - oxcore-persistence-model + gluu-orm-model @@ -44,6 +44,14 @@ javax.annotation javax.annotation-api + + jakarta.xml.bind + jakarta.xml.bind-api + + + javax.annotation + javax.annotation-api + \ No newline at end of file diff --git a/oxModel/src/main/java/org/gluu/model/attribute/Attribute.java b/oxModel/src/main/java/org/gluu/model/attribute/Attribute.java index f47be136..ae6b7eaa 100644 --- a/oxModel/src/main/java/org/gluu/model/attribute/Attribute.java +++ b/oxModel/src/main/java/org/gluu/model/attribute/Attribute.java @@ -27,7 +27,7 @@ * @author Javier Rojas Blum * @version February 9, 2015 */ -@DataEntry(sortBy = { "displayName" }) +@DataEntry(sortBy = "displayName") @ObjectClass(value = "Attribute") @JsonIgnoreProperties(ignoreUnknown = true) public class Attribute extends Entry implements Serializable { diff --git a/oxModel/src/main/java/org/gluu/model/metric/ldap/MetricEntry.java b/oxModel/src/main/java/org/gluu/model/metric/ldap/MetricEntry.java index 4e4d4a81..3dd0e341 100644 --- a/oxModel/src/main/java/org/gluu/model/metric/ldap/MetricEntry.java +++ b/oxModel/src/main/java/org/gluu/model/metric/ldap/MetricEntry.java @@ -10,6 +10,7 @@ import org.gluu.persist.annotation.AttributeName; import org.gluu.persist.annotation.DN; import org.gluu.persist.annotation.DataEntry; +import org.gluu.persist.annotation.Expiration; import org.gluu.persist.annotation.ObjectClass; import java.util.Date; @@ -19,7 +20,7 @@ * * @author Yuriy Movchan Date: 07/27/2015 */ -@DataEntry(sortBy = "startDate") +@DataEntry(sortBy = "startDate", sortByName = "oxStartDate") @ObjectClass(value = "oxMetric") public class MetricEntry { @@ -49,6 +50,10 @@ public class MetricEntry { @AttributeName(name = "exp") private Date expirationDate; + + @Expiration + private Integer ttl; + @AttributeName(name = "del") private boolean deletable = true; @@ -133,7 +138,15 @@ public void setExpirationDate(Date expirationDate) { this.expirationDate = expirationDate; } - public boolean isDeletable() { + public Integer getTtl() { + return ttl; + } + + public void setTtl(Integer ttl) { + this.ttl = ttl; + } + + public boolean isDeletable() { return deletable; } diff --git a/oxRadius/pom.xml b/oxRadius/pom.xml index 8a39e359..46dfa093 100644 --- a/oxRadius/pom.xml +++ b/oxRadius/pom.xml @@ -8,17 +8,17 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final org.gluu - oxcore-persistence-ldap + gluu-orm-ldap org.gluu - oxcore-persistence-annotation + gluu-orm-annotation diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index 744add4d..e8850911 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final @@ -53,7 +53,6 @@ org.gluu oxcore-document-store - ${project.version} @@ -67,12 +66,16 @@ org.opensaml opensaml - 2.6.4 jakarta.xml.bind jakarta.xml.bind-api - 2.3.3 + + + + + org.apache.santuario + xmlsec diff --git a/oxSaml/src/main/java/org/gluu/saml/Response.java b/oxSaml/src/main/java/org/gluu/saml/Response.java index f1662262..348316a5 100644 --- a/oxSaml/src/main/java/org/gluu/saml/Response.java +++ b/oxSaml/src/main/java/org/gluu/saml/Response.java @@ -85,15 +85,15 @@ public void loadXml(String xml) throws ParserConfigurationException, SAXExceptio fty.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); DocumentBuilder builder = fty.newDocumentBuilder(); - ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes()); + ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes("UTF-8")); xmlDoc = builder.parse(bais); } public void loadXmlFromBase64(String response) throws ParserConfigurationException, SAXException, IOException { Base64 base64 = new Base64(); byte[] decodedResponse = base64.decode(response); - String decodedS = new String(decodedResponse); - loadXml(decodedS); + String decoded = new String(decodedResponse, "UTF-8"); + loadXml(decoded); } public boolean isValid() throws Exception { @@ -115,6 +115,30 @@ public boolean isValid() throws Exception { return xmlSignature.validate(ctx); } + + public boolean isValidNew() throws Exception { + NodeList nodes = xmlDoc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); + + if (nodes == null || nodes.getLength() == 0) { + throw new Exception("Can't find signature in document."); + } + + if (setIdAttributeExists()) { + tagIdAttributes(xmlDoc); + } + + X509Certificate cert = samlSettings.getCertificate(); + + // It's do initialization only on first call + org.apache.xml.security.Init.init(); + + Element sigElement = (Element) nodes.item(0); + org.apache.xml.security.signature.XMLSignature signature = new org.apache.xml.security.signature.XMLSignature( + sigElement, null); + + return signature.checkSignatureValue(cert); + } + public boolean isAuthnFailed() throws Exception { XPath xPath = XPathFactory.newInstance().newXPath(); diff --git a/oxService/pom.xml b/oxService/pom.xml index 191ce500..8ec15de1 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final @@ -46,15 +46,23 @@ ${project.groupId} - oxcore-persistence-ldap + gluu-orm-ldap ${project.groupId} - oxcore-persistence-couchbase + gluu-orm-couchbase ${project.groupId} - oxcore-persistence-hybrid + gluu-orm-spanner + + + ${project.groupId} + gluu-orm-sql + + + ${project.groupId} + gluu-orm-hybrid ${project.groupId} @@ -89,11 +97,6 @@ jboss-annotations-api_1.2_spec provided - - org.jboss.spec.javax.interceptor - jboss-interceptors-api_1.2_spec - provided - javax.inject javax.inject @@ -102,11 +105,6 @@ javax.validation validation-api - - org.jboss.spec.javax.ejb - jboss-ejb-api_3.2_spec - provided - @@ -154,14 +152,8 @@ - javax.mail - mail - - - javax.activation - activation - - + com.sun.mail + jakarta.mail diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index 63ad01df..8faca14f 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -126,7 +126,6 @@ public class AppConfiguration implements Configuration, Serializable { private String recaptchaSecretKey; private boolean authenticationRecaptchaEnabled; - private boolean scimTestMode; private boolean oxTrustApiTestMode; private boolean enableUpdateNotification; @@ -166,6 +165,8 @@ public class AppConfiguration implements Configuration, Serializable { private Boolean useLocalCache = false; + private boolean passIdTokenHintToLogoutRedirectUri = false; + public ScimProperties getScimProperties() { return scimProperties; } @@ -656,14 +657,6 @@ public void setRecaptchaSecretKey(String recaptchaSecretKey) { this.recaptchaSecretKey = recaptchaSecretKey; } - public boolean isScimTestMode() { - return scimTestMode; - } - - public void setScimTestMode(boolean scimTestMode) { - this.scimTestMode = scimTestMode; - } - public boolean isOxTrustApiTestMode() { return oxTrustApiTestMode; } @@ -963,4 +956,11 @@ public void setEnableUpdateNotification(boolean enableUpdateNotification) { this.enableUpdateNotification = enableUpdateNotification; } + public boolean isPassIdTokenHintToLogoutRedirectUri() { + return passIdTokenHintToLogoutRedirectUri; + } + + public void setPassIdTokenHintToLogoutRedirectUri(boolean passIdTokenHintToLogoutRedirectUri) { + this.passIdTokenHintToLogoutRedirectUri = passIdTokenHintToLogoutRedirectUri; + } } diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/ScimMode.java b/oxService/src/main/java/org/gluu/config/oxtrust/ScimMode.java new file mode 100644 index 00000000..45bf82f1 --- /dev/null +++ b/oxService/src/main/java/org/gluu/config/oxtrust/ScimMode.java @@ -0,0 +1,3 @@ +package org.gluu.config.oxtrust; + +public enum ScimMode { OAUTH, TEST, UMA, BYPASS }; diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/ScimProperties.java b/oxService/src/main/java/org/gluu/config/oxtrust/ScimProperties.java index 5f822073..8e700fc1 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/ScimProperties.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/ScimProperties.java @@ -14,13 +14,33 @@ public class ScimProperties implements Serializable { private static final long serialVersionUID = -5154249316054593386L; private int maxCount; + + private ScimMode protectionMode; + + private String userExtensionSchemaURI; public int getMaxCount() { - return this.maxCount; + return maxCount; } public void setMaxCount(int maxCount) { this.maxCount = maxCount; } + + public ScimMode getProtectionMode() { + return protectionMode; + } + + public void setProtectionMode(ScimMode mode) { + protectionMode = mode; + } + + public String getUserExtensionSchemaURI() { + return userExtensionSchemaURI; + } + + public void setUserExtensionSchemaURI(String userExtensionSchemaURI) { + this.userExtensionSchemaURI = userExtensionSchemaURI; + } } diff --git a/oxService/src/main/java/org/gluu/model/DisplayNameEntry.java b/oxService/src/main/java/org/gluu/model/DisplayNameEntry.java index 624f7c73..283fd9fa 100644 --- a/oxService/src/main/java/org/gluu/model/DisplayNameEntry.java +++ b/oxService/src/main/java/org/gluu/model/DisplayNameEntry.java @@ -17,7 +17,7 @@ * * @author Yuriy Movchan Date: 08/11/2010 */ -@DataEntry(sortBy = { "displayName" }) +@DataEntry(sortBy = "displayName") public class DisplayNameEntry extends Entry implements Serializable { private static final long serialVersionUID = 2536007777903091939L; diff --git a/oxService/src/main/java/org/gluu/model/GluuAttribute.java b/oxService/src/main/java/org/gluu/model/GluuAttribute.java index e4da922e..eb1acf57 100644 --- a/oxService/src/main/java/org/gluu/model/GluuAttribute.java +++ b/oxService/src/main/java/org/gluu/model/GluuAttribute.java @@ -28,7 +28,7 @@ * @author Javier Rojas Blum * @version May 2, 2019 */ -@DataEntry(sortBy = { "displayName" }) +@DataEntry(sortBy = "displayName") @ObjectClass(value = "gluuAttribute") public class GluuAttribute extends Entry implements Serializable { @@ -39,15 +39,9 @@ public class GluuAttribute extends Entry implements Serializable { @AttributeName(ignoreDuringUpdate = true) private String inum; - @AttributeName - private String lifetime; - @AttributeName(name = "oxSourceAttribute") private String sourceAttribute; - @AttributeName - private String salt; - @AttributeName(name = "oxNameIdType") private String nameIdType; @@ -138,14 +132,6 @@ public void setInum(String inum) { this.inum = inum; } - public String getLifetime() { - return lifetime; - } - - public void setLifetime(String lifetime) { - this.lifetime = lifetime; - } - public String getSourceAttribute() { return sourceAttribute; } @@ -154,14 +140,6 @@ public void setSourceAttribute(String sourceAttribute) { this.sourceAttribute = sourceAttribute; } - public String getSalt() { - return salt; - } - - public void setSalt(String salt) { - this.salt = salt; - } - public String getNameIdType() { return nameIdType; } @@ -381,7 +359,6 @@ public int hashCode() { result = prime * result + Arrays.hashCode(editType); result = prime * result + ((gluuTooltip == null) ? 0 : gluuTooltip.hashCode()); result = prime * result + ((inum == null) ? 0 : inum.hashCode()); - result = prime * result + ((lifetime == null) ? 0 : lifetime.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((nameIdType == null) ? 0 : nameIdType.hashCode()); result = prime * result + ((origin == null) ? 0 : origin.hashCode()); @@ -389,7 +366,6 @@ public int hashCode() { result = prime * result + ((oxMultiValuedAttribute == null) ? 0 : oxMultiValuedAttribute.hashCode()); result = prime * result + ((oxSCIMCustomAttribute == null) ? 0 : oxSCIMCustomAttribute.hashCode()); result = prime * result + (requred ? 1231 : 1237); - result = prime * result + ((salt == null) ? 0 : salt.hashCode()); result = prime * result + ((saml1Uri == null) ? 0 : saml1Uri.hashCode()); result = prime * result + ((saml2Uri == null) ? 0 : saml2Uri.hashCode()); result = prime * result + ((seeAlso == null) ? 0 : seeAlso.hashCode()); diff --git a/oxService/src/main/java/org/gluu/model/security/Group.java b/oxService/src/main/java/org/gluu/model/security/Group.java new file mode 100644 index 00000000..0d6fa465 --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/security/Group.java @@ -0,0 +1,62 @@ +package org.gluu.model.security; + +import java.util.Enumeration; +import java.security.Principal; + +/** + * This interface is used to represent a group of principals. (A principal + * represents an entity such as an individual user or a company).

+ * + * Note that Group extends Principal. Thus, either a Principal or a Group can + * be passed as an argument to methods containing a Principal parameter. For + * example, you can add either a Principal or a Group to a Group object by + * calling the object's {@code addMember} method, passing it the + * Principal or Group. + * + */ +@Deprecated(since="9", forRemoval=true) +public interface Group extends Principal { + + /** + * Adds the specified member to the group. + * + * @param user the principal to add to this group. + * + * @return true if the member was successfully added, + * false if the principal was already a member. + */ + public boolean addMember(Principal user); + + /** + * Removes the specified member from the group. + * + * @param user the principal to remove from this group. + * + * @return true if the principal was removed, or + * false if the principal was not a member. + */ + public boolean removeMember(Principal user); + + /** + * Returns true if the passed principal is a member of the group. + * This method does a recursive search, so if a principal belongs to a + * group which is a member of this group, true is returned. + * + * @param member the principal whose membership is to be checked. + * + * @return true if the principal is a member of this group, + * false otherwise. + */ + public boolean isMember(Principal member); + + + /** + * Returns an enumeration of the members in the group. + * The returned objects can be instances of either Principal + * or Group (which is a subclass of Principal). + * + * @return an enumeration of the group members. + */ + public Enumeration members(); + +} diff --git a/oxService/src/main/java/org/gluu/model/security/Identity.java b/oxService/src/main/java/org/gluu/model/security/Identity.java index 1c1c263a..21e6fb0f 100644 --- a/oxService/src/main/java/org/gluu/model/security/Identity.java +++ b/oxService/src/main/java/org/gluu/model/security/Identity.java @@ -2,7 +2,6 @@ import java.io.Serializable; import java.security.Principal; -import java.security.acl.Group; import java.util.HashMap; import javax.annotation.PostConstruct; diff --git a/oxService/src/main/java/org/gluu/model/security/SimpleGroup.java b/oxService/src/main/java/org/gluu/model/security/SimpleGroup.java index fb522d06..3e3399be 100644 --- a/oxService/src/main/java/org/gluu/model/security/SimpleGroup.java +++ b/oxService/src/main/java/org/gluu/model/security/SimpleGroup.java @@ -2,7 +2,6 @@ import java.io.Serializable; import java.security.Principal; -import java.security.acl.Group; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; diff --git a/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java b/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java index 97b0003c..1da3c354 100644 --- a/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java +++ b/oxService/src/main/java/org/gluu/service/DataSourceTypeService.java @@ -1,15 +1,15 @@ package org.gluu.service; -import org.gluu.persist.PersistenceEntryManager; -import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; - import java.io.Serializable; + import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; -import javax.inject.Named; + +import org.gluu.persist.PersistenceEntryManager; +import org.gluu.persist.cloud.spanner.impl.SpannerEntryManagerFactory; +import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; @ApplicationScoped -@Named public class DataSourceTypeService implements Serializable { private static final long serialVersionUID = -1941135478226842653L; @@ -17,6 +17,10 @@ public class DataSourceTypeService implements Serializable { @Inject private PersistenceEntryManager entryManager; + public boolean isSpanner(String key) { + return entryManager.getPersistenceType(key).equals(SpannerEntryManagerFactory.PERSISTENCE_TYPE); + } + public boolean isLDAP(String key) { return entryManager.getPersistenceType(key).equals(LdapEntryManagerFactory.PERSISTENCE_TYPE); } diff --git a/oxService/src/main/java/org/gluu/service/LookupService.java b/oxService/src/main/java/org/gluu/service/LookupService.java index e80ffe09..a408f263 100644 --- a/oxService/src/main/java/org/gluu/service/LookupService.java +++ b/oxService/src/main/java/org/gluu/service/LookupService.java @@ -15,7 +15,9 @@ import javax.inject.Inject; import javax.inject.Named; +import org.apache.commons.lang3.StringUtils; import org.gluu.model.DisplayNameEntry; +import org.gluu.orm.util.StringHelper; import org.gluu.persist.PersistenceEntryManager; import org.gluu.persist.model.base.Entry; import org.gluu.search.filter.Filter; @@ -57,6 +59,30 @@ public DisplayNameEntry getDisplayNameEntry(String dn) throws Exception { return entry; } + /** + * Returns DisplayNameEntry based on display name + * + * @param dn + * display name + * @return DisplayNameEntry object + */ + public Object getTypedEntry(String dn, String clazz) throws Exception { + if (StringUtils.isEmpty(clazz)) { + return null; + } + + Class entryClass = Class.class.forName(clazz); + String key = "l_" + dn; + Object entry = cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); + if (entry == null) { + entry = persistenceEntryManager.find(entryClass, dn); + + cacheService.put(OxConstants.CACHE_LOOKUP_NAME, key, entry); + } + + return entry; + } + /** * Returns list of DisplayNameEntry objects * diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index 0cc0e6e0..2a393072 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -2,7 +2,8 @@ * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. * * Copyright (c) 2014, Gluu - */package org.gluu.service; + */ +package org.gluu.service; import java.util.Date; import java.util.Properties; diff --git a/oxService/src/main/java/org/gluu/service/OrganizationService.java b/oxService/src/main/java/org/gluu/service/OrganizationService.java index 11efdf2a..8a26dfad 100644 --- a/oxService/src/main/java/org/gluu/service/OrganizationService.java +++ b/oxService/src/main/java/org/gluu/service/OrganizationService.java @@ -9,6 +9,8 @@ import java.io.Serializable; +import org.gluu.model.ApplicationType; + /** * @author "Oleksiy Tataryn" * @@ -17,6 +19,8 @@ public abstract class OrganizationService implements Serializable { private static final long serialVersionUID = -6601700282123372943L; + public static final int ONE_MINUTE_IN_SECONDS = 60; + public String getDnForOrganization(String baseDn) { if (baseDn == null) { baseDn = "o=gluu"; @@ -24,4 +28,5 @@ public String getDnForOrganization(String baseDn) { return baseDn; } + public abstract ApplicationType getApplicationType(); } diff --git a/oxService/src/main/java/org/gluu/service/SchemaService.java b/oxService/src/main/java/org/gluu/service/SchemaService.java index fa33aecc..60d061f1 100644 --- a/oxService/src/main/java/org/gluu/service/SchemaService.java +++ b/oxService/src/main/java/org/gluu/service/SchemaService.java @@ -20,7 +20,7 @@ import org.gluu.model.SchemaEntry; import org.gluu.persist.PersistenceEntryManager; -import org.gluu.persist.hybrid.impl.HybridEntryManagerFactory; +import org.gluu.orm.hybrid.impl.HybridEntryManagerFactory; import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; import org.gluu.persist.ldap.operation.LdapOperationService; import org.gluu.util.StringHelper; diff --git a/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java index ba29a53e..5f664f4f 100644 --- a/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java +++ b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java @@ -66,9 +66,9 @@ public void executePersistenceExtensionAfterCreate(Properties connectionProperti persistenceExternalContext.setPersistenceEntryManager(persistenceEntryManager); executeExternalOnAfterCreateMethod(persistenceExternalContext); - - setPersistenceExtension(persistenceEntryManager); } + + setPersistenceExtension(persistenceEntryManager); } public void executePersistenceExtensionAfterDestroy(PersistenceEntryManager persistenceEntryManager) { diff --git a/oxService/src/main/java/org/gluu/service/logger/LoggerService.java b/oxService/src/main/java/org/gluu/service/logger/LoggerService.java index 286e4404..cb94ae7a 100644 --- a/oxService/src/main/java/org/gluu/service/logger/LoggerService.java +++ b/oxService/src/main/java/org/gluu/service/logger/LoggerService.java @@ -1,259 +1,292 @@ -package org.gluu.service.logger; - -import org.apache.commons.lang.StringUtils; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.ConsoleAppender; -import org.apache.logging.log4j.core.appender.RollingFileAppender; -import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.config.LoggerConfig; -import org.apache.logging.log4j.core.layout.JsonLayout; -import org.gluu.model.types.LoggingLayoutType; -import org.gluu.service.cdi.async.Asynchronous; -import org.gluu.service.cdi.event.ConfigurationUpdate; -import org.gluu.service.cdi.event.LoggerUpdateEvent; -import org.gluu.service.cdi.event.Scheduled; -import org.gluu.service.timer.event.TimerEvent; -import org.gluu.service.timer.schedule.TimerSchedule; -import org.gluu.util.StringHelper; -import org.slf4j.Logger; - -import javax.annotation.PostConstruct; -import javax.enterprise.event.Event; -import javax.enterprise.event.Observes; -import javax.inject.Inject; -import java.io.File; -import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.logging.LogManager; - -/** - * Logger service - * - * @author Yuriy Movchan Date: 08/19/2018 - */ -public abstract class LoggerService { - - private final static int DEFAULT_INTERVAL = 15; // 15 seconds - - @Inject - private Logger log; - - @Inject - private Event timerEvent; - - private AtomicBoolean isActive; - - @PostConstruct - public void create() { - this.isActive = new AtomicBoolean(false); - } - - public void initTimer() { - log.info("Initializing Logger Update Timer"); - - final int delay = 15; - final int interval = DEFAULT_INTERVAL; - - timerEvent.fire(new TimerEvent(new TimerSchedule(delay, interval), new LoggerUpdateEvent(), - Scheduled.Literal.INSTANCE)); - } - - @Asynchronous - public void updateLoggerTimerEvent(@Observes @Scheduled LoggerUpdateEvent loggerUpdateEvent) { - if (this.isActive.get()) { - return; - } - - if (!this.isActive.compareAndSet(false, true)) { - return; - } - - try { - updateLoggerConfiguration(); - } catch (Throwable ex) { - log.error("Exception happened while updating newly added logger configuration", ex); - } finally { - this.isActive.set(false); - } - } - - private void updateLoggerConfiguration() { - String loggingLevel = getLoggingLevel(); - if (StringHelper.isEmpty(loggingLevel)) { - return; - } - - Level level = Level.toLevel(loggingLevel, Level.INFO); - if (StringHelper.equalsIgnoreCase("DEFAULT", loggingLevel)) { - return; - } - if (StringUtils.isEmpty(this.getLoggingLayout())) { - return; - } - LoggingLayoutType loggingLayout = LoggingLayoutType.getByValue(this.getLoggingLayout().toUpperCase()); - if (loggingLayout == LoggingLayoutType.TEXT) { - final LoggerContext ctx = LoggerContext.getContext(false); - ctx.reconfigure(); - updateLoggers(level); - } else if (loggingLayout == LoggingLayoutType.JSON) { - updateAppendersToJson(level); - } - } - - public void updateLoggerSeverity(@Observes @ConfigurationUpdate Object appConfiguration) { - if (this.isActive.get()) { - return; - } - - if (!this.isActive.compareAndSet(false, true)) { - return; - } - - try { - updateLoggerSeverityImpl(); - } catch (Throwable ex) { - log.error("Exception happened while updating logger configuration after base configuration update", ex); - } finally { - this.isActive.set(false); - } - } - - public void updateLoggerSeverity() { - updateLoggerSeverityImpl(); - } - - private void updateLoggerSeverityImpl() { - if (isDisableJdkLogger()) { - disableJdkLogger(); - } - updateLoggerConfigLocation(); - - String loggingLevel = getLoggingLevel(); - if (StringHelper.isEmpty(loggingLevel)) { - return; - } - - log.info("Setting loggers level to: '{}'", loggingLevel); - if (StringHelper.equalsIgnoreCase("DEFAULT", loggingLevel)) { - log.info("Reloading log4j configuration"); - LoggerContext loggerContext = LoggerContext.getContext(false); - loggerContext.reconfigure(); - return; - } - - Level level = Level.toLevel(loggingLevel, Level.INFO); - updateLoggers(level); - } - - private void updateLoggers(Level level) { - LoggerContext loggerContext = LoggerContext.getContext(false); - - int count = 0; - for (org.apache.logging.log4j.core.Logger logger : loggerContext.getLoggers()) { - String loggerName = logger.getName(); - if (loggerName.startsWith("org.gluu")) { - if (logger.getLevel() != level) { - count++; - logger.setLevel(level); - } - } - } - - if (count > 0) { - log.info("Updated log level of '{}' loggers to {}", count, level.toString()); - } - } - - /** - * First trying to set external logger config from GluuAppliance. - * If there is no valid external path to log4j2.xml location then set default configuration. - */ - public void updateLoggerConfigLocation() { - if (setExternalLoggerConfig()) { - return; - } - - LoggerContext loggerContext = LoggerContext.getContext(false); - if (loggerContext.getConfigLocation() != null) { - loggerContext.setConfigLocation(null); - loggerContext.reconfigure(); - } - } - - private void disableJdkLogger() { - LogManager.getLogManager().reset(); - java.util.logging.Logger globalLogger = java.util.logging.Logger.getLogger(java.util.logging.Logger.GLOBAL_LOGGER_NAME); - if (globalLogger != null) { - globalLogger.setLevel(java.util.logging.Level.OFF); - } - } - - private boolean setExternalLoggerConfig() { - String externalLoggerConfiguration = getExternalLoggerConfiguration(); - log.info("External log configuration: {}", externalLoggerConfiguration); - if (StringUtils.isEmpty(externalLoggerConfiguration)) { - return false; - } - - File log4jFile = new File(externalLoggerConfiguration); - if (!log4jFile.exists()) { - log.info("External log configuration does not exist."); - return false; - } - - LoggerContext loggerContext = LoggerContext.getContext(false); - loggerContext.setConfigLocation(log4jFile.toURI()); - loggerContext.reconfigure(); - - return true; - } - - private void updateAppendersToJson(Level level) { - JsonLayout jsonLayout = JsonLayout.createDefaultLayout(); - - final LoggerContext ctx = LoggerContext.getContext(false); - - final Configuration config = ctx.getConfiguration(); - LoggerConfig loggerConfig = config.getLoggerConfig("root"); - for (Map.Entry appenderEntry : loggerConfig.getAppenders().entrySet()) { - if (appenderEntry.getValue() instanceof RollingFileAppender) { - RollingFileAppender rollingFile = (RollingFileAppender) appenderEntry.getValue(); - if (rollingFile.getLayout() instanceof JsonLayout) - return; - RollingFileAppender newFileAppender = RollingFileAppender.newBuilder() - .setLayout(jsonLayout) - .withStrategy(rollingFile.getManager().getRolloverStrategy()) - .withPolicy(rollingFile.getTriggeringPolicy()) - .withFileName(rollingFile.getFileName()) - .withFilePattern(rollingFile.getFilePattern()) - .setName(rollingFile.getName()) - .build(); - loggerConfig.removeAppender(appenderEntry.getKey()); - loggerConfig.addAppender(newFileAppender, level, null); - } else if (appenderEntry.getValue() instanceof ConsoleAppender) { - ConsoleAppender consoleAppender = (ConsoleAppender) appenderEntry.getValue(); - if (consoleAppender.getLayout() instanceof JsonLayout) - return; - ConsoleAppender newConsoleAppender = ConsoleAppender.newBuilder() - .setLayout(jsonLayout) - .setTarget(consoleAppender.getTarget()) - .setName(consoleAppender.getName()) - .build(); - loggerConfig.removeAppender(appenderEntry.getKey()); - loggerConfig.addAppender(newConsoleAppender, level, null); - } - } - ctx.updateLoggers(); - } - - public abstract boolean isDisableJdkLogger(); - - public abstract String getLoggingLevel(); - - public abstract String getExternalLoggerConfiguration(); - - public abstract String getLoggingLayout(); - -} +package org.gluu.service.logger; + +import org.apache.commons.lang.StringUtils; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.core.Appender; +import org.apache.logging.log4j.core.Layout; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.appender.AbstractAppender; +import org.apache.logging.log4j.core.appender.ConsoleAppender; +import org.apache.logging.log4j.core.appender.RollingFileAppender; +import org.apache.logging.log4j.core.config.AbstractConfiguration; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.layout.JsonLayout; +import org.apache.logging.log4j.core.layout.PatternLayout; +import org.gluu.model.types.LoggingLayoutType; +import org.gluu.service.cdi.async.Asynchronous; +import org.gluu.service.cdi.event.ConfigurationUpdate; +import org.gluu.service.cdi.event.LoggerUpdateEvent; +import org.gluu.service.cdi.event.Scheduled; +import org.gluu.service.timer.event.TimerEvent; +import org.gluu.service.timer.schedule.TimerSchedule; +import org.gluu.util.StringHelper; +import org.slf4j.Logger; + +import javax.annotation.PostConstruct; +import javax.enterprise.event.Event; +import javax.enterprise.event.Observes; +import javax.inject.Inject; +import java.io.File; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.LogManager; + +/** + * Logger service + * + * @author Yuriy Movchan Date: 08/19/2018 + */ +public abstract class LoggerService { + + private final static int DEFAULT_INTERVAL = 15; // 15 seconds + + @Inject + private Logger log; + + @Inject + private Event timerEvent; + + private AtomicBoolean isActive; + + @PostConstruct + public void create() { + this.isActive = new AtomicBoolean(false); + } + + public void initTimer() { + log.info("Initializing Logger Update Timer"); + + final int delay = 15; + final int interval = DEFAULT_INTERVAL; + + timerEvent.fire(new TimerEvent(new TimerSchedule(delay, interval), new LoggerUpdateEvent(), + Scheduled.Literal.INSTANCE)); + } + + @Asynchronous + public void updateLoggerTimerEvent(@Observes @Scheduled LoggerUpdateEvent loggerUpdateEvent) { + if (this.isActive.get()) { + return; + } + + if (!this.isActive.compareAndSet(false, true)) { + return; + } + + try { + updateLoggerConfiguration(); + } catch (Throwable ex) { + log.error("Exception happened while updating newly added logger configuration", ex); + } finally { + this.isActive.set(false); + } + } + + private void updateLoggerConfiguration() { + // Do periodic update to apply changes to new loggers as well + String loggingLevel = getLoggingLevel(); + if (StringHelper.isEmpty(loggingLevel) || StringUtils.isEmpty(this.getLoggingLayout()) + || StringHelper.equalsIgnoreCase("DEFAULT", loggingLevel)) { + return; + } + + Level level = Level.toLevel(loggingLevel, Level.INFO); + LoggingLayoutType loggingLayout = LoggingLayoutType.getByValue(this.getLoggingLayout().toUpperCase()); + + updateAppendersAndLogLevel(loggingLayout, level); + } + + public void updateLoggerSeverity(@Observes @ConfigurationUpdate Object appConfiguration) { + if (this.isActive.get()) { + return; + } + + if (!this.isActive.compareAndSet(false, true)) { + return; + } + + try { + updateLoggerSeverityImpl(); + } catch (Throwable ex) { + log.error("Exception happened while updating logger configuration after base configuration update", ex); + } finally { + this.isActive.set(false); + } + } + + public void updateLoggerSeverity() { + // Full log4j2 configuration reload + updateLoggerSeverityImpl(); + } + + private void updateLoggerSeverityImpl() { + setDisableJdkLogger(); + + if (setExternalLoggerConfig()) { + return; + } + + resetLoggerConfigLocation(); + + String loggingLevel = getLoggingLevel(); + if (StringHelper.isEmpty(loggingLevel) || StringUtils.isEmpty(this.getLoggingLayout()) + || StringHelper.equalsIgnoreCase("DEFAULT", loggingLevel)) { + return; + } + + Level level = Level.toLevel(loggingLevel, Level.INFO); + LoggingLayoutType loggingLayout = LoggingLayoutType.getByValue(this.getLoggingLayout().toUpperCase()); + + log.info("Setting layout and loggers level to '{}`, `{}' after configuration update", loggingLayout, loggingLevel); + + updateAppendersAndLogLevel(loggingLayout, level); + } + + private void setDisableJdkLogger() { + if (isDisableJdkLogger()) { + LogManager.getLogManager().reset(); + java.util.logging.Logger globalLogger = java.util.logging.Logger.getLogger(java.util.logging.Logger.GLOBAL_LOGGER_NAME); + if (globalLogger != null) { + globalLogger.setLevel(java.util.logging.Level.OFF); + } + } + } + + private boolean setExternalLoggerConfig() { + String externalLoggerConfiguration = getExternalLoggerConfiguration(); + log.info("External log configuration: {}", externalLoggerConfiguration); + if (StringUtils.isEmpty(externalLoggerConfiguration)) { + return false; + } + + File log4jFile = new File(externalLoggerConfiguration); + if (!log4jFile.exists()) { + log.info("External log configuration does not exist."); + return false; + } + + LoggerContext loggerContext = LoggerContext.getContext(false); + loggerContext.setConfigLocation(log4jFile.toURI()); + loggerContext.reconfigure(); + + return true; + } + + public void resetLoggerConfigLocation() { + log.info("Reloading log4j2 configuration"); + + LoggerContext loggerContext = LoggerContext.getContext(false); + if (loggerContext.getConfigLocation() != null) { + loggerContext.setConfigLocation(null); + } + loggerContext.reconfigure(); + } + + private void updateAppendersAndLogLevel(LoggingLayoutType loggingLayout, Level level) { + if (loggingLayout == LoggingLayoutType.TEXT) { + final LoggerContext ctx = LoggerContext.getContext(false); + ctx.reconfigure(); + LoggerContext loggerContext = LoggerContext.getContext(false); + + int count = 0; + for (org.apache.logging.log4j.core.Logger logger : loggerContext.getLoggers()) { + String loggerName = logger.getName(); + if (loggerName.startsWith("org.gluu")) { + if (logger.getLevel() != level) { + count++; + logger.setLevel(level); + } + } + } + + if (count > 0) { + log.info("Updated log level of '{}' loggers to {}", count, level.toString()); + } + } +// boolean runLoggersUpdate = false; +// int loggerConfigUpdates = 0; +// int appenderConfigUpdates = 0; +// LoggerContext ctx = LoggerContext.getContext(false); +// +// AbstractConfiguration config = (AbstractConfiguration) ctx.getConfiguration(); +// for (Entry loggerConfigEntry : config.getLoggers().entrySet()) { +// LoggerConfig loggerConfig = loggerConfigEntry.getValue(); +// log.trace("Updating log configuration '{}'", loggerConfig.getName()); +// +// if (!loggerConfig.getLevel().equals(level)) { +// loggerConfig.setLevel(level); +// log.trace("Updating log level in configuration '{}' to '{}'", loggerConfig.getName(), level); +// runLoggersUpdate = true; +// loggerConfigUpdates++; +// } +// +// for (Map.Entry appenderEntry : loggerConfig.getAppenders().entrySet()) { +// Appender appender = appenderEntry.getValue(); +// log.trace("Updating appender '{}'", appender.getName()); +// +// Layout layout = appender.getLayout(); +// if (loggingLayout == LoggingLayoutType.TEXT) { +// layout = PatternLayout.newBuilder().withPattern("%d %-5p [%t] [%C{6}] (%F:%L) - %m%n").build(); +// } else if (loggingLayout == LoggingLayoutType.JSON) { +// layout = JsonLayout.createDefaultLayout(); +// } +// +// if (appender instanceof RollingFileAppender) { +// RollingFileAppender rollingFile = (RollingFileAppender) appender; +// if (rollingFile.getLayout().getClass().isAssignableFrom(layout.getClass())) { +// continue; +// } +// RollingFileAppender newFileAppender = RollingFileAppender.newBuilder() +// .setLayout(layout) +// .withStrategy(rollingFile.getManager().getRolloverStrategy()) +// .withPolicy(rollingFile.getTriggeringPolicy()) +// .withFileName(rollingFile.getFileName()) +// .withFilePattern(rollingFile.getFilePattern()) +// .setName(rollingFile.getName()) +// .build(); +// newFileAppender.start(); +// appender.stop(); +// loggerConfig.removeAppender(appenderEntry.getKey()); +// loggerConfig.addAppender(newFileAppender, null, null); +// +// runLoggersUpdate = true; +// appenderConfigUpdates++; +// } else if (appender instanceof ConsoleAppender) { +// ConsoleAppender consoleAppender = (ConsoleAppender) appender; +// if (consoleAppender.getLayout().getClass().isAssignableFrom(layout.getClass())) { +// continue; +// } +// +// ConsoleAppender newConsoleAppender = ConsoleAppender.newBuilder() +// .setLayout(layout) +// .setTarget(consoleAppender.getTarget()) +// .setName(consoleAppender.getName()) +// .build(); +// newConsoleAppender.start(); +// appender.stop(); +// loggerConfig.removeAppender(appenderEntry.getKey()); +// loggerConfig.addAppender(newConsoleAppender, null, null); +// +// runLoggersUpdate = true; +// appenderConfigUpdates++; +// } +// } +// } +// +// if (runLoggersUpdate) { +// log.trace("Trigger loggers update after '{}' updates", loggerConfigUpdates + appenderConfigUpdates); +// ctx.updateLoggers(); +// } + } + + public abstract boolean isDisableJdkLogger(); + + public abstract String getLoggingLevel(); + + public abstract String getExternalLoggerConfiguration(); + + public abstract String getLoggingLayout(); + +} diff --git a/oxService/src/main/java/org/gluu/service/metric/LdapEntryReporter.java b/oxService/src/main/java/org/gluu/service/metric/LdapEntryReporter.java index ca227682..0cd9c40f 100644 --- a/oxService/src/main/java/org/gluu/service/metric/LdapEntryReporter.java +++ b/oxService/src/main/java/org/gluu/service/metric/LdapEntryReporter.java @@ -243,6 +243,9 @@ private void addMandatoryAttributes(MetricService metricService, Date startTime, metricEntry.setEndDate(endTime); metricEntry.setCreationDate(creationTime); metricEntry.setExpirationDate(DateUtils.addDays(creationTime, metricService.getEntryLifetimeInDays())); + + int ttl = (int) ((metricEntry.getExpirationDate().getTime() - creationTime.getTime()) / 1000L); + metricEntry.setTtl(ttl); } } diff --git a/oxService/src/main/java/org/gluu/service/metric/MetricService.java b/oxService/src/main/java/org/gluu/service/metric/MetricService.java index fe504669..f93efc32 100644 --- a/oxService/src/main/java/org/gluu/service/metric/MetricService.java +++ b/oxService/src/main/java/org/gluu/service/metric/MetricService.java @@ -169,7 +169,7 @@ public void remove(MetricEntry metricEntry) { } public void removeBranch(String branchDn) { - getEntryManager().removeRecursively(branchDn); + getEntryManager().removeRecursively(branchDn, SimpleBranch.class); } public MetricEntry getMetricEntryByDn(MetricType metricType, String metricEventDn) { @@ -223,9 +223,15 @@ public Map> findMetricEntry(ApplicationT return result; } - public List getExpiredMetricEntries(DefaultBatchOperation batchOperation, String baseDnForPeriod, Date expirationDate, + public List getExpiredMetricEntries(DefaultBatchOperation batchOperation, ApplicationType applicationType, String baseDnForPeriod, Date expirationDate, int count, int chunkSize) { - Filter expiratioFilter = Filter.createLessOrEqualFilter("oxStartDate", getEntryManager().encodeTime(baseDnForPeriod, expirationDate)); + Filter expiratioStartDateFilter = Filter.createLessOrEqualFilter("oxStartDate", getEntryManager().encodeTime(baseDnForPeriod, expirationDate)); + Filter expiratioFilter = expiratioStartDateFilter; + + if (applicationType != null) { + Filter applicationTypeFilter = Filter.createEqualityFilter("oxMetricType", applicationType.getValue()); + expiratioFilter = Filter.createANDFilter(expiratioStartDateFilter, applicationTypeFilter); + } List metricEntries = getEntryManager().findEntries(baseDnForPeriod, MetricEntry.class, expiratioFilter, SearchScope.SUB, new String[] { "uniqueIdentifier" }, batchOperation, 0, count, chunkSize); @@ -244,7 +250,7 @@ public List findAllPeriodBranches(DefaultBatchOperation keepBaseDnForPeriod = getBaseDnForPeriod(applicationType, expirationDate, new Date()); // Remove expired entries @@ -262,33 +268,35 @@ public void performAction(List entries) { } } }; - getExpiredMetricEntries(metricEntryBatchOperation, baseDnForPeriod, expirationDate, count, chunkSize); + getExpiredMetricEntries(metricEntryBatchOperation, applicationType, baseDnForPeriod, expirationDate, count, chunkSize); } - DefaultBatchOperation batchOperation = new DefaultBatchOperation() { - @Override - public boolean collectSearchResult(int size) { - return false; - } - - @Override - public void performAction(List objects) { - String baseDn = buildDn(null, null, applicationType); - Set periodBranchesStrings = new HashSet(); - for (SimpleBranch periodBranch : objects) { - if (!StringHelper.equalsIgnoreCase(baseDn, periodBranch.getDn())) { - periodBranchesStrings.add(periodBranch.getDn()); - } - } - periodBranchesStrings.removeAll(keepBaseDnForPeriod); - - // Remove expired months - for (String baseDnForPeriod : periodBranchesStrings) { - removeBranch(baseDnForPeriod); - } - } - }; - findAllPeriodBranches(batchOperation, applicationType, count, chunkSize); + if (!getEntryManager().hasBranchesSupport(buildDn(null, null, applicationType))) { + DefaultBatchOperation batchOperation = new DefaultBatchOperation() { + @Override + public boolean collectSearchResult(int size) { + return false; + } + + @Override + public void performAction(List objects) { + String baseDn = buildDn(null, null, applicationType); + Set periodBranchesStrings = new HashSet(); + for (SimpleBranch periodBranch : objects) { + if (!StringHelper.equalsIgnoreCase(baseDn, periodBranch.getDn())) { + periodBranchesStrings.add(periodBranch.getDn()); + } + } + periodBranchesStrings.removeAll(keepBaseDnForPeriod); + + // Remove expired months + for (String baseDnForPeriod : periodBranchesStrings) { + removeBranch(baseDnForPeriod); + } + } + }; + findAllPeriodBranches(batchOperation, applicationType, count, chunkSize); + } } private Set getBaseDnForPeriod(ApplicationType applicationType, Date startDate, Date endDate) { diff --git a/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeBenchmarkCacheTest.java b/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeBenchmarkCacheTest.java index 29620c32..7a00f031 100644 --- a/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeBenchmarkCacheTest.java +++ b/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeBenchmarkCacheTest.java @@ -10,8 +10,8 @@ import java.util.Properties; import java.util.UUID; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManagerFactory; +import org.gluu.orm.couchbase.impl.CouchbaseEntryManager; +import org.gluu.orm.couchbase.impl.CouchbaseEntryManagerFactory; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; diff --git a/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeCacheTest.java b/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeCacheTest.java index 2d8d418f..e3a40b2c 100644 --- a/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeCacheTest.java +++ b/oxService/src/test/java/org/gluu/service/cache/CouchbaseNativeCacheTest.java @@ -1,7 +1,7 @@ package org.gluu.service.cache; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManagerFactory; +import org.gluu.orm.couchbase.impl.CouchbaseEntryManager; +import org.gluu.orm.couchbase.impl.CouchbaseEntryManagerFactory; import org.testng.annotations.Test; import java.io.IOException; diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index 900e25ba..80fb228d 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -9,13 +9,13 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final org.gluu - oxcore-persistence-annotation + gluu-orm-annotation diff --git a/oxUtil/src/main/java/org/gluu/net/ProxyUtil.java b/oxUtil/src/main/java/org/gluu/net/ProxyUtil.java new file mode 100644 index 00000000..fa9e35c4 --- /dev/null +++ b/oxUtil/src/main/java/org/gluu/net/ProxyUtil.java @@ -0,0 +1,17 @@ +package org.gluu.net; + +import org.apache.commons.lang3.StringUtils; + +/** + * Proxy utilities + * + * @author Yuriy Movchan + * @version 1.0, 08/27/2021 + */ +public class ProxyUtil { + + public static boolean isProxyRequied() { + return (StringUtils.isNotBlank(System.getProperty("http.proxyHost")) && StringUtils.isNotBlank(System.getProperty("http.proxyPort"))) + || (StringUtils.isNotBlank(System.getProperty("https.proxyHost")) && StringUtils.isNotBlank(System.getProperty("https.proxyPort"))); + } +} diff --git a/oxUtil/src/main/java/org/gluu/util/init/Initializable.java b/oxUtil/src/main/java/org/gluu/util/init/Initializable.java index 2cced6ae..04b60a66 100644 --- a/oxUtil/src/main/java/org/gluu/util/init/Initializable.java +++ b/oxUtil/src/main/java/org/gluu/util/init/Initializable.java @@ -43,4 +43,7 @@ public boolean isInitialized() { protected abstract void initInternal(); + protected void resetInitialized() { + this.initialized = false; + } } diff --git a/oxUtil/src/main/java/org/gluu/util/security/StringEncrypter.java b/oxUtil/src/main/java/org/gluu/util/security/StringEncrypter.java index ef64ad28..e1abf941 100644 --- a/oxUtil/src/main/java/org/gluu/util/security/StringEncrypter.java +++ b/oxUtil/src/main/java/org/gluu/util/security/StringEncrypter.java @@ -108,12 +108,8 @@ public EncryptionException(final Throwable t) { * Byte stream * @return String representation */ - private static String bytes2String(final byte[] bytes) { - final StringBuffer stringBuffer = new StringBuffer(); - for (final byte element : bytes) { - stringBuffer.append((char) element); - } - return stringBuffer.toString(); + private static String bytes2String(final byte[] bytes) throws UnsupportedEncodingException { + return new String(bytes, Util.UTF8); } /** @@ -210,7 +206,7 @@ private String decrypt(final String encryptedString, KeySpec keySpec, boolean si final byte[] cleartext = base64.decode(encryptedString.getBytes(Util.UTF8)); final byte[] ciphertext = cipher.doFinal(cleartext); - return StringEncrypter.bytes2String(ciphertext); + return bytes2String(ciphertext); } catch (final Exception e) { if (silent) { return encryptedString; diff --git a/persistence-annotation/pom.xml b/persistence-annotation/pom.xml deleted file mode 100644 index 6187e81e..00000000 --- a/persistence-annotation/pom.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - 4.0.0 - oxcore-persistence-annotation - jar - persistence-annotation - - - org.gluu - oxcore - 5.0.0-SNAPSHOT - - - \ No newline at end of file diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributeEnum.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributeEnum.java deleted file mode 100644 index 12ae84e0..00000000 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributeEnum.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.annotation; - -/** - * Base interface for Persistance enumerations - * - * @author Yuriy Movchan Date: 10.07.2010 - */ -public interface AttributeEnum { - - String getValue(); - - Enum resolveByValue(String value); - -} diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributeName.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributeName.java deleted file mode 100644 index a3c2e3da..00000000 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributeName.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Persistance Attribute - * - * @author Yuriy Movchan Date: 10.07.2010 - */ -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface AttributeName { - - /** - * (Optional) The name of the Persistance attribute. Defaults to the field name. - */ - String name() default ""; - - /** - * (Optional) Specify that we ignore this Persistance attribute during read. - * Defaults value is false. - */ - boolean ignoreDuringRead() default false; - - /** - * (Optional) Specify that we ignore this Persistance attribute during update. - * Defaults value is false. - */ - boolean ignoreDuringUpdate() default false; - - /** - * (Optional) Specify that we will only update this attribute, and never - * remove it (set to null). Use this with health status attributes. - */ - boolean updateOnly() default false; - - /** - * (Optional) Specify that search request should wait for indexes update - * Defaults value is false. - */ - boolean consistency() default false; -} diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributesList.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributesList.java deleted file mode 100644 index 3e5e3578..00000000 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/AttributesList.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Persistance Attributes List - * - * @author Yuriy Movchan Date: 10.07.2010 - */ -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface AttributesList { - - /** - * (Required) The class property name which contains Persistance attribute name. - */ - String name(); - - /** - * (Required) The class property name which contains Persistance attribute value. - */ - String value(); - - /** - * (Optional) The class property name which contains Persistance attribute value. - */ - String multiValued() default ""; - - /** - * (Optional) Holds additional configuration for Persistance attributes. Defaults - * value not provides additional configuration. - */ - AttributeName[] attributesConfiguration() default {}; - - /** - * (Optional) Specify if attributes should be sorted by property name value. - */ - boolean sortByName() default false; - -} diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/CustomObjectClass.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/CustomObjectClass.java deleted file mode 100644 index c88980b2..00000000 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/CustomObjectClass.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Persistance Object Class - * - * @author Yuriy Movchan Date: 10.21.2010 - */ -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface CustomObjectClass { -} diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/DN.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/DN.java deleted file mode 100644 index ef0f42a9..00000000 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/DN.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * Persistance DN - * - * @author Yuriy Movchan Date: 10.07.2010 - */ -@Target({ FIELD }) -@Retention(RUNTIME) -public @interface DN { -} diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/DataEntry.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/DataEntry.java deleted file mode 100644 index f8622ad1..00000000 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/DataEntry.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Mark POJO class as Persistance entry - * - * @author Yuriy Movchan Date: 10.07.2010 - */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface DataEntry { - - /** - * (Optional) Specify that this entry contains LDAP configuration definition. - */ - boolean configurationDefinition() default false; - - /** - * (Optional) Specify sortBy properties to sort by default list of Entries. - */ - String[] sortBy() default {}; - -} diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/Expiration.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/Expiration.java deleted file mode 100644 index f79e7f2d..00000000 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/Expiration.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -/** - * Persistance Expiration - * - * @author Yuriy Movchan Date: 03/26/2020 - */ -@Target({ FIELD }) -@Retention(RUNTIME) -public @interface Expiration { -} diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/JsonObject.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/JsonObject.java deleted file mode 100644 index 9b5c1173..00000000 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/JsonObject.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Persistance Json Object - * - * @author Yuriy Movchan Date: 01/31/2014 - */ -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface JsonObject { -} diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/ObjectClass.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/ObjectClass.java deleted file mode 100644 index 19ab786e..00000000 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/ObjectClass.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Persistance Object Class - * - * @author Yuriy Movchan Date: 10.07.2010 - */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface ObjectClass { - - @Deprecated // TODO: Remove it in 4.0 - String[] values() default {}; - - String value() default ""; -} diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/Password.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/Password.java deleted file mode 100644 index 20f581f7..00000000 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/Password.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Mark that attribute contains password - * - * @author Yuriy Movchan Date: 05/15/2018 - */ -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface Password { -} diff --git a/persistence-annotation/src/main/java/org/gluu/persist/annotation/SchemaEntry.java b/persistence-annotation/src/main/java/org/gluu/persist/annotation/SchemaEntry.java deleted file mode 100644 index 7ef04de8..00000000 --- a/persistence-annotation/src/main/java/org/gluu/persist/annotation/SchemaEntry.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Mark POJO class as Persistance schema entry - * - * @author Yuriy Movchan Date: 10.07.2010 - */ -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface SchemaEntry { -} diff --git a/persistence-cdi/pom.xml b/persistence-cdi/pom.xml deleted file mode 100644 index 013e121d..00000000 --- a/persistence-cdi/pom.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - 4.0.0 - oxcore-persistence-cdi - Persistence CDI services - - - org.gluu - oxcore - 5.0.0-SNAPSHOT - - - - ${maven.min-version} - - - - - - src/main/resources - true - - **/*.xml - **/services/* - **/*.properties - - - - - - - - org.gluu - oxcore-persistence-core - - - org.gluu - oxcore-persistence-annotation - - - org.gluu - oxcore-persistence-ldap - - - org.slf4j - slf4j-simple - - - - - javax.enterprise - cdi-api - provided - - - - \ No newline at end of file diff --git a/persistence-cdi/src/main/java/org/gluu/persist/service/PersistanceFactoryService.java b/persistence-cdi/src/main/java/org/gluu/persist/service/PersistanceFactoryService.java deleted file mode 100644 index 80f72ef6..00000000 --- a/persistence-cdi/src/main/java/org/gluu/persist/service/PersistanceFactoryService.java +++ /dev/null @@ -1,233 +0,0 @@ -package org.gluu.persist.service; - -import java.io.File; -import java.util.Iterator; -import java.util.Map; - -import javax.enterprise.context.ApplicationScoped; -import javax.enterprise.inject.Instance; -import javax.enterprise.inject.Produces; -import javax.inject.Inject; - -import org.apache.commons.configuration.PropertiesConfiguration; -import org.gluu.persist.PersistenceEntryManagerFactory; -import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; -import org.gluu.persist.model.PersistenceConfiguration; -import org.gluu.util.StringHelper; -import org.gluu.util.properties.FileConfiguration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Factory which creates Persistence Entry Manager - * - * @author Yuriy Movchan Date: 05/10/2019 - */ -@ApplicationScoped -public class PersistanceFactoryService implements BaseFactoryService { - - static { - if (System.getProperty("gluu.base") != null) { - BASE_DIR = System.getProperty("gluu.base"); - } else if ((System.getProperty("catalina.base") != null) && (System.getProperty("catalina.base.ignore") == null)) { - BASE_DIR = System.getProperty("catalina.base"); - } else if (System.getProperty("catalina.home") != null) { - BASE_DIR = System.getProperty("catalina.home"); - } else if (System.getProperty("jboss.home.dir") != null) { - BASE_DIR = System.getProperty("jboss.home.dir"); - } else { - BASE_DIR = null; - } - } - - public static final String BASE_DIR; - public static final String DIR = BASE_DIR + File.separator + "conf" + File.separator; - private static final String GLUU_FILE_PATH = DIR + "gluu.properties"; - - @Inject - private Logger log; - - @Inject - private Instance persistenceEntryManagerFactoryInstance; - - @Override - public PersistenceConfiguration loadPersistenceConfiguration() { - return loadPersistenceConfiguration(null); - } - - @Override - public PersistenceConfiguration loadPersistenceConfiguration(String applicationPropertiesFile) { - PersistenceConfiguration currentPersistenceConfiguration = null; - - String gluuFileName = determineGluuConfigurationFileName(applicationPropertiesFile); - if (gluuFileName != null) { - currentPersistenceConfiguration = createPersistenceConfiguration(gluuFileName); - } - - // Fall back to old LDAP persistence layer - if (currentPersistenceConfiguration == null) { - getLog().warn("Failed to load persistence configuration. Attempting to use LDAP layer"); - PersistenceEntryManagerFactory defaultEntryManagerFactory = getPersistenceEntryManagerFactory(LdapEntryManagerFactory.class); - currentPersistenceConfiguration = createPersistenceConfiguration(defaultEntryManagerFactory.getPersistenceType(), LdapEntryManagerFactory.class, - defaultEntryManagerFactory.getConfigurationFileNames()); - } - - return currentPersistenceConfiguration; - } - - private PersistenceConfiguration createPersistenceConfiguration(String gluuFileName) { - try { - // Determine persistence type - FileConfiguration gluuFileConf = new FileConfiguration(gluuFileName); - if (!gluuFileConf.isLoaded()) { - getLog().error("Unable to load configuration file '{}'", gluuFileName); - return null; - } - - String persistenceType = gluuFileConf.getString("persistence.type"); - PersistenceEntryManagerFactory persistenceEntryManagerFactory = getPersistenceEntryManagerFactory(persistenceType); - if (persistenceEntryManagerFactory == null) { - getLog().error("Unable to get Persistence Entry Manager Factory by type '{}'", persistenceType); - return null; - } - - // Determine configuration file name and factory class type - Class persistenceEntryManagerFactoryType = (Class) persistenceEntryManagerFactory.getClass(); - if (PersistenceEntryManagerFactory.class.isAssignableFrom(persistenceEntryManagerFactoryType.getSuperclass())) { - persistenceEntryManagerFactoryType = (Class) persistenceEntryManagerFactoryType.getSuperclass(); - } - Map persistenceFileNames = persistenceEntryManagerFactory.getConfigurationFileNames(); - - PersistenceConfiguration persistenceConfiguration = createPersistenceConfiguration(persistenceType, persistenceEntryManagerFactoryType, - persistenceFileNames); - - return persistenceConfiguration; - } catch (Exception e) { - getLog().error(e.getMessage(), e); - } - - return null; - } - - private PersistenceConfiguration createPersistenceConfiguration(String persistenceType, Class persistenceEntryManagerFactoryType, - Map persistenceFileNames) { - if (persistenceFileNames == null) { - getLog().error("Unable to get Persistence Entry Manager Factory by type '{}'", persistenceType); - return null; - } - - PropertiesConfiguration mergedPropertiesConfiguration = new PropertiesConfiguration(); - long mergedPersistenceFileLastModifiedTime = -1; - StringBuilder mergedPersistenceFileName = new StringBuilder(); - - for (String prefix : persistenceFileNames.keySet()) { - String persistenceFileName = persistenceFileNames.get(prefix); - - // Build merged file name - if (mergedPersistenceFileName.length() > 0) { - mergedPersistenceFileName.append("!"); - } - mergedPersistenceFileName.append(persistenceFileName); - - // Find last changed file modification time - String persistenceFileNamePath = DIR + persistenceFileName; - File persistenceFile = new File(persistenceFileNamePath); - if (!persistenceFile.exists()) { - getLog().error("Unable to load configuration file '{}'", persistenceFileNamePath); - return null; - } - mergedPersistenceFileLastModifiedTime = Math.max(mergedPersistenceFileLastModifiedTime, persistenceFile.lastModified()); - - // Load persistence configuration - FileConfiguration persistenceFileConf = new FileConfiguration(persistenceFileNamePath); - if (!persistenceFileConf.isLoaded()) { - getLog().error("Unable to load configuration file '{}'", persistenceFileNamePath); - return null; - } - PropertiesConfiguration propertiesConfiguration = persistenceFileConf.getPropertiesConfiguration(); - - // Allow to override value via environment variables - replaceWithSystemValues(propertiesConfiguration); - - // Merge all configuration into one with prefix - appendPropertiesWithPrefix(mergedPropertiesConfiguration, propertiesConfiguration, prefix); - } - - FileConfiguration mergedFileConfiguration = new FileConfiguration(mergedPersistenceFileName.toString(), mergedPropertiesConfiguration); - - PersistenceConfiguration persistenceConfiguration = new PersistenceConfiguration(mergedPersistenceFileName.toString(), mergedFileConfiguration, - persistenceEntryManagerFactoryType, mergedPersistenceFileLastModifiedTime); - - return persistenceConfiguration; - } - - private void replaceWithSystemValues(PropertiesConfiguration propertiesConfiguration) { - Iterator keys = propertiesConfiguration.getKeys(); - while (keys.hasNext()) { - String key = (String) keys.next(); - if (System.getenv(key) != null) { - propertiesConfiguration.setProperty(key, System.getenv(key)); - } - } - } - - private void appendPropertiesWithPrefix(PropertiesConfiguration mergedConfiguration, PropertiesConfiguration appendConfiguration, String prefix) { - Iterator keys = appendConfiguration.getKeys(); - while (keys.hasNext()) { - String key = (String) keys.next(); - Object value = appendConfiguration.getProperty(key); - mergedConfiguration.setProperty(prefix + "." + key, value); - } - } - - private String determineGluuConfigurationFileName(String applicationPropertiesFile) { - String applicationFilePath = DIR + applicationPropertiesFile; - File applicationFile = new File(applicationFilePath); - if (applicationFile.exists()) { - return applicationFilePath; - } - - File ldapFile = new File(GLUU_FILE_PATH); - if (ldapFile.exists()) { - return GLUU_FILE_PATH; - } - - return null; - } - - @Override - public PersistenceEntryManagerFactory getPersistenceEntryManagerFactory(PersistenceConfiguration persistenceConfiguration) { - return getPersistenceEntryManagerFactory(persistenceConfiguration.getEntryManagerFactoryType()); - } - - @Override - public PersistenceEntryManagerFactory getPersistenceEntryManagerFactory(Class persistenceEntryManagerFactoryClass) { - PersistenceEntryManagerFactory persistenceEntryManagerFactory = persistenceEntryManagerFactoryInstance - .select(persistenceEntryManagerFactoryClass).get(); - - return persistenceEntryManagerFactory; - } - - @Override - public PersistenceEntryManagerFactory getPersistenceEntryManagerFactory(String persistenceType) { - // Get persistence entry manager factory - for (PersistenceEntryManagerFactory currentPersistenceEntryManagerFactory : persistenceEntryManagerFactoryInstance) { - log.debug("Found Persistence Entry Manager Factory with type '{}'", currentPersistenceEntryManagerFactory); - if (StringHelper.equalsIgnoreCase(currentPersistenceEntryManagerFactory.getPersistenceType(), persistenceType)) { - return currentPersistenceEntryManagerFactory; - } - } - - return null; - } - - @Override - public Logger getLog() { - if (this.log == null) { - this.log = LoggerFactory.getLogger(PersistanceFactoryService.class); - } - - return this.log; - - } -} diff --git a/persistence-cdi/src/main/resources/META-INF/beans.xml b/persistence-cdi/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 2f4f7e27..00000000 --- a/persistence-cdi/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/persistence-cdi/src/test/java/org/gluu/persist/service/test/.gitignore b/persistence-cdi/src/test/java/org/gluu/persist/service/test/.gitignore deleted file mode 100644 index eabb0d0d..00000000 --- a/persistence-cdi/src/test/java/org/gluu/persist/service/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/manual/ diff --git a/persistence-core/docs/LDAP to Couchbase data mapping.png b/persistence-core/docs/LDAP to Couchbase data mapping.png deleted file mode 100644 index ac923958b91ed67bf4fcd82d0de3e69271beba55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 320788 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

TgmUx(iDN>Tf(9ZmQOI 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 z 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 diff --git a/persistence-core/docs/Persistent layer design.png b/persistence-core/docs/Persistent layer design.png deleted file mode 100644 index 4fdaded5461fe87bbdc859755be91fa24bba42fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 59183 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�L5oXp@FQ##27c?VT$Z7#$n;T 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

JU$1|YtDZ2h$3Ys4B%f%6&Kd;F@P86FrUqZ-3 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 Y$%kHXVSlEHKl{-8f9FntP)|Am0O?!tK>z>% diff --git a/persistence-core/docs/src/ldap_tree.png b/persistence-core/docs/src/ldap_tree.png deleted file mode 100644 index e9b989491053b23f6ecae39ba5ee5466c3141a47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71733 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 z 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 - - 4.0.0 - oxcore-persistence-core - jar - persistence-core - - - org.gluu - oxcore - 5.0.0-SNAPSHOT - - - - - - src/main/resources - - **/*.json - **/*.xml - **/*.yml - **/*.properties - - - - - - src/test/resources - - **/*.json - **/*.xml - **/*.yml - **/*.properties - - - - - - - - org.gluu - oxcore-util - - - org.gluu - oxcore-persistence-filter - - - org.gluu - oxcore-persistence-model - - - org.gluu - oxcore-persistence-annotation - - - - - org.testng - testng - - - - \ No newline at end of file diff --git a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java deleted file mode 100644 index 0584f78a..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManager.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist; - -import java.util.Date; -import java.util.List; -import java.util.Map; - -import javax.persistence.EntityManager; -import javax.persistence.EntityTransaction; -import javax.persistence.FlushModeType; -import javax.persistence.LockModeType; -import javax.persistence.Query; - -import org.gluu.persist.event.DeleteNotifier; -import org.gluu.persist.exception.extension.PersistenceExtension; -import org.gluu.persist.model.AttributeData; -import org.gluu.persist.model.BatchOperation; -import org.gluu.persist.model.PagedResult; -import org.gluu.persist.model.SearchScope; -import org.gluu.persist.model.SortOrder; -import org.gluu.persist.operation.PersistenceOperationService; -import org.gluu.search.filter.Filter; - -/** - * Methods which Entry Manager must provide - * - * @author Yuriy Movchan Date: 01/29/2018 - */ -public interface PersistenceEntryManager extends EntityManager { - - boolean authenticate(String primaryKey, String password); - boolean authenticate(String baseDN, Class entryClass, String userName, String password); - - void persist(Object entry); - - Void merge(Object entry); - - @Deprecated - boolean contains(Object entity); - - boolean contains(String primaryKey, Class entryClass); - boolean contains(String primaryKey, Class entryClass, Filter filter); - - int countEntries(Object entry); - - int countEntries(String primaryKey, Class entryClass, Filter filter); - int countEntries(String primaryKey, Class entryClass, Filter filter, SearchScope scope); - - List createEntities(Class entryClass, Map> entriesAttributes); - - T find(Object primaryKey, Class entryClass, String[] ldapReturnAttributes); - - /** - * Search by sample - * - * @param entry Sample - * @return Result entries - */ - List findEntries(Object entry); - List findEntries(Object entry, int count); - - List findEntries(String primaryKey, Class entryClass, Filter filter); - List findEntries(String primaryKey, Class entryClass, Filter filter, int count); - List findEntries(String primaryKey, Class entryClass, Filter filter, String[] ldapReturnAttributes); - List findEntries(String primaryKey, Class entryClass, Filter filter, String[] ldapReturnAttributes, int count); - List findEntries(String primaryKey, Class entryClass, Filter filter, SearchScope scope, String[] ldapReturnAttributes, - int start, int count, int chunkSize); - List findEntries(String primaryKey, Class entryClass, Filter filter, SearchScope scope, String[] ldapReturnAttributes, - BatchOperation batchOperation, int start, int count, int chunkSize); - - // TODO: Combine sortBy and SortOrder into Sort - PagedResult findPagedEntries(String primaryKey, Class entryClass, Filter filter, String[] ldapReturnAttributes, String sortBy, - SortOrder sortOrder, int start, int count, int chunkSize); - - void remove(Object entry); - void remove(String dn); - int remove(String dn, Class entryClass, Filter filter, int count); - void removeRecursively(String primaryKey); - - boolean hasBranchesSupport(String primaryKey); - boolean hasExpirationSupport(String primaryKey); - String getPersistenceType(); - String getPersistenceType(String primaryKey); - - Date decodeTime(String primaryKey, String date); - String encodeTime(String primaryKey, Date date); - - int getHashCode(Object entry); - - String[] getObjectClasses(Object entry, Class entryClass); - - Map> groupListByProperties(Class entryClass, List entries, boolean caseSensetive, String groupByProperties, - String sumByProperties); - - void addDeleteSubscriber(DeleteNotifier subscriber); - void removeDeleteSubscriber(DeleteNotifier subscriber); - - void sortListByProperties(Class entryClass, List entries, boolean caseSensetive, String... sortByProperties); - - List exportEntry(String dn); - - void importEntry(String dn, List data); - - PersistenceOperationService getOperationService(); - PersistenceEntryManager getPersistenceEntryManager(String persistenceType); - - void setPersistenceExtension(PersistenceExtension persistenceExtension); - - boolean destroy(); - - default void clear() { - throw new UnsupportedOperationException("Method not implemented."); - } - - default void close() { - throw new UnsupportedOperationException("Method not implemented."); - } - - default Query createNamedQuery(String name) { - throw new UnsupportedOperationException("Method not implemented."); - } - - default Query createNativeQuery(String sqlString) { - throw new UnsupportedOperationException("Method not implemented."); - } - - default Query createNativeQuery(String sqlString, @SuppressWarnings("rawtypes") Class resultClass) { - throw new UnsupportedOperationException("Method not implemented."); - } - - default Query createNativeQuery(String sqlString, String resultSetMapping) { - throw new UnsupportedOperationException("Method not implemented."); - } - - default Query createQuery(String qlString) { - throw new UnsupportedOperationException("Method not implemented."); - } - - default void flush() { - throw new UnsupportedOperationException("Method not implemented."); - } - - default Object getDelegate() { - throw new UnsupportedOperationException("Method not implemented."); - } - - default FlushModeType getFlushMode() { - throw new UnsupportedOperationException("Method not implemented."); - } - - default T getReference(Class entryClass, Object primaryKey) { - throw new UnsupportedOperationException("Method not implemented."); - } - - default EntityTransaction getTransaction() { - throw new UnsupportedOperationException("Method not implemented."); - } - - default boolean isOpen() { - throw new UnsupportedOperationException("Method not implemented."); - } - - default void joinTransaction() { - throw new UnsupportedOperationException("Method not implemented."); - } - - default void lock(Object entry, LockModeType lockMode) { - throw new UnsupportedOperationException("Method not implemented."); - } - - default void refresh(Object entry) { - throw new UnsupportedOperationException("Method not implemented."); - } - - default void setFlushMode(FlushModeType flushMode) { - throw new UnsupportedOperationException("Method not implemented."); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManagerFactory.java b/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManagerFactory.java deleted file mode 100644 index 14560814..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/PersistenceEntryManagerFactory.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist; - -import java.util.Map; -import java.util.Properties; - -import org.gluu.persist.service.BaseFactoryService; - -/** - * Factory which creates Persistence Entry Manager - * - * @author Yuriy Movchan Date: 02/02/2018 - */ -public interface PersistenceEntryManagerFactory { - - void initStandalone(BaseFactoryService persistanceFactoryService); - - String getPersistenceType(); - - Map getConfigurationFileNames(); - - PersistenceEntryManager createEntryManager(Properties conf); - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/event/DeleteNotifier.java b/persistence-core/src/main/java/org/gluu/persist/event/DeleteNotifier.java deleted file mode 100644 index a98b5679..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/event/DeleteNotifier.java +++ /dev/null @@ -1,15 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.event; - -public interface DeleteNotifier { - - void onBeforeRemove(String dn); - - void onAfterRemove(String dn); - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/AuthenticationException.java b/persistence-core/src/main/java/org/gluu/persist/exception/AuthenticationException.java deleted file mode 100644 index 943b5935..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/AuthenticationException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception; - -/** - * An exception is a result if user don't have required permissions or failed to authenticate him - * - * @author Yuriy Movchan Date: 10.26.2010 - */ -public class AuthenticationException extends EntryPersistenceException { - - private static final long serialVersionUID = -3321766232087075304L; - - public AuthenticationException(Throwable root) { - super(root); - } - - public AuthenticationException(String string, Throwable root) { - super(string, root); - } - - public AuthenticationException(String s) { - super(s); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/BasePersistenceException.java b/persistence-core/src/main/java/org/gluu/persist/exception/BasePersistenceException.java deleted file mode 100644 index 2e7048a3..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/BasePersistenceException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception; - -/** - * The base {@link Throwable} type for LDAP Mapping. - */ -public class BasePersistenceException extends RuntimeException { - - private static final long serialVersionUID = 1071769232087073304L; - - public BasePersistenceException(Throwable root) { - super(root); - } - - public BasePersistenceException(String string, Throwable root) { - super(string, root); - } - - public BasePersistenceException(String s) { - super(s); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/EntryDeleteException.java b/persistence-core/src/main/java/org/gluu/persist/exception/EntryDeleteException.java deleted file mode 100644 index 683e170a..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/EntryDeleteException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception; - -/** - * An exception is a result if LDAP entry defined incorrectly. - * - * @author Yuriy Movchan Date: 2019/08/26 - */ -public class EntryDeleteException extends BasePersistenceException { - - private static final long serialVersionUID = 1321766232087075304L; - - public EntryDeleteException(Throwable root) { - super(root); - } - - public EntryDeleteException(String string, Throwable root) { - super(string, root); - } - - public EntryDeleteException(String s) { - super(s); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/EntryPersistenceException.java b/persistence-core/src/main/java/org/gluu/persist/exception/EntryPersistenceException.java deleted file mode 100644 index f21a7d90..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/EntryPersistenceException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception; - -/** - * An exception is a result if LDAP entry defined incorrectly. - * - * @author Yuriy Movchan Date: 10.07.2010 - */ -public class EntryPersistenceException extends BasePersistenceException { - - private static final long serialVersionUID = 1321766232087075304L; - - public EntryPersistenceException(Throwable root) { - super(root); - } - - public EntryPersistenceException(String string, Throwable root) { - super(string, root); - } - - public EntryPersistenceException(String s) { - super(s); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/InvalidArgumentException.java b/persistence-core/src/main/java/org/gluu/persist/exception/InvalidArgumentException.java deleted file mode 100644 index 818affac..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/InvalidArgumentException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception; - -/** - * An exception is a result of something wrong in input parameters. - */ -public class InvalidArgumentException extends MappingException { - - private static final long serialVersionUID = -2223352885909511209L; - - public InvalidArgumentException(String msg, Throwable root) { - super(msg, root); - } - - public InvalidArgumentException(Throwable root) { - super(root); - } - - public InvalidArgumentException(String s) { - super(s); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/KeyConversionException.java b/persistence-core/src/main/java/org/gluu/persist/exception/KeyConversionException.java deleted file mode 100644 index 727cb6f6..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/KeyConversionException.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.exception; - -/** - * Exception thrown when a dn to key conversion problem occurs - * - * @author Yuriy Movchan Date: 30/05/2018 - */ -public class KeyConversionException extends BasePersistenceException { - - private static final long serialVersionUID = -5254637442590218891L; - - public KeyConversionException(String message) { - super(message); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/MappingException.java b/persistence-core/src/main/java/org/gluu/persist/exception/MappingException.java deleted file mode 100644 index c7f95b17..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/MappingException.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception; - -/** - * An exception is a result of something screwy in the O-R mappings. - */ -public class MappingException extends BasePersistenceException { - - private static final long serialVersionUID = 1113352885909511209L; - - public MappingException(String msg, Throwable root) { - super(msg, root); - } - - public MappingException(Throwable root) { - super(root); - } - - public MappingException(String s) { - super(s); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/PropertyAccessException.java b/persistence-core/src/main/java/org/gluu/persist/exception/PropertyAccessException.java deleted file mode 100644 index 87f16e90..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/PropertyAccessException.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception; - -import org.gluu.util.StringHelper; - -/** - * A problem occurred accessing a property of an instance of a persistent class - * by reflection. There are a number of possible underlying causes, including - *

- */ -public class PropertyAccessException extends MappingException { - - private static final long serialVersionUID = 1076767768405558202L; - - private final Class persistentClass; - private final String propertyName; - private final boolean wasSetter; - - public PropertyAccessException(Throwable root, String s, boolean wasSetter, Class persistentClass, String propertyName) { - super(s, root); - this.persistentClass = persistentClass; - this.wasSetter = wasSetter; - this.propertyName = propertyName; - } - - public Class getPersistentClass() { - return persistentClass; - } - - public String getPropertyName() { - return propertyName; - } - - @Override - public String getMessage() { - return super.getMessage() + (wasSetter ? " setter of " : " getter of ") - + StringHelper.qualify(persistentClass.getName(), propertyName); - } -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/PropertyNotFoundException.java b/persistence-core/src/main/java/org/gluu/persist/exception/PropertyNotFoundException.java deleted file mode 100644 index ad3883b4..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/PropertyNotFoundException.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception; - -/** - * Indicates that an expected getter or setter method could not be found on a - * class. - */ -public class PropertyNotFoundException extends MappingException { - - private static final long serialVersionUID = 2351260797243441135L; - - public PropertyNotFoundException(String s) { - super(s); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/UnsupportedOperationException.java b/persistence-core/src/main/java/org/gluu/persist/exception/UnsupportedOperationException.java deleted file mode 100644 index 37f07af3..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/UnsupportedOperationException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception; - -/** - * An exception is a result if server doesn't support operation. - * - * @author Yuriy Movchan Date: 08.07.2012 - */ -public class UnsupportedOperationException extends BasePersistenceException { - - private static final long serialVersionUID = 2321766232087075304L; - - public UnsupportedOperationException(Throwable root) { - super(root); - } - - public UnsupportedOperationException(String string, Throwable root) { - super(string, root); - } - - public UnsupportedOperationException(String s) { - super(s); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/extension/PersistenceExtension.java b/persistence-core/src/main/java/org/gluu/persist/exception/extension/PersistenceExtension.java deleted file mode 100644 index 4ee11b27..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/extension/PersistenceExtension.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.gluu.persist.exception.extension; - -/** - * Base interface for persistence script - * - * @author Yuriy Movchan Date: 06/04/2020 - */ -public interface PersistenceExtension { - - String createHashedPassword(String credential); - boolean compareHashedPasswords(String credential, String storedCredential); - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/operation/ConfigurationException.java b/persistence-core/src/main/java/org/gluu/persist/exception/operation/ConfigurationException.java deleted file mode 100644 index 8797c4cd..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/operation/ConfigurationException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception.operation; - -/** - * Configuration exception - * - * @author Yuriy Movchan - * @version 0.1, 05/16/2013 - */ -public class ConfigurationException extends RuntimeException { - - private static final long serialVersionUID = -7590161991536595499L; - - public ConfigurationException() { - } - - public ConfigurationException(String message) { - super(message); - } - - public ConfigurationException(Throwable cause) { - super(cause); - } - - public ConfigurationException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/operation/ConnectionException.java b/persistence-core/src/main/java/org/gluu/persist/exception/operation/ConnectionException.java deleted file mode 100644 index 5893302c..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/operation/ConnectionException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception.operation; - -/** - * Configuration exception - * - * @author Yuriy Movchan - * @version 0.1, 05/16/2013 - */ -public class ConnectionException extends RuntimeException { - - private static final long serialVersionUID = -7590161991536595499L; - - public ConnectionException() { - } - - public ConnectionException(String message) { - super(message); - } - - public ConnectionException(Throwable cause) { - super(cause); - } - - public ConnectionException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/operation/DeleteException.java b/persistence-core/src/main/java/org/gluu/persist/exception/operation/DeleteException.java deleted file mode 100644 index 65b5df84..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/operation/DeleteException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception.operation; - -/** - * Exception thrown when a delte problem occurs - * - * @author Yuriy Movchan Date: 2019/08/26 - */ -public class DeleteException extends PersistenceException { - - private static final long serialVersionUID = 5017957214447362606L; - - public DeleteException(String message, Throwable ex, int errorCode) { - super(message, ex, errorCode); - } - - public DeleteException(String message, int errorCode) { - super(message, errorCode); - } - - public DeleteException(String message) { - super(message); - } - - public DeleteException(String message, Throwable ex) { - super(message, ex); - } - - public DeleteException(Throwable ex, int errorCode) { - super(ex, errorCode); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/operation/DuplicateEntryException.java b/persistence-core/src/main/java/org/gluu/persist/exception/operation/DuplicateEntryException.java deleted file mode 100644 index fa3e77ca..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/operation/DuplicateEntryException.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception.operation; - -/** - * Duplicate LDAP entry exception - * - * @author Pankaj - */ -public class DuplicateEntryException extends PersistenceException { - /** - * Serialization ID - */ - private static final long serialVersionUID = 6749290172742578916L; - - /** - * Default constructor - */ - public DuplicateEntryException() { - super("Entry already exists"); - } - - /** - * Constructor for returning the offending DN - * - * @param dn - * DN that returned a duplicate - */ - public DuplicateEntryException(final String dn) { - super("Entry already exists: " + dn); - } -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/operation/EntryNotFoundException.java b/persistence-core/src/main/java/org/gluu/persist/exception/operation/EntryNotFoundException.java deleted file mode 100644 index 6bd13afa..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/operation/EntryNotFoundException.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception.operation; - -/** - * Exception thrown when a there is no entry - * - * @author Yuriy Movchan Date: 2017/12/29 - */ -public class EntryNotFoundException extends PersistenceException { - - private static final long serialVersionUID = 5017957214447362606L; - - private int resultCode; - - public EntryNotFoundException(String message, Throwable ex, int resultCode) { - super(message, ex); - this.resultCode = resultCode; - } - - public EntryNotFoundException(String message, int resultCode) { - super(message); - this.resultCode = resultCode; - } - - public EntryNotFoundException(String message) { - super(message); - } - - public EntryNotFoundException(String message, Throwable ex) { - super(message, ex); - } - - public EntryNotFoundException(Throwable ex, int resultCode) { - super(ex); - this.resultCode = resultCode; - } - - public final int getResultCode() { - return resultCode; - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/operation/PersistenceException.java b/persistence-core/src/main/java/org/gluu/persist/exception/operation/PersistenceException.java deleted file mode 100644 index f64c358d..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/operation/PersistenceException.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception.operation; - -/** - * Generic operation layer exception - * - * @author Yuriy Movchan Date: 29/01/2018 - */ -public class PersistenceException extends Exception { - - /** - * S Serialization ID - */ - private static final long serialVersionUID = 1518677859552078437L; - - /** - * LDAP error code - */ - private int errorCode = 0; - - /** - * Constructor with wrapped exception - * - * @param e - * Wrapped LDAP exception - */ - public PersistenceException(final Throwable e) { - super(e); - } - - public PersistenceException(final Throwable e, final int errorCode) { - super(e); - this.errorCode = errorCode; - } - - /** - * Constructor with detailed error - * - * @param message - * Detailed message - */ - public PersistenceException(final String message) { - super(message); - } - - public PersistenceException(final String message, final int errorCode) { - super(message); - this.errorCode = errorCode; - } - - /** - * Constructor with error and wrapped exception - * - * @param message - * Detailed error - * @param e - * Wrapped LDAP exception - */ - public PersistenceException(final String message, final Throwable e) { - super(message, e); - } - - public PersistenceException(final String message, final Throwable e, final int errorCode) { - super(message, e); - this.errorCode = errorCode; - } - - /** - * Get the LDAP error code - * - * @return The LDAP error code - */ - public int getErrorCode() { - return errorCode; - } - - /** - * Set the LDAP error code - * - * @param code - * Error code - */ - public void setErrorCode(final int code) { - errorCode = code; - } - - /** - * Get the message for display - * - * @return Message for display - */ - @Override - public String toString() { - return getMessage(); - } -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/operation/SearchException.java b/persistence-core/src/main/java/org/gluu/persist/exception/operation/SearchException.java deleted file mode 100644 index e75ed1fe..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/operation/SearchException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception.operation; - -/** - * Exception thrown when a search problem occurs - * - * @author Yuriy Movchan Date: 2017/12/29 - */ -public class SearchException extends PersistenceException { - - private static final long serialVersionUID = 5017957214447362606L; - - public SearchException(String message, Throwable ex, int errorCode) { - super(message, ex, errorCode); - } - - public SearchException(String message, int errorCode) { - super(message, errorCode); - } - - public SearchException(String message) { - super(message); - } - - public SearchException(String message, Throwable ex) { - super(message, ex); - } - - public SearchException(Throwable ex, int errorCode) { - super(ex, errorCode); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/exception/operation/SearchScopeException.java b/persistence-core/src/main/java/org/gluu/persist/exception/operation/SearchScopeException.java deleted file mode 100644 index 7a7675f2..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/exception/operation/SearchScopeException.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.exception.operation; - -/** - * Exception thrown when a search scope problem occurs - * - * @author Yuriy Movchan Date: 29/01/2018 - */ -public class SearchScopeException extends PersistenceException { - - private static final long serialVersionUID = -4554637442590218891L; - - public SearchScopeException(String message) { - super(message); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java b/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java deleted file mode 100644 index a95361b2..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/impl/BaseEntryManager.java +++ /dev/null @@ -1,2074 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.impl; - -import java.io.Serializable; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.apache.commons.codec.binary.Base64; -import org.gluu.persist.PersistenceEntryManager; -import org.gluu.persist.annotation.AttributeEnum; -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.Expiration; -import org.gluu.persist.annotation.JsonObject; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.persist.annotation.SchemaEntry; -import org.gluu.persist.exception.EntryPersistenceException; -import org.gluu.persist.exception.InvalidArgumentException; -import org.gluu.persist.exception.MappingException; -import org.gluu.persist.exception.extension.PersistenceExtension; -import org.gluu.persist.model.AttributeData; -import org.gluu.persist.model.AttributeDataModification; -import org.gluu.persist.model.AttributeDataModification.AttributeModificationType; -import org.gluu.persist.model.SearchScope; -import org.gluu.persist.operation.PersistenceOperationService; -import org.gluu.persist.reflect.property.Getter; -import org.gluu.persist.reflect.property.PropertyAnnotation; -import org.gluu.persist.reflect.property.Setter; -import org.gluu.persist.reflect.util.ReflectHelper; -import org.gluu.search.filter.Filter; -import org.gluu.util.ArrayHelper; -import org.gluu.util.StringHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.fasterxml.jackson.databind.ObjectMapper; - -/** - * Abstract Entry Manager - * - * @author Yuriy Movchan Date: 10.07.2010 - */ -public abstract class BaseEntryManager implements PersistenceEntryManager { - - private static final Logger LOG = LoggerFactory.getLogger(BaseEntryManager.class); - - private static final Class[] LDAP_ENTRY_TYPE_ANNOTATIONS = { DataEntry.class, SchemaEntry.class, - ObjectClass.class }; - private static final Class[] LDAP_ENTRY_PROPERTY_ANNOTATIONS = { AttributeName.class, AttributesList.class, - JsonObject.class }; - private static final Class[] LDAP_CUSTOM_OBJECT_CLASS_PROPERTY_ANNOTATION = { CustomObjectClass.class }; - private static final Class[] LDAP_DN_PROPERTY_ANNOTATION = { DN.class }; - private static final Class[] LDAP_EXPIRATION_PROPERTY_ANNOTATION = { Expiration.class }; - - public static final String OBJECT_CLASS = "objectClass"; - public static final String[] EMPTY_STRING_ARRAY = new String[0]; - - private static final Class[] GROUP_BY_ALLOWED_DATA_TYPES = { String.class, Date.class, Integer.class, - AttributeEnum.class }; - private static final Class[] SUM_BY_ALLOWED_DATA_TYPES = { int.class, Integer.class, float.class, Float.class, - double.class, Double.class }; - - private final Map> classAnnotations = new HashMap>(); - private final Map classGetters = new HashMap(); - private final Map classSetters = new HashMap(); - - private static Object CLASS_ANNOTATIONS_LOCK = new Object(); - private static Object CLASS_SETTERS_LOCK = new Object(); - private static Object CLASS_GETTERS_LOCK = new Object(); - - private static final ObjectMapper JSON_OBJECT_MAPPER = new ObjectMapper(); - - protected static final String[] NO_STRINGS = new String[0]; - protected static final Object[] NO_OBJECTS = new Object[0]; - - protected static final Comparator LINE_LENGHT_COMPARATOR = new LineLenghtComparator(false); - - protected static final int DEFAULT_PAGINATION_SIZE = 100; - - protected PersistenceOperationService operationService = null; - protected PersistenceExtension persistenceExtension = null; - - @Override - public void persist(Object entry) { - if (entry == null) { - throw new MappingException("Entry to persist is null"); - } - - // Check entry class - Class entryClass = entry.getClass(); - checkEntryClass(entryClass, false); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - - Object dnValue = getDNValue(entry, entryClass); - - Integer expirationValue = getExpirationValue(entry, entryClass); - - List attributes = getAttributesListForPersist(entry, propertiesAnnotations); - - // Add object classes - String[] objectClasses = getObjectClasses(entry, entryClass); - attributes.add(new AttributeData(OBJECT_CLASS, objectClasses, true)); - - LOG.debug(String.format("LDAP attributes for persist: %s", attributes)); - - persist(dnValue.toString(), attributes, expirationValue); - } - - protected abstract void persist(String dn, List attributes, Integer expiration); - - @Override - @SuppressWarnings("unchecked") - public List findEntries(Object entry, int count) { - if (entry == null) { - throw new MappingException("Entry to find is null"); - } - - // Check entry class - Class entryClass = (Class) entry.getClass(); - checkEntryClass(entryClass, false); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - - Object dnValue = getDNValue(entry, entryClass); - - List attributes = getAttributesListForPersist(entry, propertiesAnnotations); - Filter searchFilter = createFilterByEntry(entry, entryClass, attributes); - - return findEntries(dnValue.toString(), entryClass, searchFilter, SearchScope.SUB, null, 0, count, - DEFAULT_PAGINATION_SIZE); - } - - @Override - public List findEntries(Object entry) { - return findEntries(entry, 0); - } - - @Override - public List findEntries(String baseDN, Class entryClass, Filter filter) { - return findEntries(baseDN, entryClass, filter, SearchScope.SUB, null, null, 0, 0, 0); - } - - @Override - public List findEntries(String baseDN, Class entryClass, Filter filter, int count) { - return findEntries(baseDN, entryClass, filter, SearchScope.SUB, null, null, 0, count, 0); - } - - @Override - public List findEntries(String baseDN, Class entryClass, Filter filter, String[] ldapReturnAttributes) { - return findEntries(baseDN, entryClass, filter, SearchScope.SUB, ldapReturnAttributes, null, 0, 0, 0); - } - - @Override - public List findEntries(String baseDN, Class entryClass, Filter filter, String[] ldapReturnAttributes, - int count) { - return findEntries(baseDN, entryClass, filter, SearchScope.SUB, ldapReturnAttributes, null, 0, count, 0); - } - - @Override - public List findEntries(String baseDN, Class entryClass, Filter filter, SearchScope scope, - String[] ldapReturnAttributes, int start, int count, int chunkSize) { - return findEntries(baseDN, entryClass, filter, scope, ldapReturnAttributes, null, start, count, chunkSize); - } - - @SuppressWarnings("unchecked") - public int countEntries(Object entry) { - if (entry == null) { - throw new MappingException("Entry to count is null"); - } - - // Check entry class - Class entryClass = (Class) entry.getClass(); - checkEntryClass(entryClass, false); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - - Object dnValue = getDNValue(entry, entryClass); - - List attributes = getAttributesListForPersist(entry, propertiesAnnotations); - Filter searchFilter = createFilterByEntry(entry, entryClass, attributes); - - return countEntries(dnValue.toString(), entryClass, searchFilter); - } - - @SuppressWarnings("unchecked") - protected Void merge(Object entry, boolean isSchemaUpdate, boolean isConfigurationUpdate, AttributeModificationType schemaModificationType) { - if (entry == null) { - throw new MappingException("Entry to persist is null"); - } - - Class entryClass = entry.getClass(); - checkEntryClass(entryClass, isSchemaUpdate); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - Map propertiesAnnotationsMap = prepareEntryPropertiesTypes(entryClass, propertiesAnnotations); - - Object dnValue = getDNValue(entry, entryClass); - - Integer expirationValue = getExpirationValue(entry, entryClass); - - List attributesToPersist = getAttributesListForPersist(entry, propertiesAnnotations); - Map attributesToPersistMap = getAttributesMap(attributesToPersist); - - // Load entry - List attributesFromLdap; - if (isSchemaUpdate) { - // If it's schema modification request we don't need to load - // attributes from LDAP - attributesFromLdap = new ArrayList(); - } else { - List currentLdapReturnAttributesList = getAttributesList(entry, propertiesAnnotations, false); - if (!isConfigurationUpdate) { - currentLdapReturnAttributesList.add("objectClass"); - } - - attributesFromLdap = find(dnValue.toString(), propertiesAnnotationsMap, currentLdapReturnAttributesList.toArray(EMPTY_STRING_ARRAY)); - } - Map attributesFromLdapMap = getAttributesMap(attributesFromLdap); - - // Prepare list of modifications - - // Process properties with Attribute annotation - List attributeDataModifications = collectAttributeModifications( - propertiesAnnotations, attributesToPersistMap, attributesFromLdapMap, isSchemaUpdate, - schemaModificationType); - - updateMergeChanges(dnValue.toString(), entry, isSchemaUpdate | isConfigurationUpdate, entryClass, attributesFromLdapMap, attributeDataModifications); - - LOG.debug(String.format("LDAP attributes for merge: %s", attributeDataModifications)); - - merge(dnValue.toString(), attributeDataModifications, expirationValue); - - return null; - } - - protected abstract void updateMergeChanges(String baseDn, T entry, boolean isConfigurationUpdate, Class entryClass, - Map attributesFromLdapMap, - List attributeDataModifications); - - protected List collectAttributeModifications( - List propertiesAnnotations, Map attributesToPersistMap, - Map attributesFromLdapMap, boolean isSchemaUpdate, - AttributeModificationType schemaModificationType) { - List attributeDataModifications = new ArrayList(); - - for (PropertyAnnotation propertiesAnnotation : propertiesAnnotations) { - String propertyName = propertiesAnnotation.getPropertyName(); - Annotation ldapAttribute; - - ldapAttribute = ReflectHelper.getAnnotationByType(propertiesAnnotation.getAnnotations(), - AttributeName.class); - if (ldapAttribute != null) { - String ldapAttributeName = ((AttributeName) ldapAttribute).name(); - if (StringHelper.isEmpty(ldapAttributeName)) { - ldapAttributeName = propertyName; - } - ldapAttributeName = ldapAttributeName.toLowerCase(); - - AttributeData attributeToPersist = attributesToPersistMap.get(ldapAttributeName); - AttributeData attributeFromLdap = attributesFromLdapMap.get(ldapAttributeName); - - // Remove processed attributes - attributesToPersistMap.remove(ldapAttributeName); - attributesFromLdapMap.remove(ldapAttributeName); - - AttributeName ldapAttributeAnnotation = (AttributeName) ldapAttribute; - if (ldapAttributeAnnotation.ignoreDuringUpdate()) { - continue; - } - - if (attributeFromLdap != null && attributeToPersist != null) { - // Modify DN entry attribute in DS - if (!attributeFromLdap.equals(attributeToPersist)) { - if (isEmptyAttributeValues(attributeToPersist) && !ldapAttributeAnnotation.updateOnly()) { - attributeDataModifications.add(new AttributeDataModification( - AttributeModificationType.REMOVE, null, attributeFromLdap)); - } else { - attributeDataModifications.add(new AttributeDataModification( - AttributeModificationType.REPLACE, attributeToPersist, attributeFromLdap)); - } - } - } else if ((attributeFromLdap == null) && (attributeToPersist != null)) { - // Add entry attribute or change schema - if (isSchemaUpdate && (attributeToPersist.getValue() == null - && Arrays.equals(attributeToPersist.getValues(), new Object[] {}))) { - continue; - } - AttributeModificationType modType = isSchemaUpdate ? schemaModificationType - : AttributeModificationType.ADD; - if (AttributeModificationType.ADD.equals(modType)) { - if (!isEmptyAttributeValues(attributeToPersist)) { - attributeDataModifications.add( - new AttributeDataModification(AttributeModificationType.ADD, attributeToPersist)); - } - } else { - attributeDataModifications.add(new AttributeDataModification(AttributeModificationType.REMOVE, - null, attributeToPersist)); - } - } else if ((attributeFromLdap != null) && (attributeToPersist == null)) { - // Remove if attribute not marked as ignoreDuringRead = true - // or updateOnly = true - if (!ldapAttributeAnnotation.ignoreDuringRead() && !ldapAttributeAnnotation.updateOnly()) { - attributeDataModifications.add(new AttributeDataModification(AttributeModificationType.REMOVE, - null, attributeFromLdap)); - } - } - } - } - - // Process properties with @AttributesList annotation - for (PropertyAnnotation propertiesAnnotation : propertiesAnnotations) { - Annotation ldapAttribute; - ldapAttribute = ReflectHelper.getAnnotationByType(propertiesAnnotation.getAnnotations(), - AttributesList.class); - if (ldapAttribute != null) { - Map ldapAttributesConfiguration = new HashMap(); - for (AttributeName ldapAttributeConfiguration : ((AttributesList) ldapAttribute) - .attributesConfiguration()) { - ldapAttributesConfiguration.put(ldapAttributeConfiguration.name(), ldapAttributeConfiguration); - } - - // Prepare attributes for removal - for (AttributeData attributeFromLdap : attributesFromLdapMap.values()) { - String attributeName = attributeFromLdap.getName(); - if (OBJECT_CLASS.equalsIgnoreCase(attributeName)) { - continue; - } - - AttributeName ldapAttributeConfiguration = ldapAttributesConfiguration.get(attributeName); - if ((ldapAttributeConfiguration != null) && ldapAttributeConfiguration.ignoreDuringUpdate()) { - continue; - } - - if (!attributesToPersistMap.containsKey(attributeName.toLowerCase())) { - // Remove if attribute not marked as ignoreDuringRead = - // true - if ((ldapAttributeConfiguration == null) || ((ldapAttributeConfiguration != null) - && !ldapAttributeConfiguration.ignoreDuringRead())) { - attributeDataModifications.add(new AttributeDataModification( - AttributeModificationType.REMOVE, null, attributeFromLdap)); - } - } - } - - // Prepare attributes for adding and replace - for (AttributeData attributeToPersist : attributesToPersistMap.values()) { - String attributeName = attributeToPersist.getName(); - - AttributeName ldapAttributeConfiguration = ldapAttributesConfiguration.get(attributeName); - if ((ldapAttributeConfiguration != null) && ldapAttributeConfiguration.ignoreDuringUpdate()) { - continue; - } - - AttributeData attributeFromLdap = attributesFromLdapMap.get(attributeName.toLowerCase()); - if (attributeFromLdap == null) { - // Add entry attribute or change schema - AttributeModificationType modType = isSchemaUpdate ? schemaModificationType - : AttributeModificationType.ADD; - if (AttributeModificationType.ADD.equals(modType)) { - if (!isEmptyAttributeValues(attributeToPersist)) { - attributeDataModifications.add(new AttributeDataModification( - AttributeModificationType.ADD, attributeToPersist)); - } - } else { - attributeDataModifications.add(new AttributeDataModification( - AttributeModificationType.REMOVE, null, attributeToPersist)); - } - } else if ((attributeFromLdap != null) - && (Arrays.equals(attributeToPersist.getValues(), new String[] {}))) { - - attributeDataModifications.add(new AttributeDataModification(AttributeModificationType.REMOVE, - null, attributeFromLdap)); - } else { - if (!attributeFromLdap.equals(attributeToPersist)) { - if (isEmptyAttributeValues(attributeToPersist) - && (ldapAttributeConfiguration == null || !ldapAttributeConfiguration.updateOnly())) { - attributeDataModifications.add(new AttributeDataModification( - AttributeModificationType.REMOVE, null, attributeFromLdap)); - } else { - attributeDataModifications.add(new AttributeDataModification( - AttributeModificationType.REPLACE, attributeToPersist, attributeFromLdap)); - } - } - } - } - - } - } - - return attributeDataModifications; - } - - protected boolean isEmptyAttributeValues(AttributeData attributeData) { - Object[] attributeToPersistValues = attributeData.getValues(); - - return ArrayHelper.isEmpty(attributeToPersistValues) - || ((attributeToPersistValues.length == 1) && StringHelper.isEmpty(String.valueOf(attributeToPersistValues[0]))); - } - - protected abstract void merge(String dn, List attributeDataModifications, Integer expiration); - - public abstract void remove(String dn); - - @Override - public boolean contains(Object entry) { - if (entry == null) { - throw new MappingException("Entry to persist is null"); - } - - // Check entry class - Class entryClass = entry.getClass(); - checkEntryClass(entryClass, false); - String[] objectClasses = getObjectClasses(entry, entryClass); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - - Object dnValue = getDNValue(entry, entryClass); - - List attributes = getAttributesListForPersist(entry, propertiesAnnotations); - - String[] ldapReturnAttributes = getAttributes(null, propertiesAnnotations, false); - - return contains(dnValue.toString(), entryClass, propertiesAnnotations, attributes, objectClasses, ldapReturnAttributes); - } - - protected boolean contains(Class entryClass, String primaryKey, String[] ldapReturnAttributes) { - if (StringHelper.isEmptyString(primaryKey)) { - throw new MappingException("DN to find entry is null"); - } - - checkEntryClass(entryClass, true); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - Map propertiesAnnotationsMap = prepareEntryPropertiesTypes(entryClass, propertiesAnnotations); - - try { - List results = find(primaryKey, propertiesAnnotationsMap, ldapReturnAttributes); - return (results != null) && (results.size() > 0); - } catch (EntryPersistenceException ex) { - return false; - } - } - - @Override - public boolean contains(String baseDN, Class entryClass, Filter filter) { - // Check entry class - checkEntryClass(entryClass, false); - String[] objectClasses = getTypeObjectClasses(entryClass); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - String[] ldapReturnAttributes = getAttributes(null, propertiesAnnotations, false); - - return contains(baseDN, entryClass, propertiesAnnotations, filter, objectClasses, ldapReturnAttributes); - } - - protected boolean contains(String baseDN, Class entryClass, List propertiesAnnotations, List attributes, String[] objectClasses, - String... ldapReturnAttributes) { - Filter[] attributesFilters = createAttributesFilter(attributes); - Filter attributesFilter = null; - if (attributesFilters != null) { - attributesFilter = Filter.createANDFilter(attributesFilters); - } - - return contains(baseDN, entryClass, propertiesAnnotations, attributesFilter, objectClasses, ldapReturnAttributes); - } - - protected abstract boolean contains(String baseDN, Class entryClass, List propertiesAnnotations, - Filter filter, String[] objectClasses, String[] ldapReturnAttributes); - - @Override - public boolean contains(String primaryKey, Class entryClass) { - return contains(entryClass, primaryKey, (String[]) null); - } - - @Override - public T find(Class entryClass, Object primaryKey) { - return find(primaryKey, entryClass, null); - } - - @Override - public T find(Object primaryKey, Class entryClass, String[] ldapReturnAttributes) { - if (StringHelper.isEmptyString(primaryKey)) { - throw new MappingException("DN to find entry is null"); - } - - checkEntryClass(entryClass, true); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - Map propertiesAnnotationsMap = prepareEntryPropertiesTypes(entryClass, propertiesAnnotations); - - return find(entryClass, primaryKey, ldapReturnAttributes, propertiesAnnotations, propertiesAnnotationsMap); - } - - protected String[] getAttributes(T entry, List propertiesAnnotations, - boolean isIgnoreAttributesList) { - List attributes = getAttributesList(entry, propertiesAnnotations, isIgnoreAttributesList); - - if (attributes == null) { - return null; - } - - return attributes.toArray(new String[0]); - } - - protected String[] getAttributes(Map attributesMap) { - if (attributesMap == null) { - return null; - } - return attributesMap.keySet().toArray(new String[0]); - } - - protected List getAttributesList(T entry, List propertiesAnnotations, - boolean isIgnoreAttributesList) { - Map attributesMap = getAttributesMap(entry, propertiesAnnotations, isIgnoreAttributesList); - - if (attributesMap == null) { - return null; - } - - return new ArrayList(attributesMap.keySet()); - } - - protected Map getAttributesMap(T entry, List propertiesAnnotations, - boolean isIgnoreAttributesList) { - Map attributes = new HashMap(); - - for (PropertyAnnotation propertiesAnnotation : propertiesAnnotations) { - String propertyName = propertiesAnnotation.getPropertyName(); - Annotation ldapAttribute; - - if (!isIgnoreAttributesList) { - ldapAttribute = ReflectHelper.getAnnotationByType(propertiesAnnotation.getAnnotations(), - AttributesList.class); - if (ldapAttribute != null) { - if (entry == null) { - return null; - } else { - List attributesList = getAttributesFromAttributesList(entry, - ldapAttribute, propertyName); - for (AttributeData attributeData : attributesList) { - String ldapAttributeName = attributeData.getName(); - if (!attributes.containsKey(ldapAttributeName)) { - attributes.put(ldapAttributeName, propertiesAnnotation); - } - } - } - } - } - - // Process properties with AttributeName annotation - ldapAttribute = ReflectHelper.getAnnotationByType(propertiesAnnotation.getAnnotations(), - AttributeName.class); - if (ldapAttribute != null) { - String ldapAttributeName = ((AttributeName) ldapAttribute).name(); - if (StringHelper.isEmpty(ldapAttributeName)) { - ldapAttributeName = propertyName; - } - - if (!attributes.containsKey(ldapAttributeName)) { - attributes.put(ldapAttributeName, propertiesAnnotation); - } - } - } - - if (attributes.size() == 0) { - return null; - } - - return attributes; - } - - protected Map prepareEntryPropertiesTypes(Class entryClass, List propertiesAnnotations) { - Map propertiesAnnotationsMap = getAttributesMap(null, propertiesAnnotations, true); - if (propertiesAnnotationsMap== null) { - return new HashMap(0); - } - - preparePropertyAnnotationTypes(entryClass, propertiesAnnotationsMap); - - return propertiesAnnotationsMap; - } - - protected void preparePropertyAnnotationTypes(Class entry, Map propertiesAnnotationsMap) { - for (PropertyAnnotation propertiesAnnotation : propertiesAnnotationsMap.values()) { - String propertyName = propertiesAnnotation.getPropertyName(); - - Class parameterType = getSetterPropertyType(entry, propertyName); - propertiesAnnotation.setParameterType(parameterType); - } - } - - private Class getSetterPropertyType(Class entry, String propertyName) { - Setter propertyValueSetter = getSetter(entry, propertyName); - if (propertyValueSetter == null) { - throw new MappingException("Entry should has setter for property " + propertyName); - } - - Class parameterType = ReflectHelper.getSetterType(propertyValueSetter); - return parameterType; - } - - private T find(Class entryClass, Object primaryKey, String[] ldapReturnAttributes, - List propertiesAnnotations, Map propertiesAnnotationsMap) { - Map> entriesAttributes = new HashMap>(); - - String[] currentLdapReturnAttributes = ldapReturnAttributes; - if (ArrayHelper.isEmpty(currentLdapReturnAttributes)) { - currentLdapReturnAttributes = getAttributes(null, propertiesAnnotations, false); - } - - List ldapAttributes = find(primaryKey.toString(), propertiesAnnotationsMap, currentLdapReturnAttributes); - - entriesAttributes.put(String.valueOf(primaryKey), ldapAttributes); - List results = createEntities(entryClass, propertiesAnnotations, entriesAttributes); - return results.get(0); - } - - protected abstract List find(String dn, Map propertiesAnnotationsMap, String... attributes); - - protected boolean checkEntryClass(Class entryClass, boolean isAllowSchemaEntry) { - if (entryClass == null) { - throw new MappingException("Entry class is null"); - } - - // Check if entry is LDAP Entry - List entryAnnotations = ReflectHelper.getClassAnnotations(entryClass, LDAP_ENTRY_TYPE_ANNOTATIONS); - - Annotation ldapSchemaEntry = ReflectHelper.getAnnotationByType(entryAnnotations, SchemaEntry.class); - Annotation ldapEntry = ReflectHelper.getAnnotationByType(entryAnnotations, DataEntry.class); - if (isAllowSchemaEntry) { - if ((ldapSchemaEntry == null) && (ldapEntry == null)) { - throw new MappingException("Entry should has DataEntry or SchemaEntry annotation"); - } - } else { - if (ldapEntry == null) { - throw new MappingException("Entry should has DataEntry annotation"); - } - } - - return true; - } - - protected boolean isSchemaEntry(Class entryClass) { - if (entryClass == null) { - throw new MappingException("Entry class is null"); - } - - // Check if entry is LDAP Entry - List entryAnnotations = ReflectHelper.getClassAnnotations(entryClass, LDAP_ENTRY_TYPE_ANNOTATIONS); - - return ReflectHelper.getAnnotationByType(entryAnnotations, SchemaEntry.class) != null; - } - - protected boolean isConfigurationEntry(Class entryClass) { - if (entryClass == null) { - throw new MappingException("Entry class is null"); - } - - // Check if entry is LDAP Entry - List entryAnnotations = ReflectHelper.getClassAnnotations(entryClass, LDAP_ENTRY_TYPE_ANNOTATIONS); - - DataEntry dataEntry = (DataEntry) ReflectHelper.getAnnotationByType(entryAnnotations, DataEntry.class); - if (dataEntry == null) { - return false; - } - - return dataEntry.configurationDefinition(); - } - - protected String[] getEntrySortBy(Class entryClass) { - if (entryClass == null) { - throw new MappingException("Entry class is null"); - } - - // Check if entry is LDAP Entry - List entryAnnotations = ReflectHelper.getClassAnnotations(entryClass, LDAP_ENTRY_TYPE_ANNOTATIONS); - Annotation annotation = ReflectHelper.getAnnotationByType(entryAnnotations, DataEntry.class); - - if (annotation == null) { - return null; - } - - return ((DataEntry) annotation).sortBy(); - } - - @Override - public String[] getObjectClasses(Object entry, Class entryClass) { - String[] typeObjectClasses = getTypeObjectClasses(entryClass); - String[] customObjectClasses = getCustomObjectClasses(entry, entryClass); - - if (ArrayHelper.isEmpty(typeObjectClasses)) { - return customObjectClasses; - } - - String[] mergedArray = ArrayHelper.arrayMerge(typeObjectClasses, customObjectClasses); - Set objecClassSet = new HashSet(); - objecClassSet.addAll(Arrays.asList(mergedArray)); - return objecClassSet.toArray(new String[0]); - } - - protected String[] getTypeObjectClasses(Class entryClass) { - // Check if entry is LDAP Entry - List entryAnnotations = ReflectHelper.getClassAnnotations(entryClass, LDAP_ENTRY_TYPE_ANNOTATIONS); - - // Get object classes - Annotation ldapObjectClass = ReflectHelper.getAnnotationByType(entryAnnotations, ObjectClass.class); - if (ldapObjectClass == null) { - return EMPTY_STRING_ARRAY; - } - - if (StringHelper.isEmpty(((ObjectClass) ldapObjectClass).value())) { - return EMPTY_STRING_ARRAY; - } - - return new String[] { ((ObjectClass) ldapObjectClass).value() }; - } - - protected String[] getCustomObjectClasses(Object entry, Class entryClass) { - List result = new ArrayList(); - List customObjectAnnotations = getEntryCustomObjectClassAnnotations(entryClass); - - for (PropertyAnnotation propertiesAnnotation : customObjectAnnotations) { - String propertyName = propertiesAnnotation.getPropertyName(); - - Getter getter = getGetter(entryClass, propertyName); - if (getter == null) { - throw new MappingException("Entry should has getter for property " + propertyName); - } - - Class parameterType = getSetterPropertyType(entryClass, propertyName); - boolean multiValued = isMultiValued(parameterType); - - AttributeData attribute = getAttributeData(propertyName, propertyName, getter, entry, multiValued, false); - if (attribute != null) { - for (String objectClass : attribute.getStringValues()) { - if (objectClass != null) { - result.add(objectClass); - } - } - } - break; - } - - return result.toArray(new String[0]); - } - - protected void setCustomObjectClasses(Object entry, Class entryClass, String[] objectClasses) { - List customObjectAnnotations = getEntryCustomObjectClassAnnotations(entryClass); - - for (PropertyAnnotation propertiesAnnotation : customObjectAnnotations) { - String propertyName = propertiesAnnotation.getPropertyName(); - - Setter setter = getSetter(entryClass, propertyName); - if (setter == null) { - throw new MappingException("Entry should has setter for property " + propertyName); - } - - AttributeData attribute = new AttributeData(propertyName, objectClasses); - - setPropertyValue(propertyName, setter, entry, attribute, false); - break; - } - } - - protected String getDNPropertyName(Class entryClass) { - List propertiesAnnotations = getEntryDnAnnotations(entryClass); - if (propertiesAnnotations.size() == 0) { - throw new MappingException("Entry should has property with annotation DN"); - } - - if (propertiesAnnotations.size() > 1) { - throw new MappingException("Entry should has only one property with annotation DN"); - } - - return propertiesAnnotations.get(0).getPropertyName(); - } - - protected String getExpirationPropertyName(Class entryClass) { - List propertiesAnnotations = getEntryExpirationAnnotations(entryClass); - if (propertiesAnnotations.size() == 0) { - return null; - } - - if (propertiesAnnotations.size() > 1) { - throw new MappingException("Entry should has only one property with annotation Expiration"); - } - - return propertiesAnnotations.get(0).getPropertyName(); - } - - protected List createEntities(Class entryClass, List propertiesAnnotations, - Map> entriesAttributes) { - return createEntities(entryClass, propertiesAnnotations, entriesAttributes, true); - } - - protected List createEntities(Class entryClass, List propertiesAnnotations, - Map> entriesAttributes, boolean doSort) { - // Check if entry has DN property - String dnProperty = getDNPropertyName(entryClass); - - // Get DN value - Setter dnSetter = getSetter(entryClass, dnProperty); - if (dnSetter == null) { - throw new MappingException("Entry should has getter for property " + dnProperty); - } - - // Type object classes - String[] typeObjectClasses = getTypeObjectClasses(entryClass); - Arrays.sort(typeObjectClasses); - - List results = new ArrayList(entriesAttributes.size()); - for (Entry> entryAttributes : entriesAttributes.entrySet()) { - String dn = entryAttributes.getKey(); - List attributes = entryAttributes.getValue(); - Map attributesMap = getAttributesMap(attributes); - - T entry; - List customObjectClasses = null; - try { - entry = ReflectHelper.createObjectByDefaultConstructor(entryClass); - } catch (Exception ex) { - throw new MappingException(String.format("Entry %s should has default constructor", entryClass)); - } - results.add(entry); - - dnSetter.set(entry, dn); - - // Remove processed DN attribute - attributesMap.remove(dnProperty); - - // Set loaded properties to entry - - // Process properties with AttributeName annotation - for (PropertyAnnotation propertiesAnnotation : propertiesAnnotations) { - String propertyName = propertiesAnnotation.getPropertyName(); - Annotation ldapAttribute; - - ldapAttribute = ReflectHelper.getAnnotationByType(propertiesAnnotation.getAnnotations(), - AttributeName.class); - if (ldapAttribute != null) { - String ldapAttributeName = ((AttributeName) ldapAttribute).name(); - if (StringHelper.isEmpty(ldapAttributeName)) { - ldapAttributeName = propertyName; - } - ldapAttributeName = ldapAttributeName.toLowerCase(); - - AttributeData attributeData = attributesMap.get(ldapAttributeName); - - // Remove processed attributes - attributesMap.remove(ldapAttributeName); - - if (((AttributeName) ldapAttribute).ignoreDuringRead()) { - continue; - } - - Setter setter = getSetter(entryClass, propertyName); - if (setter == null) { - throw new MappingException("Entry should has setter for property " + propertyName); - } - - Annotation ldapJsonObject = ReflectHelper.getAnnotationByType(propertiesAnnotation.getAnnotations(), - JsonObject.class); - boolean jsonObject = ldapJsonObject != null; - - setPropertyValue(propertyName, setter, entry, attributeData, jsonObject); - } - } - - // Process properties with @AttributesList annotation - for (PropertyAnnotation propertiesAnnotation : propertiesAnnotations) { - String propertyName = propertiesAnnotation.getPropertyName(); - Annotation ldapAttribute; - - ldapAttribute = ReflectHelper.getAnnotationByType(propertiesAnnotation.getAnnotations(), - AttributesList.class); - if (ldapAttribute != null) { - Map ldapAttributesConfiguration = new HashMap(); - for (AttributeName ldapAttributeConfiguration : ((AttributesList) ldapAttribute) - .attributesConfiguration()) { - ldapAttributesConfiguration.put(ldapAttributeConfiguration.name(), ldapAttributeConfiguration); - } - - Setter setter = getSetter(entryClass, propertyName); - if (setter == null) { - throw new MappingException("Entry should has setter for property " + propertyName); - } - - List propertyValue = new ArrayList(); - setter.set(entry, propertyValue); - - Class entryItemType = ReflectHelper.getListType(setter); - if (entryItemType == null) { - throw new MappingException( - "Entry property " + propertyName + " should has setter with specified element type"); - } - - String entryPropertyName = ((AttributesList) ldapAttribute).name(); - Setter entryPropertyNameSetter = getSetter(entryItemType, entryPropertyName); - if (entryPropertyNameSetter == null) { - throw new MappingException( - "Entry should has setter for property " + propertyName + "." + entryPropertyName); - } - - String entryPropertyValue = ((AttributesList) ldapAttribute).value(); - Setter entryPropertyValueSetter = getSetter(entryItemType, entryPropertyValue); - if (entryPropertyValueSetter == null) { - throw new MappingException( - "Entry should has getter for property " + propertyName + "." + entryPropertyValue); - } - - for (AttributeData entryAttribute : attributesMap.values()) { - if (OBJECT_CLASS.equalsIgnoreCase(entryAttribute.getName())) { - String[] objectClasses = entryAttribute.getStringValues(); - if (ArrayHelper.isEmpty(objectClasses)) { - continue; - } - - if (customObjectClasses == null) { - customObjectClasses = new ArrayList(); - } - - for (String objectClass : objectClasses) { - int idx = Arrays.binarySearch(typeObjectClasses, objectClass, new Comparator() { - public int compare(String o1, String o2) { - return o1.toLowerCase().compareTo(o2.toLowerCase()); - } - }); - - if (idx < 0) { - customObjectClasses.add(objectClass); - } - } - - continue; - } - - AttributeName ldapAttributeConfiguration = ldapAttributesConfiguration - .get(entryAttribute.getName()); - if ((ldapAttributeConfiguration != null) && ldapAttributeConfiguration.ignoreDuringRead()) { - continue; - } - - String entryPropertyMultivalued = ((AttributesList) ldapAttribute).multiValued(); - Setter entryPropertyMultivaluedSetter = null; - if (StringHelper.isNotEmpty(entryPropertyMultivalued)) { - entryPropertyMultivaluedSetter = getSetter(entryItemType, entryPropertyMultivalued); - } - if (entryPropertyMultivaluedSetter != null) { - Class parameterType = ReflectHelper.getSetterType(entryPropertyMultivaluedSetter); - if (!parameterType.equals(Boolean.TYPE)) { - throw new MappingException( - "Entry should has getter for property " + propertyName + "." + entryPropertyMultivalued + " with boolean type"); - } - } - - Object listItem = getListItem(propertyName, entryPropertyNameSetter, entryPropertyValueSetter, - entryPropertyMultivaluedSetter, entryItemType, entryAttribute); - if (listItem != null) { - propertyValue.add(listItem); - } - } - - if (doSort) { - sortAttributesListIfNeeded((AttributesList) ldapAttribute, entryItemType, - propertyValue); - } - } - } - - if ((customObjectClasses != null) && (customObjectClasses.size() > 0)) { - setCustomObjectClasses(entry, entryClass, customObjectClasses.toArray(new String[0])); - } - } - - return results; - } - - @Override - public List createEntities(Class entryClass, Map> entriesAttributes) { - checkEntryClass(entryClass, true); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - - return createEntities(entryClass, propertiesAnnotations, entriesAttributes); - } - - @SuppressWarnings("unchecked") - private void sortAttributesListIfNeeded(AttributesList ldapAttribute, Class entryItemType, - List list) { - if (!ldapAttribute.sortByName()) { - return; - } - - sortListByProperties(entryItemType, (List) list, ldapAttribute.name()); - } - - protected void sortEntriesIfNeeded(Class entryClass, List entries) { - String[] sortByProperties = getEntrySortBy(entryClass); - - if (ArrayHelper.isEmpty(sortByProperties)) { - return; - } - - sortListByProperties(entryClass, entries, sortByProperties); - } - - @Override - public void sortListByProperties(Class entryClass, List entries, boolean caseSensetive, - String... sortByProperties) { - // Check input parameters - if (entries == null) { - throw new MappingException("Entries list to sort is null"); - } - - if (entries.size() == 0) { - return; - } - - if ((sortByProperties == null) || (sortByProperties.length == 0)) { - throw new InvalidArgumentException( - "Invalid list of sortBy properties " + Arrays.toString(sortByProperties)); - } - - // Get getters for all properties - Getter[][] propertyGetters = new Getter[sortByProperties.length][]; - for (int i = 0; i < sortByProperties.length; i++) { - String[] tmpProperties = sortByProperties[i].split("\\."); - propertyGetters[i] = new Getter[tmpProperties.length]; - Class currentEntryClass = entryClass; - for (int j = 0; j < tmpProperties.length; j++) { - if (j > 0) { - currentEntryClass = propertyGetters[i][j - 1].getReturnType(); - } - propertyGetters[i][j] = getGetter(currentEntryClass, tmpProperties[j]); - } - - if (propertyGetters[i][tmpProperties.length - 1] == null) { - throw new MappingException("Entry should has getteres for all properties " + sortByProperties[i]); - } - - Class propertyType = propertyGetters[i][tmpProperties.length - 1].getReturnType(); - if (!((propertyType == String.class) || (propertyType == Date.class) || (propertyType == Integer.class) - || (propertyType == Integer.TYPE))) { - throw new MappingException("Entry properties should has String, Date or Integer type. Property: '" - + tmpProperties[tmpProperties.length - 1] + "'"); - } - } - - PropertyComparator comparator = new PropertyComparator(propertyGetters, caseSensetive); - Collections.sort(entries, comparator); - } - - protected void sortListByProperties(Class entryClass, List entries, String... sortByProperties) { - sortListByProperties(entryClass, entries, false, sortByProperties); - } - - @Override - public Map> groupListByProperties(Class entryClass, List entries, boolean caseSensetive, - String groupByProperties, String sumByProperties) { - // Check input parameters - if (entries == null) { - throw new MappingException("Entries list to group is null"); - } - - if (entries.size() == 0) { - return new HashMap>(0); - } - - if (StringHelper.isEmpty(groupByProperties)) { - throw new InvalidArgumentException("List of groupBy properties is null"); - } - - // Get getters for all properties - Getter[] groupPropertyGetters = getEntryPropertyGetters(entryClass, groupByProperties, - GROUP_BY_ALLOWED_DATA_TYPES); - Setter[] groupPropertySetters = getEntryPropertySetters(entryClass, groupByProperties, - GROUP_BY_ALLOWED_DATA_TYPES); - Getter[] sumPropertyGetters = getEntryPropertyGetters(entryClass, sumByProperties, SUM_BY_ALLOWED_DATA_TYPES); - Setter[] sumPropertySetter = getEntryPropertySetters(entryClass, sumByProperties, SUM_BY_ALLOWED_DATA_TYPES); - - return groupListByPropertiesImpl(entryClass, entries, caseSensetive, groupPropertyGetters, groupPropertySetters, - sumPropertyGetters, sumPropertySetter); - } - - private Getter[] getEntryPropertyGetters(Class entryClass, String properties, Class[] allowedTypes) { - if (StringHelper.isEmpty(properties)) { - return null; - } - - String[] tmpProperties = properties.split("\\,"); - Getter[] propertyGetters = new Getter[tmpProperties.length]; - for (int i = 0; i < tmpProperties.length; i++) { - propertyGetters[i] = getGetter(entryClass, tmpProperties[i].trim()); - - if (propertyGetters[i] == null) { - throw new MappingException("Entry should has getter for property " + tmpProperties[i]); - } - - Class returnType = propertyGetters[i].getReturnType(); - boolean found = false; - for (Class clazz : allowedTypes) { - if (ReflectHelper.assignableFrom(returnType, clazz)) { - found = true; - break; - } - } - - if (!found) { - throw new MappingException( - "Entry property getter should has next data types " + Arrays.toString(allowedTypes)); - } - } - - return propertyGetters; - } - - private Setter[] getEntryPropertySetters(Class entryClass, String properties, Class[] allowedTypes) { - if (StringHelper.isEmpty(properties)) { - return null; - } - - String[] tmpProperties = properties.split("\\,"); - Setter[] propertySetters = new Setter[tmpProperties.length]; - for (int i = 0; i < tmpProperties.length; i++) { - propertySetters[i] = getSetter(entryClass, tmpProperties[i].trim()); - - if (propertySetters[i] == null) { - throw new MappingException("Entry should has setter for property " + tmpProperties[i]); - } - - Class paramType = ReflectHelper.getSetterType(propertySetters[i]); - boolean found = false; - for (Class clazz : allowedTypes) { - if (ReflectHelper.assignableFrom(paramType, clazz)) { - found = true; - break; - } - } - - if (!found) { - throw new MappingException( - "Entry property setter should has next data types " + Arrays.toString(allowedTypes)); - } - } - - return propertySetters; - } - - protected Map> groupListByProperties(Class entryClass, List entries, String groupByProperties, - String sumByProperties) { - return groupListByProperties(entryClass, entries, false, groupByProperties, sumByProperties); - } - - private Map> groupListByPropertiesImpl(Class entryClass, List entries, boolean caseSensetive, - Getter[] groupPropertyGetters, Setter[] groupPropertySetters, Getter[] sumProperyGetters, - Setter[] sumPropertySetter) { - Map keys = new HashMap(); - Map> groups = new IdentityHashMap>(); - - for (T entry : entries) { - String key = getEntryKey(entry, caseSensetive, groupPropertyGetters); - - T entryKey = keys.get(key); - if (entryKey == null) { - try { - entryKey = ReflectHelper.createObjectByDefaultConstructor(entryClass); - } catch (Exception ex) { - throw new MappingException(String.format("Entry %s should has default constructor", entryClass), - ex); - } - try { - ReflectHelper.copyObjectPropertyValues(entry, entryKey, groupPropertyGetters, groupPropertySetters); - } catch (Exception ex) { - throw new MappingException("Failed to set values in group Entry", ex); - } - keys.put(key, entryKey); - } - - List groupValues = groups.get(entryKey); - if (groupValues == null) { - groupValues = new ArrayList(); - groups.put(entryKey, groupValues); - } - - try { - if (sumProperyGetters != null) { - ReflectHelper.sumObjectPropertyValues(entryKey, entry, sumProperyGetters, sumPropertySetter); - } - } catch (Exception ex) { - throw new MappingException("Failed to sum values in group Entry", ex); - } - - groupValues.add(entry); - } - - return groups; - } - - private Map getAttributesMap(List attributes) { - Map attributesMap = new HashMap(attributes.size()); - for (AttributeData attribute : attributes) { - attributesMap.put(attribute.getName().toLowerCase(), attribute); - } - - return attributesMap; - } - - private AttributeData getAttributeData(String propertyName, String ldapAttributeName, Getter propertyValueGetter, - Object entry, boolean multiValued, boolean jsonObject) { - Object propertyValue = propertyValueGetter.get(entry); - if (propertyValue == null) { - return null; - } - - Object[] attributeValues = getAttributeValues(propertyName, jsonObject, propertyValue); - - if (LOG.isDebugEnabled()) { - LOG.debug(String.format("Property: %s, LdapProperty: %s, PropertyValue: %s", propertyName, - ldapAttributeName, Arrays.toString(attributeValues))); - } - - if (attributeValues.length == 0) { - attributeValues = new String[] {}; - } else if ((attributeValues.length == 1) && (attributeValues[0] == null)) { - return null; - } - - return new AttributeData(ldapAttributeName, attributeValues, multiValued); - } - - private Object[] getAttributeValues(String propertyName, boolean jsonObject, Object propertyValue) { - Object[] attributeValues = new Object[1]; - - boolean nativeType = getNativeAttributeValue(propertyValue, attributeValues); - if (nativeType) { - // We do conversion in getNativeAttributeValue method already - } else if (propertyValue instanceof AttributeEnum) { - attributeValues[0] = ((AttributeEnum) propertyValue).getValue(); - } else if (propertyValue instanceof AttributeEnum[]) { - AttributeEnum[] propertyValues = (AttributeEnum[]) propertyValue; - attributeValues = new String[propertyValues.length]; - for (int i = 0; i < propertyValues.length; i++) { - attributeValues[i] = (propertyValues[i] == null) ? null : propertyValues[i].getValue(); - } - } else if (propertyValue instanceof String[]) { - attributeValues = (String[]) propertyValue; - } else if (propertyValue instanceof Object[]) { - attributeValues = (Object[]) propertyValue; - } else if (propertyValue instanceof List) { - attributeValues = new Object[((List) propertyValue).size()]; - int index = 0; - Object nativeAttributeValue[] = new Object[1]; - for (Object tmpPropertyValue : (List) propertyValue) { - if (jsonObject) { - attributeValues[index++] = convertValueToJson(tmpPropertyValue); - } else { - if (getNativeAttributeValue(tmpPropertyValue, nativeAttributeValue)) { - attributeValues[index++] = nativeAttributeValue[0]; - } else { - attributeValues[index++] = StringHelper.toString(tmpPropertyValue); - } - } - } - } else if (jsonObject) { - attributeValues[0] = convertValueToJson(propertyValue); - } else { - throw new MappingException("Entry property '" + propertyName - + "' should has getter with String, String[], Boolean, Integer, Long, Date, List, AttributeEnum or AttributeEnum[]" - + " return type or has annotation JsonObject"); - } - return attributeValues; - } - - /* - * This method doesn't produces new object to avoid extra garbage creation - */ - private boolean getNativeAttributeValue(Object propertyValue, Object[] resultValue) { - // Clean result - resultValue[0] = null; - - if (propertyValue instanceof String) { - resultValue[0] = StringHelper.toString(propertyValue); - } else if (propertyValue instanceof Boolean) { - resultValue[0] = propertyValue; - } else if (propertyValue instanceof Integer) { - resultValue[0] = propertyValue; - } else if (propertyValue instanceof Long) { - resultValue[0] = propertyValue; - } else if (propertyValue instanceof Date) { - resultValue[0] = encodeTime((Date) propertyValue); - } else { - return false; - } - - return true; - } - - protected boolean isAttributeMultivalued(Object[] values) { - if (values.length > 1) { - return true; - - } - - return false; - } - - protected Object convertValueToJson(Object propertyValue) { - try { - String value = JSON_OBJECT_MAPPER.writeValueAsString(propertyValue); - - return value; - } catch (Exception ex) { - LOG.error("Failed to convert '{}' to json value:", propertyValue, ex); - throw new MappingException(String.format("Failed to convert '%s' to json value", propertyValue)); - } - } - - protected List getAttributesListForPersist(Object entry, - List propertiesAnnotations) { - // Prepare list of properties to persist - List attributes = new ArrayList(); - for (PropertyAnnotation propertiesAnnotation : propertiesAnnotations) { - String propertyName = propertiesAnnotation.getPropertyName(); - Annotation ldapAttribute; - - // Process properties with AttributeName annotation - ldapAttribute = ReflectHelper.getAnnotationByType(propertiesAnnotation.getAnnotations(), - AttributeName.class); - if (ldapAttribute != null) { - AttributeData attribute = getAttributeDataFromAttribute(entry, ldapAttribute, propertiesAnnotation, - propertyName); - if (attribute != null) { - attributes.add(attribute); - } - - continue; - } - - // Process properties with @AttributesList annotation - ldapAttribute = ReflectHelper.getAnnotationByType(propertiesAnnotation.getAnnotations(), - AttributesList.class); - if (ldapAttribute != null) { - List listAttributes = getAttributesFromAttributesList(entry, ldapAttribute, - propertyName); - if (listAttributes != null) { - attributes.addAll(listAttributes); - } - - continue; - } - } - - return attributes; - } - - private AttributeData getAttributeDataFromAttribute(Object entry, Annotation ldapAttribute, - PropertyAnnotation propertiesAnnotation, String propertyName) { - Class entryClass = entry.getClass(); - - String ldapAttributeName = ((AttributeName) ldapAttribute).name(); - if (StringHelper.isEmpty(ldapAttributeName)) { - ldapAttributeName = propertyName; - } - - Getter getter = getGetter(entryClass, propertyName); - if (getter == null) { - throw new MappingException("Entry should has getter for property " + propertyName); - } - - Class parameterType = getSetterPropertyType(entryClass, propertyName); - boolean multiValued = isMultiValued(parameterType); - - Annotation ldapJsonObject = ReflectHelper.getAnnotationByType(propertiesAnnotation.getAnnotations(), - JsonObject.class); - boolean jsonObject = ldapJsonObject != null; - AttributeData attribute = getAttributeData(propertyName, ldapAttributeName, getter, entry, multiValued, jsonObject); - - return attribute; - } - - private List getAttributesFromAttributesList(Object entry, Annotation ldapAttribute, - String propertyName) { - Class entryClass = entry.getClass(); - List listAttributes = new ArrayList(); - - Getter getter = getGetter(entryClass, propertyName); - if (getter == null) { - throw new MappingException("Entry should has getter for property " + propertyName); - } - - Object propertyValue = getter.get(entry); - if (propertyValue == null) { - return null; - } - - if (!(propertyValue instanceof List)) { - throw new MappingException("Entry property should has List base type"); - } - - Class elementType = ReflectHelper.getListType(getter); - - String entryPropertyName = ((AttributesList) ldapAttribute).name(); - Getter entryPropertyNameGetter = getGetter(elementType, entryPropertyName); - if (entryPropertyNameGetter == null) { - throw new MappingException( - "Entry should has getter for property " + propertyName + "." + entryPropertyName); - } - - String entryPropertyValue = ((AttributesList) ldapAttribute).value(); - Getter entryPropertyValueGetter = getGetter(elementType, entryPropertyValue); - if (entryPropertyValueGetter == null) { - throw new MappingException( - "Entry should has getter for property " + propertyName + "." + entryPropertyValue); - } - - String entryPropertyMultivalued = ((AttributesList) ldapAttribute).multiValued(); - Getter entryPropertyMultivaluedGetter = null; - if (StringHelper.isNotEmpty(entryPropertyMultivalued)) { - entryPropertyMultivaluedGetter = getGetter(elementType, entryPropertyMultivalued); - } - if (entryPropertyMultivaluedGetter != null) { - Class propertyType = entryPropertyMultivaluedGetter.getReturnType(); - if (!propertyType.equals(Boolean.TYPE)) { - throw new MappingException( - "Entry should has getter for property " + propertyName + "." + entryPropertyMultivalued + " with boolean type"); - } - } - - for (Object entryAttribute : (List) propertyValue) { - AttributeData attribute = getAttributeData(propertyName, entryPropertyNameGetter, entryPropertyValueGetter, - entryAttribute, false); - if (attribute != null) { - if (entryPropertyMultivaluedGetter != null) { - boolean multiValued = (boolean) entryPropertyMultivaluedGetter.get(entryAttribute); - attribute.setMultiValued(multiValued); - } else { - // Detect if attribute has more than one value - boolean multiValued = attribute.getValues().length > 1; - attribute.setMultiValued(multiValued); - } - - listAttributes.add(attribute); - } - } - - return listAttributes; - } - - protected List getEntryPropertyAnnotations(Class entryClass) { - final List annotations = getEntryClassAnnotations(entryClass, "property_", LDAP_ENTRY_PROPERTY_ANNOTATIONS); -// KeyShortcuter.initIfNeeded(entryClass, annotations); - return annotations; - } - - protected List getEntryDnAnnotations(Class entryClass) { - return getEntryClassAnnotations(entryClass, "dn_", LDAP_DN_PROPERTY_ANNOTATION); - } - - protected List getEntryExpirationAnnotations(Class entryClass) { - return getEntryClassAnnotations(entryClass, "exp_", LDAP_EXPIRATION_PROPERTY_ANNOTATION); - } - - protected List getEntryCustomObjectClassAnnotations(Class entryClass) { - return getEntryClassAnnotations(entryClass, "custom_", LDAP_CUSTOM_OBJECT_CLASS_PROPERTY_ANNOTATION); - } - - protected List getEntryClassAnnotations(Class entryClass, String keyCategory, - Class[] annotationTypes) { - String key = keyCategory + entryClass.getName(); - - List annotations = classAnnotations.get(key); - if (annotations == null) { - synchronized (CLASS_ANNOTATIONS_LOCK) { - annotations = classAnnotations.get(key); - if (annotations == null) { - Map> annotationsMap = ReflectHelper.getPropertiesAnnotations(entryClass, - annotationTypes); - annotations = convertToPropertyAnnotationList(annotationsMap); - classAnnotations.put(key, annotations); - } - } - } - - return annotations; - } - - private List convertToPropertyAnnotationList(Map> annotations) { - List result = new ArrayList(annotations.size()); - for (Entry> entry : annotations.entrySet()) { - result.add(new PropertyAnnotation(entry.getKey(), entry.getValue())); - } - - Collections.sort(result); - - return result; - } - - protected Getter getGetter(Class entryClass, String propertyName) { - String key = entryClass.getName() + "." + propertyName; - - Getter getter = classGetters.get(key); - if (getter == null) { - synchronized (CLASS_GETTERS_LOCK) { - getter = classGetters.get(key); - if (getter == null) { - getter = ReflectHelper.getGetter(entryClass, propertyName); - classGetters.put(key, getter); - } - } - } - - return getter; - } - - protected Setter getSetter(Class entryClass, String propertyName) { - String key = entryClass.getName() + "." + propertyName; - - Setter setter = classSetters.get(key); - if (setter == null) { - synchronized (CLASS_SETTERS_LOCK) { - setter = classSetters.get(key); - if (setter == null) { - setter = ReflectHelper.getSetter(entryClass, propertyName); - classSetters.put(key, setter); - } - } - } - - return setter; - } - - private AttributeData getAttributeData(String propertyName, Getter propertyNameGetter, Getter propertyValueGetter, - Object entry, boolean jsonObject) { - Object ldapAttributeName = propertyNameGetter.get(entry); - if (ldapAttributeName == null) { - return null; - } - - return getAttributeData(propertyName, ldapAttributeName.toString(), propertyValueGetter, entry, false, jsonObject); - } - - private void setPropertyValue(String propertyName, Setter propertyValueSetter, Object entry, - AttributeData attribute, boolean jsonObject) { - if (attribute == null) { - return; - } - - LOG.debug(String.format("LdapProperty: %s, AttributeName: %s, AttributeValue: %s", propertyName, - attribute.getName(), Arrays.toString(attribute.getValues()))); - - Class parameterType = ReflectHelper.getSetterType(propertyValueSetter); - if (parameterType.equals(String.class)) { - Object value = attribute.getValue(); - if (value instanceof Date) { - value = encodeTime((Date) value); - } - propertyValueSetter.set(entry, String.valueOf(value)); - } else if (parameterType.equals(Boolean.class) || parameterType.equals(Boolean.TYPE)) { - propertyValueSetter.set(entry, toBooleanValue(attribute)); - } else if (parameterType.equals(Integer.class) || parameterType.equals(Integer.TYPE)) { - propertyValueSetter.set(entry, toIntegerValue(attribute)); - } else if (parameterType.equals(Long.class) || parameterType.equals(Long.TYPE)) { - propertyValueSetter.set(entry, toLongValue(attribute)); - } else if (parameterType.equals(Date.class)) { - propertyValueSetter.set(entry, attribute.getValue() instanceof Date ? (Date) attribute.getValue() : decodeTime(String.valueOf(attribute.getValue()))); - } else if (parameterType.equals(String[].class)) { - propertyValueSetter.set(entry, attribute.getStringValues()); - } else if (ReflectHelper.assignableFrom(parameterType, List.class)) { - if (jsonObject) { - Object[] values = attribute.getValues(); - List jsonValues = new ArrayList(values.length); - - for (Object value : values) { - Object jsonValue = convertJsonToValue(ReflectHelper.getListType(propertyValueSetter), value); - jsonValues.add(jsonValue); - } - propertyValueSetter.set(entry, jsonValues); - } else { - List resultValues = attributeToTypedList(ReflectHelper.getListType(propertyValueSetter), attribute); - propertyValueSetter.set(entry, resultValues); - } - } else if (ReflectHelper.assignableFrom(parameterType, AttributeEnum.class)) { - try { - propertyValueSetter.set(entry, parameterType.getMethod("resolveByValue", String.class) - .invoke(parameterType.getEnumConstants()[0], attribute.getValue())); - } catch (Exception ex) { - throw new MappingException("Failed to resolve Enum '" + parameterType + "' by value '" + attribute.getValue() + "'", ex); - } - } else if (ReflectHelper.assignableFrom(parameterType, AttributeEnum[].class)) { - Class itemType = parameterType.getComponentType(); - Method enumResolveByValue; - try { - enumResolveByValue = itemType.getMethod("resolveByValue", String.class); - } catch (Exception ex) { - throw new MappingException("Failed to resolve Enum '" + parameterType + "' by value '" + Arrays.toString(attribute.getValues()) + "'", - ex); - } - - Object[] attributeValues = attribute.getValues(); - AttributeEnum[] ldapEnums = (AttributeEnum[]) ReflectHelper.createArray(itemType, attributeValues.length); - for (int i = 0; i < attributeValues.length; i++) { - try { - ldapEnums[i] = (AttributeEnum) enumResolveByValue.invoke(itemType.getEnumConstants()[0], - attributeValues[i]); - } catch (Exception ex) { - throw new MappingException( - "Failed to resolve Enum '" + parameterType + "' by value '" + Arrays.toString(attribute.getValues()) + "'", ex); - } - } - propertyValueSetter.set(entry, ldapEnums); - } else if (jsonObject) { - Object stringValue = attribute.getValue(); - Object jsonValue = convertJsonToValue(parameterType, stringValue); - propertyValueSetter.set(entry, jsonValue); - } else { - throw new MappingException("Entry property '" + propertyName - + "' should has setter with String, Boolean, Integer, Long, Date, String[], List, AttributeEnum or AttributeEnum[]" - + " parameter type or has annotation JsonObject"); - } - } - - private List attributeToTypedList(Class listType, AttributeData attributeData) { - if (listType.equals(String.class)) { - ArrayList result = new ArrayList(); - for (Object value : attributeData.getValues()) { - String resultValue; - if (value instanceof Date) { - resultValue = encodeTime((Date) value); - } else { - resultValue = String.valueOf(value); - } - - result.add(resultValue); - } - - return result; - } - - return Arrays.asList(attributeData.getValues()); - } - - private Boolean toBooleanValue(AttributeData attribute) { - Boolean propertyValue = null; - Object propertyValueObject = attribute.getValue(); - if (propertyValueObject != null) { - if (propertyValueObject instanceof Boolean) { - propertyValue = (Boolean) propertyValueObject; - } else { - propertyValue = Boolean.valueOf(String.valueOf(propertyValueObject)); - } - } - return propertyValue; - } - - private Integer toIntegerValue(AttributeData attribute) { - Integer propertyValue = null; - Object propertyValueObject = attribute.getValue(); - if (propertyValueObject != null) { - if (propertyValueObject instanceof Long) { - propertyValue = (Integer) propertyValueObject; - } else { - propertyValue = Integer.valueOf(String.valueOf(propertyValueObject)); - } - } - return propertyValue; - } - - private Long toLongValue(AttributeData attribute) { - Long propertyValue = null; - Object propertyValueObject = attribute.getValue(); - if (propertyValueObject != null) { - if (propertyValueObject instanceof Long) { - propertyValue = (Long) propertyValueObject; - } else { - propertyValue = Long.valueOf(String.valueOf(propertyValueObject)); - } - } - return propertyValue; - } - - protected Object convertJsonToValue(Class parameterType, Object propertyValue) { - try { - Object jsonValue = JSON_OBJECT_MAPPER.readValue(String.valueOf(propertyValue), parameterType); - return jsonValue; - } catch (Exception ex) { - LOG.error("Failed to convert json value '{}' to object `{}`", propertyValue, parameterType, ex); - throw new MappingException(String.format("Failed to convert json value '%s' to object of type %s", - propertyValue, parameterType)); - } - } - - private Object getListItem(String propertyName, Setter propertyNameSetter, Setter propertyValueSetter, - Setter entryPropertyMultivaluedSetter, Class classType, AttributeData attribute) { - if (attribute == null) { - return null; - } - - Object result; - try { - result = ReflectHelper.createObjectByDefaultConstructor(classType); - } catch (Exception ex) { - throw new MappingException(String.format("Entry %s should has default constructor", classType)); - } - propertyNameSetter.set(result, attribute.getName()); - setPropertyValue(propertyName, propertyValueSetter, result, attribute, false); - - if ((entryPropertyMultivaluedSetter != null) && (attribute.getMultiValued() != null)) { - entryPropertyMultivaluedSetter.set(result, attribute.getMultiValued()); - } - - return result; - } - - protected Object getDNValue(Object entry) { - Class entryClass = entry.getClass(); - - return getDNValue(entry, entryClass); - } - - protected Object getDNValue(Object entry, Class entryClass) { - // Check if entry has DN property - String dnProperty = getDNPropertyName(entryClass); - - // Get DN value - Getter dnGetter = getGetter(entryClass, dnProperty); - if (dnGetter == null) { - throw new MappingException("Entry should has getter for property " + dnProperty); - } - - Object dnValue = dnGetter.get(entry); - if (StringHelper.isEmptyString(dnValue)) { - throw new MappingException("Entry should has not null base DN property value"); - } - - return dnValue; - } - - protected Integer getExpirationValue(Object entry, Class entryClass) { - // Check if entry has Expiration property - String expirationProperty = getExpirationPropertyName(entryClass); - - if (expirationProperty == null) { - // No entry expiration property - return null; - } - - // Get Expiration value - Getter expirationGetter = getGetter(entryClass, expirationProperty); - if (expirationGetter == null) { - throw new MappingException("Entry should has getter for property " + expirationGetter); - } - - Class propertyType = expirationGetter.getReturnType(); - if (!((propertyType == Integer.class) || (propertyType == Integer.TYPE))) { - throw new MappingException("Entry expiration property should has Integer type. Property: '" - + expirationGetter + "'"); - } - - Object expirationValue = expirationGetter.get(entry); - if (expirationValue == null) { - // No entry expiration or null - return null; - } - - Integer resultExpirationValue; - if (expirationValue instanceof Integer) { - resultExpirationValue = (Integer) expirationValue; - } else { - resultExpirationValue = Integer.valueOf((int) expirationValue); - } - - // TTL can't be negative - if (resultExpirationValue < 0) { - resultExpirationValue = 0; - } - - return resultExpirationValue; - } - - private String getEntryKey(T entry, boolean caseSensetive, Getter[] propertyGetters) { - StringBuilder sb = new StringBuilder("key"); - for (Getter getter : propertyGetters) { - sb.append("__").append(getter.get(entry)); - } - - if (caseSensetive) { - return sb.toString(); - } else { - return sb.toString().toLowerCase(); - } - } - - private Map getAttributesDataMap(List attributesData) { - Map result = new HashMap(); - - for (AttributeData attributeData : attributesData) { - result.put(attributeData.getName(), attributeData); - } - - return result; - } - - private String getEntryKey(Object dnValue, boolean caseSensetive, List propertiesAnnotations, - List attributesData) { - StringBuilder sb = new StringBuilder("_HASH__").append((String.valueOf(dnValue)).toLowerCase()).append("__"); - - List processedProperties = new ArrayList(); - Map attributesDataMap = getAttributesDataMap(attributesData); - for (PropertyAnnotation propertiesAnnotation : propertiesAnnotations) { - Annotation ldapAttribute = ReflectHelper.getAnnotationByType(propertiesAnnotation.getAnnotations(), - AttributeName.class); - if (ldapAttribute == null) { - continue; - } - - String ldapAttributeName = ((AttributeName) ldapAttribute).name(); - if (StringHelper.isEmpty(ldapAttributeName)) { - ldapAttributeName = propertiesAnnotation.getPropertyName(); - } - - processedProperties.add(ldapAttributeName); - - String[] values = null; - - AttributeData attributeData = attributesDataMap.get(ldapAttributeName); - if ((attributeData != null) && (attributeData.getValues() != null)) { - values = attributeData.getStringValues(); - Arrays.sort(values); - } - - addPropertyWithValuesToKey(sb, ldapAttributeName, values); - } - - for (AttributeData attributeData : attributesData) { - if (processedProperties.contains(attributeData.getName())) { - continue; - } - - addPropertyWithValuesToKey(sb, attributeData.getName(), attributeData.getStringValues()); - } - - if (caseSensetive) { - return sb.toString(); - } else { - return sb.toString().toLowerCase(); - } - } - - private void addPropertyWithValuesToKey(StringBuilder sb, String propertyName, String[] values) { - sb.append(':').append(propertyName).append('='); - if (values == null) { - sb.append("null"); - } else { - if (values.length == 1) { - sb.append(values[0]); - } else { - String[] tmpValues = values.clone(); - Arrays.sort(tmpValues); - - for (int i = 0; i < tmpValues.length; i++) { - sb.append(tmpValues[i]); - if (i < tmpValues.length - 1) { - sb.append(';'); - } - } - } - } - } - - @Override - public int getHashCode(Object entry) { - if (entry == null) { - throw new MappingException("Entry to persist is null"); - } - - // Check entry class - Class entryClass = entry.getClass(); - checkEntryClass(entryClass, false); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - - Object dnValue = getDNValue(entry, entryClass); - - List attributes = getAttributesListForPersist(entry, propertiesAnnotations); - String key = getEntryKey(dnValue, false, propertiesAnnotations, attributes); - if (LOG.isDebugEnabled()) { - LOG.debug(String.format("Entry key HashCode is: %s", key.hashCode())); - } - - return key.hashCode(); - } - - protected byte[][] toBinaryValues(String[] attributeValues) { - byte[][] binaryValues = new byte[attributeValues.length][]; - - for (int i = 0; i < attributeValues.length; i++) { - binaryValues[i] = Base64.decodeBase64(attributeValues[i]); - } - return binaryValues; - } - - protected Filter createFilterByEntry(Object entry, Class entryClass, List attributes) { - Filter[] attributesFilters = createAttributesFilter(attributes); - Filter attributesFilter = null; - if (attributesFilters != null) { - attributesFilter = Filter.createANDFilter(attributesFilters); - } - - String[] objectClasses = getObjectClasses(entry, entryClass); - return addObjectClassFilter(attributesFilter, objectClasses); - } - - protected Filter[] createAttributesFilter(List attributes) { - if ((attributes == null) || (attributes.size() == 0)) { - return null; - } - - List results = new ArrayList(attributes.size()); - - for (AttributeData attribute : attributes) { - String attributeName = attribute.getName(); - for (Object value : attribute.getValues()) { - Filter filter = Filter.createEqualityFilter(attributeName, value); - if ((attribute.getMultiValued() != null) && attribute.getMultiValued()) { - filter.multiValued(); - } - - results.add(filter); - } - } - - return results.toArray(new Filter[results.size()]); - } - - protected Filter addObjectClassFilter(Filter filter, String[] objectClasses) { - if (objectClasses.length == 0) { - return filter; - } - - Filter[] objectClassFilter = new Filter[objectClasses.length]; - for (int i = 0; i < objectClasses.length; i++) { - objectClassFilter[i] = Filter.createEqualityFilter(OBJECT_CLASS, objectClasses[i]).multiValued(); - } - Filter searchFilter = Filter.createANDFilter(objectClassFilter); - if (filter != null) { - searchFilter = Filter.createANDFilter(Filter.createANDFilter(objectClassFilter), filter); - } - return searchFilter; - } - - protected boolean isMultiValued(Class parameterType) { - if (parameterType == null) { - return false; - } - - boolean isMultiValued = parameterType.equals(String[].class) || ReflectHelper.assignableFrom(parameterType, List.class) || ReflectHelper.assignableFrom(parameterType, AttributeEnum[].class); - - return isMultiValued; - } - - protected abstract Date decodeTime(String date); - - protected abstract String encodeTime(Date date); - - public void setPersistenceExtension(PersistenceExtension persistenceExtension) { - this.persistenceExtension = persistenceExtension; - - if (this.operationService != null) { - this.operationService.setPersistenceExtension(persistenceExtension); - } - } - - protected static final class PropertyComparator implements Comparator, Serializable { - - private static final long serialVersionUID = 574848841116711467L; - private Getter[][] propertyGetters; - private boolean caseSensetive; - - private PropertyComparator(Getter[][] propertyGetters, boolean caseSensetive) { - this.propertyGetters = propertyGetters; - this.caseSensetive = caseSensetive; - } - - @Override - public int compare(T entry1, T entry2) { - if ((entry1 == null) && (entry2 == null)) { - return 0; - } - if ((entry1 == null) && (entry2 != null)) { - return -1; - } else if ((entry1 != null) && (entry2 == null)) { - return 1; - } - - int result = 0; - for (Getter[] curPropertyGetters : propertyGetters) { - result = compare(entry1, entry2, curPropertyGetters); - if (result != 0) { - break; - } - } - - return result; - } - - public int compare(T entry1, T entry2, Getter[] propertyGetters) { - Object value1 = ReflectHelper.getPropertyValue(entry1, propertyGetters); - Object value2 = ReflectHelper.getPropertyValue(entry2, propertyGetters); - - if ((value1 == null) && (value2 == null)) { - return 0; - } - if ((value1 == null) && (value2 != null)) { - return -1; - } else if ((value1 != null) && (value2 == null)) { - return 1; - } - - if (value1 instanceof Date) { - return ((Date) value1).compareTo((Date) value2); - } else if (value1 instanceof Integer) { - return ((Integer) value1).compareTo((Integer) value2); - } else if (value1 instanceof String && value2 instanceof String) { - if (caseSensetive) { - return ((String) value1).compareTo((String) value2); - } else { - return ((String) value1).toLowerCase().compareTo(((String) value2).toLowerCase()); - } - } - return 0; - } - } - - protected static final class LineLenghtComparator implements Comparator, Serializable { - - private static final long serialVersionUID = 575848841116711467L; - private boolean ascending; - - public LineLenghtComparator(boolean ascending) { - this.ascending = ascending; - } - - @Override - public int compare(T entry1, T entry2) { - if ((entry1 == null) && (entry2 == null)) { - return 0; - } - if ((entry1 == null) && (entry2 != null)) { - return -1; - } else if ((entry1 != null) && (entry2 == null)) { - return 1; - } - - int result = entry1.toString().length() - entry2.toString().length(); - if (ascending) { - return result; - } else { - return -result; - } - } - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/key/impl/GenericKeyConverter.java b/persistence-core/src/main/java/org/gluu/persist/key/impl/GenericKeyConverter.java deleted file mode 100644 index 4e3b2c08..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/key/impl/GenericKeyConverter.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - /* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.key.impl; - -import org.gluu.persist.exception.KeyConversionException; -import org.gluu.persist.key.impl.model.ParsedKey; -import org.gluu.util.StringHelper; - -/** - * DN to Generic key convert - * - * @author Yuriy Movchan Date: 05/30/2018 - */ -public class GenericKeyConverter { - - public ParsedKey convertToKey(String dn) { - if (StringHelper.isEmpty(dn)) { - throw new KeyConversionException("Failed to convert empty DN to Key"); - } - - StringBuilder result = new StringBuilder(); - String[] tokens = dn.split(","); - - String orgInum = null; - String attributeName = null; - for (String token : tokens) { - int pos = token.indexOf("="); - if (pos == -1) { - throw new KeyConversionException("Failed to convert empty DN to Key"); - } - - String name = token.substring(0, pos); - if (attributeName == null) { - attributeName = name; - } - String value = token.substring(pos + 1, token.length()); - if (StringHelper.equalsIgnoreCase(name, "o")) { - if (!StringHelper.equalsIgnoreCase(value, "gluu")) { - orgInum = value; - } - continue; - } - - result.insert(0, "_" + value); - } - - String key = result.toString(); - if (key.length() == 0) { - key = "_"; - } else { - key = key.substring(1); - } - - return new ParsedKey(key, attributeName, orgInum); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/key/impl/KeyShortcuter.java b/persistence-core/src/main/java/org/gluu/persist/key/impl/KeyShortcuter.java deleted file mode 100644 index 7d6adea8..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/key/impl/KeyShortcuter.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.gluu.persist.key.impl; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.common.collect.Lists; -import org.apache.commons.lang.StringUtils; -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.reflect.property.PropertyAnnotation; -import org.gluu.persist.reflect.util.ReflectHelper; -import org.gluu.util.Util; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.annotation.Annotation; -import java.util.List; -import java.util.Map; - -/** - * Utility class which provides shorter version of the key - * - * @author Yuriy Zabrovarnyy - */ -public class KeyShortcuter { - - private static final Logger LOG = LoggerFactory.getLogger(KeyShortcuter.class); - - public static final String CONF_FILE_NAME = "key-shortcuter-rules.json"; - - private static final List PROCESSED_ENTRIES = Lists.newArrayList(); - - private static final BiMap MAP = HashBiMap.create(); - private static final BiMap INVERSE_MAP = MAP.inverse(); - - private KeyShortcuter() { - } - - private static KeyShortcuterConf conf = load(); - - private static KeyShortcuterConf load() { - try (InputStream is = KeyShortcuter.class.getResourceAsStream("/" + CONF_FILE_NAME)) { - return Util.createJsonMapper().readValue(is, KeyShortcuterConf.class); - } catch (IOException e) { - LOG.error("Failed to load key shortcuter configuration from file: " + CONF_FILE_NAME, e); - return null; - } - } - - public static String fromShortcut(String shortcut) { - return INVERSE_MAP.getOrDefault(shortcut, shortcut); - } - - public static String shortcut(String key) { - if (conf == null) { - LOG.error("Failed to load key shortcuter configuration from file: " + CONF_FILE_NAME); - return key; - } - if (StringUtils.isBlank(key)) { - return key; - } - - final String cachedShortcut = MAP.get(key); - if (cachedShortcut != null) { - return cachedShortcut; - } - - String copy = key; - - final String exclusion = conf.getExclusions().get(key); - if (StringUtils.isNotBlank(exclusion)) { - MAP.put(copy, exclusion); - return exclusion; - } - - for (String prefix : conf.getPrefixes()) { - if (key.startsWith(prefix)) { - key = StringUtils.removeStart(key, prefix); - } - } - - for (Map.Entry replace : conf.getReplaces().entrySet()) { - key = StringUtils.replace(key, replace.getKey(), replace.getValue()); - } - - key = lowercaseFirstChar(key); - try { - MAP.put(copy, key); - } catch (IllegalArgumentException e) { - LOG.error("Found duplicate for key: " + key + ", duplicate from: " + MAP.inverse().get(key)); - return copy; // skip shortcuting and return original key - } - return key; - } - - public static String lowercaseFirstChar(String key) { - return Character.toLowerCase(key.charAt(0)) + key.substring(1); - } - - public static void initIfNeeded(Class entryClass, List propertiesAnnotations) { - if (entryClass == null || propertiesAnnotations == null || PROCESSED_ENTRIES.contains(entryClass)) { - return; - } - - for (PropertyAnnotation propertiesAnnotation : propertiesAnnotations) { - // Process properties with AttributeName annotation - Annotation annotation = ReflectHelper.getAnnotationByType(propertiesAnnotation.getAnnotations(), AttributeName.class); - if (annotation != null) { - shortcut(((AttributeName) annotation).name()); - continue; - } - - // Process properties with @AttributesList annotation - annotation = ReflectHelper.getAnnotationByType(propertiesAnnotation.getAnnotations(), AttributesList.class); - if (annotation != null) { - for (AttributeName attributeConfiguration : ((AttributesList) annotation).attributesConfiguration()) { - shortcut(attributeConfiguration.name()); - } - } - } - - - PROCESSED_ENTRIES.add(entryClass); - } -} diff --git a/persistence-core/src/main/java/org/gluu/persist/key/impl/KeyShortcuterConf.java b/persistence-core/src/main/java/org/gluu/persist/key/impl/KeyShortcuterConf.java deleted file mode 100644 index 65678939..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/key/impl/KeyShortcuterConf.java +++ /dev/null @@ -1,52 +0,0 @@ -package org.gluu.persist.key.impl; - -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; -import java.util.Map; - -/** - * @author Yuriy Zabrovarnyy - */ -public class KeyShortcuterConf { - - @JsonProperty - private List prefixes; - @JsonProperty - private Map replaces; - @JsonProperty - private Map exclusions; - - public List getPrefixes() { - return prefixes; - } - - public void setPrefixes(List prefixes) { - this.prefixes = prefixes; - } - - public Map getReplaces() { - return replaces; - } - - public void setReplaces(Map replaces) { - this.replaces = replaces; - } - - public Map getExclusions() { - return exclusions; - } - - public void setExclusions(Map exclusions) { - this.exclusions = exclusions; - } - - @Override - public String toString() { - return "KeyShortcuterConf{" + - "prefixes=" + prefixes + - ", replaces=" + replaces + - ", exclusions=" + exclusions + - '}'; - } -} diff --git a/persistence-core/src/main/java/org/gluu/persist/key/impl/model/ParsedKey.java b/persistence-core/src/main/java/org/gluu/persist/key/impl/model/ParsedKey.java deleted file mode 100644 index a971f1c3..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/key/impl/model/ParsedKey.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ -package org.gluu.persist.key.impl.model; - -/** - * Couchbase key with inum - * - * @author Yuriy Movchan Date: 05/31/2018 - */ -public class ParsedKey { - - private final String key; - private final String name; - private final String inum; - - public ParsedKey(final String key, final String name, String inum) { - this.key = key; - this.name = name; - this.inum = inum; - } - - public final String getKey() { - return key; - } - - public String getName() { - return name; - } - - public final String getInum() { - return inum; - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/model/AttributeData.java b/persistence-core/src/main/java/org/gluu/persist/model/AttributeData.java deleted file mode 100644 index 2d9e0036..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/model/AttributeData.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model; - -import java.util.Arrays; - -import org.gluu.util.ArrayHelper; -import org.gluu.util.StringHelper; - -/** - * LDAP Attribute - * - * @author Yuriy Movchan Date: 10.10.2010 - */ -public class AttributeData { - private final String name; - private final Object[] values; - private Boolean multiValued; - - public AttributeData(String name, Object[] values) { - this(name, values, null); - } - - public AttributeData(String name, Object[] values, Boolean multiValued) { - this.name = name; - this.values = values; - this.multiValued = multiValued; - } - - public AttributeData(String name, Object value) { - this.name = name; - this.values = new Object[1]; - this.values[0] = value; - this.multiValued = null; - } - - public final String getName() { - return name; - } - - public final Object[] getValues() { - return values; - } - - public final String[] getStringValues() { - return StringHelper.toStringArray(this.values); - } - - public Object getValue() { - if ((this.values == null) || (this.values.length == 0)) { - return null; - } - - return this.values[0]; - } - - public void setMultiValued(Boolean multiValued) { - this.multiValued = multiValued; - } - - public Boolean getMultiValued() { - return multiValued; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((multiValued == null) ? 0 : multiValued.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + Arrays.deepHashCode(values); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - AttributeData other = (AttributeData) obj; - if ((multiValued != null) && (other.multiValued != null)) { - if (!multiValued.equals(other.multiValued)) - return false; - } - if (name == null) { - if (other.name != null) - return false; - } else if (!name.equals(other.name)) - return false; - - if ((values == null) && (other.values == null)) { - return true; - } - - if ((values == null) || (other.values == null) || values.length != other.values.length) { - return false; - } - - for (int i = 0; i < values.length; i++) { - if (!StringHelper.equals(String.valueOf(values[i]), String.valueOf(other.values[i]))) { - return false; - } - } - - return true; - } - - @Override - public String toString() { - return "AttributeData [name=" + name + ", values=" + Arrays.toString(values) + ", multiValued=" + multiValued + "]"; - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/model/AttributeDataModification.java b/persistence-core/src/main/java/org/gluu/persist/model/AttributeDataModification.java deleted file mode 100644 index 8cd3df66..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/model/AttributeDataModification.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model; - -/** - * LDAP Attribute - * - * @author Yuriy Movchan Date: 10.10.2010 - */ -public class AttributeDataModification { - - public enum AttributeModificationType { - ADD, REMOVE, REPLACE; - } - - private final AttributeModificationType modificationType; - private final AttributeData attribute; - private final AttributeData oldAttribute; - - public AttributeDataModification(AttributeModificationType modificationType, AttributeData attribute) { - this(modificationType, attribute, null); - } - - public AttributeDataModification(AttributeModificationType modificationType, AttributeData attribute, AttributeData oldAttribute) { - this.modificationType = modificationType; - this.attribute = attribute; - this.oldAttribute = oldAttribute; - } - - public final AttributeModificationType getModificationType() { - return modificationType; - } - - public final AttributeData getOldAttribute() { - return oldAttribute; - } - - public final AttributeData getAttribute() { - return attribute; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((modificationType == null) ? 0 : modificationType.hashCode()); - result = prime * result + ((attribute == null) ? 0 : attribute.hashCode()); - result = prime * result + ((oldAttribute == null) ? 0 : oldAttribute.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - AttributeDataModification other = (AttributeDataModification) obj; - if (modificationType == null) { - if (other.modificationType != null) { - return false; - } - } else if (!modificationType.equals(other.modificationType)) { - return false; - } - if (attribute == null) { - if (other.attribute != null) { - return false; - } - } else if (!attribute.equals(other.attribute)) { - return false; - } - if (oldAttribute == null) { - if (other.oldAttribute != null) { - return false; - } - } else if (!oldAttribute.equals(other.oldAttribute)) { - return false; - } - return true; - } - - @Override - public String toString() { - return String.format("AttributeModification [modificationType=%s, attribute=%s, oldAttribute=%s]", modificationType, attribute, - oldAttribute); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/model/BatchOperation.java b/persistence-core/src/main/java/org/gluu/persist/model/BatchOperation.java deleted file mode 100644 index 957bff49..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/model/BatchOperation.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.model; - -import java.util.List; - -/** - * Batch operation - * - * @author Yuriy Movchan Date: 01/29/2018 - */ -public interface BatchOperation { - - boolean collectSearchResult(int size); - - void performAction(List entries); - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/model/DefaultBatchOperation.java b/persistence-core/src/main/java/org/gluu/persist/model/DefaultBatchOperation.java deleted file mode 100644 index 02c4ede4..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/model/DefaultBatchOperation.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.model; - -/** - * @author Yuriy Movchan Date: 02/07/2018 - */ -public abstract class DefaultBatchOperation implements BatchOperation { - - public boolean collectSearchResult(int size) { - return true; - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/model/PagedResult.java b/persistence-core/src/main/java/org/gluu/persist/model/PagedResult.java deleted file mode 100644 index d2b458ff..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/model/PagedResult.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ -package org.gluu.persist.model; - -import java.io.Serializable; -import java.util.List; - -/** - * @author Val Pecaoco - * @author Yuriy Movchan Date: 01/25/2018 - */ -public class PagedResult implements Serializable { - - private static final long serialVersionUID = -4211997747213144092L; - - private int start; - - private int totalEntriesCount; - - private int entriesCount; - - private List entries; - - public int getTotalEntriesCount() { - return totalEntriesCount; - } - - public void setTotalEntriesCount(int totalEntriesCount) { - this.totalEntriesCount = totalEntriesCount; - } - - public int getEntriesCount() { - return entriesCount; - } - - public void setEntriesCount(int entriesCount) { - this.entriesCount = entriesCount; - } - - public int getStart() { - return start; - } - - public void setStart(int start) { - this.start = start; - } - - public final List getEntries() { - return entries; - } - - public final void setEntries(List entries) { - this.entries = entries; - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/model/PersistenceConfiguration.java b/persistence-core/src/main/java/org/gluu/persist/model/PersistenceConfiguration.java deleted file mode 100644 index 22d8f119..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/model/PersistenceConfiguration.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.gluu.persist.model; - -import org.gluu.persist.PersistenceEntryManagerFactory; -import org.gluu.util.properties.FileConfiguration; - -/** - * Persistence configuration - * - * @author Yuriy Movchan Date: 05/10/2019 - */ -public class PersistenceConfiguration { - - private String fileName; - private FileConfiguration configuration; - private Class entryManagerFactoryType; - private long lastModifiedTime; - - public PersistenceConfiguration() {} - - public PersistenceConfiguration(String fileName, FileConfiguration configuration, - Class entryManagerFactoryType, long lastModifiedTime) { - this.fileName = fileName; - this.configuration = configuration; - this.entryManagerFactoryType = entryManagerFactoryType; - this.lastModifiedTime = lastModifiedTime; - } - - public String getFileName() { - return fileName; - } - - public FileConfiguration getConfiguration() { - return configuration; - } - - public Class getEntryManagerFactoryType() { - return entryManagerFactoryType; - } - - public long getLastModifiedTime() { - return lastModifiedTime; - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/model/ProcessBatchOperation.java b/persistence-core/src/main/java/org/gluu/persist/model/ProcessBatchOperation.java deleted file mode 100644 index 610623f4..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/model/ProcessBatchOperation.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.model; - -/** - * @author Yuriy Movchan Date: 02/07/2018 - */ -public abstract class ProcessBatchOperation implements BatchOperation { - - public boolean collectSearchResult(int size) { - return false; - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/model/SearchScope.java b/persistence-core/src/main/java/org/gluu/persist/model/SearchScope.java deleted file mode 100644 index cc4b6f6d..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/model/SearchScope.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model; - -/** - * LDAP search scope - * - * @author Yuriy Movchan Date: 11/18/2016 - */ -public enum SearchScope { - - /** - * A predefined baseObject scope value, which indicates that only the entry - * specified by the base DN should be considered. - */ - BASE, - - /** - * A predefined singleLevel scope value, which indicates that only entries - * that are immediate subordinates of the entry specified by the base DN - * (but not the base entry itself) should be considered. - */ - ONE, - - /** - * A predefined wholeSubtree scope value, which indicates that the base - * entry itself and any subordinate entries (to any depth) should be - * considered. - */ - SUB; - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/model/SortOrder.java b/persistence-core/src/main/java/org/gluu/persist/model/SortOrder.java deleted file mode 100644 index 8f5de472..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/model/SortOrder.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model; - -import java.util.HashMap; -import java.util.Map; - -import org.gluu.persist.annotation.AttributeEnum; - -/** - * @author Val Pecaoco - */ -public enum SortOrder implements AttributeEnum { - - ASCENDING("ascending"), - DESCENDING("descending"); - - private String value; - - private static Map MAP_BY_VALUES = new HashMap(); - - static { - for (SortOrder enumType : values()) { - MAP_BY_VALUES.put(enumType.getValue(), enumType); - } - } - - SortOrder(String value) { - this.value = value; - } - - @Override - public String getValue() { - return value; - } - - public static SortOrder getByValue(String value) { - return MAP_BY_VALUES.get(value); - } - - @Override - public SortOrder resolveByValue(String value) { - return getByValue(value); - } -} diff --git a/persistence-core/src/main/java/org/gluu/persist/operation/PersistenceOperationService.java b/persistence-core/src/main/java/org/gluu/persist/operation/PersistenceOperationService.java deleted file mode 100644 index b41979de..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/operation/PersistenceOperationService.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.operation; - -import org.gluu.persist.exception.extension.PersistenceExtension; - -/** - * Base interface for Operation Service - * - * @author Yuriy Movchan Date: 06/22/2018 - */ -public interface PersistenceOperationService { - - boolean isConnected(); - - public void setPersistenceExtension(PersistenceExtension persistenceExtension); - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/operation/auth/PasswordDetails.java b/persistence-core/src/main/java/org/gluu/persist/operation/auth/PasswordDetails.java deleted file mode 100644 index b145ddfb..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/operation/auth/PasswordDetails.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.operation.auth; - -/** - * Store informations about an password - */ -public class PasswordDetails { - private final PasswordEncryptionMethod algorithm; - private final byte[] salt; - private final byte[] password; - - /** - * Creates a new PasswordDetails instance - */ - public PasswordDetails(PasswordEncryptionMethod algorithm, byte[] salt, byte[] password) { - this.algorithm = algorithm; - this.salt = salt; - this.password = password; - } - - /** - * The hash algorithm used to hash the password, null for plain text passwords - */ - public PasswordEncryptionMethod getAlgorithm() { - return algorithm; - } - - /** - * The salt used to hash the password, null if no salt was used - */ - public byte[] getSalt() { - return salt; - } - - /** - * The hashed or plain text password - */ - public byte[] getPassword() { - return password; - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/operation/auth/PasswordEncryptionHelper.java b/persistence-core/src/main/java/org/gluu/persist/operation/auth/PasswordEncryptionHelper.java deleted file mode 100644 index ae892a0c..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/operation/auth/PasswordEncryptionHelper.java +++ /dev/null @@ -1,482 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.operation.auth; - -import java.security.Key; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.spec.KeySpec; -import java.util.Arrays; -import java.util.Base64; - -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.PBEKeySpec; - -import org.apache.commons.codec.digest.Crypt; -import org.gluu.util.StringHelper; -import org.gluu.util.security.BCrypt; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Perform authentication and password encryption - */ -public final class PasswordEncryptionHelper { - - private static final Logger LOG = LoggerFactory.getLogger(PasswordEncryptionHelper.class); - - private static final byte[] CRYPT_SALT_CHARS = StringHelper.getBytesUtf8("./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); - - private PasswordEncryptionHelper() { - } - - /** - * Get the algorithm from the stored password - */ - public static PasswordEncryptionMethod findAlgorithm(String credentials) { - return findAlgorithm(StringHelper.getBytesUtf8(credentials)); - } - - /** - * Get the algorithm from the stored password - */ - public static PasswordEncryptionMethod findAlgorithm(byte[] credentials) { - if ((credentials == null) || (credentials.length == 0)) { - return null; - } - - if (credentials[0] == '{') { - // Get the algorithm - int pos = 1; - - while (pos < credentials.length) { - if (credentials[pos] == '}') { - break; - } - - pos++; - } - - if (pos < credentials.length) { - if (pos == 1) { - // We don't have an algorithm : return the credentials as is - return null; - } - - String algorithm = StringHelper.toLowerCase(StringHelper.utf8ToString(credentials, 1, pos - 1)); - - // Support for crypt additional encryption algorithms (e.g. - // {crypt}$1$salt$ez2vlPGdaLYkJam5pWs/Y1) - if (credentials.length > pos + 3 && credentials[pos + 1] == '$' && Character.isDigit(credentials[pos + 2])) { - if (credentials[pos + 3] == '$') { - algorithm += StringHelper.utf8ToString(credentials, pos + 1, 3); - } else if (credentials.length > pos + 4 && credentials[pos + 4] == '$') { - algorithm += StringHelper.utf8ToString(credentials, pos + 1, 4); - } - } - - return PasswordEncryptionMethod.getMethod(algorithm); - } else { - // We don't have an algorithm - return null; - } - } else { - // No '{algo}' part - return null; - } - } - - /** - * @see #createStoragePassword(byte[], PasswordEncryptionMethod) - */ - public static String createStoragePassword(String credentials, PasswordEncryptionMethod algorithm) { - byte[] resultBytes = createStoragePassword(StringHelper.getBytesUtf8(credentials), algorithm); - - return StringHelper.utf8ToString(resultBytes); - } - - /** - * Create a hashed password in a format that can be stored in the server. If the - * specified algorithm requires a salt then a random salt of 8 byte size is used - */ - public static byte[] createStoragePassword(byte[] credentials, PasswordEncryptionMethod algorithm) { - // Check plain text password - if (algorithm == null) { - return credentials; - } - - byte[] salt; - - switch (algorithm) { - case HASH_METHOD_SSHA: - case HASH_METHOD_SSHA256: - case HASH_METHOD_SSHA384: - case HASH_METHOD_SSHA512: - case HASH_METHOD_SMD5: - // Use 8 byte salt always except for "crypt" which needs 2 byte salt - salt = new byte[8]; - new SecureRandom().nextBytes(salt); - break; - - case HASH_METHOD_PKCS5S2: - // Use 16 byte salt for PKCS5S2 - salt = new byte[16]; - new SecureRandom().nextBytes(salt); - break; - - case HASH_METHOD_CRYPT: - salt = generateCryptSalt(2); - break; - - case HASH_METHOD_CRYPT_MD5: - case HASH_METHOD_CRYPT_SHA256: - case HASH_METHOD_CRYPT_SHA512: - salt = generateCryptSalt(8); - break; - - case HASH_METHOD_CRYPT_BCRYPT: - case HASH_METHOD_CRYPT_BCRYPT_B: - salt = StringHelper.getBytesUtf8(BCrypt.genSalt()); - break; - - default: - salt = null; - } - - byte[] hashedPassword = encryptPassword(credentials, algorithm, salt); - StringBuilder sb = new StringBuilder(); - - sb.append('{').append(StringHelper.toUpperCase(algorithm.getPrefix())).append('}'); - - if (algorithm == PasswordEncryptionMethod.HASH_METHOD_CRYPT || algorithm == PasswordEncryptionMethod.HASH_METHOD_CRYPT_BCRYPT) { - sb.append(StringHelper.utf8ToString(salt)); - sb.append(StringHelper.utf8ToString(hashedPassword)); - } else if (algorithm == PasswordEncryptionMethod.HASH_METHOD_CRYPT_MD5 || algorithm == PasswordEncryptionMethod.HASH_METHOD_CRYPT_SHA256 - || algorithm == PasswordEncryptionMethod.HASH_METHOD_CRYPT_SHA512) { - sb.append(algorithm.getSubPrefix()); - sb.append(StringHelper.utf8ToString(salt)); - sb.append('$'); - sb.append(StringHelper.utf8ToString(hashedPassword)); - } else if (salt != null) { - byte[] hashedPasswordWithSaltBytes = new byte[hashedPassword.length + salt.length]; - - if (algorithm == PasswordEncryptionMethod.HASH_METHOD_PKCS5S2) { - merge(hashedPasswordWithSaltBytes, salt, hashedPassword); - } else { - merge(hashedPasswordWithSaltBytes, hashedPassword, salt); - } - - sb.append(String.valueOf(Base64.getEncoder().encodeToString(hashedPasswordWithSaltBytes))); - } else { - sb.append(String.valueOf(Base64.getEncoder().encodeToString(hashedPassword))); - } - - return StringHelper.getBytesUtf8(sb.toString()); - } - - /** - * Compare the credentials - */ - public static boolean compareCredentials(String receivedCredentials, String storedCredentials) { - return compareCredentials(StringHelper.getBytesUtf8(receivedCredentials), StringHelper.getBytesUtf8(storedCredentials)); - } - - /** - * Compare the credentials - */ - public static boolean compareCredentials(byte[] receivedCredentials, byte[] storedCredentials) { - PasswordEncryptionMethod algorithm = findAlgorithm(storedCredentials); - - if (algorithm != null) { - // Get the encrypted part of the stored password - PasswordDetails passwordDetails = splitCredentials(storedCredentials); - - // Reuse the saltedPassword information to construct the encrypted password given by the user - byte[] userPassword = encryptPassword(receivedCredentials, passwordDetails.getAlgorithm(), passwordDetails.getSalt()); - - return compareBytes(userPassword, passwordDetails.getPassword()); - } else { - return compareBytes(receivedCredentials, storedCredentials); - } - } - - /** - * Compare two byte[] in a constant time. This is necessary because using an - * Array.equals() is not Timing attack safe ([1], [2] and [3]), a breach that - * can be exploited to break some hashes. - * - * [1] https://en.wikipedia.org/wiki/Timing_attack [2] - * http://rdist.root.org/2009/05/28/timing-attack-in-google-keyczar-library/ [3] - * https://cryptocoding.net/index.php/Coding_rules - */ - private static boolean compareBytes(byte[] provided, byte[] stored) { - if (stored == null) { - return provided == null; - } else if (provided == null) { - return false; - } - - // Now, compare the two passwords, using a constant time method - if (stored.length != provided.length) { - return false; - } - - // Loop on *every* byte in both passwords, and at the end, if one char at least is different, return false - int result = 0; - - for (int i = 0; i < stored.length; i++) { - // If both bytes are equal, xor will be == 0, otherwise it will be != 0 and it will be result - result |= (stored[i] ^ provided[i]); - } - - return result == 0; - } - - /** - * Encrypts the given credentials based on the algorithm name and optional salt - */ - private static byte[] encryptPassword(byte[] credentials, PasswordEncryptionMethod algorithm, byte[] salt) { - switch (algorithm) { - case HASH_METHOD_SHA: - case HASH_METHOD_SSHA: - return digest(PasswordEncryptionMethod.HASH_METHOD_SHA, credentials, salt); - - case HASH_METHOD_SHA256: - case HASH_METHOD_SSHA256: - return digest(PasswordEncryptionMethod.HASH_METHOD_SHA256, credentials, salt); - - case HASH_METHOD_SHA384: - case HASH_METHOD_SSHA384: - return digest(PasswordEncryptionMethod.HASH_METHOD_SHA384, credentials, salt); - - case HASH_METHOD_SHA512: - case HASH_METHOD_SSHA512: - return digest(PasswordEncryptionMethod.HASH_METHOD_SHA512, credentials, salt); - - case HASH_METHOD_MD5: - case HASH_METHOD_SMD5: - return digest(PasswordEncryptionMethod.HASH_METHOD_MD5, credentials, salt); - - case HASH_METHOD_CRYPT: - String saltWithCrypted = Crypt.crypt(StringHelper.utf8ToString(credentials), StringHelper.utf8ToString(salt)); - String crypted = saltWithCrypted.substring(2); - return StringHelper.getBytesUtf8(crypted); - - case HASH_METHOD_CRYPT_MD5: - case HASH_METHOD_CRYPT_SHA256: - case HASH_METHOD_CRYPT_SHA512: - String saltWithCrypted2 = Crypt.crypt(StringHelper.utf8ToString(credentials), algorithm.getSubPrefix() + StringHelper.utf8ToString(salt)); - String crypted2 = saltWithCrypted2.substring(saltWithCrypted2.lastIndexOf('$') + 1); - return StringHelper.getBytesUtf8(crypted2); - - case HASH_METHOD_CRYPT_BCRYPT: - case HASH_METHOD_CRYPT_BCRYPT_B: - String crypted3 = BCrypt.hashPw(StringHelper.utf8ToString(credentials), StringHelper.utf8ToString(salt)); - return StringHelper.getBytesUtf8(crypted3.substring(crypted3.length() - 31)); - - case HASH_METHOD_PKCS5S2: - return generatePbkdf2Hash(credentials, algorithm, salt); - - default: - return credentials; - } - } - - /** - * Compute the hashed password given an algorithm, the credentials and an optional salt. - */ - private static byte[] digest(PasswordEncryptionMethod algorithm, byte[] password, byte[] salt) { - MessageDigest digest; - - try { - digest = MessageDigest.getInstance(algorithm.getAlgorithm()); - } catch (NoSuchAlgorithmException ex) { - return null; - } - - if (salt != null) { - digest.update(password); - digest.update(salt); - return digest.digest(); - } else { - return digest.digest(password); - } - } - - /** - * Decompose the stored password in an algorithm, an eventual salt and the - * password itself. - * - * If the algorithm is SHA, SSHA, MD5 or SMD5, the part following the algorithm - * is base64 encoded - * - * @param credentials - * The byte[] containing the credentials to split - * @return The password - */ - public static PasswordDetails splitCredentials(byte[] credentials) { - PasswordEncryptionMethod algorithm = findAlgorithm(credentials); - - // check plain text password - if (algorithm == null) { - return new PasswordDetails(null, null, credentials); - } - - int algoLength = algorithm.getPrefix().length() + 2; - byte[] password; - - switch (algorithm) { - case HASH_METHOD_MD5: - case HASH_METHOD_SMD5: - return getCredentials(credentials, algoLength, algorithm.getHashLength(), algorithm); - - case HASH_METHOD_SHA: - case HASH_METHOD_SSHA: - return getCredentials(credentials, algoLength, algorithm.getHashLength(), algorithm); - - case HASH_METHOD_SHA256: - case HASH_METHOD_SSHA256: - return getCredentials(credentials, algoLength, algorithm.getHashLength(), algorithm); - - case HASH_METHOD_SHA384: - case HASH_METHOD_SSHA384: - return getCredentials(credentials, algoLength, algorithm.getHashLength(), algorithm); - - case HASH_METHOD_SHA512: - case HASH_METHOD_SSHA512: - return getCredentials(credentials, algoLength, algorithm.getHashLength(), algorithm); - - case HASH_METHOD_PKCS5S2: - return getPbkdf2Credentials(credentials, algoLength, algorithm); - - case HASH_METHOD_CRYPT: - // The password is associated with a salt. Decompose it - // in two parts, no decoding required. - // The salt comes first, not like for SSHA and SMD5, and is 2 bytes long - // The algorithm, salt, and password will be stored into the PasswordDetails - // structure. - byte[] salt = new byte[2]; - password = new byte[credentials.length - salt.length - algoLength]; - split(credentials, algoLength, salt, password); - return new PasswordDetails(algorithm, salt, password); - - case HASH_METHOD_CRYPT_BCRYPT: - case HASH_METHOD_CRYPT_BCRYPT_B: - salt = Arrays.copyOfRange(credentials, algoLength, credentials.length - 31); - password = Arrays.copyOfRange(credentials, credentials.length - 31, credentials.length); - - return new PasswordDetails(algorithm, salt, password); - case HASH_METHOD_CRYPT_MD5: - case HASH_METHOD_CRYPT_SHA256: - case HASH_METHOD_CRYPT_SHA512: - // skip $x$ - algoLength = algoLength + 3; - return getCryptCredentials(credentials, algoLength, algorithm); - - default: - // unknown method - throw new IllegalArgumentException("Unknown hash algorithm " + algorithm); - } - } - - /** - * Compute the credentials - */ - private static PasswordDetails getCredentials(byte[] credentials, int algoLength, int hashLen, PasswordEncryptionMethod algorithm) { - // The password is associated with a salt. Decompose it in two parts, after having decoded the password. - // The salt is at the end of the credentials. - // The algorithm, salt, and password will be stored into the PasswordDetails structure - byte[] passwordAndSalt = Base64.getDecoder().decode(StringHelper.utf8ToString(credentials, algoLength, credentials.length - algoLength)); - - int saltLength = passwordAndSalt.length - hashLen; - byte[] salt = saltLength == 0 ? null : new byte[saltLength]; - byte[] password = new byte[hashLen]; - split(passwordAndSalt, 0, password, salt); - - return new PasswordDetails(algorithm, salt, password); - } - - private static void split(byte[] all, int offset, byte[] left, byte[] right) { - System.arraycopy(all, offset, left, 0, left.length); - if (right != null) { - System.arraycopy(all, offset + left.length, right, 0, right.length); - } - } - - private static void merge(byte[] all, byte[] left, byte[] right) { - System.arraycopy(left, 0, all, 0, left.length); - System.arraycopy(right, 0, all, left.length, right.length); - } - - /** - * Generates a hash based on the - * PKCS5S2 spec - */ - private static byte[] generatePbkdf2Hash(byte[] credentials, PasswordEncryptionMethod algorithm, byte[] salt) { - try { - SecretKeyFactory sk = SecretKeyFactory.getInstance(algorithm.getAlgorithm()); - char[] password = StringHelper.utf8ToString(credentials).toCharArray(); - KeySpec keySpec = new PBEKeySpec(password, salt, 10000, algorithm.getHashLength() * 8); - Key key = sk.generateSecret(keySpec); - return key.getEncoded(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Gets the credentials from a PKCS5S2 hash. The salt for PKCS5S2 hash is - * prepended to the password - */ - private static PasswordDetails getPbkdf2Credentials(byte[] credentials, int algoLength, PasswordEncryptionMethod algorithm) { - // The password is associated with a salt. Decompose it in two parts, after having decoded the password. - // The salt is at the *beginning* of the credentials, and is 16 bytes long - // The algorithm, salt, and password will be stored into the PasswordDetails structure - byte[] passwordAndSalt = Base64.getDecoder().decode(StringHelper.utf8ToString(credentials, algoLength, credentials.length - algoLength)); - - int saltLength = passwordAndSalt.length - algorithm.getHashLength(); - byte[] salt = new byte[saltLength]; - byte[] password = new byte[algorithm.getHashLength()]; - - split(passwordAndSalt, 0, salt, password); - - return new PasswordDetails(algorithm, salt, password); - } - - private static byte[] generateCryptSalt(int length) { - byte[] salt = new byte[length]; - SecureRandom sr = new SecureRandom(); - for (int i = 0; i < salt.length; i++) { - salt[i] = CRYPT_SALT_CHARS[sr.nextInt(CRYPT_SALT_CHARS.length)]; - } - - return salt; - } - - private static PasswordDetails getCryptCredentials(byte[] credentials, int algoLength, PasswordEncryptionMethod algorithm) { - // The password is associated with a salt. Decompose it in two parts, no decoding required. - // The salt length is dynamic, between the 2nd and 3rd '$'. - // The algorithm, salt, and password will be stored into the PasswordDetails structure. - - // Skip {crypt}$x$ - int pos = algoLength; - while (pos < credentials.length) { - if (credentials[pos] == '$') { - break; - } - - pos++; - } - - byte[] salt = Arrays.copyOfRange(credentials, algoLength, pos); - byte[] password = Arrays.copyOfRange(credentials, pos + 1, credentials.length); - - return new PasswordDetails(algorithm, salt, password); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/operation/auth/PasswordEncryptionMethod.java b/persistence-core/src/main/java/org/gluu/persist/operation/auth/PasswordEncryptionMethod.java deleted file mode 100644 index b5292442..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/operation/auth/PasswordEncryptionMethod.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ -package org.gluu.persist.operation.auth; - -/** - * Password encryption methods - */ -public enum PasswordEncryptionMethod { - /** The SHA encryption method */ - HASH_METHOD_SHA("SHA", "SHA", "sha", 20), - - /** The Salted SHA encryption method */ - HASH_METHOD_SSHA("SSHA", "SHA", "ssha", 20), - - /** The SHA-256 encryption method */ - HASH_METHOD_SHA256("SHA-256", "SHA-256", "sha256", 32), - - /** The salted SHA-256 encryption method */ - HASH_METHOD_SSHA256("SSHA-256", "SHA-256", "ssha256", 32), - - /** The SHA-384 encryption method */ - HASH_METHOD_SHA384("SHA-384", "SHA-384", "sha384", 48), - - /** The salted SHA-384 encryption method */ - HASH_METHOD_SSHA384("SSHA-384", "SHA-384", "ssha384", 48), - - /** The SHA-512 encryption method */ - HASH_METHOD_SHA512("SHA-512", "SHA-512", "sha512", 64), - - /** The salted SHA-512 encryption method */ - HASH_METHOD_SSHA512("SSHA-512", "SHA-512", "ssha512", 64), - - /** The MD5 encryption method */ - HASH_METHOD_MD5("MD5", "MD5", "md5", 16), - - /** The Salter MD5 encryption method */ - HASH_METHOD_SMD5("SMD5", "MD5", "smd5", 16), - - /** The crypt encryption method */ - HASH_METHOD_CRYPT("CRYPT", "CRYPT", "crypt", 11), - - /** The crypt (MD5) encryption method */ - HASH_METHOD_CRYPT_MD5("CRYPT-MD5", "MD5", "crypt", "$1$", 22), - - /** The crypt (SHA-256) encryption method */ - HASH_METHOD_CRYPT_SHA256("CRYPT-SHA-256", "SHA-256", "crypt", "$5$", 43), - - /** The crypt (SHA-512) encryption method */ - HASH_METHOD_CRYPT_SHA512("CRYPT-SHA-512", "SHA-512", "crypt", "$6$", 86), - - /** The BCrypt encryption method */ - HASH_METHOD_CRYPT_BCRYPT("CRYPT-BCRYPT", "BCRYPT", "crypt", "$2a$", 31), - - /** The BCrypt encryption method */ - HASH_METHOD_CRYPT_BCRYPT_B("CRYPT-BCRYPT", "BCRYPT", "bcrypt", "$2b$", 31), - - /** The PBKDF2-based encryption method */ - HASH_METHOD_PKCS5S2("PKCS5S2", "PBKDF2WithHmacSHA1", "PKCS5S2", 32); - - /** The associated name */ - private final String name; - - /** The associated algorithm */ - private final String algorithm; - - /** The associated prefix */ - private final String prefix; - - /** The optional sub-prefix */ - private final String subPrefix; - - /** Hash length */ - private final int hashLength; - - PasswordEncryptionMethod(String name, String algorithm, String prefix, int hashLength) { - this(name, algorithm, prefix, "", hashLength); - } - - PasswordEncryptionMethod(String name, String algorithm, String prefix, String subPrefix, int hashLength) { - this.name = name; - this.algorithm = algorithm; - this.prefix = prefix; - this.subPrefix = subPrefix; - this.hashLength = hashLength; - } - - public String getName() { - return name; - } - - public String getAlgorithm() { - return algorithm; - } - - public String getPrefix() { - return prefix; - } - - public String getSubPrefix() { - return subPrefix; - } - - public final int getHashLength() { - return hashLength; - } - - /** - * Get the associated constant from a string - */ - public static PasswordEncryptionMethod getMethod(String algorithm) { - if (matches(algorithm, HASH_METHOD_SHA)) { - return HASH_METHOD_SHA; - } - - if (matches(algorithm, HASH_METHOD_SSHA)) { - return HASH_METHOD_SSHA; - } - if (matches(algorithm, HASH_METHOD_MD5)) { - return HASH_METHOD_MD5; - } - - if (matches(algorithm, HASH_METHOD_SMD5)) { - return HASH_METHOD_SMD5; - } - - if (matches(algorithm, HASH_METHOD_CRYPT)) { - return HASH_METHOD_CRYPT; - } - - if (matches(algorithm, HASH_METHOD_CRYPT_MD5)) { - return HASH_METHOD_CRYPT_MD5; - } - - if (matches(algorithm, HASH_METHOD_CRYPT_SHA256)) { - return HASH_METHOD_CRYPT_SHA256; - } - - if (matches(algorithm, HASH_METHOD_CRYPT_SHA512)) { - return HASH_METHOD_CRYPT_SHA512; - } - - if (matches(algorithm, HASH_METHOD_CRYPT_BCRYPT)) { - return HASH_METHOD_CRYPT_BCRYPT; - } - - if (matches(algorithm, HASH_METHOD_CRYPT_BCRYPT_B)) { - return HASH_METHOD_CRYPT_BCRYPT_B; - } - - if (matches(algorithm, HASH_METHOD_SHA256)) { - return HASH_METHOD_SHA256; - } - - if (matches(algorithm, HASH_METHOD_SSHA256)) { - return HASH_METHOD_SSHA256; - } - - if (matches(algorithm, HASH_METHOD_SHA384)) { - return HASH_METHOD_SHA384; - } - - if (matches(algorithm, HASH_METHOD_SSHA384)) { - return HASH_METHOD_SSHA384; - } - - if (matches(algorithm, HASH_METHOD_SHA512)) { - return HASH_METHOD_SHA512; - } - - if (matches(algorithm, HASH_METHOD_SSHA512)) { - return HASH_METHOD_SSHA512; - } - - if (matches(algorithm, HASH_METHOD_PKCS5S2)) { - return HASH_METHOD_PKCS5S2; - } - - return null; - } - - private static boolean matches(String algorithm, PasswordEncryptionMethod constant) { - return constant.name.equalsIgnoreCase(algorithm) || (constant.prefix + constant.subPrefix).equalsIgnoreCase(algorithm); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/reflect/property/BasicPropertyAccessor.java b/persistence-core/src/main/java/org/gluu/persist/reflect/property/BasicPropertyAccessor.java deleted file mode 100644 index 5c242470..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/reflect/property/BasicPropertyAccessor.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.reflect.property; - -import java.beans.Introspector; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import org.gluu.persist.exception.BasePersistenceException; -import org.gluu.persist.exception.PropertyAccessException; -import org.gluu.persist.exception.PropertyNotFoundException; -import org.gluu.persist.reflect.util.ReflectHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Accesses property values via a get/set pair, which may be nonpublic. The - * default (and recommended strategy). - */ -public class BasicPropertyAccessor implements PropertyAccessor { - - private static final Logger LOG = LoggerFactory.getLogger(BasicPropertyAccessor.class); - - public static final class BasicSetter implements Setter { - - private static final long serialVersionUID = 1660638549257218450L; - - private Class clazz; - private final transient Method method; - private final String propertyName; - - private BasicSetter(Class clazz, Method method, String propertyName) { - this.clazz = clazz; - this.method = method; - this.propertyName = propertyName; - } - - public void set(Object target, Object value) throws BasePersistenceException { - try { - method.invoke(target, new Object[] {value}); - } catch (NullPointerException npe) { - if (value == null && method.getParameterTypes()[0].isPrimitive()) { - throw new PropertyAccessException(npe, "Null value was assigned to a property of primitive type", true, clazz, - propertyName); - } else { - throw new PropertyAccessException(npe, "NullPointerException occurred while calling", true, clazz, propertyName); - } - } catch (InvocationTargetException ite) { - throw new PropertyAccessException(ite, "Exception occurred inside", true, clazz, propertyName); - } catch (IllegalAccessException iae) { - throw new PropertyAccessException(iae, "IllegalAccessException occurred while calling", true, clazz, propertyName); - // cannot occur - } catch (IllegalArgumentException iae) { - if (value == null && method.getParameterTypes()[0].isPrimitive()) { - throw new PropertyAccessException(iae, "Null value was assigned to a property of primitive type", true, clazz, - propertyName); - } else { - LOG.error("IllegalArgumentException in class: " + clazz.getName() + ", setter method of property: " + propertyName); - LOG.error("expected type: " + method.getParameterTypes()[0].getName() + ", actual value: " - + (value == null ? null : value.getClass().getName())); - throw new PropertyAccessException(iae, "IllegalArgumentException occurred while calling", true, clazz, propertyName); - } - } - } - - public Method getMethod() { - return method; - } - - public String getMethodName() { - return method.getName(); - } - - Object readResolve() { - return createSetter(clazz, propertyName); - } - - @Override - public String toString() { - return "BasicSetter(" + clazz.getName() + '.' + propertyName + ')'; - } - } - - public static final class BasicGetter implements Getter { - - private static final long serialVersionUID = -5736635201315368096L; - - private Class clazz; - private final transient Method method; - private final String propertyName; - - private BasicGetter(Class clazz, Method method, String propertyName) { - this.clazz = clazz; - this.method = method; - this.propertyName = propertyName; - } - - public Object get(Object target) throws BasePersistenceException { - try { - return method.invoke(target, (Object[]) null); - } catch (InvocationTargetException ite) { - throw new PropertyAccessException(ite, "Exception occurred inside", false, clazz, propertyName); - } catch (IllegalAccessException iae) { - throw new PropertyAccessException(iae, "IllegalAccessException occurred while calling", false, clazz, propertyName); - // cannot occur - } catch (IllegalArgumentException iae) { - LOG.error("IllegalArgumentException in class: " + clazz.getName() + ", getter method of property: " + propertyName); - throw new PropertyAccessException(iae, "IllegalArgumentException occurred calling", false, clazz, propertyName); - } - } - - public Class getReturnType() { - return method.getReturnType(); - } - - public Method getMethod() { - return method; - } - - public String getMethodName() { - return method.getName(); - } - - @Override - public String toString() { - return "BasicGetter(" + clazz.getName() + '.' + propertyName + ')'; - } - - Object readResolve() { - return createGetter(clazz, propertyName); - } - } - - public Setter getSetter(Class theClass, String propertyName) throws PropertyNotFoundException { - return createSetter(theClass, propertyName); - } - - private static Setter createSetter(Class theClass, String propertyName) throws PropertyNotFoundException { - BasicSetter result = getSetterOrNull(theClass, propertyName); - if (result == null) { - throw new PropertyNotFoundException("Could not find a setter for property " + propertyName + " in class " + theClass.getName()); - } - return result; - } - - private static BasicSetter getSetterOrNull(Class theClass, String propertyName) { - if ((theClass == Object.class) || (theClass == null)) { - return null; - } - - Method method = setterMethod(theClass, propertyName); - - if (method != null) { - if (!ReflectHelper.isPublic(theClass, method)) { - method.setAccessible(true); - } - - return new BasicSetter(theClass, method, propertyName); - } else { - BasicSetter setter = getSetterOrNull(theClass.getSuperclass(), propertyName); - if (setter == null) { - Class[] interfaces = theClass.getInterfaces(); - for (int i = 0; setter == null && i < interfaces.length; i++) { - setter = getSetterOrNull(interfaces[i], propertyName); - } - } - return setter; - } - - } - - private static Method setterMethod(Class theClass, String propertyName) { - - BasicGetter getter = getGetterOrNull(theClass, propertyName); - Class returnType = (getter == null) ? null : getter.getReturnType(); - - Method[] methods = theClass.getDeclaredMethods(); - Method potentialSetter = null; - for (int i = 0; i < methods.length; i++) { - String methodName = methods[i].getName(); - - if (methods[i].getParameterTypes().length == 1 && methodName.startsWith("set")) { - String testStdMethod = Introspector.decapitalize(methodName.substring(3)); - String testOldMethod = methodName.substring(3); - if (testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName)) { - potentialSetter = methods[i]; - if (returnType == null || methods[i].getParameterTypes()[0].equals(returnType)) { - return potentialSetter; - } - } - } - } - return potentialSetter; - } - - public Getter getGetter(Class theClass, String propertyName) throws PropertyNotFoundException { - return createGetter(theClass, propertyName); - } - - public static Getter createGetter(Class theClass, String propertyName) throws PropertyNotFoundException { - BasicGetter result = getGetterOrNull(theClass, propertyName); - if (result == null) { - throw new PropertyNotFoundException("Could not find a getter for " + propertyName + " in class " + theClass.getName()); - } - return result; - - } - - private static BasicGetter getGetterOrNull(Class theClass, String propertyName) { - if ((theClass == Object.class) || (theClass == null)) { - return null; - } - - Method method = getterMethod(theClass, propertyName); - - if (method != null) { - if (!ReflectHelper.isPublic(theClass, method)) { - method.setAccessible(true); - } - - return new BasicGetter(theClass, method, propertyName); - } else { - BasicGetter getter = getGetterOrNull(theClass.getSuperclass(), propertyName); - if (getter == null) { - Class[] interfaces = theClass.getInterfaces(); - for (int i = 0; getter == null && i < interfaces.length; i++) { - getter = getGetterOrNull(interfaces[i], propertyName); - } - } - return getter; - } - } - - private static Method getterMethod(Class theClass, String propertyName) { - - Method[] methods = theClass.getDeclaredMethods(); - for (int i = 0; i < methods.length; i++) { - // only carry on if the method has no parameters - if (methods[i].getParameterTypes().length == 0) { - String methodName = methods[i].getName(); - - // try "get" - if (methodName.startsWith("get")) { - String testStdMethod = Introspector.decapitalize(methodName.substring(3)); - String testOldMethod = methodName.substring(3); - if (testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName)) { - return methods[i]; - } - - } - - // if not "get", then try "is" - if (methodName.startsWith("is")) { - String testStdMethod = Introspector.decapitalize(methodName.substring(2)); - String testOldMethod = methodName.substring(2); - if (testStdMethod.equals(propertyName) || testOldMethod.equals(propertyName)) { - return methods[i]; - } - } - } - } - return null; - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/reflect/property/BasicPropertyAnnotationResolver.java b/persistence-core/src/main/java/org/gluu/persist/reflect/property/BasicPropertyAnnotationResolver.java deleted file mode 100644 index 3e295b32..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/reflect/property/BasicPropertyAnnotationResolver.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.reflect.property; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.gluu.persist.exception.PropertyNotFoundException; -import org.gluu.persist.reflect.util.ReflectHelper; -import org.gluu.util.StringHelper; - -/** - * Defines a strategy for accessing class and propery annotations. - * - * @author Yuriy Movchan Date: 10.08.2010 - */ -public class BasicPropertyAnnotationResolver implements PropertyAnnotationResolver { - - public List getClassAnnotations(Class theClass, Class... allowedAnnotations) { - List result = getOnlyAllowedAnntotations(theClass.getAnnotations(), allowedAnnotations); - - Class superClass = theClass.getSuperclass(); - while (ReflectHelper.isNotPrimitiveClass(superClass)) { - result.addAll(getOnlyAllowedAnntotations(superClass.getAnnotations(), allowedAnnotations)); - superClass = superClass.getSuperclass(); - } - - return result; - } - - public List getPropertyAnnotations(Class theClass, String propertyName, Class... allowedAnnotations) - throws PropertyNotFoundException { - if (StringHelper.isEmpty(propertyName)) { - throw new PropertyNotFoundException("Could not find property " + propertyName + " in class " + theClass.getName()); - } - - Class thisClass = theClass; - while (ReflectHelper.isNotPrimitiveClass(thisClass)) { - Field[] fileds = thisClass.getDeclaredFields(); - for (Field filed : fileds) { - if (propertyName.equals(filed.getName())) { - return getOnlyAllowedAnntotations(filed.getAnnotations(), allowedAnnotations); - } - } - thisClass = thisClass.getSuperclass(); - } - - throw new PropertyNotFoundException("Could not find property " + propertyName + " in class " + theClass.getName()); - } - - public Map> getPropertiesAnnotations(Class theClass, Class... allowedAnnotations) { - Map> result = new HashMap>(); - - Class thisClass = theClass; - while (ReflectHelper.isNotPrimitiveClass(thisClass)) { - Field[] fields = thisClass.getDeclaredFields(); - for (Field field : fields) { - List annotations = getOnlyAllowedAnntotations(field.getAnnotations(), allowedAnnotations); - if ((annotations == null) || (annotations.size() == 0)) { - continue; - } - - result.put(field.getName(), annotations); - } - thisClass = thisClass.getSuperclass(); - } - - return result; - } - - private List getOnlyAllowedAnntotations(Annotation[] annotations, Class[] allowedAnnotations) { - List result = new ArrayList(); - if (annotations.length == 0) { - return result; - } - - for (Annotation annotation : annotations) { - for (Class allowedAnnotation : allowedAnnotations) { - if (annotation.annotationType().equals(allowedAnnotation)) { - result.add(annotation); - } - } - } - - return result; - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/reflect/property/DirectPropertyAccessor.java b/persistence-core/src/main/java/org/gluu/persist/reflect/property/DirectPropertyAccessor.java deleted file mode 100644 index ad893cea..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/reflect/property/DirectPropertyAccessor.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.reflect.property; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -import org.gluu.persist.exception.BasePersistenceException; -import org.gluu.persist.exception.PropertyAccessException; -import org.gluu.persist.exception.PropertyNotFoundException; -import org.gluu.persist.reflect.util.ReflectHelper; - -/** - * Accesses fields directly. - */ -public class DirectPropertyAccessor implements PropertyAccessor { - - public static final class DirectGetter implements Getter { - - private static final long serialVersionUID = 242538698307476168L; - - private final transient Field field; - private final Class clazz; - private final String name; - - DirectGetter(Field field, Class clazz, String name) { - this.field = field; - this.clazz = clazz; - this.name = name; - } - - public Object get(Object target) throws BasePersistenceException { - try { - return field.get(target); - } catch (Exception e) { - throw new PropertyAccessException(e, "could not get a field value by reflection", false, clazz, name); - } - } - - public Method getMethod() { - return null; - } - - public String getMethodName() { - return null; - } - - public Class getReturnType() { - return field.getType(); - } - - Object readResolve() { - return new DirectGetter(getField(clazz, name), clazz, name); - } - - @Override - public String toString() { - return "DirectGetter(" + clazz.getName() + '.' + name + ')'; - } - } - - public static final class DirectSetter implements Setter { - - private static final long serialVersionUID = 7468445825009849335L; - - private final transient Field field; - private final Class clazz; - private final String name; - - DirectSetter(Field field, Class clazz, String name) { - this.field = field; - this.clazz = clazz; - this.name = name; - } - - public Method getMethod() { - return null; - } - - public String getMethodName() { - return null; - } - - public void set(Object target, Object value) throws BasePersistenceException { - try { - field.set(target, value); - } catch (Exception e) { - if (value == null && field.getType().isPrimitive()) { - throw new PropertyAccessException(e, "Null value was assigned to a property of primitive type", true, clazz, name); - } else { - throw new PropertyAccessException(e, "could not set a field value by reflection", true, clazz, name); - } - } - } - - @Override - public String toString() { - return "DirectSetter(" + clazz.getName() + '.' + name + ')'; - } - - Object readResolve() { - return new DirectSetter(getField(clazz, name), clazz, name); - } - } - - private static Field getField(Class clazz, String name) throws PropertyNotFoundException { - if (clazz == null || clazz == Object.class) { - throw new PropertyNotFoundException("field not found: " + name); - } - Field field; - try { - field = clazz.getDeclaredField(name); - } catch (NoSuchFieldException nsfe) { - field = getField(clazz, clazz.getSuperclass(), name); - } - if (!ReflectHelper.isPublic(clazz, field)) { - field.setAccessible(true); - } - return field; - } - - private static Field getField(Class root, Class clazz, String name) throws PropertyNotFoundException { - if (clazz == null || clazz == Object.class) { - throw new PropertyNotFoundException("field [" + name + "] not found on " + root.getName()); - } - Field field; - try { - field = clazz.getDeclaredField(name); - } catch (NoSuchFieldException nsfe) { - field = getField(root, clazz.getSuperclass(), name); - } - if (!ReflectHelper.isPublic(clazz, field)) { - field.setAccessible(true); - } - return field; - } - - public Getter getGetter(Class theClass, String propertyName) throws PropertyNotFoundException { - return new DirectGetter(getField(theClass, propertyName), theClass, propertyName); - } - - public Setter getSetter(Class theClass, String propertyName) throws PropertyNotFoundException { - return new DirectSetter(getField(theClass, propertyName), theClass, propertyName); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/reflect/property/Getter.java b/persistence-core/src/main/java/org/gluu/persist/reflect/property/Getter.java deleted file mode 100644 index f6bfa57c..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/reflect/property/Getter.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.reflect.property; - -import java.io.Serializable; -import java.lang.reflect.Method; - -import org.gluu.persist.exception.BasePersistenceException; - -/** - * Gets values of a particular property - */ -public interface Getter extends Serializable { - /** - * Get the property value from the given instance. - * - * @param owner - * The instance containing the value to be retreived. - * @return The extracted value. - * @throws BasePersistenceException - */ - Object get(Object owner) throws BasePersistenceException; - - /** - * Get the declared Java type - */ - Class getReturnType(); - - /** - * Optional operation (return null) - */ - String getMethodName(); - - /** - * Optional operation (return null) - */ - Method getMethod(); -} diff --git a/persistence-core/src/main/java/org/gluu/persist/reflect/property/PropertyAccessor.java b/persistence-core/src/main/java/org/gluu/persist/reflect/property/PropertyAccessor.java deleted file mode 100644 index 6057aff1..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/reflect/property/PropertyAccessor.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.reflect.property; - -import org.gluu.persist.exception.PropertyNotFoundException; - -/** - * Abstracts the notion of a "property". Defines a strategy for accessing the - * value of an attribute. - */ -public interface PropertyAccessor { - /** - * Create a "getter" for the named attribute - */ - Getter getGetter(Class theClass, String propertyName) throws PropertyNotFoundException; - - /** - * Create a "setter" for the named attribute - */ - Setter getSetter(Class theClass, String propertyName) throws PropertyNotFoundException; -} diff --git a/persistence-core/src/main/java/org/gluu/persist/reflect/property/PropertyAnnotation.java b/persistence-core/src/main/java/org/gluu/persist/reflect/property/PropertyAnnotation.java deleted file mode 100644 index 7b5375b8..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/reflect/property/PropertyAnnotation.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.reflect.property; - -import java.io.Serializable; -import java.lang.annotation.Annotation; -import java.util.List; - -/** - * Hold property with their annotations - * - * @author Yuriy Movchan Date: 04.14.2011 - */ -public class PropertyAnnotation implements Comparable, Serializable { - - private static final long serialVersionUID = 4620529664753916995L; - - private final String propertyName; - private final transient List annotations; - - private transient Class parameterType; - - public PropertyAnnotation(String property, List annotations) { - this.propertyName = property; - this.annotations = annotations; - this.parameterType = null; - } - - public String getPropertyName() { - return propertyName; - } - - public List getAnnotations() { - return annotations; - } - - public Class getParameterType() { - return parameterType; - } - - public void setParameterType(Class parameterType) { - this.parameterType = parameterType; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((propertyName == null) ? 0 : propertyName.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - - if ((obj == null) || (getClass() != obj.getClass())) { - return false; - } - - PropertyAnnotation other = (PropertyAnnotation) obj; - if (propertyName == null) { - if (other.propertyName != null) { - return false; - } - } else if (!propertyName.equals(other.propertyName)) { - return false; - } - - return true; - } - - public int compareTo(PropertyAnnotation other) { - if ((other == null) || (other.getPropertyName() == null)) { - return (propertyName == null) ? 0 : 1; - } else { - return (propertyName == null) ? -1 : propertyName.compareTo(other.getPropertyName()); - } - } - - @Override - public String toString() { - return String.format("PropertyAnnotation [propertyName=%s, annotations=%s]", propertyName, annotations); - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/reflect/property/PropertyAnnotationResolver.java b/persistence-core/src/main/java/org/gluu/persist/reflect/property/PropertyAnnotationResolver.java deleted file mode 100644 index 8ab082cb..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/reflect/property/PropertyAnnotationResolver.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.reflect.property; - -import java.lang.annotation.Annotation; -import java.util.List; -import java.util.Map; - -import org.gluu.persist.exception.PropertyNotFoundException; - -/** - * Defines a strategy for accessing class and propery annotations. - * - * @author Yuriy Movchan Date: 10.08.2010 - */ -public interface PropertyAnnotationResolver { - - /** - * Get list of class annotations - */ - List getClassAnnotations(Class theClass, Class... allowedAnnotations); - - /** - * Get list of property annotations - */ - List getPropertyAnnotations(Class theClass, String propertyName, Class... allowedAnnotations) - throws PropertyNotFoundException; - - /** - * Get map of properties annotations - */ - Map> getPropertiesAnnotations(Class theClass, Class... allowedAnnotations); - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/reflect/property/Setter.java b/persistence-core/src/main/java/org/gluu/persist/reflect/property/Setter.java deleted file mode 100644 index f40487eb..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/reflect/property/Setter.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.reflect.property; - -import java.io.Serializable; -import java.lang.reflect.Method; - -import org.gluu.persist.exception.BasePersistenceException; - -/** - * Sets values to a particular property. - */ -public interface Setter extends Serializable { - /** - * Set the property value from the given instance - * - * @param target - * The instance upon which to set the given value. - * @param value - * The value to be set on the target. - * @throws BasePersistenceException - */ - void set(Object target, Object value) throws BasePersistenceException; - - /** - * Optional operation (return null) - */ - String getMethodName(); - - /** - * Optional operation (return null) - */ - Method getMethod(); -} diff --git a/persistence-core/src/main/java/org/gluu/persist/reflect/util/ReflectHelper.java b/persistence-core/src/main/java/org/gluu/persist/reflect/util/ReflectHelper.java deleted file mode 100644 index eff05821..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/reflect/util/ReflectHelper.java +++ /dev/null @@ -1,574 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.reflect.util; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Member; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import org.gluu.persist.exception.MappingException; -import org.gluu.persist.exception.PropertyNotFoundException; -import org.gluu.persist.reflect.property.BasicPropertyAccessor; -import org.gluu.persist.reflect.property.BasicPropertyAnnotationResolver; -import org.gluu.persist.reflect.property.DirectPropertyAccessor; -import org.gluu.persist.reflect.property.Getter; -import org.gluu.persist.reflect.property.PropertyAccessor; -import org.gluu.persist.reflect.property.Setter; - -/** - * Utility class for various reflection operations. - */ -public final class ReflectHelper { - - private static final PropertyAccessor BASIC_PROPERTY_ACCESSOR = new BasicPropertyAccessor(); - private static final PropertyAccessor DIRECT_PROPERTY_ACCESSOR = new DirectPropertyAccessor(); - - private static final BasicPropertyAnnotationResolver BASIC_PROPERTY_ANNOTATION_RESOLVER = new BasicPropertyAnnotationResolver(); - - public static final Class[] NO_PARAM_SIGNATURE = new Class[0]; - public static final Object[] NO_PARAMS = new Object[0]; - public static final Annotation[] NO_ANNOTATIONS = new Annotation[0]; - - // findbugs: mutable static field should be package protected. In case it needed outside of the class please copy via method - private static final Class[] SINGLE_OBJECT_PARAM_SIGNATURE = new Class[] {Object.class}; - - private static final Method OBJECT_EQUALS; - private static final Method OBJECT_HASHCODE; - - static { - Method eq; - Method hash; - try { - eq = extractEqualsMethod(Object.class); - hash = extractHashCodeMethod(Object.class); - } catch (Exception e) { - throw new RuntimeException("Could not find Object.equals() or Object.hashCode()", e); - } - OBJECT_EQUALS = eq; - OBJECT_HASHCODE = hash; - } - - /** - * Disallow instantiation of ReflectHelper. - */ - private ReflectHelper() { - } - - /** - * Encapsulation of getting hold of a class's {@link Object#equals equals} - * method. - * - * @param clazz - * The class from which to extract the equals method. - * @return The equals method reference - * @throws NoSuchMethodException - * Should indicate an attempt to extract equals method from - * interface. - */ - public static Method extractEqualsMethod(Class clazz) throws NoSuchMethodException { - return clazz.getMethod("equals", SINGLE_OBJECT_PARAM_SIGNATURE); - } - - /** - * Encapsulation of getting hold of a class's {@link Object#hashCode - * hashCode} method. - * - * @param clazz - * The class from which to extract the hashCode method. - * @return The hashCode method reference - * @throws NoSuchMethodException - * Should indicate an attempt to extract hashCode method from - * interface. - */ - public static Method extractHashCodeMethod(Class clazz) throws NoSuchMethodException { - return clazz.getMethod("hashCode", NO_PARAM_SIGNATURE); - } - - /** - * Determine if the given class defines an {@link Object#equals} override. - * - * @param clazz - * The class to check - * @return True if clazz defines an equals override. - */ - public static boolean overridesEquals(Class clazz) { - Method equals; - try { - equals = extractEqualsMethod(clazz); - } catch (NoSuchMethodException nsme) { - return false; // its an interface so we can't really tell - // anything... - } - return !OBJECT_EQUALS.equals(equals); - } - - /** - * Determine if the given class defines a {@link Object#hashCode} override. - * - * @param clazz - * The class to check - * @return True if clazz defines an hashCode override. - */ - public static boolean overridesHashCode(Class clazz) { - Method hashCode; - try { - hashCode = extractHashCodeMethod(clazz); - } catch (NoSuchMethodException nsme) { - return false; // its an interface so we can't really tell - // anything... - } - return !OBJECT_HASHCODE.equals(hashCode); - } - - /** - * Determine if the given class implements or extend the given class. - * - * @param clazz - * The class to check - * @param intf - * The interface to check it against. - * @return True if the class does implement the interface, false otherwise. - */ - public static boolean assignableFrom(Class clazz, Class intf) { - return intf.isAssignableFrom(clazz); - } - - /** - * Perform resolution of a class name. - *

- * Here we first check the context classloader, if one, before delegating to - * {@link Class#forName(String, boolean, ClassLoader)} using the caller's - * classloader - * - * @param name - * The class name - * @param caller - * The class from which this call originated (in order to access - * that class's loader). - * @return The class reference. - * @throws ClassNotFoundException - * From {@link Class#forName(String, boolean, ClassLoader)}. - */ - public static Class classForName(String name, Class caller) throws ClassNotFoundException { - try { - ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - if (contextClassLoader != null) { - return contextClassLoader.loadClass(name); - } - } catch (Throwable ignore) { - } - return Class.forName(name, true, caller.getClassLoader()); - } - - /** - * Perform resolution of a class name. - *

- * Same as {@link #classForName(String, Class)} except that here we delegate - * to {@link Class#forName(String)} if the context classloader lookup is - * unsuccessful. - * - * @param name - * The class name - * @return The class reference. - * @throws ClassNotFoundException - * From {@link Class#forName(String)}. - */ - public static Class classForName(String name) throws ClassNotFoundException { - try { - ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); - if (contextClassLoader != null) { - return contextClassLoader.loadClass(name); - } - } catch (Throwable ignore) { - } - return Class.forName(name); - } - - /** - * Is this member publicly accessible. - *

- * Short-hand for {@link #isPublic(Class, Member)} passing the member + - * {@link Member#getDeclaringClass()} - * - * @param member - * The member to check - * @return True if the member is publicly accessible. - */ - public static boolean isPublic(Member member) { - return isPublic(member.getDeclaringClass(), member); - } - - /** - * Is this member publicly accessible. - * - * @param clazz - * The class which defines the member - * @param member - * The memeber. - * @return True if the member is publicly accessible, false otherwise. - */ - public static boolean isPublic(Class clazz, Member member) { - return Modifier.isPublic(member.getModifiers()) && Modifier.isPublic(clazz.getModifiers()); - } - - /** - * Attempt to resolve the specified property type through reflection. - * - * @param className - * The name of the class owning the property. - * @param name - * The name of the property. - * @return The type of the property. - * @throws MappingException - * Indicates we were unable to locate the property. - */ - public static Class reflectedPropertyClass(String className, String name) throws MappingException { - try { - Class clazz = ReflectHelper.classForName(className); - return getter(clazz, name).getReturnType(); - } catch (ClassNotFoundException cnfe) { - throw new MappingException("class " + className + " not found while looking for property: " + name, cnfe); - } - } - - private static Getter getter(Class clazz, String name) throws MappingException { - try { - return BASIC_PROPERTY_ACCESSOR.getGetter(clazz, name); - } catch (PropertyNotFoundException pnfe) { - return DIRECT_PROPERTY_ACCESSOR.getGetter(clazz, name); - } - } - - private static Setter setter(Class clazz, String name) throws MappingException { - try { - return BASIC_PROPERTY_ACCESSOR.getSetter(clazz, name); - } catch (PropertyNotFoundException pnfe) { - return DIRECT_PROPERTY_ACCESSOR.getSetter(clazz, name); - } - } - - /** - * Directly retrieve the {@link Getter} reference via the - * {@link BasicPropertyAccessor}. - * - * @param theClass - * The class owning the property - * @param name - * The name of the property - * @return The getter. - * @throws MappingException - * Indicates we were unable to locate the property. - */ - public static Getter getGetter(Class theClass, String name) throws MappingException { - return BASIC_PROPERTY_ACCESSOR.getGetter(theClass, name); - } - - public static Getter getMethodOrPropertyGetter(Class theClass, String name) throws MappingException { - return getter(theClass, name); - } - - /** - * Directly retrieve the {@link Setter} reference via the - * {@link BasicPropertyAccessor}. - * - * @param theClass - * The class owning the property - * @param name - * The name of the property - * @return The setter. - * @throws MappingException - * Indicates we were unable to locate the property. - */ - public static Setter getSetter(Class theClass, String name) throws MappingException { - return BASIC_PROPERTY_ACCESSOR.getSetter(theClass, name); - } - - public static Setter getMethodOrPropertySetter(Class theClass, String name) throws MappingException { - return setter(theClass, name); - } - - /** - * Retrieve the default (no arg) constructor from the given class. - * - * @param clazz - * The class for which to retrieve the default ctor. - * @return The default constructor. - * @throws PropertyNotFoundException - * Indicates there was not publicly accessible, no-arg - * constructor (todo : why PropertyNotFoundException???) - */ - public static Constructor getDefaultConstructor(Class clazz) throws PropertyNotFoundException { - if (isAbstractClass(clazz)) { - return null; - } - - try { - Constructor constructor = clazz.getDeclaredConstructor(NO_PARAM_SIGNATURE); - if (!isPublic(clazz, constructor)) { - constructor.setAccessible(true); - } - return constructor; - } catch (NoSuchMethodException nme) { - throw new PropertyNotFoundException("Object class [" + clazz.getName() + "] must declare a default (no-argument) constructor"); - } - } - - public static T createObjectByDefaultConstructor(Class clazz) throws PropertyNotFoundException, IllegalArgumentException, - InstantiationException, IllegalAccessException, InvocationTargetException { - return getDefaultConstructor(clazz).newInstance(NO_PARAMS); - } - - /** - * Determine if the given class is declared abstract. - * - * @param clazz - * The class to check. - * @return True if the class is abstract, false otherwise. - */ - public static boolean isAbstractClass(Class clazz) { - int modifier = clazz.getModifiers(); - return Modifier.isAbstract(modifier) || Modifier.isInterface(modifier); - } - - /** - * Determine is the given class is declared final. - * - * @param clazz - * The class to check. - * @return True if the class is final, flase otherwise. - */ - public static boolean isFinalClass(Class clazz) { - return Modifier.isFinal(clazz.getModifiers()); - } - - /** - * Retrieve a constructor for the given class, with arguments matching the - * specified Hibernate mapping. - * - * @param clazz - * The class needing instantiation - * @param parameterTypes - * The types representing the required ctor param signature - * @return The matching constructor. - * @throws PropertyNotFoundException - * Indicates we could not locate an appropriate constructor - * (todo : again with PropertyNotFoundException???) - */ - public static Constructor getConstructor(Class clazz, Class... parameterTypes) throws PropertyNotFoundException { - Constructor constructor = null; - try { - constructor = clazz.getConstructor(parameterTypes); - } catch (Exception e) { - throw new PropertyNotFoundException("Object class [" + clazz.getName() + "] must declare constructor with specifid types " - + Arrays.toString(parameterTypes)); - } - - if (constructor != null) { - if (!isPublic(clazz, constructor)) { - constructor.setAccessible(true); - } - return constructor; - } - - throw new PropertyNotFoundException("no appropriate constructor in class: " + clazz.getName()); - } - - public static Method getMethod(Class clazz, Method method) { - try { - return clazz.getMethod(method.getName(), method.getParameterTypes()); - } catch (Exception e) { - return null; - } - } - - public static Annotation getAnnotationByType(List annotations, Class annotationType) { - if (annotations == null) { - return null; - } - - return getAnnotationByType(annotations.toArray(NO_ANNOTATIONS), annotationType); - } - - public static Annotation getAnnotationByType(Annotation[] annotations, Class annotationType) { - - for (Annotation annotation : annotations) { - if (annotation.annotationType().equals(annotationType)) { - return annotation; - } - } - - return null; - } - - public static String getPropertyNameByType(Map> propertiesAnnotations, Class annotationType) { - for (Entry> propertiesAnnotation : propertiesAnnotations.entrySet()) { - Annotation annotation = getAnnotationByType(propertiesAnnotation.getValue(), annotationType); - if (annotation != null) { - return propertiesAnnotation.getKey(); - } - } - - return null; - } - - public static boolean isNotPrimitiveClass(Class theClass) { - return !((theClass == null) || theClass.equals(Object.class) || theClass.isPrimitive()); - } - - public static List getClassAnnotations(Class theClass, Class... allowedAnnotations) throws PropertyNotFoundException { - return BASIC_PROPERTY_ANNOTATION_RESOLVER.getClassAnnotations(theClass, allowedAnnotations); - } - - public static List getPropertyAnnotations(Class theClass, String propertyName, Class... allowedAnnotations) - throws PropertyNotFoundException { - return BASIC_PROPERTY_ANNOTATION_RESOLVER.getPropertyAnnotations(theClass, propertyName, allowedAnnotations); - } - - public static Map> getPropertiesAnnotations(Class theClass, Class... allowedAnnotations) { - return BASIC_PROPERTY_ANNOTATION_RESOLVER.getPropertiesAnnotations(theClass, allowedAnnotations); - } - - public static Class getListType(Getter getter) { - if (getter == null) { - return null; - } - - Type type = getter.getMethod().getGenericReturnType(); - if (assignableFrom(type.getClass(), ParameterizedType.class)) { - return (Class) (((ParameterizedType) type).getActualTypeArguments())[0]; - } else { - return null; - } - } - - public static Class getListType(Setter setter) { - if (setter == null) { - return null; - } - - Type[] types = setter.getMethod().getGenericParameterTypes(); - if (assignableFrom(ParameterizedType[].class, types.getClass())) { - return (Class) ((ParameterizedType) types[0]).getActualTypeArguments()[0]; - } else { - return null; - } - } - - public static Class getSetterType(Setter setter) { - if (setter == null) { - return null; - } - - return setter.getMethod().getParameterTypes()[0]; - } - - public static Object getValue(Object object, String name) throws MappingException { - if (object == null) { - throw new MappingException("Input value is null"); - } - - Getter getter = BASIC_PROPERTY_ACCESSOR.getGetter(object.getClass(), name); - - return getter.get(object); - } - - public static Object createArray(Class clazz, int length) { - if (clazz.isArray()) { - return Array.newInstance(clazz.getComponentType(), length); - } else { - return Array.newInstance(clazz, length); - } - } - - public static Object getPropertyValue(Object entry, Getter[] propertyGetters) { - if ((entry == null) || (propertyGetters.length == 0)) { - return null; - } - - Object curEntry = entry; - for (Getter propertyGetter : propertyGetters) { - if (curEntry == null) { - break; - } - curEntry = propertyGetter.get(curEntry); - } - - return curEntry; - } - - public static void copyObjectPropertyValues(Object fromEntry, Object toEntry, Getter[] propertyGetters, Setter[] propertySetters) { - if ((fromEntry == null) || (toEntry == null) || (propertyGetters.length == 0)) { - return; - } - - if (propertyGetters.length != propertySetters.length) { - throw new MappingException("Invalid numbers of setters specified"); - } - - for (int i = 0; i < propertyGetters.length; i++) { - Object value = propertyGetters[i].get(fromEntry); - propertySetters[i].set(toEntry, value); - } - } - - public static void sumObjectPropertyValues(Object resultEntry, Object entryToAdd, Getter[] propertyGetters, Setter[] propertySetters) { - if ((resultEntry == null) || (entryToAdd == null) || (propertyGetters.length == 0)) { - return; - } - - if (propertyGetters.length != propertySetters.length) { - throw new MappingException("Invalid numbers of setters specified"); - } - - for (int i = 0; i < propertyGetters.length; i++) { - Class returnType = propertyGetters[i].getReturnType(); - Object value1 = propertyGetters[i].get(resultEntry); - Object value2 = propertyGetters[i].get(entryToAdd); - - Object resultValue; - if ((returnType == int.class) || (returnType == Integer.class)) { - Integer num1 = (value1 == null) ? 0 : (Integer) value1; - Integer num2 = (value2 == null) ? 0 : (Integer) value2; - - resultValue = (int) 0 + num1 + num2; - } else if ((returnType == float.class) || (returnType == Float.class)) { - Float num1 = (value1 == null) ? 0 : (Float) value1; - Float num2 = (value2 == null) ? 0 : (Float) value2; - - resultValue = 0.0f + num1 + num2; - } else if ((returnType == double.class) || (returnType == Double.class)) { - Double num1 = (value1 == null) ? 0 : (Double) value1; - Double num2 = (value2 == null) ? 0 : (Double) value2; - - resultValue = 0.0d + num1 + num2; - } else { - throw new MappingException("Invalid return type of method " + propertyGetters[i].getMethodName()); - } - - propertySetters[i].set(resultEntry, resultValue); - } - } - - public static Method getMethod(Class clazz, String methodName, Class[] methodParams) throws NoSuchMethodException { - try { - return clazz.getMethod(methodName, methodParams); - } catch (Exception ex) { - throw new NoSuchMethodException("Method " + methodName + " doesn't exist in class " + clazz); - } - } - -} diff --git a/persistence-core/src/main/java/org/gluu/persist/service/BaseFactoryService.java b/persistence-core/src/main/java/org/gluu/persist/service/BaseFactoryService.java deleted file mode 100644 index 89f4c2b9..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/service/BaseFactoryService.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.gluu.persist.service; - -import org.gluu.persist.PersistenceEntryManagerFactory; -import org.gluu.persist.model.PersistenceConfiguration; -import org.slf4j.Logger; - -public interface BaseFactoryService { - - PersistenceConfiguration loadPersistenceConfiguration(); - - PersistenceConfiguration loadPersistenceConfiguration(String applicationPropertiesFile); - - PersistenceEntryManagerFactory getPersistenceEntryManagerFactory(PersistenceConfiguration persistenceConfiguration); - - PersistenceEntryManagerFactory getPersistenceEntryManagerFactory( - Class persistenceEntryManagerFactoryClass); - - PersistenceEntryManagerFactory getPersistenceEntryManagerFactory(String persistenceType); - - Logger getLog(); - -} \ No newline at end of file diff --git a/persistence-core/src/main/java/org/gluu/persist/watch/DurationUtil.java b/persistence-core/src/main/java/org/gluu/persist/watch/DurationUtil.java deleted file mode 100644 index 0b6a7275..00000000 --- a/persistence-core/src/main/java/org/gluu/persist/watch/DurationUtil.java +++ /dev/null @@ -1,33 +0,0 @@ -package org.gluu.persist.watch; - -import java.time.Duration; -import java.time.Instant; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Simple duration calculator helper - * - * @author Yuriy Movchan Date: 02/07/2019 - */ -public abstract class DurationUtil { - - protected static final Logger log = LoggerFactory.getLogger(DurationUtil.class); - - public Instant now() { - return Instant.now(); - } - - public Duration duration(Instant start) { - Instant end = Instant.now(); - return Duration.between(start, end); - } - - public Duration duration(Instant start, Instant end) { - return Duration.between(start, end); - } - - public abstract void logDebug(String format, Object... arguments); - -} \ No newline at end of file diff --git a/persistence-core/src/main/resources/key-shortcuter-rules.json b/persistence-core/src/main/resources/key-shortcuter-rules.json deleted file mode 100644 index ecfc6181..00000000 --- a/persistence-core/src/main/resources/key-shortcuter-rules.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "prefixes": [ - "gluu", - "oxAuth", - "oxTrust", - "ox" - ], - "replaces": { - "Group": "_g", - "Client": "_c", - "Type": "_t", - "User": "_u", - "Default": "_d", - "Configuration": "Conf", - "Attribute": "Attr", - "Application": "App", - "Request": "Req", - "Response": "Resp", - "Authentication": "Authn", - "Authorization": "Authz", - "Encrypted": "Enc", - "Encryption": "Enc", - "Signing": "Sig", - "Expiration": "Exp", - "Object": "Obj", - "Token": "Tok", - "Deletable": "del", - "description" : "desc", - "uniqueIdentifier": "_id", - "Password": "Pass", - "Address": "Addr", - "Lifetime": "Life" - }, - "exclusions": { - "oxSoftwareVersion": "softwareVer", - "oxTrustFaviconPath": "_trFaviconPath", - "oxAuthFaviconPath": "_auFaviconPath", - "oxTrustLogoPath": "_trLogoPath", - "oxAuthLogoPath": "_auLogoPath", - "oxApplicationType": "application_t", - "oxTrustLocale": "_trLocale", - "oxTrustnickname": "_trNickName", - "oxTrustMiddleName": "_trMiddleName", - "gluuUrl": "_gUrl", - "oxUrl": "oxUrl", - "oxTrustRole": "_trRole", - "oxAuthX509URL": "_auX509URL", - "oxAuthX509PEM": "_auX509PEM", - "oxTrustConfApplication": "_trConfApp", - "gluuStatus": "_gStatus", - "gluuFaviconImage": "_gFaviconImage", - "oxAssociatedClient": "ass_c" - } -} \ No newline at end of file diff --git a/persistence-core/src/test/java/org/gluu/persist/key/impl/KeyShortcuterTest.java b/persistence-core/src/test/java/org/gluu/persist/key/impl/KeyShortcuterTest.java deleted file mode 100644 index e3b50dff..00000000 --- a/persistence-core/src/test/java/org/gluu/persist/key/impl/KeyShortcuterTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.gluu.persist.key.impl; - -import org.testng.annotations.Test; - -import static org.gluu.persist.key.impl.KeyShortcuter.fromShortcut; -import static org.gluu.persist.key.impl.KeyShortcuter.shortcut; -import static org.testng.Assert.assertEquals; - -/** - * @author Yuriy Zabrovarnyy - */ -public class KeyShortcuterTest { - - //@Test - public void prefixDropped() { - assertEquals(shortcut("gluuAttributeName"), "attrName"); - assertEquals(shortcut("gluuAttributeType"), "attr_t"); - assertEquals(shortcut("oxAuthAppType"), "app_t"); - assertEquals(shortcut("oxAuthLogoutSessionRequired"), "logoutSessionRequired"); - assertEquals(shortcut("oxIconUrl"), "iconUrl"); - assertEquals(shortcut("oxTrustActive"), "active"); - - // reverse - assertEquals(fromShortcut("attrName"), "gluuAttributeName"); - assertEquals(fromShortcut("attr_t"), "gluuAttributeType"); - assertEquals(fromShortcut("app_t"), "oxAuthAppType"); - assertEquals(fromShortcut("logoutSessionRequired"), "oxAuthLogoutSessionRequired"); - assertEquals(fromShortcut("iconUrl"), "oxIconUrl"); - assertEquals(fromShortcut("active"), "oxTrustActive"); - } - - //@Test - public void shortcutsWithMarkers() { - assertEquals(shortcut("gluuGroupVisibility"), "_gVisibility"); - assertEquals(shortcut("oxAuthTrustedClient"), "trusted_c"); - assertEquals(shortcut("oxAuthSubjectType"), "subject_t"); - assertEquals(shortcut("uid"), "_uId"); - assertEquals(shortcut("oxAuthUserDN"), "_uDN"); - assertEquals(shortcut("oxAuthDefaultAcrValues"), "_dAcrValues"); - assertEquals(shortcut("uniqueIdentifier"), "_id"); - assertEquals(shortcut("oxId"), "id"); - - // reverse - assertEquals(fromShortcut("_gVisibility"), "gluuGroupVisibility"); - assertEquals(fromShortcut("trusted_c"), "oxAuthTrustedClient"); - assertEquals(fromShortcut("subject_t"), "oxAuthSubjectType"); - assertEquals(fromShortcut("_uId"), "uid"); - assertEquals(fromShortcut("_uDN"), "oxAuthUserDN"); - assertEquals(fromShortcut("_dAcrValues"), "oxAuthDefaultAcrValues"); - assertEquals(fromShortcut("_id"), "uniqueIdentifier"); - assertEquals(fromShortcut("id"), "oxId"); - } - - //@Test - public void shortcutsWithoutMarkers() { - assertEquals(shortcut("oxSmtpConfiguration"), "smtpConf"); - assertEquals(shortcut("oxTrustConfApplication"), "_trConfApp"); - assertEquals(shortcut("oxTrustConfApplication"), "_trConfApp"); // same again by intention - assertEquals(shortcut("oxAuthUserInfoEncryptedResponseAlg"), "_uInfoEncRespAlg"); - assertEquals(shortcut("authnTime"), "authnTime"); - assertEquals(shortcut("oxIDPAuthentication"), "iDPAuthn"); - assertEquals(shortcut("oxAuthSkipAuthorization"), "skipAuthz"); - assertEquals(shortcut("oxAuthTokenEndpointAuthSigningAlg"), "tokEndpointAuthSigAlg"); - assertEquals(shortcut("oxLinkExpirationDate"), "linkExpDate"); - assertEquals(shortcut("oxAuthRequestObjectEncryptionAlg"), "reqObjEncAlg"); - assertEquals(shortcut("tknTyp"), "tok_t"); - assertEquals(shortcut("oxAuthTokenEndpointAuthSigningAlg"), "tokEndpointAuthSigAlg"); - assertEquals(shortcut("del"), "del"); - assertEquals(shortcut("description"), "desc"); - - // reverse - assertEquals(fromShortcut("smtpConf"), "oxSmtpConfiguration"); - assertEquals(fromShortcut("_trConfApp"), "oxTrustConfApplication"); - assertEquals(fromShortcut("_trConfApp"), "oxTrustConfApplication");// same again by intention - assertEquals(fromShortcut("_uInfoEncRespAlg"), "oxAuthUserInfoEncryptedResponseAlg"); - assertEquals(fromShortcut("authnTime"), "authnTime"); - assertEquals(fromShortcut("iDPAuthn"), "oxIDPAuthentication"); - assertEquals(fromShortcut("skipAuthz"), "oxAuthSkipAuthorization"); - assertEquals(fromShortcut("tokEndpointAuthSigAlg"), "oxAuthTokenEndpointAuthSigningAlg"); - assertEquals(fromShortcut("linkExpDate"), "oxLinkExpirationDate"); - assertEquals(fromShortcut("reqObjEncAlg"), "oxAuthRequestObjectEncryptionAlg"); - assertEquals(fromShortcut("tok_t"), "tknTyp"); - assertEquals(fromShortcut("tokEndpointAuthSigAlg"), "oxAuthTokenEndpointAuthSigningAlg"); - assertEquals(fromShortcut("del"), "del"); - assertEquals(fromShortcut("desc"), "description"); - } -} diff --git a/persistence-core/src/test/java/org/gluu/persist/key/impl/dev/KeyShortcuterManualTest.java b/persistence-core/src/test/java/org/gluu/persist/key/impl/dev/KeyShortcuterManualTest.java deleted file mode 100644 index 53bfbfcf..00000000 --- a/persistence-core/src/test/java/org/gluu/persist/key/impl/dev/KeyShortcuterManualTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.gluu.persist.key.impl.dev; - -import java.util.Arrays; - -import org.gluu.persist.key.impl.KeyShortcuter; - -public class KeyShortcuterManualTest { - - - public static void main(String[] args) { - // All - String[] attrs = new String[] { "oxAssociatedClient", "associatedClient", "associatedPerson", "blowfishPassword", "county", "creationDate", "defaultScope", "deployedAppliances", "federationRules", "gluuAddPersonCapability", "gluuAdditionalBandwidth", "gluuAdditionalMemory", "gluuAdditionalUsers", "gluuApplianceDnsServer", "gluuAppliancePollingInterval", "gluuApplianceUpdateRequestList", "gluuApplianceUpdateReuestList", "gluuAttributeViewType", "gluuAttributeEditType", "gluuAttributeName", "gluuAttributeOrigin", "gluuAttributeSystemEditType", "gluuAttributeType", "gluuAttributeUsageType", "gluuBandwidthRX", "gluuBandwidthTX", "gluuCategory", "gluuContainerFederation", "gluuCustomMessage", "gluuDSstatus", "gluuEntityId", "gluuFaviconImage", "gluuFederationHostingEnabled", "gluuFreeDiskSpace", "gluuFreeMemory", "gluuFreeSwap", "gluuHTTPstatus", "gluuGroupCount", "gluuGroupType", "gluuGroupVisibility", "gluuHostname", "gluuInvoiceAmount", "gluuInvoiceDate", "gluuInvoiceLineItemName", "gluuInvoiceNo", "gluuInvoiceNumber", "gluuInvoiceProductNumber", "gluuInvoiceQuantity", "gluuInvoiceStatus", "gluuIpAddress", "gluuIsFederation", "gluuLastUpdate", "gluuLifeRay", "TODO-remove", "gluuLoadAvg", "gluuLogoImage", "gluuManageIdentityPermission", "gluuManagedOrganizations", "gluuManager", "gluuManagerGroup", "gluuMaxLogSize", "gluuOptOuts", "gluuOrgProfileMgt", "gluuOrgShortName", "gluuPaidUntil", "gluuPaymentProcessorTimestamp", "gluuPersonCount", "gluuPrivate", "gluuProStoresUser", "gluuProfileConfiguration", "gluuPublishIdpMetadata", "gluuReleasedAttribute", "gluuResizeInitiated", "gluuRulesAccepted", "gluuSAML1URI", "gluuSAML2URI", "gluuSAMLMetaDataFilter", "gluuSAMLTrustEngine", "gluuSAMLmaxRefreshDelay", "gluuSAMLspMetaDataFN", "gluuSAMLspMetaDataSourceType", "gluuSAMLspMetaDataURL", "gluuSLAManager", "gluuSPTR", "gluuScimEnabled", "gluuShibAssertionsIssued", "gluuShibFailedAuth", "gluuShibSecurityEvents", "gluuShibSuccessfulAuths", "gluuSmtpFromEmailAddress", "gluuSmtpFromName", "gluuSmtpHost", "gluuSmtpPassword", "gluuSmtpPort", "gluuSmtpRequiresAuthentication", "gluuSmtpRequiresSsl", "gluuSmtpUserName", "gluuSpecificRelyingPartyConfig", "gluuSslExpiry", "gluuStatus", "gluuSystemUptime", "gluuTargetRAM", "gluuTempFaviconImage", "gluuThemeColor", "gluuTrustContact", "gluuTrustDeconstruction", "gluuUrl", "gluuVDSenabled", "gluuVDSstatus", "gluuValidationLog", "gluuValidationStatus", "gluuVdsCacheRefreshEnabled", "gluuVdsCacheRefreshLastUpdate", "gluuVdsCacheRefreshLastUpdateCount", "gluuVdsCacheRefreshPollingInterval", "gluuVdsCacheRefreshProblemCount", "gluuWhitePagesEnabled", "gluuWhitePagesListed", "iname", "inum", "inumFN", "literalBinaryValue", "literalValue", "memberOf", "nonProfit", "organizationalOwner", "oxAmHost", "oxAuthClaimName", "oxAuthAppType", "authnTime", "authzCode", "oxAuthClaim", "oxAuthGroupClaims", "oxAuthClientId", "oxAuthClientIdIssuedAt", "oxAuthClientSecret", "oxAuthClientSecretExpiresAt", "oxAuthClientURI", "oxAuthConfDynamic", "oxAuthConfErrors", "oxAuthConfStatic", "oxAuthConfWebKeys", "oxAuthContact", "iat", "oxAuthDefaultAcrValues", "oxAuthDefaultMaxAge", "oxAuthExpiration", "grtId", "grtTyp", "oxAuthIdTokenEncryptedResponseAlg", "oxAuthIdTokenEncryptedResponseEnc", "oxAuthIdTokenSignedResponseAlg", "oxAuthInitiateLoginURI", "oxAuthJwksURI", "oxAuthJwks", "jwtReq", "oxAuthLogoURI", "nnc", "oxSessionState", "oxAuthPermissionGrantedMap", "oxAuthPersistentJWT", "oxAuthPolicyURI", "oxAuthLogoutURI", "oxAuthLogoutSessionRequired", "oxAuthPostLogoutRedirectURI", "oxAuthRedirectURI", "oxAuthRegistrationAccessToken", "oxAuthReleasedScope", "oxAuthRequestObjectSigningAlg", "oxAuthRequestObjectEncryptionAlg", "oxAuthRequestObjectEncryptionEnc", "oxAuthRequestURI", "oxAuthRequireAuthTime", "oxAuthResponseType", "scp", "oxScopeType", "oxAuthSectorIdentifierURI", "oxAuthSignedResponseAlg", "oxAuthSkipAuthorization", "oxAuthSubjectType", "tknCde", "oxAuthTokenEndpointAuthMethod", "oxAuthTokenEndpointAuthSigningAlg", "tknTyp", "oxAuthTosURI", "oxAuthTrustedClient", "oxAuthUmaScope", "oxAuthUserDN", "uid", "oxAuthUserInfoEncryptedResponseAlg", "oxAuthUserInfoEncryptedResponseEnc", "oxAuthExtraConf", "oxAuthX509PEM", "oxAuthX509URL", "oxAuthenticationMode", "oxTrustAuthenticationMode", "oxConfigurationCode", "oxCreationTimestamp", "oxDomain", "oxExternalUid", "oxFaviconImage", "oxGroup", "oxGuid", "oxHost", "oxIDPAuthentication", "oxIconUrl", "oxId", "oxAsJwt", "oxJwt", "oxInvolvedClients", "oxLastAccessTime", "oxLastLogonTime", "oxLinkCreator", "oxLinkExpirationDate", "oxLinkLinktrack", "oxLinkModerated", "oxLinkModerators", "oxLinkPending", "oxLinktrackEnabled", "oxLinktrackLogin", "oxLinktrackPassword", "oxLogViewerConfig", "oxMultiValuedAttribute", "oxName", "oxNameIdType", "oxPolicyRule", "oxUmaPolicyScriptDn", "oxProxConf", "oxProxyAccessToken", "oxProxyClaimMapping", "oxState", "oxCounter", "oxStatus", "oxApplication", "oxDeviceRegistrationConf", "oxDeviceKeyHandle", "oxDeviceHashCode", "oxRequest", "oxRequestId", "oxDeviceData", "oxEnrollmentCode", "oxProxyClientId", "oxProxyScope", "oxProxyToOpClientMapping", "oxPushApplication", "oxPushApplicationConf", "oxPushDeviceConf", "oxRegistrationConfiguration", "oxResource", "oxResourceSetId", "oxRevision", "oxLevel", "oxSCIMCustomAttribute", "oxScript", "oxScriptDn", "oxScriptType", "oxScriptError", "oxSmtpConfiguration", "oxSourceAttribute", "oxTicket", "oxTrustActive", "oxTrustCacheRefreshServerIpAddress", "oxTrustAddresses", "oxTrustConfApplication", "oxTrustConfCacheRefresh", "oxConfApplication", "oxTrustCustAttrB", "oxTrustEmail", "oxTrustEntitlements", "oxTrustExternalId", "oxTrustImsValue", "oxTrustMetaCreated", "oxTrustMetaLastModified", "oxTrustMetaLocation", "oxTrustMetaVersion", "oxTrustNameFormatted", "oxTrustPhoneValue", "oxTrustPhotos", "oxTrustProfileURL", "oxTrustRole", "oxTrustStoreCert", "oxTrustStoreConf", "oxTrustTitle", "oxTrustUserType", "oxTrusthonorificPrefix", "oxTrusthonorificSuffix", "oxTrustx509Certificate", "oxType", "oxUmaPermission", "oxUrl", "oxX509PEM", "oxX509URL", "passwordResetAllowed", "persistentId", "personInum", "primaryKeyAttrName", "primaryKeyValue", "proStoresToken", "programmingLanguage", "prostoresTimestamp", "registrationDate", "role", "scimAuthMode", "scimGroup", "scimStatus", "secondaryKeyAttrName", "secondaryKeyValue", "secretAnswer", "secretQuestion", "softwareVersion", "sourceRelationalXdiStatement", "targetRelationalXdiStatement", "tertiaryKeyAttrName", "tertiaryKeyValue", "transientId", "url", "urn", "x", "xdiStatement", "xri", "middleName", "oxTrustMiddleName", "nickname", "oxTrustnickname", "preferredUsername", "profile", "picture", "photo1", "website", "emailVerified", "gender", "birthdate", "zoneinfo", "timezone", "locale", "oxTrustLocale", "phoneNumberVerified", "address", "updatedAt", "gluuRegExp", "gluuTooltip", "oxModuleProperty", "oxConfigurationProperty", "oxAuthSessionAttribute", "researchAndScholarshipEnabled", "oxStartDate", "oxEndDate", "oxApplicationType", "oxMetricType", "oxData", "chlng", "chlngMth", "oxSectorIdentifier", "oxPersistClientAuthorizations", "oxTrustConfImportPerson", "oxSessionStateId", "ssnId", "oxPasswordExpirationDate", "oxCountInvalidLogin", "gluuIMAPData", "gluuPassportConfiguration", "gluuPassportEnabled", "gluuRadiusEnabled", "gluuSamlEnabled", "oxValidation", "gluuEntityType", "oxPPID", "oxAuthSessionId", "oxCacheConfiguration", "oxLogConfigLocation", "oxIncludeClaimsInIdToken", "oxClaimValues", "oxClaimRedirectURI", "oxAttributes", "userRandomKey", "oxRefreshTokenLifetime", "oxTrustConfAttributeResolver", "oxAuthPermissionGranted", "oxNickName", "oxDeviceNotificationConf", "clms", "oxDisabled", "oxWebKeysSettings", "oxScopeExpression", "oxPreferredMethod", "oxOTPDevices", "oxMobileDevices", "oxdId", "oxAuthAuthorizedOrigins", "oxStrongAuthPolicy", "oxTrustedDevicesInfo", "tknBndCnf", "oxUnlinkedExternalUids", "oxAccessTokenAsJwt", "oxAccessTokenSigningAlg", "oxRegistrationData", "oxAuthenticationData", "oxPublicKeyId", "oxAccessTokenLifetime", "oxSoftwareId", "oxSoftwareVersion", "oxSoftwareStatement", "oxRptAsJwt", "oxCodeChallengeHash", "del", "oxEnabled", "oxAlias", "oxTrustLogoPath", "oxTrustFaviconPath", "oxAuthLogoPath", "oxAuthFaviconPath", "idpLogoPath", "idpFaviconPath", "parent", "classRef", "gluuSmtpServerTrust" }; - - // Token -// String[] attrs = new String[] { "tknTyp", "grtId", "grtTyp", "authzCode", -// "scp", "objectClass", "tknCde", "dn", "del", "uid", "nnc", -// "authnTime", "iat", "oxAuthExpiration", "oxAttributes", "oxAuthClientId", "ssnId" }; - - // Mimimal user -// String[] attrs = new String[] { "cn", "displayName", "dn", "givenName", "gluuStatus", "inum", "mail", "objectClass", "sn", "uid", -// "userPassword", "oxLastLogonTime" }; - - System.out.println("Attrs:\n" + Arrays.toString(attrs)); - System.out.println("\n==============================="); - - int origSize = 0, shortSize = 0, totalDiff = 0; - for(int i = 0; i < attrs.length; i++) { - String name = attrs[i]; - String shortName = KeyShortcuter.shortcut(name); - - int diff = name.length() - shortName.length(); - origSize += name.length(); - shortSize += shortName.length(); - totalDiff += diff; - - System.out.println(String.format("%s -> %s \t\t-> %d", name, shortName, -diff)); - } - - System.out.println(String.format("\nTOTAL: %d - %d \t\t-> %d", origSize, shortSize, -totalDiff)); - } - -} diff --git a/persistence-couchbase-sample/pom.xml b/persistence-couchbase-sample/pom.xml deleted file mode 100644 index 6b55696f..00000000 --- a/persistence-couchbase-sample/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - 4.0.0 - oxcore-persistence-couchbase-sample - Persistence Couchbase sample - Sample project to show persistence-couchbase functionality - - - org.gluu - oxcore - 5.0.0-SNAPSHOT - - - - ${maven.min-version} - - - - - - src/main/resources - - **/*.json - **/*.xml - **/*.yml - **/*.properties - - - - - - src/test/resources - - **/*.json - **/*.xml - **/*.yml - **/*.properties - - - - - - - - org.gluu - oxcore-persistence-couchbase - - - org.apache.logging.log4j - log4j-slf4j-impl - - - - - org.gluu - oxcore-persistence-annotation - - - org.slf4j - slf4j-simple - - - - - org.testng - testng - - - - \ No newline at end of file diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomMultiValuedTypesSample.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomMultiValuedTypesSample.java deleted file mode 100644 index 8c89a422..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomMultiValuedTypesSample.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.gluu.couchbase; - -import java.util.Arrays; -import java.util.List; - -import org.gluu.couchbase.model.SimpleUser; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; -import org.gluu.persist.couchbase.operation.impl.CouchbaseConnectionProvider; -import org.gluu.persist.model.base.CustomObjectAttribute; -import org.gluu.search.filter.Filter; -import org.gluu.util.StringHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author Yuriy Movchan Date: 09/16/2019 - */ -public final class CouchbaseCustomMultiValuedTypesSample { - - private static final Logger LOG = LoggerFactory.getLogger(CouchbaseConnectionProvider.class); - - private CouchbaseCustomMultiValuedTypesSample() { - } - - public static void main(String[] args) { - // Prepare sample connection details - CouchbaseSampleEntryManager couchbaseSampleEntryManager = new CouchbaseSampleEntryManager(); - - // Create Couchbase entry manager - CouchbaseEntryManager couchbaseEntryManager = couchbaseSampleEntryManager.createCouchbaseEntryManager(); - - // Add dummy user - SimpleUser newUser = new SimpleUser(); - newUser.setDn(String.format("inum=%s,ou=people,o=gluu", System.currentTimeMillis())); - newUser.setUserId("sample_user_" + System.currentTimeMillis()); - newUser.setUserPassword("test"); - newUser.getCustomAttributes().add(new CustomObjectAttribute("streetAddress", Arrays.asList("London", "Texas", "Kiev"))); - newUser.getCustomAttributes().add(new CustomObjectAttribute("test", "test_value")); - newUser.getCustomAttributes().add(new CustomObjectAttribute("fuzzy", "test_value")); - newUser.setNotes(Arrays.asList("note 1", "note 2", "note 3")); - - couchbaseEntryManager.persist(newUser); - - LOG.info("Added User '{}' with uid '{}' and key '{}'", newUser, newUser.getUserId(), newUser.getDn()); - LOG.info("Persisted custom attributes '{}'", newUser.getCustomAttributes()); - - // Find added dummy user - SimpleUser foundUser = couchbaseEntryManager.find(SimpleUser.class, newUser.getDn()); - LOG.info("Found User '{}' with uid '{}' and key '{}'", foundUser, foundUser.getUserId(), foundUser.getDn()); - - LOG.info("Custom attributes '{}'", foundUser.getCustomAttributes()); - - // Update custom attributes - foundUser.setAttributeValues("streetAddress", Arrays.asList("London", "Texas", "Kiev", "Dublin")); - foundUser.setAttributeValues("test", Arrays.asList("test_value_1", "test_value_2", "test_value_3", "test_value_4")); - foundUser.setAttributeValues("fuzzy", Arrays.asList("fuzzy_value_1", "fuzzy_value_2")); - foundUser.setAttributeValue("simple", "simple"); - - CustomObjectAttribute multiValuedSingleValue = new CustomObjectAttribute("multivalued", "multivalued_single_valued"); - multiValuedSingleValue.setMultiValued(true); - foundUser.getCustomAttributes().add(multiValuedSingleValue); - couchbaseEntryManager.merge(foundUser); - LOG.info("Updated custom attributes '{}'", foundUser.getCustomAttributes()); - - // Find updated dummy user - SimpleUser foundUpdatedUser = couchbaseEntryManager.find(SimpleUser.class, newUser.getDn()); - LOG.info("Found User '{}' with uid '{}' and key '{}'", foundUpdatedUser, foundUpdatedUser.getUserId(), foundUpdatedUser.getDn()); - - LOG.info("Cusom attributes '{}'", foundUpdatedUser.getCustomAttributes()); - - Filter filter = Filter.createEqualityFilter(Filter.createLowercaseFilter("givenName"), StringHelper.toLowerCase("jon")); - List foundUpdatedUsers = couchbaseEntryManager.findEntries("o=gluu", SimpleUser.class, filter); - System.out.println(foundUpdatedUsers); - - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomObjectAttributesSample.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomObjectAttributesSample.java deleted file mode 100644 index 5fdea32e..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomObjectAttributesSample.java +++ /dev/null @@ -1,78 +0,0 @@ -package org.gluu.couchbase; - -import java.util.Arrays; -import java.util.Date; -import java.util.List; - -import org.gluu.couchbase.model.SimpleUser; -import org.gluu.couchbase.model.UserRole; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; -import org.gluu.persist.couchbase.operation.impl.CouchbaseConnectionProvider; -import org.gluu.persist.model.base.CustomObjectAttribute; -import org.gluu.search.filter.Filter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author Yuriy Movchan Date: 09/24/2019 - */ -public final class CouchbaseCustomObjectAttributesSample { - - private static final Logger LOG = LoggerFactory.getLogger(CouchbaseConnectionProvider.class); - - private CouchbaseCustomObjectAttributesSample() { - } - - public static void main(String[] args) { - // Prepare sample connection details - CouchbaseSampleEntryManager couchbaseSampleEntryManager = new CouchbaseSampleEntryManager(); - - // Create Couchbase entry manager - CouchbaseEntryManager couchbaseEntryManager = couchbaseSampleEntryManager.createCouchbaseEntryManager(); - - // Add dummy user - SimpleUser newUser = new SimpleUser(); - newUser.setDn(String.format("inum=%s,ou=people,o=gluu", System.currentTimeMillis())); - newUser.setUserId("sample_user_" + System.currentTimeMillis()); - newUser.setUserPassword("test"); - newUser.getCustomAttributes().add(new CustomObjectAttribute("streetAddress", Arrays.asList("London", "Texas", "Kiev"))); - newUser.getCustomAttributes().add(new CustomObjectAttribute("test", "test_value")); - newUser.getCustomAttributes().add(new CustomObjectAttribute("birthdate", new Date())); - newUser.getCustomAttributes().add(new CustomObjectAttribute("enabled", false)); - newUser.getCustomAttributes().add(new CustomObjectAttribute("age", 18)); - - newUser.setUserRole(UserRole.ADMIN); - newUser.setNotes(Arrays.asList("note 1", "note 2", "note 3")); - - couchbaseEntryManager.persist(newUser); - - LOG.info("Added User '{}' with uid '{}' and key '{}'", newUser, newUser.getUserId(), newUser.getDn()); - - // Find added dummy user - SimpleUser foundUser = couchbaseEntryManager.find(SimpleUser.class, newUser.getDn()); - LOG.info("Found User '{}' with uid '{}' and key '{}'", foundUser, foundUser.getUserId(), foundUser.getDn()); - - LOG.info("Custom attributes '{}'", foundUser.getCustomAttributes()); - for (CustomObjectAttribute customAttribute : foundUser.getCustomAttributes()) { - if (customAttribute.getValue() instanceof Date) { - LOG.info("Found date custom attribute '{}' with value '{}'", customAttribute.getName(), customAttribute.getValue()); - } else if (customAttribute.getValue() instanceof Integer) { - LOG.info("Found integer custom attribute '{}' with value '{}'", customAttribute.getName(), customAttribute.getValue()); - } else if (customAttribute.getValue() instanceof Boolean) { - LOG.info("Found boolean custom attribute '{}' with value '{}'", customAttribute.getName(), customAttribute.getValue()); - } - - } - - // Find added dummy user by numeric attribute - Filter filter = Filter.createGreaterOrEqualFilter("age", 16); - List foundUsers = couchbaseEntryManager.findEntries("ou=people,o=gluu", SimpleUser.class, filter); - if (foundUsers.size() > 0) { - foundUser = foundUsers.get(0); - LOG.info("Found User '{}' by filter '{}' with uid '{}' and key '{}'", foundUser, filter, foundUser, foundUser); - } else { - LOG.error("Can't find User by filter '{}'", filter); - } - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomStringAttributesSample.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomStringAttributesSample.java deleted file mode 100644 index 71564e5a..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseCustomStringAttributesSample.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.gluu.couchbase; - -import java.util.Arrays; -import java.util.List; - -import org.gluu.couchbase.model.SimpleCustomStringUser; -import org.gluu.couchbase.model.UserRole; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; -import org.gluu.persist.couchbase.operation.impl.CouchbaseConnectionProvider; -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.search.filter.Filter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author Yuriy Movchan Date: 09/27/2019 - */ -public final class CouchbaseCustomStringAttributesSample { - - private static final Logger LOG = LoggerFactory.getLogger(CouchbaseConnectionProvider.class); - - private CouchbaseCustomStringAttributesSample() { - } - - public static void main(String[] args) { - // Prepare sample connection details - CouchbaseSampleEntryManager couchbaseSampleEntryManager = new CouchbaseSampleEntryManager(); - - // Create Couchbase entry manager - CouchbaseEntryManager couchbaseEntryManager = couchbaseSampleEntryManager.createCouchbaseEntryManager(); - - String randomExternalUid = "otp:" + System.currentTimeMillis(); - - // Add dummy user - SimpleCustomStringUser newUser = new SimpleCustomStringUser(); - newUser.setDn(String.format("inum=%s,ou=people,o=gluu", System.currentTimeMillis())); - newUser.setUserId("sample_user_" + System.currentTimeMillis()); - newUser.setUserPassword("test"); - newUser.getCustomAttributes().add(new CustomAttribute("streetAddress", Arrays.asList("London", "Texas", "Kiev"))); - newUser.getCustomAttributes().add((new CustomAttribute("oxExternalUid", randomExternalUid)).setMultiValued(true)); - - newUser.setUserRole(UserRole.ADMIN); - newUser.setNotes(Arrays.asList("note 1", "note 2", "note 3")); - - couchbaseEntryManager.persist(newUser); - - LOG.info("Added User '{}' with uid '{}' and key '{}'", newUser, newUser.getUserId(), newUser.getDn()); - - // Find added dummy user but use custom class with String values - SimpleCustomStringUser foundUser = couchbaseEntryManager.find(SimpleCustomStringUser.class, newUser.getDn()); - LOG.info("Found User '{}' with uid '{}' and key '{}'", foundUser, foundUser.getUserId(), foundUser.getDn()); - - LOG.info("Custom attributes '{}'", foundUser.getCustomAttributes()); - for (CustomAttribute customAttribute : foundUser.getCustomAttributes()) { - LOG.info("Found custom attribute '{}' with value '{}'", customAttribute.getName(), customAttribute.getValue()); - } - - // Find by oxExternalUid - Filter oxExternalUidFilter = Filter.createEqualityFilter("oxExternalUid", randomExternalUid).multiValued(); - List foundUsers = couchbaseEntryManager.findEntries("ou=people,o=gluu", SimpleCustomStringUser.class, oxExternalUidFilter); - for (SimpleCustomStringUser foundUser2 : foundUsers) { - LOG.info("Found User '{}' by oxExternalUid with uid '{}' and key '{}'", foundUser2, foundUser2.getUserId(), foundUser2.getDn()); - } - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSample.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSample.java deleted file mode 100644 index 7622cac5..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSample.java +++ /dev/null @@ -1,118 +0,0 @@ -package org.gluu.couchbase; - -import java.util.Arrays; -import java.util.List; - -import org.gluu.couchbase.model.SimpleAttribute; -import org.gluu.couchbase.model.SimpleGrant; -import org.gluu.couchbase.model.SimpleSession; -import org.gluu.couchbase.model.SimpleUser; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; -import org.gluu.persist.couchbase.operation.impl.CouchbaseConnectionProvider; -import org.gluu.persist.model.PagedResult; -import org.gluu.persist.model.SearchScope; -import org.gluu.persist.model.SortOrder; -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.persist.model.base.CustomObjectAttribute; -import org.gluu.search.filter.Filter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author Yuriy Movchan Date: 11/03/2016 - */ -public final class CouchbaseSample { - - private static final Logger LOG = LoggerFactory.getLogger(CouchbaseConnectionProvider.class); - - private CouchbaseSample() { - } - - public static void main(String[] args) { - // Prepare sample connection details - CouchbaseSampleEntryManager couchbaseSampleEntryManager = new CouchbaseSampleEntryManager(); - - // Create Couchbase entry manager - CouchbaseEntryManager couchbaseEntryManager = couchbaseSampleEntryManager.createCouchbaseEntryManager(); - - SimpleUser newUser = new SimpleUser(); - newUser.setDn(String.format("inum=%s,ou=people,o=gluu", System.currentTimeMillis())); - newUser.setUserId("sample_user_" + System.currentTimeMillis()); - newUser.setUserPassword("test"); - newUser.getCustomAttributes().add(new CustomObjectAttribute("streetAddress", Arrays.asList("London", "Texas", "Kiev"))); - newUser.getCustomAttributes().add(new CustomObjectAttribute("test", "test_value")); - couchbaseEntryManager.persist(newUser); - -// SimpleUser dummyUser = couchbaseEntryManager.find(SimpleUser.class, "inum=test,o=test,o=gluu"); -// LOG.info("Dummy User '{}'", dummyUser); - - // Find all users which have specified object classes defined in SimpleUser - List users = couchbaseEntryManager.findEntries("o=@!5304.5F36.0E64.E1AC!0001!179C.62D7,o=gluu", SimpleUser.class, null); - for (SimpleUser user : users) { - LOG.info("User with uid: '{}' with DN: '{}'", user.getUserId(), user.getDn()); - } - - if (users.size() > 0) { - // Add attribute "streetAddress" to first user - SimpleUser user = users.get(3); - LOG.info("Updating: " + user.getUserId()); - - String[] values = new String[] { "Somewhere: " + System.currentTimeMillis(), "Somewhere2: " + System.currentTimeMillis() }; - user.getCustomAttributes().add(new CustomObjectAttribute("streetAddress", Arrays.asList(values))); - user.getCustomAttributes().add(new CustomObjectAttribute("test", "test_value")); - user.getCustomAttributes().add(new CustomObjectAttribute("test2", "test_value2")); - user.getCustomAttributes().add(new CustomObjectAttribute("test3", "test_value3")); - user.setUserId("user1"); - user.setUserPassword("test"); - - couchbaseEntryManager.merge(user); - } - - for (SimpleUser user : users) { - boolean result1 = couchbaseEntryManager.authenticate(user.getDn(), "test"); - boolean result2 = couchbaseEntryManager.authenticate("ou=people,o=gluu", SimpleUser.class, user.getUserId(), "test"); - System.out.println("authetication result: " + result1 + ", " + result2); - } - - Filter filter = Filter.createEqualityFilter("gluuStatus", "active"); - List attributes = couchbaseEntryManager.findEntries("o=gluu", SimpleAttribute.class, filter, SearchScope.SUB, null, null, 10, - 0, 0); - for (SimpleAttribute attribute : attributes) { - LOG.info("Attribute with displayName: " + attribute.getCustomAttributes().get(1)); - } - - List sessions = couchbaseEntryManager.findEntries("o=gluu", SimpleSession.class, filter, SearchScope.SUB, null, null, 10, 0, - 0); - LOG.info("Found sessions: " + sessions.size()); - - List grants = couchbaseEntryManager.findEntries("o=gluu", SimpleGrant.class, null, SearchScope.SUB, - new String[] { "grtId" }, null, 1, 0, 0); - LOG.info("Found grants: " + grants.size()); - - try { - PagedResult listViewResponse = couchbaseEntryManager.findPagedEntries("o=gluu", SimpleUser.class, null, - new String[] { "uid", "displayName", "gluuStatus" }, "uid", SortOrder.ASCENDING, 0, 6, 4); - - LOG.info("Found persons: " + listViewResponse.getEntriesCount() + ", total persons: " + listViewResponse.getTotalEntriesCount()); - for (SimpleUser user : listViewResponse.getEntries()) { - System.out.println(user.getUserId()); - } - } catch (Exception ex) { - LOG.info("Failed to search", ex); - } - - try { - PagedResult listViewResponse = couchbaseEntryManager.findPagedEntries("o=gluu", SimpleUser.class, null, - new String[] { "uid", "displayName", "gluuStatus" }, "uid", SortOrder.DESCENDING, 0, 6, 4); - - LOG.info("Found persons: " + listViewResponse.getEntriesCount() + ", total persons: " + listViewResponse.getTotalEntriesCount()); - for (SimpleUser user : listViewResponse.getEntries()) { - System.out.println(user.getUserId()); - } - } catch (Exception ex) { - LOG.info("Failed to search", ex); - } - - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleBatchJob.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleBatchJob.java deleted file mode 100644 index 3d6a9c54..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleBatchJob.java +++ /dev/null @@ -1,150 +0,0 @@ -package org.gluu.couchbase; - -import org.apache.log4j.Logger; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.status.StatusLogger; -import org.gluu.couchbase.model.SimpleClient; -import org.gluu.couchbase.model.SimpleSession; -import org.gluu.couchbase.model.SimpleTokenCouchbase; -import org.gluu.log.LoggingHelper; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; -import org.gluu.persist.exception.EntryPersistenceException; -import org.gluu.persist.model.BatchOperation; -import org.gluu.persist.model.DefaultBatchOperation; -import org.gluu.persist.model.ProcessBatchOperation; -import org.gluu.persist.model.SearchScope; -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.search.filter.Filter; - -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; - -/** - * Created by eugeniuparvan on 1/12/17. - */ -public final class CouchbaseSampleBatchJob { - private static final Logger LOG; - - static { - StatusLogger.getLogger().setLevel(Level.OFF); - LoggingHelper.configureConsoleAppender(); - LOG = Logger.getLogger(CouchbaseSample.class); - } - - private CouchbaseSampleBatchJob() { } - - public static void main(String[] args) { - // Prepare sample connection details - CouchbaseSampleEntryManager couchbaseSampleEntryManager = new CouchbaseSampleEntryManager(); - - // Create Couchbase entry manager - final CouchbaseEntryManager couchbaseEntryManager = couchbaseSampleEntryManager.createCouchbaseEntryManager(); - - BatchOperation tokenCouchbaseBatchOperation = new ProcessBatchOperation() { - private int processedCount = 0; - - @Override - public void performAction(List objects) { - for (SimpleTokenCouchbase simpleTokenCouchbase : objects) { - try { - CustomAttribute customAttribute = getUpdatedAttribute(couchbaseEntryManager, simpleTokenCouchbase.getDn(), "exp", - simpleTokenCouchbase.getAttribute("exp")); - simpleTokenCouchbase.setCustomAttributes(Arrays.asList(new CustomAttribute[] {customAttribute})); - couchbaseEntryManager.merge(simpleTokenCouchbase); - processedCount++; - } catch (EntryPersistenceException ex) { - LOG.error("Failed to update entry", ex); - } - } - - LOG.info("Total processed: " + processedCount); - } - }; - - final Filter filter1 = Filter.createPresenceFilter("exp"); - couchbaseEntryManager.findEntries("o=gluu", SimpleTokenCouchbase.class, filter1, SearchScope.SUB, new String[] {"exp"}, - tokenCouchbaseBatchOperation, 0, 0, 100); - - BatchOperation sessionBatchOperation = new ProcessBatchOperation() { - private int processedCount = 0; - - @Override - public void performAction(List objects) { - for (SimpleSession simpleSession : objects) { - try { - CustomAttribute customAttribute = getUpdatedAttribute(couchbaseEntryManager, simpleSession.getDn(), "oxLastAccessTime", - simpleSession.getAttribute("oxLastAccessTime")); - simpleSession.setCustomAttributes(Arrays.asList(new CustomAttribute[] {customAttribute})); - couchbaseEntryManager.merge(simpleSession); - processedCount++; - } catch (EntryPersistenceException ex) { - LOG.error("Failed to update entry", ex); - } - } - - LOG.info("Total processed: " + processedCount); - } - }; - - final Filter filter2 = Filter.createPresenceFilter("oxLastAccessTime"); - couchbaseEntryManager.findEntries("o=gluu", SimpleSession.class, filter2, SearchScope.SUB, new String[] {"oxLastAccessTime"}, - sessionBatchOperation, 0, 0, 100); - - BatchOperation clientBatchOperation = new ProcessBatchOperation() { - private int processedCount = 0; - - @Override - public void performAction(List objects) { - for (SimpleClient simpleClient : objects) { - processedCount++; - } - - LOG.info("Total processed: " + processedCount); - } - }; - - final Filter filter3 = Filter.createPresenceFilter("exp"); - List result3 = couchbaseEntryManager.findEntries("o=gluu", SimpleClient.class, filter3, SearchScope.SUB, - new String[] {"exp"}, clientBatchOperation, 0, 0, 1000); - - LOG.info("Result count (without collecting results): " + result3.size()); - - BatchOperation clientBatchOperation2 = new DefaultBatchOperation() { - private int processedCount = 0; - - @Override - public void performAction(List objects) { - for (SimpleClient simpleClient : objects) { - processedCount++; - } - - LOG.info("Total processed: " + processedCount); - } - }; - - final Filter filter4 = Filter.createPresenceFilter("exp"); - List result4 = couchbaseEntryManager.findEntries("o=gluu", SimpleClient.class, filter4, SearchScope.SUB, - new String[] {"exp"}, clientBatchOperation2, 0, 0, 1000); - - LOG.info("Result count (with collecting results): " + result4.size()); - } - - private static CustomAttribute getUpdatedAttribute(CouchbaseEntryManager couchbaseEntryManager, String baseDn, String attributeName, String attributeValue) { - try { - Calendar calendar = Calendar.getInstance(); - Date oxLastAccessTimeDate = new Date(); //TODO: Fix it StaticUtils.decodeGeneralizedTime(attributeValue); - calendar.setTime(oxLastAccessTimeDate); - calendar.add(Calendar.SECOND, -1); - - CustomAttribute customAttribute = new CustomAttribute(); - customAttribute.setName(attributeName); - customAttribute.setValue(couchbaseEntryManager.encodeTime(baseDn, calendar.getTime())); - return customAttribute; - } catch (Exception ex) { - LOG.error("Can't parse attribute", ex); - } - return null; - } -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleDelete.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleDelete.java deleted file mode 100644 index 22cf16c1..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleDelete.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.gluu.couchbase; - -import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; -import org.gluu.persist.couchbase.operation.impl.CouchbaseConnectionProvider; -import org.gluu.persist.model.base.DeletableEntity; -import org.gluu.search.filter.Filter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Date; - -/** - * @author Yuriy Movchan Date: 11/03/2016 - */ -public final class CouchbaseSampleDelete { - - private static final Logger LOG = LoggerFactory.getLogger(CouchbaseConnectionProvider.class); - - private CouchbaseSampleDelete() { - } - - public static void main(String[] args) { - // Prepare sample connection details - CouchbaseSampleEntryManager couchbaseSampleEntryManager = new CouchbaseSampleEntryManager(); - - // Create Couchbase entry manager - CouchbaseEntryManager couchbaseEntryManager = couchbaseSampleEntryManager.createCouchbaseEntryManager(); - - String baseDn = "ou=cache,o=gluu"; - Filter filter = Filter.createANDFilter( - Filter.createEqualityFilter("del", true), - Filter.createLessOrEqualFilter("exp", couchbaseEntryManager.encodeTime(baseDn, new Date())) - ); - - int result = couchbaseEntryManager.remove(baseDn, DeletableEntity.class, filter, 100); - System.out.println(result); - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleEntryManager.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleEntryManager.java deleted file mode 100644 index f40e1983..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleEntryManager.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.gluu.couchbase; - -import java.util.Properties; - -import org.apache.log4j.Logger; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManagerFactory; - -/** - * @author Yuriy Movchan - * Date: 01/13/2017 - */ -public class CouchbaseSampleEntryManager { - - private static final Logger LOG = Logger.getLogger(CouchbaseSampleEntryManager.class); - - private Properties getSampleConnectionProperties() { - Properties connectionProperties = new Properties(); - - connectionProperties.put("couchbase.servers", "test.gluu.info"); - connectionProperties.put("couchbase.auth.userName", "admin"); - connectionProperties.put("couchbase.auth.userPassword", "secret"); -// connectionProperties.put("couchbase.buckets", "gluu"); - connectionProperties.put("couchbase.buckets", "gluu, gluu_user, gluu_token"); - - connectionProperties.put("couchbase.bucket.default", "gluu"); - connectionProperties.put("couchbase.bucket.gluu_user.mapping", "people, groups"); - connectionProperties.put("couchbase.bucket.gluu_token.mapping", "sessions"); - - connectionProperties.put("couchbase.password.encryption.method", "CRYPT-SHA-256"); - - return connectionProperties; - } - - public CouchbaseEntryManager createCouchbaseEntryManager() { - CouchbaseEntryManagerFactory couchbaseEntryManagerFactory = new CouchbaseEntryManagerFactory(); - couchbaseEntryManagerFactory.create(); - Properties connectionProperties = getSampleConnectionProperties(); - - CouchbaseEntryManager couchbaseEntryManager = couchbaseEntryManagerFactory.createEntryManager(connectionProperties); - LOG.debug("Created CouchbaseEntryManager: " + couchbaseEntryManager); - - return couchbaseEntryManager; - } - -} \ No newline at end of file diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleSimpleSessionSample.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleSimpleSessionSample.java deleted file mode 100644 index 0e98b417..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleSimpleSessionSample.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.gluu.couchbase; - -import java.util.Date; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; - -import org.apache.log4j.Logger; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.status.StatusLogger; -import org.gluu.couchbase.model.SimpleSessionState; -import org.gluu.log.LoggingHelper; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; - -/** - * @author Yuriy Movchan Date: 01/25/2016 - */ -public final class CouchbaseSampleSimpleSessionSample { - - private static final Logger LOG; - - static { - StatusLogger.getLogger().setLevel(Level.OFF); - LoggingHelper.configureConsoleAppender(); - LOG = Logger.getLogger(CouchbaseSampleSimpleSessionSample.class); - } - - private CouchbaseSampleSimpleSessionSample() { - } - - public static void main(String[] args) throws InterruptedException { - // Prepare sample connection details - CouchbaseSampleEntryManager couchbaseSampleEntryManager = new CouchbaseSampleEntryManager(); - final CouchbaseEntryManager couchbaseEntryManager = couchbaseSampleEntryManager.createCouchbaseEntryManager(); - - try { - // Create Couchbase entry manager - String sessionId = "xyzcyzxy-a41a-45ad-8a83-61485dbad561"; - final String sessionDn = "uniqueIdentifier=" + sessionId + ",ou=session,o=gluu"; - final String userDn = - "inum=@!E8F2.853B.1E7B.ACE2!0001!39A4.C163!0000!A8F2.DE1E.D7FB,ou=people,o=gluu"; - - final SimpleSessionState simpleSessionState = new SimpleSessionState(); - simpleSessionState.setDn(sessionDn); - simpleSessionState.setId(sessionId); - simpleSessionState.setLastUsedAt(new Date()); - - couchbaseEntryManager.persist(simpleSessionState); - System.out.println("Persisted"); - - int threadCount = 500; - ExecutorService executorService = Executors.newFixedThreadPool(threadCount, daemonThreadFactory()); - for (int i = 0; i < threadCount; i++) { - final int count = i; - executorService.execute(new Runnable() { - @Override - public void run() { - final SimpleSessionState simpleSessionStateFromCouchbase = couchbaseEntryManager.find(SimpleSessionState.class, sessionDn); - String beforeUserDn = simpleSessionStateFromCouchbase.getUserDn(); - String randomUserDn = count % 2 == 0 ? userDn : ""; - - try { - simpleSessionStateFromCouchbase.setUserDn(randomUserDn); - simpleSessionStateFromCouchbase.setLastUsedAt(new Date()); - couchbaseEntryManager.merge(simpleSessionStateFromCouchbase); - System.out.println("Merged thread: " + count + ", userDn: " + randomUserDn + ", before userDn: " + beforeUserDn); - } catch (Throwable e) { - System.out.println("ERROR !!!, thread: " + count + ", userDn: " + randomUserDn + ", before userDn: " + beforeUserDn - + ", error:" + e.getMessage()); - // e.printStackTrace(); - } - } - }); - } - - Thread.sleep(5000L); - } finally { - couchbaseEntryManager.destroy(); - } - } - - public static ThreadFactory daemonThreadFactory() { - return new ThreadFactory() { - public Thread newThread(Runnable runnable) { - Thread thread = new Thread(runnable); - thread.setDaemon(true); - return thread; - } - }; - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleUserSearchSample.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleUserSearchSample.java deleted file mode 100644 index 87ff4c52..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/CouchbaseSampleUserSearchSample.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.gluu.couchbase; - -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicLong; - -import org.apache.log4j.Logger; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.status.StatusLogger; -import org.gluu.couchbase.model.SimpleUser; -import org.gluu.log.LoggingHelper; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; -import org.gluu.search.filter.Filter; -import org.gluu.util.StringHelper; - -/** - * @author Yuriy Movchan Date: 09/18/2019 - */ -public final class CouchbaseSampleUserSearchSample { - - private static final Logger LOG; - - static { - StatusLogger.getLogger().setLevel(Level.OFF); - LoggingHelper.configureConsoleAppender(); - LOG = Logger.getLogger(CouchbaseSampleUserSearchSample.class); - } - - private static AtomicLong successResult = new AtomicLong(0) ; - private static AtomicLong failedResult = new AtomicLong(0) ; - private static AtomicLong errorResult = new AtomicLong(0) ; - private static AtomicLong totalTime = new AtomicLong(0) ; - private static AtomicLong activeCount = new AtomicLong(0) ; - - private CouchbaseSampleUserSearchSample() { - } - - public static void main(String[] args) throws InterruptedException { - // Prepare sample connection details - CouchbaseSampleEntryManager couchbaseSampleEntryManager = new CouchbaseSampleEntryManager(); - final CouchbaseEntryManager couchbaseEntryManager = couchbaseSampleEntryManager.createCouchbaseEntryManager(); - - int countUsers = 1000000; - int threadCount = 200; - int threadIterationCount = 10; - - long totalStart = System.currentTimeMillis(); - try { - ExecutorService executorService = Executors.newFixedThreadPool(threadCount, daemonThreadFactory()); - for (int i = 0; i < threadCount; i++) { - activeCount.incrementAndGet(); - final int count = i; - executorService.execute(new Runnable() { - @Override - public void run() { - long start = System.currentTimeMillis(); - for (int j = 0; j < threadIterationCount; j++) { - long userUid = Math.round(Math.random() * countUsers); - String uid = String.format("user%06d", userUid); - try { - Filter filter = Filter.createEqualityFilter(Filter.createLowercaseFilter("uid"), StringHelper.toLowerCase(uid)); -// Filter filter = Filter.createEqualityFilter("uid", uid); - List foundUsers = couchbaseEntryManager.findEntries("ou=people,o=gluu", SimpleUser.class, filter); - if (foundUsers.size() > 0) { - successResult.incrementAndGet(); - } else { - LOG.warn("Failed to find user: " + uid); - failedResult.incrementAndGet(); - } - } catch (Throwable e) { - errorResult.incrementAndGet(); - System.out.println("ERROR !!!, thread: " + count + ", uid: " + uid + ", error:" + e.getMessage()); - e.printStackTrace(); - } - } - - long end = System.currentTimeMillis(); - long duration = end - start; - LOG.info("Thread " + count + " execution time: " + duration); - totalTime.addAndGet(duration); - activeCount.decrementAndGet(); - } - }); - } - - while (activeCount.get() != 0) { - Thread.sleep(1000L); - } - } finally { - couchbaseEntryManager.destroy(); - } - long totalEnd = System.currentTimeMillis(); - long duration = totalEnd - totalStart; - - LOG.info("Total execution time: " + duration + " after execution: " + (threadCount * threadIterationCount)); - - System.out.println(String.format("successResult: '%d', failedResult: '%d', errorResult: '%d'", successResult.get(), failedResult.get(), errorResult.get())); - } - - public static ThreadFactory daemonThreadFactory() { - return new ThreadFactory() { - public Thread newThread(Runnable runnable) { - Thread thread = new Thread(runnable); - thread.setDaemon(true); - return thread; - } - }; - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleAttribute.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleAttribute.java deleted file mode 100644 index 3fc8e527..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleAttribute.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.couchbase.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.util.StringHelper; - -/** - * @author Yuriy Movchan - * Date: 12/30/2016 - */ -@DataEntry -@ObjectClass(value = "gluuAttribute") -public class SimpleAttribute implements Serializable { - - private static final long serialVersionUID = -1634191420188575733L; - - @DN - private String dn; - - @AttributesList(name = "name", value = "values", sortByName = true) - private List customAttributes = new ArrayList(); - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String getAttribute(String ldapAttribute) { - String attribute = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(ldapAttribute)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String ldapAttribute) { - List values = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), ldapAttribute)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleClient.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleClient.java deleted file mode 100644 index 4fe79087..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleClient.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.couchbase.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.util.StringHelper; - -/** - * @author Yuriy Movchan - * Date: 02/08/2018 - */ -@DataEntry -@ObjectClass(value = "oxAuthClient") -public class SimpleClient implements Serializable { - - private static final long serialVersionUID = -2534191420188575733L; - - @DN - private String dn; - - @AttributesList(name = "name", value = "values", sortByName = true) - private List customAttributes = new ArrayList(); - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String getAttribute(String ldapAttribute) { - String attribute = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(ldapAttribute)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String ldapAttribute) { - List values = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), ldapAttribute)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleCustomStringUser.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleCustomStringUser.java deleted file mode 100644 index c191aad6..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleCustomStringUser.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.couchbase.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.util.StringHelper; - -/** - * @author Yuriy Movchan - * Date: 11/03/2016 - */ -@DataEntry -@ObjectClass(value = "gluuPerson") -public class SimpleCustomStringUser implements Serializable { - - private static final long serialVersionUID = -1634191420188575733L; - - @DN - private String dn; - - @AttributeName(name = "uid") - private String userId; - - @AttributeName(name = "userPassword") - private String userPassword; - - @AttributeName(name = "role") - private UserRole userRole; - - @AttributeName(name = "notes") - private List notes; - - @AttributesList(name = "name", value = "values", multiValued = "multiValued", sortByName = true) - private List customAttributes = new ArrayList(); - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } - - public String getUserPassword() { - return userPassword; - } - - public void setUserPassword(String userPassword) { - this.userPassword = userPassword; - } - - public UserRole getUserRole() { - return userRole; - } - - public void setUserRole(UserRole userRole) { - this.userRole = userRole; - } - - public List getNotes() { - return notes; - } - - public void setNotes(List notes) { - this.notes = notes; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String getAttribute(String attributeName) { - String attribute = null; - if (attributeName != null && !attributeName.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(attributeName)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String attributeName) { - List values = null; - if (attributeName != null && !attributeName.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), attributeName)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public void setAttributeValue(String attributeName, String attributeValue) { - if (attributeName != null && !attributeName.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), attributeName)) { - customAttribute.setValue(attributeValue); - return; - } - } - customAttributes.add(new CustomAttribute(attributeName, attributeValue)); - } - } - - public void setAttributeValues(String attributeName, List attributeValues) { - if (attributeName != null && !attributeName.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), attributeName)) { - customAttribute.setValues(attributeValues); - return; - } - } - customAttributes.add(new CustomAttribute(attributeName, attributeValues)); - } - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleGrant.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleGrant.java deleted file mode 100644 index f0c5c983..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleGrant.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.couchbase.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.util.StringHelper; - -/** - * @author Yuriy Movchan - * Date: 12/30/2016 - */ -@DataEntry -@ObjectClass(value = "oxAuthGrant") -public class SimpleGrant implements Serializable { - - private static final long serialVersionUID = -1234191420188575733L; - - @DN - private String dn; - - @AttributesList(name = "name", value = "values", sortByName = true) - private List customAttributes = new ArrayList(); - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String getAttribute(String ldapAttribute) { - String attribute = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(ldapAttribute)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String ldapAttribute) { - List values = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), ldapAttribute)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleSession.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleSession.java deleted file mode 100644 index a8f717b1..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleSession.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.couchbase.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.util.StringHelper; - -/** - * @author Yuriy Movchan - * Date: 12/30/2016 - */ -@DataEntry -@ObjectClass(value = "oxAuthSessionId") -public class SimpleSession implements Serializable { - - private static final long serialVersionUID = -1534191420188575733L; - - @DN - private String dn; - - @AttributesList(name = "name", value = "values", sortByName = true) - private List customAttributes = new ArrayList(); - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String getAttribute(String ldapAttribute) { - String attribute = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(ldapAttribute)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String ldapAttribute) { - List values = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), ldapAttribute)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleSessionState.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleSessionState.java deleted file mode 100644 index 019157d8..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleSessionState.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.couchbase.model; - -import java.io.Serializable; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -import javax.persistence.Transient; - -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.JsonObject; -import org.gluu.persist.annotation.ObjectClass; - -/** - * @author Yuriy Zabrovarnyy - * @author Javier Rojas Blum - * @version December 15, 2015 - */ -@DataEntry -@ObjectClass(value = "oxAuthSessionId") -public class SimpleSessionState implements Serializable { - - private static final long serialVersionUID = -237476411915686378L; - - @DN - private String dn; - - @AttributeName(name = "uniqueIdentifier") - private String id; - - @AttributeName(name = "oxLastAccessTime") - private Date lastUsedAt; - - @AttributeName(name = "oxAuthUserDN") - private String userDn; - - @AttributeName(name = "authnTime") - private Date authenticationTime; - - @AttributeName(name = "oxAuthSessionState") - private Boolean permissionGranted; - - @AttributeName(name = "oxAsJwt") - private Boolean isJwt = false; - - @AttributeName(name = "oxJwt") - private String jwt; - - @JsonObject - @AttributeName(name = "oxAuthSessionAttribute") - private Map sessionAttributes; - - @Transient - private transient boolean persisted; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public String getJwt() { - return jwt; - } - - public void setJwt(String jwt) { - this.jwt = jwt; - } - - public Boolean getIsJwt() { - return isJwt; - } - - public void setIsJwt(Boolean isJwt) { - this.isJwt = isJwt; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public Date getLastUsedAt() { - return lastUsedAt != null ? new Date(lastUsedAt.getTime()) : null; - } - - public void setLastUsedAt(Date lastUsedAt) { - this.lastUsedAt = lastUsedAt != null ? new Date(lastUsedAt.getTime()) : null; - } - - public String getUserDn() { - return userDn; - } - - public void setUserDn(String userDn) { - this.userDn = userDn != null ? userDn : ""; - } - - public Date getAuthenticationTime() { - return authenticationTime != null ? new Date(authenticationTime.getTime()) : null; - } - - public void setAuthenticationTime(Date authenticationTime) { - this.authenticationTime = authenticationTime != null ? new Date(authenticationTime.getTime()) : null; - } - - public Boolean getPermissionGranted() { - return permissionGranted; - } - - public void setPermissionGranted(Boolean permissionGranted) { - this.permissionGranted = permissionGranted; - } - - public Map getSessionAttributes() { - if (sessionAttributes == null) { - sessionAttributes = new HashMap(); - } - return sessionAttributes; - } - - public void setSessionAttributes(Map sessionAttributes) { - this.sessionAttributes = sessionAttributes; - } - - public boolean isPersisted() { - return persisted; - } - - public void setPersisted(boolean persisted) { - this.persisted = persisted; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - SimpleSessionState id1 = (SimpleSessionState) o; - - return !(id != null ? !id.equals(id1.id) : id1.id != null); - } - - @Override - public int hashCode() { - return id != null ? id.hashCode() : 0; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("SessionState"); - sb.append(", dn='").append(dn).append('\''); - sb.append(", id='").append(id).append('\''); - sb.append(", isJwt=").append(isJwt); - sb.append(", lastUsedAt=").append(lastUsedAt); - sb.append(", userDn='").append(userDn).append('\''); - sb.append(", authenticationTime=").append(authenticationTime); - sb.append(", permissionGranted=").append(permissionGranted); - sb.append(", sessionAttributes=").append(sessionAttributes); - sb.append(", persisted=").append(persisted); - sb.append('}'); - return sb.toString(); - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleTokenCouchbase.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleTokenCouchbase.java deleted file mode 100644 index da716aab..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleTokenCouchbase.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.gluu.couchbase.model; - -import org.gluu.persist.annotation.*; -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.util.StringHelper; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -/** - * Created by eugeniuparvan on 1/12/17. - */ -@DataEntry -@ObjectClass(value = "token") -public class SimpleTokenCouchbase implements Serializable { - - private static final long serialVersionUID = 6726419630327625172L; - - @AttributesList(name = "name", value = "values", sortByName = true) - private List customAttributes = new ArrayList(); - - @DN - private String dn; - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String getAttribute(String ldapAttribute) { - String attribute = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(ldapAttribute)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String ldapAttribute) { - List values = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), ldapAttribute)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleUser.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleUser.java deleted file mode 100644 index e3335278..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/SimpleUser.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.couchbase.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.persist.model.base.CustomObjectAttribute; -import org.gluu.util.StringHelper; - -/** - * @author Yuriy Movchan - * Date: 11/03/2016 - */ -@DataEntry -@ObjectClass(value = "gluuPerson") -public class SimpleUser implements Serializable { - - private static final long serialVersionUID = -1634191420188575733L; - - @DN - private String dn; - - @AttributeName(name = "uid") - private String userId; - - @AttributeName(name = "userPassword") - private String userPassword; - - @AttributeName(name = "role") - private UserRole userRole; - - @AttributeName(name = "notes") - private List notes; - - @AttributesList(name = "name", value = "values", multiValued = "multiValued", sortByName = true) - private List customAttributes = new ArrayList(); - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } - - public String getUserPassword() { - return userPassword; - } - - public void setUserPassword(String userPassword) { - this.userPassword = userPassword; - } - - public UserRole getUserRole() { - return userRole; - } - - public void setUserRole(UserRole userRole) { - this.userRole = userRole; - } - - public List getNotes() { - return notes; - } - - public void setNotes(List notes) { - this.notes = notes; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public Object getAttribute(String attributeName) { - Object attribute = null; - if (attributeName != null && !attributeName.isEmpty()) { - for (CustomObjectAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(attributeName)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String attributeName) { - List values = null; - if (attributeName != null && !attributeName.isEmpty()) { - for (CustomObjectAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), attributeName)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public void setAttributeValue(String attributeName, Object attributeValue) { - if (attributeName != null && !attributeName.isEmpty()) { - for (CustomObjectAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), attributeName)) { - customAttribute.setValue(attributeValue); - return; - } - } - customAttributes.add(new CustomObjectAttribute(attributeName, attributeValue)); - } - } - - public void setAttributeValues(String attributeName, List attributeValues) { - if (attributeName != null && !attributeName.isEmpty()) { - for (CustomObjectAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), attributeName)) { - customAttribute.setValues(attributeValues); - return; - } - } - customAttributes.add(new CustomObjectAttribute(attributeName, attributeValues)); - } - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/UserRole.java b/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/UserRole.java deleted file mode 100644 index b863d503..00000000 --- a/persistence-couchbase-sample/src/main/java/org/gluu/couchbase/model/UserRole.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */package org.gluu.couchbase.model; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import org.gluu.persist.annotation.AttributeEnum; - -/** - * User role - * - * @author Yuriy Movchan Date: 11.03.2010 - */ -public enum UserRole implements AttributeEnum { - - ADMIN("admin"), OWNER("owner"), MANAGER("manager"), USER("user"); - - private String value; - - private static Map mapByValues = new HashMap(); - - static { - for (UserRole enumType : values()) { - mapByValues.put(enumType.getValue(), enumType); - } - } - - private UserRole(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - public String getRoleName() { - return value; - } - - public String getDisplayName() { - return value; - } - - public static UserRole getByValue(String value) { - return mapByValues.get(value); - } - - public static UserRole[] getByValues(String[] values) { - UserRole[] roles = new UserRole[values.length]; - for (int i = 0; i < values.length; i++) { - roles[i] = getByValue(values[i]); - } - - return roles; - } - - public static boolean equals(UserRole[] roles1, UserRole[] roles2) { - Arrays.sort(roles1); - Arrays.sort(roles2); - return Arrays.equals(roles1, roles2); - } - - public static boolean containsRole(UserRole[] roles, UserRole role) { - if ((roles == null) || (role == null)) { - return false; - } - - for (int i = 0; i < roles.length; i++) { - if (role.equals(roles[i])) { - return true; - } - } - - return false; - } - - public Enum resolveByValue(String value) { - return getByValue(value); - } - - @Override - public String toString() { - return value; - } - -} diff --git a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java deleted file mode 100644 index 343e21b9..00000000 --- a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/ManualCouchbaseEntryManagerTest.java +++ /dev/null @@ -1,111 +0,0 @@ -package org.gluu.couchbase.test; - -import com.couchbase.client.core.message.kv.subdoc.multi.Lookup; -import com.couchbase.client.java.Bucket; -import com.couchbase.client.java.document.JsonDocument; -import com.couchbase.client.java.subdoc.DocumentFragment; -import com.couchbase.client.java.subdoc.SubdocOptionsBuilder; - -import org.gluu.couchbase.model.SimpleClient; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManager; -import org.gluu.persist.couchbase.impl.CouchbaseEntryManagerFactory; -import org.gluu.persist.exception.operation.SearchException; -import org.gluu.util.Pair; -import org.testng.annotations.Test; - -import java.io.IOException; -import java.io.InputStream; -import java.util.*; - -/** - * @author Yuriy Zabrovarnyy - */ -public class ManualCouchbaseEntryManagerTest { - - @Test(enabled = false) // manual - public void sample() throws IOException { - CouchbaseEntryManager manager = createCouchbaseEntryManager(); - - try { - List attributeList = manager.findEntries("o=gluu", SimpleClient.class, null); - System.out.println(attributeList); - } finally { - manager.destroy(); - } - } - - @Test(enabled = false) // manual - public void sampleSessionId() throws IOException, SearchException { - CouchbaseEntryManager manager = createCouchbaseEntryManager(); - - try { - SessionId sessionId = createSessionId(); - manager.persist(sessionId); - - final String key = "sessions_" + sessionId.getId(); - System.out.println("Key: " + key + ", ttl:" + sessionId.getTtl()); - - Bucket sessionBucket = manager.getOperationService().getConnectionProvider().getBucketMapping("sessions").getBucket(); - final JsonDocument lookup = sessionBucket.get(key); - System.out.println("expiry: " + lookup.expiry()); - - DocumentFragment ttl = sessionBucket.lookupIn(key).get("$document.exptime", new SubdocOptionsBuilder().xattr(true)).execute(); - System.out.println("ttl: " + ttl.content("$document.exptime")); - - updateSession(sessionId); - manager.merge(sessionId); - - final JsonDocument lookup2 = manager.getOperationService().getConnectionProvider().getBucketMapping("sessions").getBucket().get(key); - System.out.println("expiry after update: " + lookup2.expiry()); - - } finally { - manager.destroy(); - } - } - - private SessionId createSessionId() { - SessionId sessionId = new SessionId(); - sessionId.setId(UUID.randomUUID().toString()); - sessionId.setDn(String.format("oxId=%s,%s", sessionId.getId(), "ou=sessions,o=gluu")); - sessionId.setCreationDate(new Date()); - - updateSession(sessionId); - return sessionId; - } - - private void updateSession(SessionId sessionId) { - final Pair expiration = expirationDate(sessionId.getCreationDate()); - sessionId.setLastUsedAt(new Date()); - sessionId.setExpirationDate(expiration.getFirst()); - sessionId.setTtl(expiration.getSecond()); - } - - private Pair expirationDate(Date creationDate) { - int expirationInSeconds = 120; - Calendar calendar = Calendar.getInstance(); - calendar.setTime(creationDate); - calendar.add(Calendar.SECOND, expirationInSeconds); - return new Pair<>(calendar.getTime(), expirationInSeconds); - } - - // MODIFY ACCORDING TO YOUR SERVER - public static Properties loadProperties() throws IOException { - Properties properties = new Properties(); - properties.put("couchbase.auth.userPassword", "1234.Gluu"); - - try (InputStream is = ManualCouchbaseEntryManagerTest.class.getResourceAsStream("cb-bench-backend.gluu.org.properties")) { - properties.load(is); - return properties; - } - } - - public static CouchbaseEntryManager createCouchbaseEntryManager() throws IOException { - CouchbaseEntryManagerFactory couchbaseEntryManagerFactory = new CouchbaseEntryManagerFactory(); - couchbaseEntryManagerFactory.create(); - - CouchbaseEntryManager couchbaseEntryManager = couchbaseEntryManagerFactory.createEntryManager(loadProperties()); - System.out.println("Created CouchbaseEntryManager: " + couchbaseEntryManager); - - return couchbaseEntryManager; - } -} diff --git a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionId.java b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionId.java deleted file mode 100644 index 1310c4e1..00000000 --- a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionId.java +++ /dev/null @@ -1,260 +0,0 @@ -package org.gluu.couchbase.test; - -/* - * oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -import com.couchbase.client.java.cluster.User; -import com.google.common.collect.Maps; -import org.gluu.persist.annotation.*; -import org.gluu.persist.model.base.Deletable; - -import javax.inject.Named; -import javax.persistence.Transient; -import java.io.Serializable; -import java.util.Date; -import java.util.Map; - -/** - * @author Yuriy Zabrovarnyy - * @author Javier Rojas Blum - * @version December 8, 2018 - */ -@Named("sessionUser") -@DataEntry -@ObjectClass(value = "oxAuthSessionId") -public class SessionId implements Deletable, Serializable { - - private static final long serialVersionUID = -237476411915686378L; - - @DN - private String dn; - - @AttributeName(name = "oxId") - private String id; - - @AttributeName(name = "oxLastAccessTime") - private Date lastUsedAt; - - @AttributeName(name = "oxAuthUserDN") - private String userDn; - - @AttributeName(name = "authnTime") - private Date authenticationTime; - - @AttributeName(name = "oxState") - private SessionIdState state; - - @AttributeName(name = "oxSessionState") - private String sessionState; - - @AttributeName(name = "oxAuthPermissionGranted") - private Boolean permissionGranted; - - @AttributeName(name = "oxAsJwt") - private Boolean isJwt = false; - - @AttributeName(name = "oxJwt") - private String jwt; - - @JsonObject - @AttributeName(name = "oxAuthSessionAttribute") - private Map sessionAttributes; - - @AttributeName(name = "exp") - private Date expirationDate; - - @AttributeName(name = "del") - private Boolean deletable = true; - - @AttributeName(name = "creationDate") - private Date creationDate = new Date(); - - @Transient - private transient boolean persisted; - - @Transient - private User user; - - @Expiration - private int ttl; - - public SessionId() { - } - - public int getTtl() { - return ttl; - } - - public void setTtl(int ttl) { - this.ttl = ttl; - } - - public String getDn() { - return dn; - } - - public void setDn(String p_dn) { - dn = p_dn; - } - - public String getJwt() { - return jwt; - } - - public void setJwt(String jwt) { - this.jwt = jwt; - } - - public Boolean getIsJwt() { - return isJwt; - } - - public void setIsJwt(Boolean isJwt) { - this.isJwt = isJwt; - } - - public SessionIdState getState() { - return state; - } - - public void setState(SessionIdState state) { - this.state = state; - } - - public String getSessionState() { - return sessionState; - } - - public void setSessionState(String sessionState) { - this.sessionState = sessionState; - } - - public String getId() { - return id; - } - - public void setId(String p_id) { - id = p_id; - } - - public Date getLastUsedAt() { - return lastUsedAt; - } - - public void setLastUsedAt(Date p_lastUsedAt) { - lastUsedAt = p_lastUsedAt; - } - - public String getUserDn() { - return userDn; - } - - public void setUserDn(String p_userDn) { - userDn = p_userDn != null ? p_userDn : ""; - } - - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - - public Date getAuthenticationTime() { - return authenticationTime; - } - - public void setAuthenticationTime(Date authenticationTime) { - this.authenticationTime = authenticationTime; - } - - public Boolean getPermissionGranted() { - return permissionGranted; - } - - public void setPermissionGranted(Boolean permissionGranted) { - this.permissionGranted = permissionGranted; - } - - public Map getSessionAttributes() { - if (sessionAttributes == null) { - sessionAttributes = Maps.newHashMap(); - } - return sessionAttributes; - } - - public void setSessionAttributes(Map sessionAttributes) { - this.sessionAttributes = sessionAttributes; - } - - public boolean isPersisted() { - return persisted; - } - - public void setPersisted(boolean persisted) { - this.persisted = persisted; - } - - public Date getExpirationDate() { - return expirationDate; - } - - public void setExpirationDate(Date expirationDate) { - this.expirationDate = expirationDate; - } - - public Boolean isDeletable() { - return deletable != null ? deletable : true; - } - - public void setDeletable(Boolean deletable) { - this.deletable = deletable; - } - - public Date getCreationDate() { - return creationDate; - } - - public void setCreationDate(Date creationDate) { - this.creationDate = creationDate; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - SessionId id1 = (SessionId) o; - - return !(id != null ? !id.equals(id1.id) : id1.id != null); - } - - @Override - public int hashCode() { - return id != null ? id.hashCode() : 0; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("SessionIdTest {"); - sb.append("dn='").append(dn).append('\''); - sb.append(", id='").append(id).append('\''); - sb.append(", lastUsedAt=").append(lastUsedAt); - sb.append(", userDn='").append(userDn).append('\''); - sb.append(", authenticationTime=").append(authenticationTime); - sb.append(", state=").append(state); - sb.append(", sessionState='").append(sessionState).append('\''); - sb.append(", permissionGranted=").append(permissionGranted); - sb.append(", isJwt=").append(isJwt); - sb.append(", jwt=").append(jwt); - sb.append(", sessionAttributes=").append(sessionAttributes); - sb.append(", persisted=").append(persisted); - sb.append("}"); - return sb.toString(); - } -} diff --git a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionIdState.java b/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionIdState.java deleted file mode 100644 index c6c8d6eb..00000000 --- a/persistence-couchbase-sample/src/test/java/org/gluu/couchbase/test/SessionIdState.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.gluu.couchbase.test; - -import org.gluu.persist.annotation.AttributeEnum; - -import java.util.HashMap; -import java.util.Map; - -/** - * @author Yuriy Zabrovarnyy - */ -public enum SessionIdState implements AttributeEnum { - - UNAUTHENTICATED("unauthenticated"), AUTHENTICATED("authenticated"); - - private final String value; - - private static Map mapByValues = new HashMap(); - - static { - for (SessionIdState enumType : values()) { - mapByValues.put(enumType.getValue(), enumType); - } - } - - private SessionIdState(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - public static SessionIdState getByValue(String value) { - return mapByValues.get(value); - } - - public Enum resolveByValue(String value) { - return getByValue(value); - } - - @Override - public String toString() { - return value; - } - -} diff --git a/persistence-couchbase-sample/src/test/resources/org/gluu/couchbase/test/c1.gluu.org.properties b/persistence-couchbase-sample/src/test/resources/org/gluu/couchbase/test/c1.gluu.org.properties deleted file mode 100644 index ea38426c..00000000 --- a/persistence-couchbase-sample/src/test/resources/org/gluu/couchbase/test/c1.gluu.org.properties +++ /dev/null @@ -1,6 +0,0 @@ -couchbase.servers=c1.gluu.org -couchbase.auth.userName=admin -couchbase.buckets=gluu -couchbase.bucket.default=gluu -couchbase.bucket.gluu.mapping=people, groups -couchbase.password.encryption.method=SSHA-256 \ No newline at end of file diff --git a/persistence-couchbase/LICENSE b/persistence-couchbase/LICENSE deleted file mode 100644 index cd069e7b..00000000 --- a/persistence-couchbase/LICENSE +++ /dev/null @@ -1,25 +0,0 @@ -The Gluu Support License (GLUU-SUPPORT) - -Copyright (c) 2019 Gluu - -Permission is hereby granted to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The end-user person or organization using this software has an active support -subscription with either Gluu or one of Gluu's OEM partners after using the -software for more than 30 days. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/persistence-couchbase/pom.xml b/persistence-couchbase/pom.xml deleted file mode 100644 index c4ac6726..00000000 --- a/persistence-couchbase/pom.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - 4.0.0 - oxcore-persistence-couchbase - jar - persistence-couchbase - - - org.gluu - oxcore - 5.0.0-SNAPSHOT - - - - - - src/main/resources - true - - **/*.xml - **/services/* - **/*.properties - - - - - - - - - org.gluu - oxcore-util - - - org.gluu - oxcore-persistence-filter - - - org.gluu - oxcore-persistence-core - - - org.gluu - oxcore-persistence-ldap - - - org.gluu - oxcore-persistence-annotation - - - - com.couchbase.client - java-client - - - - - javax.enterprise - cdi-api - provided - - - javax.inject - javax.inject - - - javax.annotation - javax.annotation-api - 1.3.2 - - - - \ No newline at end of file diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseBatchOperationWraper.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseBatchOperationWraper.java deleted file mode 100644 index 5f1e6461..00000000 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseBatchOperationWraper.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - /* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.couchbase.impl; - -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.model.BatchOperation; -import org.gluu.persist.reflect.property.PropertyAnnotation; - -import com.couchbase.client.java.document.json.JsonObject; -import com.couchbase.client.java.query.N1qlQueryRow; - -/** - * Couchbase batch operation wrapper - * - * @author Yuriy Movchan Date: 05/16/2018 - */ -public class CouchbaseBatchOperationWraper { - - private CouchbaseEntryManager couchbaseEntryManager; - private Class entryClass; - private List propertiesAnnotations; - - private BatchOperation batchOperation; - - public CouchbaseBatchOperationWraper(BatchOperation batchOperation) { - this.batchOperation = batchOperation; - } - - public CouchbaseBatchOperationWraper(BatchOperation batchOperation, CouchbaseEntryManager couchbaseEntryManager, Class entryClass, - List propertiesAnnotations) { - this.batchOperation = batchOperation; - this.couchbaseEntryManager = couchbaseEntryManager; - this.entryClass = entryClass; - this.propertiesAnnotations = propertiesAnnotations; - } - - public final BatchOperation getBatchOperation() { - return batchOperation; - } - - public List createEntities(List searchResult) { - if (couchbaseEntryManager == null) { - return new ArrayList(0); - } - - JsonObject[] resultObjects = new JsonObject[searchResult.size()]; - - int index = 0; - for (N1qlQueryRow row : searchResult) { - resultObjects[index++] = row.value(); - } - - return couchbaseEntryManager.createEntities(entryClass, propertiesAnnotations, null, resultObjects); - } - -} diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java deleted file mode 100644 index 1d66c4cf..00000000 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManager.java +++ /dev/null @@ -1,1019 +0,0 @@ -/* - /* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.couchbase.impl; - -import java.io.Serializable; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -import javax.inject.Inject; - -import org.gluu.persist.PersistenceEntryManager; -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.couchbase.model.ConvertedExpression; -import org.gluu.persist.couchbase.model.SearchReturnDataType; -import org.gluu.persist.couchbase.operation.CouchbaseOperationService; -import org.gluu.persist.couchbase.operation.impl.CouchbaseConnectionProvider; -import org.gluu.persist.event.DeleteNotifier; -import org.gluu.persist.exception.AuthenticationException; -import org.gluu.persist.exception.EntryDeleteException; -import org.gluu.persist.exception.EntryPersistenceException; -import org.gluu.persist.exception.MappingException; -import org.gluu.persist.exception.operation.SearchException; -import org.gluu.persist.impl.BaseEntryManager; -import org.gluu.persist.key.impl.GenericKeyConverter; -import org.gluu.persist.key.impl.model.ParsedKey; -import org.gluu.persist.model.AttributeData; -import org.gluu.persist.model.AttributeDataModification; -import org.gluu.persist.model.AttributeDataModification.AttributeModificationType; -import org.gluu.persist.model.BatchOperation; -import org.gluu.persist.model.DefaultBatchOperation; -import org.gluu.persist.model.PagedResult; -import org.gluu.persist.model.SearchScope; -import org.gluu.persist.model.SortOrder; -import org.gluu.persist.reflect.property.PropertyAnnotation; -import org.gluu.persist.reflect.util.ReflectHelper; -import org.gluu.search.filter.Filter; -import org.gluu.util.ArrayHelper; -import org.gluu.util.StringHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.couchbase.client.core.message.kv.subdoc.multi.Mutation; -import com.couchbase.client.java.document.json.JsonArray; -import com.couchbase.client.java.document.json.JsonObject; -import com.couchbase.client.java.query.consistency.ScanConsistency; -import com.couchbase.client.java.query.dsl.Expression; -import com.couchbase.client.java.query.dsl.Sort; -import com.couchbase.client.java.subdoc.MutationSpec; - -/** - * Couchbase Entry Manager - * - * @author Yuriy Movchan Date: 05/14/2018 - */ -public class CouchbaseEntryManager extends BaseEntryManager implements Serializable { - - private static final String JSON_DATA_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS"; - - private static final long serialVersionUID = 2127241817126412574L; - - private static final Logger LOG = LoggerFactory.getLogger(CouchbaseConnectionProvider.class); - - @Inject - private Logger log; - - private final CouchbaseFilterConverter FILTER_CONVERTER; - private static final GenericKeyConverter KEY_CONVERTER = new GenericKeyConverter(); - - private List subscribers; - - protected CouchbaseEntryManager(CouchbaseOperationService operationService) { - this.operationService = operationService; - this.FILTER_CONVERTER = new CouchbaseFilterConverter(this); - subscribers = new LinkedList(); - } - - @Override - public boolean destroy() { - if (this.operationService == null) { - return true; - } - - return ((CouchbaseOperationService) this.operationService).destroy(); - } - - public CouchbaseOperationService getOperationService() { - return (CouchbaseOperationService) operationService; - } - - @Override - public void addDeleteSubscriber(DeleteNotifier subscriber) { - subscribers.add(subscriber); - } - - @Override - public void removeDeleteSubscriber(DeleteNotifier subscriber) { - subscribers.remove(subscriber); - } - - @Override - public Void merge(Object entry) { - Class entryClass = entry.getClass(); - checkEntryClass(entryClass, true); - if (isSchemaEntry(entryClass)) { - throw new UnsupportedOperationException("Server doesn't support dynamic schema modifications"); - } else { - return merge(entry, false, false, null); - } - } - - @Override - protected void updateMergeChanges(String baseDn, T entry, boolean isConfigurationUpdate, Class entryClass, Map attributesFromDbMap, - List attributeDataModifications) { - // Update object classes if entry contains custom object classes - if (!isConfigurationUpdate) { - String[] objectClasses = getObjectClasses(entry, entryClass); - if (ArrayHelper.isEmpty(objectClasses)) { - throw new UnsupportedOperationException(String.format("There is no attribute with objectClasses to persist! Entry is invalid: '%s'", entry)); - } - - AttributeData objectClassAttributeData = attributesFromDbMap.get(OBJECT_CLASS.toLowerCase()); - if (objectClassAttributeData == null) { - throw new UnsupportedOperationException(String.format("There is no attribute with objectClasses in DB! Entry is invalid: '%s'", entry)); - } - - String[] objectClassesFromDb = objectClassAttributeData.getStringValues(); - if (ArrayHelper.isEmpty(objectClassesFromDb)) { - throw new UnsupportedOperationException(String.format("There is no attribute with objectClasses in DB! Entry is invalid: '%s'", entry)); - } - - // We need to check only first element of each array because objectCLass in Couchbase is single value attribute - if (!StringHelper.equals(objectClassesFromDb[0], objectClasses[0])) { - attributeDataModifications.add(new AttributeDataModification(AttributeModificationType.REPLACE, - new AttributeData(OBJECT_CLASS, objectClasses, false), new AttributeData(OBJECT_CLASS, objectClassesFromDb, false))); - } - } - } - - @Override - public void remove(Object entry) { - Class entryClass = entry.getClass(); - checkEntryClass(entryClass, true); - if (isSchemaEntry(entryClass)) { - throw new UnsupportedOperationException("Server doesn't support dynamic schema modifications"); - } - - Object dnValue = getDNValue(entry, entryClass); - - LOG.debug("LDAP entry to remove: '{}'", dnValue.toString()); - - remove(dnValue.toString()); - } - - @Override - protected void persist(String dn, List attributes, Integer expiration) { - JsonObject jsonObject = JsonObject.create(); - for (AttributeData attribute : attributes) { - String attributeName = attribute.getName(); - Object[] attributeValues = attribute.getValues(); - Boolean multiValued = attribute.getMultiValued(); - - - if (ArrayHelper.isNotEmpty(attributeValues) && (attributeValues[0] != null)) { - Object[] realValues = attributeValues; - - // We need to store only one objectClass value in Couchbase - if (StringHelper.equals(CouchbaseOperationService.OBJECT_CLASS, attributeName)) { - if (!ArrayHelper.isEmpty(realValues)) { - realValues = new Object[] { realValues[0] }; - multiValued = false; - } - } - - // Process userPassword - if (StringHelper.equals(CouchbaseOperationService.USER_PASSWORD, attributeName)) { - realValues = getOperationService().createStoragePassword(StringHelper.toStringArray(attributeValues)); - } - - escapeValues(realValues); - - if ((multiValued == null) || !multiValued) { - jsonObject.put(toInternalAttribute(attributeName), realValues[0]); - } else { - jsonObject.put(toInternalAttribute(attributeName), JsonArray.from(realValues)); - } - } - } - jsonObject.put(CouchbaseOperationService.DN, dn); - - // Persist entry - try { - boolean result = getOperationService().addEntry(toCouchbaseKey(dn).getKey(), jsonObject, expiration); - if (!result) { - throw new EntryPersistenceException(String.format("Failed to persist entry: %s", dn)); - } - } catch (Exception ex) { - throw new EntryPersistenceException(String.format("Failed to persist entry: %s", dn), ex); - } - } - - @Override - public void merge(String dn, List attributeDataModifications, Integer expirationValue) { - // Update entry - try { - List modifications = new ArrayList(attributeDataModifications.size()); - for (AttributeDataModification attributeDataModification : attributeDataModifications) { - AttributeData attribute = attributeDataModification.getAttribute(); - AttributeData oldAttribute = attributeDataModification.getOldAttribute(); - - String attributeName = null; - Object[] attributeValues = null; - Boolean multiValued = null; - if (attribute != null) { - attributeName = attribute.getName(); - attributeValues = attribute.getValues(); - multiValued = attribute.getMultiValued(); - } - - String oldAttributeName = null; - Object[] oldAttributeValues = null; - if (oldAttribute != null) { - oldAttributeName = oldAttribute.getName(); - oldAttributeValues = oldAttribute.getValues(); - } - - MutationSpec modification = null; - if (AttributeModificationType.ADD.equals(attributeDataModification.getModificationType())) { - modification = createModification(Mutation.DICT_ADD, toInternalAttribute(attributeName), multiValued, attributeValues); - } else { - if (AttributeModificationType.REMOVE.equals(attributeDataModification.getModificationType())) { - modification = createModification(Mutation.DELETE, toInternalAttribute(oldAttributeName), multiValued, oldAttributeValues); - } else if (AttributeModificationType.REPLACE.equals(attributeDataModification.getModificationType())) { - modification = createModification(Mutation.REPLACE, toInternalAttribute(attributeName), multiValued, attributeValues); - } - } - - if (modification != null) { - modifications.add(modification); - } - } - - if (modifications.size() > 0) { - boolean result = getOperationService().updateEntry(toCouchbaseKey(dn).getKey(), modifications, expirationValue); - if (!result) { - throw new EntryPersistenceException(String.format("Failed to update entry: %s", dn)); - } - } - } catch (Exception ex) { - throw new EntryPersistenceException(String.format("Failed to update entry: %s", dn), ex); - } - } - - @Override - public void remove(String dn) { - // Remove entry - try { - for (DeleteNotifier subscriber : subscribers) { - subscriber.onBeforeRemove(dn); - } - getOperationService().delete(toCouchbaseKey(dn).getKey()); - for (DeleteNotifier subscriber : subscribers) { - subscriber.onAfterRemove(dn); - } - } catch (Exception ex) { - throw new EntryDeleteException(String.format("Failed to remove entry: %s", dn), ex); - } - } - - @Override - public void removeRecursively(String dn) { - try { - for (DeleteNotifier subscriber : subscribers) { - subscriber.onBeforeRemove(dn); - } - getOperationService().deleteRecursively(toCouchbaseKey(dn).getKey()); - for (DeleteNotifier subscriber : subscribers) { - subscriber.onAfterRemove(dn); - } - } catch (Exception ex) { - throw new EntryDeleteException(String.format("Failed to remove entry: %s", dn), ex); - } - } - - @Override - public int remove(String dn, Class entryClass, Filter filter, int count) { - if (StringHelper.isEmptyString(dn)) { - throw new MappingException("Base DN to delete entries is null"); - } - - // Remove entries by filter - return removeImpl(dn, entryClass, filter, count); - } - - protected int removeImpl(String dn, Class entryClass, Filter filter, int count) { - // Check entry class - checkEntryClass(entryClass, false); - - String[] objectClasses = getTypeObjectClasses(entryClass); - - Filter searchFilter; - if (objectClasses.length > 0) { - LOG.trace("Filter: {}", filter); - searchFilter = addObjectClassFilter(filter, objectClasses); - } else { - searchFilter = filter; - } - - // Find entries - LOG.trace("-------------------------------------------------------"); - LOG.trace("Filter: {}", filter); - LOG.trace("objectClasses count: {} ", objectClasses.length); - LOG.trace("objectClasses: {}", objectClasses.toString()); - LOG.trace("Search filter: {}", searchFilter); - - // Prepare properties types to allow build filter properly - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - Map propertiesAnnotationsMap = prepareEntryPropertiesTypes(entryClass, propertiesAnnotations); - - ParsedKey keyWithInum = toCouchbaseKey(dn); - ConvertedExpression convertedExpression; - try { - convertedExpression = toCouchbaseFilter(searchFilter, propertiesAnnotationsMap); - } catch (SearchException ex) { - throw new EntryDeleteException(String.format("Failed to convert filter %s to expression", searchFilter)); - } - - try { - int processed = getOperationService().delete(keyWithInum.getKey(), getScanConsistency(convertedExpression), convertedExpression.expression(), count); - - return processed; - } catch (Exception ex) { - throw new EntryDeleteException(String.format("Failed to delete entries with key: %s, expression: %s", keyWithInum.getKey(), convertedExpression), ex); - } - } - - @Override - protected List find(String dn, Map propertiesAnnotationsMap, String... ldapReturnAttributes) { - try { - // Load entry - ParsedKey keyWithInum = toCouchbaseKey(dn); - ScanConsistency scanConsistency = getScanConsistency(keyWithInum.getName(), propertiesAnnotationsMap); - JsonObject entry = getOperationService().lookup(keyWithInum.getKey(), scanConsistency, toInternalAttributes(ldapReturnAttributes)); - List result = getAttributeDataList(entry); - if (result != null) { - return result; - } - } catch (Exception ex) { - throw new EntryPersistenceException(String.format("Failed to find entry: %s", dn), ex); - } - - throw new EntryPersistenceException(String.format("Failed to find entry: %s", dn)); - } - - @Override - public List findEntries(String baseDN, Class entryClass, Filter filter, SearchScope scope, String[] ldapReturnAttributes, - BatchOperation batchOperation, int start, int count, int chunkSize) { - if (StringHelper.isEmptyString(baseDN)) { - throw new MappingException("Base DN to find entries is null"); - } - - PagedResult searchResult = findEntriesImpl(baseDN, entryClass, filter, scope, ldapReturnAttributes, null, null, batchOperation, - SearchReturnDataType.SEARCH, start, count, chunkSize); - if (searchResult.getEntriesCount() == 0) { - return new ArrayList(0); - } - - List entries = createEntities(baseDN, entryClass, searchResult); - - return entries; - } - - @Override - public PagedResult findPagedEntries(String baseDN, Class entryClass, Filter filter, String[] ldapReturnAttributes, String sortBy, - SortOrder sortOrder, int start, int count, int chunkSize) { - if (StringHelper.isEmptyString(baseDN)) { - throw new MappingException("Base DN to find entries is null"); - } - - PagedResult searchResult = findEntriesImpl(baseDN, entryClass, filter, SearchScope.SUB, ldapReturnAttributes, sortBy, sortOrder, - null, SearchReturnDataType.SEARCH_COUNT, start, count, chunkSize); - - PagedResult result = new PagedResult(); - result.setEntriesCount(searchResult.getEntriesCount()); - result.setStart(searchResult.getStart()); - result.setTotalEntriesCount(searchResult.getTotalEntriesCount()); - - if (searchResult.getEntriesCount() == 0) { - result.setEntries(new ArrayList(0)); - return result; - } - - List entries = createEntities(baseDN, entryClass, searchResult); - result.setEntries(entries); - - return result; - } - - protected PagedResult findEntriesImpl(String baseDN, Class entryClass, Filter filter, SearchScope scope, - String[] ldapReturnAttributes, String sortBy, SortOrder sortOrder, BatchOperation batchOperation, SearchReturnDataType returnDataType, int start, - int count, int chunkSize) { - // Check entry class - checkEntryClass(entryClass, false); - String[] objectClasses = getTypeObjectClasses(entryClass); - - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - String[] currentLdapReturnAttributes = ldapReturnAttributes; - if (ArrayHelper.isEmpty(currentLdapReturnAttributes)) { - currentLdapReturnAttributes = getAttributes(null, propertiesAnnotations, false); - } - - Filter searchFilter; - if (objectClasses.length > 0) { - LOG.trace("Filter: {}", filter); - searchFilter = addObjectClassFilter(filter, objectClasses); - } else { - searchFilter = filter; - } - - // Find entries - LOG.trace("-------------------------------------------------------"); - LOG.trace("Filter: {}", filter); - LOG.trace("objectClasses count: {} ", objectClasses.length); - LOG.trace("objectClasses: {}", ArrayHelper.toString(objectClasses)); - LOG.trace("Search filter: {}", searchFilter); - - // Prepare default sort - Sort[] defaultSort = getDefaultSort(entryClass); - - if (StringHelper.isNotEmpty(sortBy)) { - Sort requestedSort = buildSort(sortBy, sortOrder); - - if (ArrayHelper.isEmpty(defaultSort)) { - defaultSort = new Sort[] { requestedSort }; - } else { - defaultSort = ArrayHelper.arrayMerge(new Sort[] { requestedSort }, defaultSort); - } - } - - // Prepare properties types to allow build filter properly - Map propertiesAnnotationsMap = prepareEntryPropertiesTypes(entryClass, propertiesAnnotations); - ParsedKey keyWithInum = toCouchbaseKey(baseDN); - ConvertedExpression convertedExpression; - try { - convertedExpression = toCouchbaseFilter(searchFilter, propertiesAnnotationsMap); - } catch (SearchException ex) { - throw new EntryPersistenceException(String.format("Failed to convert filter %s to expression", searchFilter)); - } - - PagedResult searchResult = null; - try { - CouchbaseBatchOperationWraper batchOperationWraper = null; - if (batchOperation != null) { - batchOperationWraper = new CouchbaseBatchOperationWraper(batchOperation, this, entryClass, propertiesAnnotations); - } - searchResult = searchImpl(keyWithInum.getKey(), getScanConsistency(convertedExpression), convertedExpression.expression(), scope, currentLdapReturnAttributes, - defaultSort, batchOperationWraper, returnDataType, start, count, chunkSize); - - if (searchResult == null) { - throw new EntryPersistenceException(String.format("Failed to find entries with key: %s, expression: %s", keyWithInum.getKey(), convertedExpression)); - } - - return searchResult; - } catch (Exception ex) { - throw new EntryPersistenceException(String.format("Failed to find entries with key: %s, expression: %s", keyWithInum.getKey(), convertedExpression), ex); - } - } - - @Override - protected boolean contains(String baseDN, Class entryClass, List propertiesAnnotations, Filter filter, String[] objectClasses, String[] ldapReturnAttributes) { - if (StringHelper.isEmptyString(baseDN)) { - throw new MappingException("Base DN to check contain entries is null"); - } - - // Create filter - Filter searchFilter; - if (objectClasses.length > 0) { - searchFilter = addObjectClassFilter(filter, objectClasses); - } else { - searchFilter = filter; - } - - // Prepare properties types to allow build filter properly - Map propertiesAnnotationsMap = prepareEntryPropertiesTypes(entryClass, propertiesAnnotations); - - ConvertedExpression convertedExpression; - try { - convertedExpression = toCouchbaseFilter(searchFilter, propertiesAnnotationsMap); - } catch (SearchException ex) { - throw new EntryPersistenceException(String.format("Failed to convert filter %s to expression", searchFilter)); - } - - PagedResult searchResult = null; - try { - ParsedKey keyWithInum = toCouchbaseKey(baseDN); - searchResult = searchImpl(keyWithInum.getKey(), getScanConsistency(convertedExpression), convertedExpression.expression(), SearchScope.SUB, ldapReturnAttributes, null, - null, SearchReturnDataType.SEARCH, 1, 1, 0); - if (searchResult == null) { - throw new EntryPersistenceException(String.format("Failed to find entry with baseDN: %s, filter: %s", baseDN, searchFilter)); - } - } catch (Exception ex) { - throw new EntryPersistenceException(String.format("Failed to find entry with baseDN: %s, filter: %s", baseDN, searchFilter), ex); - } - - return (searchResult != null) && (searchResult.getEntriesCount() > 0); - } - - private PagedResult searchImpl(String key, ScanConsistency scanConsistency, Expression expression, SearchScope scope, String[] attributes, Sort[] orderBy, - CouchbaseBatchOperationWraper batchOperationWraper, SearchReturnDataType returnDataType, int start, int count, int pageSize) throws SearchException { - return getOperationService().search(key, scanConsistency, expression, scope, toInternalAttributes(attributes), orderBy, batchOperationWraper, returnDataType, start, count, pageSize); - } - - protected List createEntities(String baseDN, Class entryClass, PagedResult searchResult) { - ParsedKey keyWithInum = toCouchbaseKey(baseDN); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - List entries = createEntities(entryClass, propertiesAnnotations, keyWithInum, - searchResult.getEntries().toArray(new JsonObject[searchResult.getEntriesCount()])); - - return entries; - } - - protected List createEntities(Class entryClass, List propertiesAnnotations, ParsedKey baseDn, - JsonObject... searchResultEntries) { - List result = new ArrayList(searchResultEntries.length); - Map> entriesAttributes = new LinkedHashMap>(100); - - int count = 0; - for (int i = 0; i < searchResultEntries.length; i++) { - count++; - JsonObject entry = searchResultEntries[i]; - // String key = entry.getString(CouchbasegetOperationService().META_DOC_ID); - String dn = entry.getString(fromInternalAttribute(CouchbaseOperationService.DN)); - entriesAttributes.put(dn, getAttributeDataList(entry)); - - // Remove reference to allow java clean up object - searchResultEntries[i] = null; - - // Allow java to clean up temporary objects - if (count >= 100) { - List currentResult = createEntities(entryClass, propertiesAnnotations, entriesAttributes); - result.addAll(currentResult); - - entriesAttributes = new LinkedHashMap>(100); - count = 0; - } - } - - List currentResult = createEntities(entryClass, propertiesAnnotations, entriesAttributes); - result.addAll(currentResult); - - return result; - } - - private List getAttributeDataList(JsonObject entry) { - if (entry == null) { - return null; - } - - List result = new ArrayList(); - for (String shortAttributeName : entry.getNames()) { - Object attributeObject = entry.get(shortAttributeName); - - String attributeName = fromInternalAttribute(shortAttributeName); - - Boolean multiValued = Boolean.FALSE; - Object[] attributeValueObjects; - if (attributeObject == null) { - attributeValueObjects = NO_OBJECTS; - } - if (attributeObject instanceof JsonArray) { - JsonArray jsonArray = (JsonArray) attributeObject; - ArrayList resultList = new ArrayList(jsonArray.size()); - for (Iterator it = jsonArray.iterator(); it.hasNext();) { - resultList.add(it.next()); - } - attributeValueObjects = resultList.toArray(NO_OBJECTS); - multiValued = Boolean.TRUE; - } else { - if ((attributeObject instanceof Boolean) || (attributeObject instanceof Integer) || (attributeObject instanceof Long) || - (attributeObject instanceof JsonObject)) { - attributeValueObjects = new Object[] { attributeObject }; - } else if (attributeObject instanceof String) { - Object value = attributeObject.toString(); - try { - SimpleDateFormat jsonDateFormat = new SimpleDateFormat(JSON_DATA_FORMAT); - value = jsonDateFormat.parse(attributeObject.toString()); - } catch (Exception ex) {} - attributeValueObjects = new Object[] { value }; - } else { - Object value = attributeObject.toString(); - attributeValueObjects = new Object[] { value }; - } - } - - unescapeValues(attributeValueObjects); - - AttributeData tmpAttribute = new AttributeData(attributeName, attributeValueObjects); - if (multiValued != null) { - tmpAttribute.setMultiValued(multiValued); - } - result.add(tmpAttribute); - } - - return result; - } - - @Override - public boolean authenticate(String baseDN, Class entryClass, String userName, String password) { - if (StringHelper.isEmptyString(baseDN)) { - throw new MappingException("Base DN to find entries is null"); - } - - // Check entry class - checkEntryClass(entryClass, false); - String[] objectClasses = getTypeObjectClasses(entryClass); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - - // Find entries - Filter searchFilter = Filter.createEqualityFilter(Filter.createLowercaseFilter(CouchbaseOperationService.UID), StringHelper.toLowerCase(userName)); - if (objectClasses.length > 0) { - searchFilter = addObjectClassFilter(searchFilter, objectClasses); - } - - // Prepare properties types to allow build filter properly - Map propertiesAnnotationsMap = prepareEntryPropertiesTypes(entryClass, propertiesAnnotations); - - ConvertedExpression convertedExpression; - try { - convertedExpression = toCouchbaseFilter(searchFilter, propertiesAnnotationsMap); - } catch (SearchException ex) { - throw new EntryPersistenceException(String.format("Failed to convert filter %s to expression", searchFilter)); - } - - try { - PagedResult searchResult = searchImpl(toCouchbaseKey(baseDN).getKey(), getScanConsistency(convertedExpression), convertedExpression.expression(), - SearchScope.SUB, null, null, null, SearchReturnDataType.SEARCH, 0, 1, 1); - if ((searchResult == null) || (searchResult.getEntriesCount() != 1)) { - return false; - } - - String bindDn = searchResult.getEntries().get(0).getString(CouchbaseOperationService.DN); - - return authenticate(bindDn, password); - } catch (SearchException ex) { - throw new AuthenticationException(String.format("Failed to find user DN: %s", userName), ex); - } catch (Exception ex) { - throw new AuthenticationException(String.format("Failed to authenticate user: %s", userName), ex); - } - } - - @Override - public boolean authenticate(String bindDn, String password) { - try { - return getOperationService().authenticate(toCouchbaseKey(bindDn).getKey(), escapeValue(password)); - } catch (Exception ex) { - throw new AuthenticationException(String.format("Failed to authenticate DN: %s", bindDn), ex); - } - } - - @Override - public int countEntries(String baseDN, Class entryClass, Filter filter) { - return countEntries(baseDN, entryClass, filter, SearchScope.SUB); - } - - @Override - public int countEntries(String baseDN, Class entryClass, Filter filter, SearchScope scope) { - if (StringHelper.isEmptyString(baseDN)) { - throw new MappingException("Base DN to find entries is null"); - } - - // Check entry class - checkEntryClass(entryClass, false); - String[] objectClasses = getTypeObjectClasses(entryClass); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - - // Find entries - Filter searchFilter; - if (objectClasses.length > 0) { - searchFilter = addObjectClassFilter(filter, objectClasses); - } else { - searchFilter = filter; - } - - // Prepare properties types to allow build filter properly - Map propertiesAnnotationsMap = prepareEntryPropertiesTypes(entryClass, propertiesAnnotations); - - ConvertedExpression convertedExpression; - try { - convertedExpression = toCouchbaseFilter(searchFilter, propertiesAnnotationsMap); - } catch (SearchException ex) { - throw new EntryPersistenceException(String.format("Failed to convert filter %s to expression", searchFilter)); - } - - PagedResult searchResult; - try { - searchResult = searchImpl(toCouchbaseKey(baseDN).getKey(), getScanConsistency(convertedExpression), convertedExpression.expression(), scope, null, null, - null, SearchReturnDataType.COUNT, 0, 0, 0); - } catch (Exception ex) { - throw new EntryPersistenceException( - String.format("Failed to calculate the number of entries with baseDN: %s, filter: %s", baseDN, searchFilter), ex); - } - - return searchResult.getTotalEntriesCount(); - } - - private MutationSpec createModification(final Mutation type, final String attributeName, final Boolean multiValued, final Object... attributeValues) { - String realAttributeName = attributeName; - - Object[] realValues = attributeValues; - if (StringHelper.equals(CouchbaseOperationService.USER_PASSWORD, realAttributeName)) { - realValues = getOperationService().createStoragePassword(StringHelper.toStringArray(attributeValues)); - } - - escapeValues(realValues); - - if ((multiValued == null) || !multiValued) { - return new MutationSpec(type, realAttributeName, realValues[0]); - } else { - return new MutationSpec(type, realAttributeName, realValues); - } - } - - protected Sort buildSort(String sortBy, SortOrder sortOrder) { - Sort requestedSort = null; - if (SortOrder.DESCENDING == sortOrder) { - requestedSort = Sort.desc(Expression.path(sortBy)); - } else if (SortOrder.ASCENDING == sortOrder) { - requestedSort = Sort.asc(Expression.path(sortBy)); - } else { - requestedSort = Sort.def(Expression.path(sortBy)); - } - return requestedSort; - } - - protected Sort[] getDefaultSort(Class entryClass) { - String[] sortByProperties = getEntrySortBy(entryClass); - - if (ArrayHelper.isEmpty(sortByProperties)) { - return null; - } - - Sort[] sort = new Sort[sortByProperties.length]; - for (int i = 0; i < sortByProperties.length; i++) { - sort[i] = Sort.def(Expression.path(sortByProperties[i])); - } - - return sort; - } - - @Override - public List exportEntry(String dn) { - try { - // Load entry - ParsedKey keyWithInum = toCouchbaseKey(dn); - JsonObject entry = getOperationService().lookup(keyWithInum.getKey(), null); - - List result = getAttributeDataList(entry); - if (result != null) { - return result; - } - - return null; - } catch (Exception ex) { - throw new EntryPersistenceException(String.format("Failed to find entry: %s", dn), ex); - } - } - @Override - public void importEntry(String dn, List attributes) { - persist(dn, attributes, 0); - } - - private ConvertedExpression toCouchbaseFilter(Filter genericFilter, Map propertiesAnnotationsMap) throws SearchException { - return FILTER_CONVERTER.convertToCouchbaseFilter(genericFilter, propertiesAnnotationsMap); - } - - private ConvertedExpression toCouchbaseFilter(Filter genericFilter, Map propertiesAnnotationsMap, Function processor) throws SearchException { - return FILTER_CONVERTER.convertToCouchbaseFilter(genericFilter, propertiesAnnotationsMap, processor); - } - - private ParsedKey toCouchbaseKey(String dn) { - return KEY_CONVERTER.convertToKey(dn); - } - - @Override - protected Filter addObjectClassFilter(Filter filter, String[] objectClasses) { - if (objectClasses.length == 0) { - return filter; - } - - // In Couchbase implementation we need to use first one as entry type - Filter searchFilter = Filter.createEqualityFilter(OBJECT_CLASS, objectClasses[0]); - if (filter != null) { - searchFilter = Filter.createANDFilter(Filter.createANDFilter(searchFilter), filter); - } - - return searchFilter; - } - - private static final class CountBatchOperation extends DefaultBatchOperation { - - private int countEntries = 0; - - @Override - public void performAction(List entries) { - } - - @Override - public boolean collectSearchResult(int size) { - countEntries += size; - return false; - } - - public int getCountEntries() { - return countEntries; - } - } - - @Override - public String encodeTime(String baseDN, Date date) { - if (date == null) { - return null; - } - - SimpleDateFormat jsonDateFormat = new SimpleDateFormat(JSON_DATA_FORMAT); - return jsonDateFormat.format(date); - } - - @Override - protected String encodeTime(Date date) { - return encodeTime(null, date); - } - - @Override - public Date decodeTime(String baseDN, String date) { - if (StringHelper.isEmpty(date)) { - return null; - } - - SimpleDateFormat jsonDateFormat = new SimpleDateFormat(JSON_DATA_FORMAT); - Date decodedDate; - try { - decodedDate = jsonDateFormat.parse(date); - } catch (Exception ex) { - LOG.error("Failed to decode generalized time '{}'", date, ex); - - return null; - } - - return decodedDate; - } - - @Override - public Date decodeTime(String date) { - return decodeTime(null, date); - } - - @Override - public boolean hasBranchesSupport(String dn) { - return false; - } - - @Override - public boolean hasExpirationSupport(String primaryKey) { - return true; - } - - @Override - public String getPersistenceType() { - return CouchbaseEntryManagerFactory.PERSISTENCE_TYPE; - } - - @Override - public String getPersistenceType(String primaryKey) { - return CouchbaseEntryManagerFactory.PERSISTENCE_TYPE; - } - - @Override - public PersistenceEntryManager getPersistenceEntryManager(String persistenceType) { - if (CouchbaseEntryManagerFactory.PERSISTENCE_TYPE.equals(persistenceType)) { - return this; - } - - return null; - } - - @Override - protected Object convertValueToJson(Object propertyValue) { - String jsonStringPropertyValue = (String) super.convertValueToJson(propertyValue); - return JsonObject.fromJson(jsonStringPropertyValue); - } - - @Override - protected Object convertJsonToValue(Class parameterType, Object propertyValue) { - Object jsonStringPropertyValue = propertyValue; - if (propertyValue instanceof JsonObject) { - JsonObject jsonObject = (JsonObject) propertyValue; - jsonStringPropertyValue = jsonObject.toString(); - } - - return super.convertJsonToValue(parameterType, jsonStringPropertyValue); - } - - private ScanConsistency getScanConsistency(ConvertedExpression convertedExpression) { - if (convertedExpression.consistency()) { - return ScanConsistency.REQUEST_PLUS; - } - - return null; - } - - private ScanConsistency getScanConsistency(String attributeName, Map propertiesAnnotationsMap) { - if (StringHelper.isEmpty(attributeName)) { - return null; - } - - PropertyAnnotation propertyAnnotation = propertiesAnnotationsMap.get(attributeName); - if ((propertyAnnotation == null) || (propertyAnnotation.getParameterType() == null)) { - return null; - } - AttributeName attributeNameAnnotation = (AttributeName) ReflectHelper.getAnnotationByType(propertyAnnotation.getAnnotations(), - AttributeName.class); - - if (attributeNameAnnotation.consistency()) { - return ScanConsistency.REQUEST_PLUS; - } - - return null; - } - - private String escapeValue(String value) { - // Couchbade SDK do this automatically -// return StringHelper.escapeJson(value); - return value; - } - - private String unescapeValue(String value) { - // Couchbade SDK do this automatically -// return StringHelper.unescapeJson(value); - return value; - } - - private void escapeValues(Object[] realValues) { - // Couchbade SDK do this automatically -// for (int i = 0; i < realValues.length; i++) { -// if (realValues[i] instanceof String) { -// realValues[i] = StringHelper.escapeJson(realValues[i]); -// } -// } - } - - private void unescapeValues(Object[] realValues) { - // Couchbade SDK do this automatically -// for (int i = 0; i < realValues.length; i++) { -// if (realValues[i] instanceof String) { -// realValues[i] = StringHelper.unescapeJson(realValues[i]); -// } -// } - } - - public String toInternalAttribute(String attributeName) { - return attributeName; -// if (getOperationService().isDisableAttributeMapping()) { -// return attributeName; -// } -// -// return KeyShortcuter.shortcut(attributeName); - } - - public String[] toInternalAttributes(String[] attributeNames) { - return attributeNames; -// if (getOperationService().isDisableAttributeMapping() || ArrayHelper.isEmpty(attributeNames)) { -// return attributeNames; -// } -// -// String[] resultAttributeNames = new String[attributeNames.length]; -// -// for (int i = 0; i < attributeNames.length; i++) { -// resultAttributeNames[i] = KeyShortcuter.shortcut(attributeNames[i]); -// } -// -// return resultAttributeNames; - } - - public String fromInternalAttribute(String internalAttributeName) { - return internalAttributeName; -// if (getOperationService().isDisableAttributeMapping()) { -// return internalAttributeName; -// } -// -// return KeyShortcuter.fromShortcut(internalAttributeName); - } - - public String[] fromInternalAttributes(String[] internalAttributeNames) { - return internalAttributeNames; -// if (getOperationService().isDisableAttributeMapping() || ArrayHelper.isEmpty(internalAttributeNames)) { -// return internalAttributeNames; -// } -// -// String[] resultAttributeNames = new String[internalAttributeNames.length]; -// -// for (int i = 0; i < internalAttributeNames.length; i++) { -// resultAttributeNames[i] = KeyShortcuter.fromShortcut(internalAttributeNames[i]); -// } -// -// return resultAttributeNames; - } - -} diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManagerFactory.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManagerFactory.java deleted file mode 100644 index 64167980..00000000 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseEntryManagerFactory.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - /* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.couchbase.impl; - -import java.util.HashMap; -import java.util.Properties; - -import javax.annotation.PostConstruct; -import javax.enterprise.context.ApplicationScoped; - -import org.gluu.persist.PersistenceEntryManagerFactory; -import org.gluu.persist.couchbase.operation.impl.CouchbaseConnectionProvider; -import org.gluu.persist.couchbase.operation.impl.CouchbaseOperationServiceImpl; -import org.gluu.persist.exception.operation.ConfigurationException; -import org.gluu.persist.service.BaseFactoryService; -import org.gluu.util.PropertiesHelper; -import org.gluu.util.StringHelper; -import org.gluu.util.init.Initializable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.couchbase.client.java.env.CouchbaseEnvironment; -import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; - -/** - * Couchbase Entry Manager Factory - * - * @author Yuriy Movchan Date: 05/31/2018 - */ -@ApplicationScoped -public class CouchbaseEntryManagerFactory extends Initializable implements PersistenceEntryManagerFactory { - - private static final Logger LOG = LoggerFactory.getLogger(CouchbaseEntryManagerFactory.class); - - public static final String PERSISTENCE_TYPE = "couchbase"; - - private DefaultCouchbaseEnvironment.Builder builder; - private CouchbaseEnvironment couchbaseEnvironment; - - private Properties couchbaseConnectionProperties; - - @PostConstruct - public void create() { - this.builder = DefaultCouchbaseEnvironment.builder().operationTracingEnabled(false); - } - - @Override - protected void initInternal() { - // SSL settings - boolean useSSL = Boolean.valueOf(couchbaseConnectionProperties.getProperty("ssl.trustStore.enable")).booleanValue(); - if (useSSL) { - String sslTrustStoreFile = couchbaseConnectionProperties.getProperty("ssl.trustStore.file"); - String sslTrustStorePin = couchbaseConnectionProperties.getProperty("ssl.trustStore.pin"); - - builder.sslEnabled(true).sslTruststoreFile(sslTrustStoreFile).sslTruststorePassword(sslTrustStorePin); - } else { - builder.sslEnabled(false); - } - - String connectTimeoutString = couchbaseConnectionProperties.getProperty("connection.connect-timeout"); - if (StringHelper.isNotEmpty(connectTimeoutString)) { - int connectTimeout = Integer.valueOf(connectTimeoutString); - builder.connectTimeout(connectTimeout); - } - - String operationTracingEnabledString = couchbaseConnectionProperties.getProperty("connection.operation-tracing-enabled"); - if (StringHelper.isNotEmpty(operationTracingEnabledString)) { - boolean operationTracingEnabled = Boolean.valueOf(operationTracingEnabledString); - builder.operationTracingEnabled(operationTracingEnabled); - } - - String mutationTokensEnabledString = couchbaseConnectionProperties.getProperty("connection.mutation-tokens-enabled"); - if (StringHelper.isNotEmpty(mutationTokensEnabledString)) { - boolean mutationTokensEnabled = Boolean.valueOf(mutationTokensEnabledString); - builder.mutationTokensEnabled(mutationTokensEnabled); - } - - String computationPoolSizeString = couchbaseConnectionProperties.getProperty("connection.computation-pool-size"); - if (StringHelper.isNotEmpty(computationPoolSizeString)) { - int computationPoolSize = Integer.valueOf(computationPoolSizeString); - builder.computationPoolSize(computationPoolSize); - } - - this.couchbaseEnvironment = builder.build(); - - this.builder = null; - } - - @Override - public String getPersistenceType() { - return PERSISTENCE_TYPE; - } - - @Override - public HashMap getConfigurationFileNames() { - HashMap confs = new HashMap(); - confs.put(PERSISTENCE_TYPE, "gluu-couchbase.properties"); - - return confs; - } - - public CouchbaseEnvironment getCouchbaseEnvironment() { - return couchbaseEnvironment; - } - - @Override - public CouchbaseEntryManager createEntryManager(Properties conf) { - Properties entryManagerConf = PropertiesHelper.filterProperties(conf, PERSISTENCE_TYPE); - - // Allow proper initialization - if (this.couchbaseConnectionProperties == null) { - this.couchbaseConnectionProperties = entryManagerConf; - } - - init(); - - if (!isInitialized()) { - throw new ConfigurationException("Failed to create Couchbase environment!"); - } - - CouchbaseConnectionProvider connectionProvider = new CouchbaseConnectionProvider(entryManagerConf, couchbaseEnvironment); - connectionProvider.create(); - if (!connectionProvider.isCreated()) { - throw new ConfigurationException( - String.format("Failed to create Couchbase connection pool! Result code: '%s'", connectionProvider.getCreationResultCode())); - } - LOG.debug("Created connectionProvider '{}' with code '{}'", connectionProvider, connectionProvider.getCreationResultCode()); - - CouchbaseEntryManager couchbaseEntryManager = new CouchbaseEntryManager(new CouchbaseOperationServiceImpl(entryManagerConf, connectionProvider)); - LOG.info("Created CouchbaseEntryManager: {}", couchbaseEntryManager.getOperationService()); - - return couchbaseEntryManager; - } - - @Override - public void initStandalone(BaseFactoryService persistanceFactoryService) { - this.builder = DefaultCouchbaseEnvironment.builder().mutationTokensEnabled(true).computationPoolSize(5); - } - - -/* - public static void main(String[] args) throws FileNotFoundException, IOException { - Properties prop = new Properties(); - prop.load(new FileInputStream(new File("D:/Temp/gluu-couchbase.properties"))); - - CouchbaseEntryManagerFactory cemf = new CouchbaseEntryManagerFactory(); - cemf.create(); - - CouchbaseEntryManager cem = cemf.createEntryManager(prop); - - System.out.println(cem.getOperationService().getConnectionProvider().isCreated()); - - } -*/ -} diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java deleted file mode 100644 index 17316593..00000000 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/impl/CouchbaseFilterConverter.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - /* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.couchbase.impl; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -import org.gluu.persist.annotation.AttributeEnum; -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.couchbase.model.ConvertedExpression; -import org.gluu.persist.exception.operation.SearchException; -import org.gluu.persist.ldap.impl.LdapFilterConverter; -import org.gluu.persist.reflect.property.PropertyAnnotation; -import org.gluu.persist.reflect.util.ReflectHelper; -import org.gluu.search.filter.Filter; -import org.gluu.search.filter.FilterType; -import org.gluu.util.ArrayHelper; -import org.gluu.util.StringHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.couchbase.client.java.document.json.JsonArray; -import com.couchbase.client.java.query.dsl.Expression; -import com.couchbase.client.java.query.dsl.functions.Collections; -import com.couchbase.client.java.query.dsl.functions.StringFunctions; - -/** - * Filter to Couchbase expressions convert - * - * @author Yuriy Movchan Date: 05/15/2018 - */ -public class CouchbaseFilterConverter { - - private static final Logger LOG = LoggerFactory.getLogger(CouchbaseFilterConverter.class); - - private LdapFilterConverter ldapFilterConverter = new LdapFilterConverter(); - - private CouchbaseEntryManager couchbaseEntryManager; - - public CouchbaseFilterConverter(CouchbaseEntryManager couchbaseEntryManager) { - this.couchbaseEntryManager = couchbaseEntryManager; - } - - public ConvertedExpression convertToCouchbaseFilter(Filter genericFilter, Map propertiesAnnotationsMap) throws SearchException { - return convertToCouchbaseFilter(genericFilter, propertiesAnnotationsMap, null); - } - - public ConvertedExpression convertToCouchbaseFilter(Filter genericFilter, Map propertiesAnnotationsMap, Function processor) throws SearchException { - Filter currentGenericFilter = genericFilter; - - FilterType type = currentGenericFilter.getType(); - if (FilterType.RAW == type) { - LOG.warn("RAW Ldap filter to Couchbase convertion will be removed in new version!!!"); - currentGenericFilter = ldapFilterConverter.convertRawLdapFilterToFilter(currentGenericFilter.getFilterString()); - type = currentGenericFilter.getType(); - } - - boolean requiredConsistency = isRequiredConsistency(currentGenericFilter, propertiesAnnotationsMap); - - if (processor != null) { - processor.apply(currentGenericFilter); - } - - if ((FilterType.NOT == type) || (FilterType.AND == type) || (FilterType.OR == type)) { - Filter[] genericFilters = currentGenericFilter.getFilters(); - ConvertedExpression[] expFilters = new ConvertedExpression[genericFilters.length]; - - if (genericFilters != null) { - boolean canJoinOrFilters = FilterType.OR == type; // We can replace only multiple OR with IN - List joinOrFilters = new ArrayList(); - String joinOrAttributeName = null; - for (int i = 0; i < genericFilters.length; i++) { - Filter tmpFilter = genericFilters[i]; - expFilters[i] = convertToCouchbaseFilter(tmpFilter, propertiesAnnotationsMap, processor); - - // Check if we can replace OR with IN - if (!canJoinOrFilters) { - continue; - } - - if (tmpFilter.getMultiValued() != null) { - canJoinOrFilters = false; - continue; - } - - if ((FilterType.EQUALITY != tmpFilter.getType()) || (tmpFilter.getFilters() != null)) { - canJoinOrFilters = false; - continue; - } - - Boolean isMultiValuedDetected = determineMultiValuedByType(tmpFilter.getAttributeName(), propertiesAnnotationsMap); - if (!Boolean.FALSE.equals(isMultiValuedDetected)) { - canJoinOrFilters = false; - continue; - } - - if (joinOrAttributeName == null) { - joinOrAttributeName = tmpFilter.getAttributeName(); - joinOrFilters.add(tmpFilter); - continue; - } - if (!joinOrAttributeName.equals(tmpFilter.getAttributeName())) { - canJoinOrFilters = false; - continue; - } - joinOrFilters.add(tmpFilter); - } - - if (FilterType.NOT == type) { - return ConvertedExpression.build(Expression.par(expFilters[0].expression().not()), expFilters[0].consistency()); - } else if (FilterType.AND == type) { - for (int i = 0; i < expFilters.length; i++) { - requiredConsistency |= expFilters[i].consistency(); - } - - Expression result = expFilters[0].expression(); - for (int i = 1; i < expFilters.length; i++) { - result = result.and(expFilters[i].expression()); - } - return ConvertedExpression.build(Expression.par(result), requiredConsistency); - } else if (FilterType.OR == type) { - for (int i = 0; i < expFilters.length; i++) { - requiredConsistency |= expFilters[i].consistency(); - } - - if (canJoinOrFilters) { - JsonArray jsonArrayValues = JsonArray.create(); - for (Filter eqFilter : joinOrFilters) { - jsonArrayValues.add(eqFilter.getAssertionValue()); - } - Expression exp = Expression - .par(Expression.path(Expression.path(joinOrAttributeName)).in(jsonArrayValues)); - return ConvertedExpression.build(exp, requiredConsistency); - } else { - Expression result = expFilters[0].expression(); - for (int i = 1; i < expFilters.length; i++) { - result = result.or(expFilters[i].expression()); - } - - return ConvertedExpression.build(Expression.par(result), requiredConsistency); - } - } - } - } - - if (FilterType.EQUALITY == type) { - boolean hasSubFilters = ArrayHelper.isNotEmpty(currentGenericFilter.getFilters()); - Boolean isMultiValuedDetected = determineMultiValuedByType(currentGenericFilter.getAttributeName(), propertiesAnnotationsMap); - - String internalAttribute = toInternalAttribute(currentGenericFilter); - if (isMultiValue(currentGenericFilter, propertiesAnnotationsMap)) { - if (hasSubFilters) { - Filter clonedFilter = currentGenericFilter.getFilters()[0]; - clonedFilter.setAttributeName(internalAttribute + "_"); - - ConvertedExpression nameConvertedExpression = convertToCouchbaseFilter(clonedFilter, propertiesAnnotationsMap); - return ConvertedExpression.build(Collections.anyIn(internalAttribute + "_", Expression.path(Expression.path(internalAttribute))).satisfies(nameConvertedExpression.expression().eq(buildTypedExpression(currentGenericFilter))), requiredConsistency); - } - - return ConvertedExpression.build(Collections.anyIn(internalAttribute + "_", Expression.path(Expression.path(internalAttribute))).satisfies(Expression.path(Expression.path(internalAttribute + "_").eq(buildTypedExpression(currentGenericFilter)))), requiredConsistency); - } else if (Boolean.FALSE.equals(currentGenericFilter.getMultiValued()) || Boolean.FALSE.equals(isMultiValuedDetected)) { - if (hasSubFilters) { - ConvertedExpression nameConvertedExpression = convertToCouchbaseFilter(currentGenericFilter.getFilters()[0], propertiesAnnotationsMap); - return ConvertedExpression.build(nameConvertedExpression.expression().eq(buildTypedExpression(currentGenericFilter)), requiredConsistency); - } - return ConvertedExpression.build(Expression.path(Expression.path(toInternalAttribute(currentGenericFilter))).eq(buildTypedExpression(currentGenericFilter)), requiredConsistency); - } else if (hasSubFilters && (isMultiValuedDetected == null)) { - ConvertedExpression nameConvertedExpression = convertToCouchbaseFilter(currentGenericFilter.getFilters()[0], propertiesAnnotationsMap); - return ConvertedExpression.build(nameConvertedExpression.expression().eq(buildTypedExpression(currentGenericFilter)), nameConvertedExpression.consistency() || requiredConsistency); - } else { - Expression nameExpression; - if (hasSubFilters) { - ConvertedExpression nameConvertedExpression = convertToCouchbaseFilter(currentGenericFilter.getFilters()[0], propertiesAnnotationsMap); - nameExpression = nameConvertedExpression.expression(); - } else { - nameExpression = Expression.path(toInternalAttribute(currentGenericFilter)); - } - Expression exp1 = Expression - .par(Expression.path(nameExpression).eq(buildTypedExpression(currentGenericFilter))); - Expression exp2 = Expression - .par(Expression.path(buildTypedExpression(currentGenericFilter)).in(nameExpression)); - return ConvertedExpression.build(Expression.par(exp1.or(exp2)), requiredConsistency); - } - } - - if (FilterType.LESS_OR_EQUAL == type) { - String internalAttribute = toInternalAttribute(currentGenericFilter); - if (isMultiValue(currentGenericFilter, propertiesAnnotationsMap)) { - return ConvertedExpression.build(Collections.anyIn(internalAttribute + "_", Expression.path(Expression.path(internalAttribute))).satisfies(Expression.path(Expression.path(internalAttribute + "_")).lte(buildTypedExpression(currentGenericFilter))), requiredConsistency); - } else { - return ConvertedExpression.build(Expression.path(Expression.path(internalAttribute)).lte(buildTypedExpression(currentGenericFilter)), requiredConsistency); - } - } - - if (FilterType.GREATER_OR_EQUAL == type) { - String internalAttribute = toInternalAttribute(currentGenericFilter); - if (isMultiValue(currentGenericFilter, propertiesAnnotationsMap)) { - return ConvertedExpression.build(Collections.anyIn(internalAttribute + "_", Expression.path(Expression.path(internalAttribute))).satisfies(Expression.path(Expression.path(internalAttribute + "_")).gte(buildTypedExpression(currentGenericFilter))), requiredConsistency); - } else { - return ConvertedExpression.build(Expression.path(Expression.path(internalAttribute)).gte(buildTypedExpression(currentGenericFilter)), requiredConsistency); - } - } - - if (FilterType.PRESENCE == type) { - String internalAttribute = toInternalAttribute(currentGenericFilter); - if (isMultiValue(currentGenericFilter, propertiesAnnotationsMap)) { - return ConvertedExpression.build(Collections.anyIn(internalAttribute + "_", Expression.path(Expression.path(internalAttribute))).satisfies(Expression.path(Expression.path(internalAttribute + "_")).isNotMissing()), requiredConsistency); - } else { - return ConvertedExpression.build(Expression.path(Expression.path(internalAttribute)).isNotMissing(), requiredConsistency); - } - } - - if (FilterType.APPROXIMATE_MATCH == type) { - throw new SearchException("Convertion from APPROXIMATE_MATCH LDAP filter to Couchbase filter is not implemented"); - } - - if (FilterType.SUBSTRING == type) { - StringBuilder like = new StringBuilder(); - if (currentGenericFilter.getSubInitial() != null) { - like.append(currentGenericFilter.getSubInitial()); - } - like.append("%"); - - String[] subAny = currentGenericFilter.getSubAny(); - if ((subAny != null) && (subAny.length > 0)) { - for (String any : subAny) { - like.append(any); - like.append("%"); - } - } - - if (currentGenericFilter.getSubFinal() != null) { - like.append(currentGenericFilter.getSubFinal()); - } - if (isMultiValue(currentGenericFilter, propertiesAnnotationsMap)) { - String internalAttribute = toInternalAttribute(currentGenericFilter); - return ConvertedExpression.build(Collections.anyIn(internalAttribute + "_", Expression.path(Expression.path(toInternalAttribute(currentGenericFilter)))).satisfies(Expression.path(Expression.path(internalAttribute + "_")).like(Expression.s(StringHelper.escapeJson(like.toString())))), requiredConsistency); - } else { - return ConvertedExpression.build(Expression.path(Expression.path(toInternalAttribute(currentGenericFilter)).like(Expression.s(StringHelper.escapeJson(like.toString())))), requiredConsistency); - } - } - - if (FilterType.LOWERCASE == type) { - return ConvertedExpression.build(StringFunctions.lower(currentGenericFilter.getAttributeName()), requiredConsistency); - } - - throw new SearchException(String.format("Unknown filter type '%s'", type)); - } - - protected Boolean isMultiValue(Filter currentGenericFilter, Map propertiesAnnotationsMap) { - Boolean isMultiValuedDetected = determineMultiValuedByType(currentGenericFilter.getAttributeName(), propertiesAnnotationsMap); - if (Boolean.TRUE.equals(currentGenericFilter.getMultiValued()) || Boolean.TRUE.equals(isMultiValuedDetected)) { - return true; - } - - return false; - } - - private String toInternalAttribute(Filter filter) { - String attributeName = filter.getAttributeName(); - - if (StringHelper.isEmpty(attributeName)) { - // Try to find inside sub-filter - for (Filter subFilter : filter.getFilters()) { - attributeName = subFilter.getAttributeName(); - if (StringHelper.isNotEmpty(attributeName)) { - break; - } - } - } - - if (couchbaseEntryManager == null) { - return attributeName; - } - - return couchbaseEntryManager.toInternalAttribute(attributeName); - } - - private Expression buildTypedExpression(Filter currentGenericFilter) { - if (currentGenericFilter.getAssertionValue() instanceof Boolean) { - return Expression.x((Boolean) currentGenericFilter.getAssertionValue()); - } else if (currentGenericFilter.getAssertionValue() instanceof Integer) { - return Expression.x((Integer) currentGenericFilter.getAssertionValue()); - } else if (currentGenericFilter.getAssertionValue() instanceof Long) { - return Expression.x((Long) currentGenericFilter.getAssertionValue()); - } - - return Expression.s(StringHelper.escapeJson(currentGenericFilter.getAssertionValue())); - } - - private Boolean determineMultiValuedByType(String attributeName, Map propertiesAnnotationsMap) { - if ((attributeName == null) || (propertiesAnnotationsMap == null)) { - return null; - } - - if (StringHelper.equalsIgnoreCase(attributeName, CouchbaseEntryManager.OBJECT_CLASS)) { - return false; - } - - PropertyAnnotation propertyAnnotation = propertiesAnnotationsMap.get(attributeName); - if ((propertyAnnotation == null) || (propertyAnnotation.getParameterType() == null)) { - return null; - } - - Class parameterType = propertyAnnotation.getParameterType(); - - boolean isMultiValued = parameterType.equals(String[].class) || ReflectHelper.assignableFrom(parameterType, List.class) || ReflectHelper.assignableFrom(parameterType, AttributeEnum[].class); - - return isMultiValued; - } - - private boolean isRequiredConsistency(Filter filter, Map propertiesAnnotationsMap) { - if (propertiesAnnotationsMap == null) { - return false; - } - - String attributeName = filter.getAttributeName(); - PropertyAnnotation propertyAnnotation = propertiesAnnotationsMap.get(attributeName); - if ((propertyAnnotation == null) || (propertyAnnotation.getParameterType() == null)) { - return false; - } - AttributeName attributeNameAnnotation = (AttributeName) ReflectHelper.getAnnotationByType(propertyAnnotation.getAnnotations(), - AttributeName.class); - - if (attributeNameAnnotation.consistency()) { - return true; - } - - return false; - } - -} diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/BucketMapping.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/BucketMapping.java deleted file mode 100644 index 939c2f38..00000000 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/BucketMapping.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ -package org.gluu.persist.couchbase.model; - -import com.couchbase.client.java.Bucket; - -/** - * Holds bucket reference associated with it's string representation - * - * @author Yuriy Movchan Date: 05/10/2018 - */ -public class BucketMapping { - - private final String bucketName; - private final Bucket bucket; - - public BucketMapping(final String bucketName, final Bucket bucket) { - this.bucketName = bucketName; - this.bucket = bucket; - } - - public final String getBucketName() { - return bucketName; - } - - public final Bucket getBucket() { - return bucket; - } -} diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/ConvertedExpression.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/ConvertedExpression.java deleted file mode 100644 index 1f858aa3..00000000 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/ConvertedExpression.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.gluu.persist.couchbase.model; - -import com.couchbase.client.java.query.dsl.Expression; - -/** - * Filter to Expression convertation result - * - * @author Yuriy Movchan Date: 06/21/2019 - */ -public class ConvertedExpression { - - private Expression expression; - private boolean consistency; - - private ConvertedExpression(Expression expression) { - this.expression = expression; - } - - private ConvertedExpression(Expression expression, boolean consistency) { - this.expression = expression; - this.consistency = consistency; - } - - public static ConvertedExpression build(Expression expression, boolean consistency) { - return new ConvertedExpression(expression, consistency); - } - - public Expression expression() { - return expression; - } - - public boolean consistency() { - return consistency; - } - - public void consistency(boolean consistency) { - this.consistency = consistency; - } - - @Override - public String toString() { - return "ConvertedExpression [expression=" + expression + ", consistency=" + consistency + "]"; - } - -} diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/CouchbaseConnectionConfiguration.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/CouchbaseConnectionConfiguration.java deleted file mode 100644 index 501011aa..00000000 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/CouchbaseConnectionConfiguration.java +++ /dev/null @@ -1,166 +0,0 @@ -package org.gluu.persist.couchbase.model; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -import java.util.List; - -/** - * @author Yuriy Zabrovarnyy - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class CouchbaseConnectionConfiguration { - - private String configId; - private String userName; - private String userPassword; - private List servers; - private String defaultBucket; - private List buckets; - private String passwordEncryptionMethod; - private Boolean operationTracingEnabled; - private Boolean mutationTokensEnabled; - private int connectTimeout; - private int computationPoolSize; - private Boolean useSSL; - private String sslTrustStoreFile; - private String sslTrustStorePin; - private String sslTrustStoreFormat; - private List binaryAttributes; - private List certificateAttributes; - - public String getConfigId() { - return configId; - } - - public void setConfigId(String configId) { - this.configId = configId; - } - - public String getUserName() { - return userName; - } - - public void setUserName(String userName) { - this.userName = userName; - } - - public String getUserPassword() { - return userPassword; - } - - public void setUserPassword(String userPassword) { - this.userPassword = userPassword; - } - - public List getServers() { - return servers; - } - - public void setServers(List servers) { - this.servers = servers; - } - - public String getDefaultBucket() { - return defaultBucket; - } - - public void setDefaultBucket(String defaultBucket) { - this.defaultBucket = defaultBucket; - } - - public List getBuckets() { - return buckets; - } - - public void setBuckets(List buckets) { - this.buckets = buckets; - } - - public String getPasswordEncryptionMethod() { - return passwordEncryptionMethod; - } - - public void setPasswordEncryptionMethod(String passwordEncryptionMethod) { - this.passwordEncryptionMethod = passwordEncryptionMethod; - } - - public Boolean getOperationTracingEnabled() { - return operationTracingEnabled; - } - - public void setOperationTracingEnabled(Boolean operationTracingEnabled) { - this.operationTracingEnabled = operationTracingEnabled; - } - - public Boolean getMutationTokensEnabled() { - return mutationTokensEnabled; - } - - public void setMutationTokensEnabled(Boolean mutationTokensEnabled) { - this.mutationTokensEnabled = mutationTokensEnabled; - } - - public int getConnectTimeout() { - return connectTimeout; - } - - public void setConnectTimeout(int connectTimeout) { - this.connectTimeout = connectTimeout; - } - - public int getComputationPoolSize() { - return computationPoolSize; - } - - public void setComputationPoolSize(int computationPoolSize) { - this.computationPoolSize = computationPoolSize; - } - - public Boolean getUseSSL() { - return useSSL; - } - - public void setUseSSL(Boolean useSSL) { - this.useSSL = useSSL; - } - - public String getSslTrustStoreFile() { - return sslTrustStoreFile; - } - - public void setSslTrustStoreFile(String sslTrustStoreFile) { - this.sslTrustStoreFile = sslTrustStoreFile; - } - - public String getSslTrustStorePin() { - return sslTrustStorePin; - } - - public void setSslTrustStorePin(String sslTrustStorePin) { - this.sslTrustStorePin = sslTrustStorePin; - } - - public String getSslTrustStoreFormat() { - return sslTrustStoreFormat; - } - - public void setSslTrustStoreFormat(String sslTrustStoreFormat) { - this.sslTrustStoreFormat = sslTrustStoreFormat; - } - - public List getBinaryAttributes() { - return binaryAttributes; - } - - public void setBinaryAttributes(List binaryAttributes) { - this.binaryAttributes = binaryAttributes; - } - - public List getCertificateAttributes() { - return certificateAttributes; - } - - public void setCertificateAttributes(List certificateAttributes) { - this.certificateAttributes = certificateAttributes; - } -} diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/ResultCode.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/ResultCode.java deleted file mode 100644 index 40506989..00000000 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/ResultCode.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.couchbase.model; - -import java.io.Serializable; - -/** - * This class defines a number of constants associated with result codes. - * - * @author Yuriy Movchan Date: 05/10/2018 - */ -public final class ResultCode implements Serializable { - - private static final long serialVersionUID = -9180126854928558942L; - - private ResultCode() { - } - - /** - * The integer value (0) for the "SUCCESS" result code. - */ - public static final int SUCCESS_INT_VALUE = 0; - - /** - * The integer value (1) for the "OPERATIONS_ERROR" result code. - */ - public static final int OPERATIONS_ERROR_INT_VALUE = 1; - - /** - * The integer value (48) for the "INAPPROPRIATE_AUTHENTICATION" result code. - */ - public static final int INAPPROPRIATE_AUTHENTICATION_INT_VALUE = 48; - -} diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/SearchReturnDataType.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/SearchReturnDataType.java deleted file mode 100644 index 26680ea3..00000000 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/model/SearchReturnDataType.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.gluu.persist.couchbase.model; -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2019, Gluu - */ - -import java.util.HashMap; -import java.util.Map; - -import org.gluu.persist.annotation.AttributeEnum; - -/** - * Couchbase search return data type - * - * @author Yuriy Movchan Date: 05/04/2019 - */ -public enum SearchReturnDataType implements AttributeEnum { - - SEARCH("search"), - COUNT("count"), - SEARCH_COUNT("search_count"); - - private String value; - - private static Map MAP_BY_VALUES = new HashMap(); - - static { - for (SearchReturnDataType enumType : values()) { - MAP_BY_VALUES.put(enumType.getValue(), enumType); - } - } - - SearchReturnDataType(String value) { - this.value = value; - } - - @Override - public String getValue() { - return value; - } - - public static SearchReturnDataType getByValue(String value) { - return MAP_BY_VALUES.get(value); - } - - @Override - public SearchReturnDataType resolveByValue(String value) { - return getByValue(value); - } -} diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java deleted file mode 100644 index 755ab0f8..00000000 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/CouchbaseOperationService.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - /* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.couchbase.operation; - -import java.util.List; - -import org.gluu.persist.couchbase.impl.CouchbaseBatchOperationWraper; -import org.gluu.persist.couchbase.model.SearchReturnDataType; -import org.gluu.persist.couchbase.operation.impl.CouchbaseConnectionProvider; -import org.gluu.persist.exception.AuthenticationException; -import org.gluu.persist.exception.operation.DeleteException; -import org.gluu.persist.exception.operation.DuplicateEntryException; -import org.gluu.persist.exception.operation.EntryNotFoundException; -import org.gluu.persist.exception.operation.PersistenceException; -import org.gluu.persist.exception.operation.SearchException; -import org.gluu.persist.model.PagedResult; -import org.gluu.persist.model.SearchScope; -import org.gluu.persist.operation.PersistenceOperationService; - -import com.couchbase.client.java.document.json.JsonObject; -import com.couchbase.client.java.query.consistency.ScanConsistency; -import com.couchbase.client.java.query.dsl.Expression; -import com.couchbase.client.java.query.dsl.Sort; -import com.couchbase.client.java.subdoc.MutationSpec; - -/** - * Couchbase operation service interface - * - * @author Yuriy Movchan Date: 05/14/2018 - */ -public interface CouchbaseOperationService extends PersistenceOperationService { - - static String DN = "dn"; - static String UID = "uid"; - static String USER_PASSWORD = "userPassword"; - static String OBJECT_CLASS = "objectClass"; - - static String META_DOC_ID = "meta_doc_id"; - - CouchbaseConnectionProvider getConnectionProvider(); - - boolean authenticate(String key, String password) throws SearchException, AuthenticationException; - - boolean addEntry(String key, JsonObject atts) throws DuplicateEntryException, PersistenceException; - boolean addEntry(String key, JsonObject jsonObject, Integer expiration) throws DuplicateEntryException, PersistenceException; - - boolean updateEntry(String key, List mods, Integer expiration) throws UnsupportedOperationException, PersistenceException; - - boolean delete(String key) throws EntryNotFoundException; - int delete(String key, ScanConsistency scanConsistency, Expression expression, int count) throws DeleteException; - boolean deleteRecursively(String key) throws EntryNotFoundException, SearchException; - - JsonObject lookup(String key, ScanConsistency scanConsistency, String... attributes) throws SearchException; - - PagedResult search(String key, ScanConsistency scanConsistency, Expression expression, SearchScope scope, - String[] attributes, Sort[] orderBy, CouchbaseBatchOperationWraper batchOperationWraper, SearchReturnDataType returnDataType, - int start, int count, int pageSize) throws SearchException; - - String[] createStoragePassword(String[] passwords); - - boolean isBinaryAttribute(String attribute); - boolean isCertificateAttribute(String attribute); - - boolean destroy(); - -} diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java deleted file mode 100644 index 8d719255..00000000 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseConnectionProvider.java +++ /dev/null @@ -1,364 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.couchbase.operation.impl; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Properties; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import org.gluu.persist.couchbase.model.BucketMapping; -import org.gluu.persist.couchbase.model.ResultCode; -import org.gluu.persist.exception.KeyConversionException; -import org.gluu.persist.exception.operation.ConfigurationException; -import org.gluu.persist.operation.auth.PasswordEncryptionMethod; -import org.gluu.util.ArrayHelper; -import org.gluu.util.StringHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.couchbase.client.core.CouchbaseException; -import com.couchbase.client.core.message.internal.PingReport; -import com.couchbase.client.core.message.internal.PingServiceHealth; -import com.couchbase.client.core.message.internal.PingServiceHealth.PingState; -import com.couchbase.client.java.Bucket; -import com.couchbase.client.java.CouchbaseCluster; -import com.couchbase.client.java.bucket.BucketInfo; -import com.couchbase.client.java.bucket.BucketManager; -import com.couchbase.client.java.env.CouchbaseEnvironment; -import com.couchbase.client.java.query.N1qlQueryResult; -import com.couchbase.client.java.query.N1qlQueryRow; -import com.couchbase.client.java.query.Select; -import com.couchbase.client.java.query.Statement; -import com.couchbase.client.java.query.dsl.Expression; - -/** - * Perform cluster initialization and open required buckets - * - * @author Yuriy Movchan Date: 05/10/2018 - */ -public class CouchbaseConnectionProvider { - - private static final Logger LOG = LoggerFactory.getLogger(CouchbaseConnectionProvider.class); - - private Properties props; - - private String[] servers; - private String[] buckets; - private String defaultBucket; - - private String userName; - private String userPassword; - - private CouchbaseEnvironment couchbaseEnvironment; - private CouchbaseCluster cluster; - private int creationResultCode; - - private HashMap bucketToBaseNameMapping; - private HashMap baseNameToBucketMapping; - private BucketMapping defaultBucketMapping; - - private ArrayList binaryAttributes, certificateAttributes; - - private PasswordEncryptionMethod passwordEncryptionMethod; - - protected CouchbaseConnectionProvider() { - } - - public CouchbaseConnectionProvider(Properties props, CouchbaseEnvironment couchbaseEnvironment) { - this.props = props; - this.couchbaseEnvironment = couchbaseEnvironment; - } - - public void create() { - try { - init(); - } catch (Exception ex) { - this.creationResultCode = ResultCode.OPERATIONS_ERROR_INT_VALUE; - - Properties clonedProperties = (Properties) props.clone(); - if (clonedProperties.getProperty("auth.userName") != null) { - clonedProperties.setProperty("auth.userPassword", "REDACTED"); - } - - LOG.error("Failed to create connection with properties: '{}'. Exception: {}", clonedProperties, ex); - ex.printStackTrace(); - } - } - - protected void init() { - this.servers = StringHelper.split(props.getProperty("servers"), ","); - - this.userName = props.getProperty("auth.userName"); - this.userPassword = props.getProperty("auth.userPassword"); - - this.defaultBucket = props.getProperty("bucket.default", null); - if (StringHelper.isEmpty(defaultBucket)) { - throw new ConfigurationException("Default bucket is not defined!"); - } - - this.buckets = StringHelper.split(props.getProperty("buckets"), ","); - if (!Arrays.asList(buckets).contains(defaultBucket)) { - this.buckets = ArrayHelper.addItemToStringArray(buckets, defaultBucket); - } - - openWithWaitImpl(); - LOG.info("Opended: '{}' buket with base names: '{}'", bucketToBaseNameMapping.keySet(), baseNameToBucketMapping.keySet()); - - if (props.containsKey("password.encryption.method")) { - this.passwordEncryptionMethod = PasswordEncryptionMethod.getMethod(props.getProperty("password.encryption.method")); - } else { - this.passwordEncryptionMethod = PasswordEncryptionMethod.HASH_METHOD_SHA256; - } - - this.binaryAttributes = new ArrayList(); - if (props.containsKey("binaryAttributes")) { - String[] binaryAttrs = StringHelper.split(props.get("binaryAttributes").toString().toLowerCase(), ","); - this.binaryAttributes.addAll(Arrays.asList(binaryAttrs)); - } - LOG.debug("Using next binary attributes: '{}'", binaryAttributes); - - this.certificateAttributes = new ArrayList(); - if (props.containsKey("certificateAttributes")) { - String[] binaryAttrs = StringHelper.split(props.get("certificateAttributes").toString().toLowerCase(), ","); - this.certificateAttributes.addAll(Arrays.asList(binaryAttrs)); - } - LOG.debug("Using next binary certificateAttributes: '{}'", certificateAttributes); - - this.creationResultCode = ResultCode.SUCCESS_INT_VALUE; - } - - private void openWithWaitImpl() { - String connectionMaxWaitTime = props.getProperty("connection.connection-max-wait-time"); - int connectionMaxWaitTimeSeconds = 30; - if (StringHelper.isNotEmpty(connectionMaxWaitTime)) { - connectionMaxWaitTimeSeconds = Integer.parseInt(connectionMaxWaitTime); - } - LOG.debug("Using Couchbase connection timeout: '{}'", connectionMaxWaitTimeSeconds); - - CouchbaseException lastException = null; - - int attempt = 0; - long currentTime = System.currentTimeMillis(); - long maxWaitTime = currentTime + connectionMaxWaitTimeSeconds * 1000; - do { - attempt++; - if (attempt > 0) { - LOG.info("Attempting to create connection: '{}'", attempt); - } - - try { - open(); - if (isConnected()) { - break; - } else { - LOG.info("Failed to connect to Couchbase"); - destory(); - } - } catch (CouchbaseException ex) { - lastException = ex; - } - - try { - Thread.sleep(5000); - } catch (InterruptedException ex) { - LOG.error("Exception happened in sleep", ex); - return; - } - currentTime = System.currentTimeMillis(); - } while (maxWaitTime > currentTime); - - if (lastException != null) { - throw lastException; - } - } - - private void open() { - this.bucketToBaseNameMapping = new HashMap(); - this.baseNameToBucketMapping = new HashMap(); - - this.cluster = CouchbaseCluster.create(couchbaseEnvironment, servers); - cluster.authenticate(userName, userPassword); - - // Open required buckets - for (String bucketName : buckets) { - String baseNamesProp = props.getProperty(String.format("bucket.%s.mapping", bucketName), ""); - String[] baseNames = StringHelper.split(baseNamesProp, ","); - - Bucket bucket = cluster.openBucket(bucketName); - - BucketMapping bucketMapping = new BucketMapping(bucketName, bucket); - - // Store in separate map to speed up search by base name - bucketToBaseNameMapping.put(bucketName, bucketMapping); - for (String baseName : baseNames) { - baseNameToBucketMapping.put(baseName, bucketMapping); - } - - if (StringHelper.equalsIgnoreCase(bucketName, defaultBucket)) { - this.defaultBucketMapping = bucketMapping; - } - } - } - - public boolean destory() { - boolean result = true; - if (bucketToBaseNameMapping != null) { - for (BucketMapping bucketMapping : bucketToBaseNameMapping.values()) { - try { - bucketMapping.getBucket().close(); - } catch (CouchbaseException ex) { - LOG.error("Failed to close bucket '{}'", bucketMapping.getBucketName(), ex); - result = false; - } - } - } - - if (cluster != null) { - result &= cluster.disconnect(); - } - - return result; - } - - public boolean isConnected() { - if (cluster == null) { - return false; - } - - boolean isConnected = true; - try { - for (BucketMapping bucketMapping : bucketToBaseNameMapping.values()) { - Bucket bucket = bucketMapping.getBucket(); - if (bucket.isClosed() || !isConnected(bucketMapping)) { - if (bucket.isClosed()) { - LOG.debug("Bucket '{}' is closed", bucketMapping.getBucketName()); - } - - LOG.error("Bucket '{}' is in invalid state", bucketMapping.getBucketName()); - isConnected = false; - break; - } - } - } catch (RuntimeException ex) { - LOG.error("Failed to check bucket", ex); - isConnected = false; - } - - return isConnected; - } - - private boolean isConnected(BucketMapping bucketMapping) { - Bucket bucket = bucketMapping.getBucket(); - - BucketManager bucketManager = bucket.bucketManager(); - BucketInfo bucketInfo = bucketManager.info(30, TimeUnit.SECONDS); - - boolean result = true; - if (com.couchbase.client.java.bucket.BucketType.COUCHBASE == bucketInfo.type()) { - // Check indexes state - Statement query = Select.select("state").from("system:indexes").where(Expression.path("state").eq(Expression.s("online")).not()); - N1qlQueryResult queryResult = bucket.query(query); - result = queryResult.finalSuccess(); - - if (result) { - result = queryResult.info().resultCount() == 0; - if (LOG.isDebugEnabled()) { - LOG.debug("There are indexes which not online"); - } - } else { - if (LOG.isDebugEnabled()) { - LOG.debug("Faield to check indexes status"); - } - } - } - - if (result) { - PingReport pingReport = bucket.ping(); - for (PingServiceHealth pingServiceHealth : pingReport.services()) { - if (PingState.OK != pingServiceHealth.state()) { - LOG.debug("Ping returns that service typ {} is not online", pingServiceHealth.type()); - result = false; - break; - } - } - } - - return result; - } - - public BucketMapping getBucketMapping(String baseName) { - BucketMapping bucketMapping = baseNameToBucketMapping.get(baseName); - if (bucketMapping == null) { - return null; - } - - return bucketMapping; - } - - public BucketMapping getBucketMappingByKey(String key) { - if ("_".equals(key)) { - return defaultBucketMapping; - } - - String[] baseNameParts = key.split("_"); - if (ArrayHelper.isEmpty(baseNameParts)) { - throw new KeyConversionException("Failed to determine base key part!"); - } - - BucketMapping bucketMapping = baseNameToBucketMapping.get(baseNameParts[0]); - if (bucketMapping != null) { - return bucketMapping; - } - - return defaultBucketMapping; - } - - public int getCreationResultCode() { - return creationResultCode; - } - - public boolean isCreated() { - return ResultCode.SUCCESS_INT_VALUE == creationResultCode; - } - - public String[] getServers() { - return servers; - } - - public ArrayList getBinaryAttributes() { - return binaryAttributes; - } - - public ArrayList getCertificateAttributes() { - return certificateAttributes; - } - - public boolean isBinaryAttribute(String attributeName) { - if (StringHelper.isEmpty(attributeName)) { - return false; - } - - return binaryAttributes.contains(attributeName.toLowerCase()); - } - - public boolean isCertificateAttribute(String attributeName) { - if (StringHelper.isEmpty(attributeName)) { - return false; - } - - return certificateAttributes.contains(attributeName.toLowerCase()); - } - - public PasswordEncryptionMethod getPasswordEncryptionMethod() { - return passwordEncryptionMethod; - } - -} - diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java deleted file mode 100644 index fc5ad563..00000000 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/impl/CouchbaseOperationServiceImpl.java +++ /dev/null @@ -1,729 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2018, Gluu - */ - -package org.gluu.persist.couchbase.operation.impl; - -import com.couchbase.client.core.CouchbaseException; -import com.couchbase.client.core.message.kv.subdoc.multi.Mutation; -import com.couchbase.client.java.Bucket; -import com.couchbase.client.java.document.JsonDocument; -import com.couchbase.client.java.document.json.JsonArray; -import com.couchbase.client.java.document.json.JsonObject; -import com.couchbase.client.java.query.*; -import com.couchbase.client.java.query.consistency.ScanConsistency; -import com.couchbase.client.java.query.dsl.Expression; -import com.couchbase.client.java.query.dsl.Sort; -import com.couchbase.client.java.query.dsl.path.*; -import com.couchbase.client.java.subdoc.DocumentFragment; -import com.couchbase.client.java.subdoc.MutateInBuilder; -import com.couchbase.client.java.subdoc.MutationSpec; -import org.gluu.persist.couchbase.impl.CouchbaseBatchOperationWraper; -import org.gluu.persist.couchbase.model.BucketMapping; -import org.gluu.persist.couchbase.model.SearchReturnDataType; -import org.gluu.persist.couchbase.operation.CouchbaseOperationService; -import org.gluu.persist.couchbase.operation.watch.OperationDurationUtil; -import org.gluu.persist.exception.extension.PersistenceExtension; -import org.gluu.persist.exception.operation.*; -import org.gluu.persist.model.BatchOperation; -import org.gluu.persist.model.PagedResult; -import org.gluu.persist.model.SearchScope; -import org.gluu.persist.operation.auth.PasswordEncryptionHelper; -import org.gluu.util.ArrayHelper; -import org.gluu.util.StringHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.time.Duration; -import java.time.Instant; -import java.util.*; -import java.util.Map.Entry; - -/** - * Base service which performs all supported Couchbase operations - * - * @author Yuriy Movchan Date: 05/10/2018 - */ -public class CouchbaseOperationServiceImpl implements CouchbaseOperationService { - - private static final Logger LOG = LoggerFactory.getLogger(CouchbaseConnectionProvider.class); - - private Properties props; - private CouchbaseConnectionProvider connectionProvider; - - private ScanConsistency scanConsistency = ScanConsistency.NOT_BOUNDED; - - private boolean ignoreAttributeScanConsistency = false; - private boolean attemptWithoutAttributeScanConsistency = true; - private boolean enableScopeSupport = false; - private boolean disableAttributeMapping = false; - - private PersistenceExtension persistenceExtension; - - - @SuppressWarnings("unused") - private CouchbaseOperationServiceImpl() { - } - - public CouchbaseOperationServiceImpl(Properties props, CouchbaseConnectionProvider connectionProvider) { - this.props = props; - this.connectionProvider = connectionProvider; - init(); - } - - private void init() { - if (props.containsKey("connection.scan-consistency")) { - String scanConsistencyString = StringHelper.toUpperCase(props.get("connection.scan-consistency").toString()); - this.scanConsistency = ScanConsistency.valueOf(scanConsistencyString); - } - - if (props.containsKey("connection.ignore-attribute-scan-consistency")) { - this.ignoreAttributeScanConsistency = StringHelper.toBoolean(props.get("connection.ignore-attribute-scan-consistency").toString(), this.ignoreAttributeScanConsistency); - } - - if (props.containsKey("connection.attempt-without-attribute-scan-consistency")) { - this.attemptWithoutAttributeScanConsistency = StringHelper.toBoolean(props.get("attempt-without-attribute-scan-consistency").toString(), this.attemptWithoutAttributeScanConsistency); - } - - if (props.containsKey("connection.enable-scope-support")) { - this.enableScopeSupport = StringHelper.toBoolean(props.get("connection.enable-scope-support").toString(), this.enableScopeSupport); - } - - if (props.containsKey("connection.disable-attribute-mapping")) { - this.disableAttributeMapping = StringHelper.toBoolean(props.get("connection.disable-attribute-mapping").toString(), this.disableAttributeMapping); - } - - LOG.info("Option scanConsistency: " + scanConsistency); - LOG.info("Option ignoreAttributeScanConsistency: " + ignoreAttributeScanConsistency); - LOG.info("Option enableScopeSupport: " + enableScopeSupport); - LOG.info("Option disableAttributeMapping: " + disableAttributeMapping); - } - - @Override - public CouchbaseConnectionProvider getConnectionProvider() { - return connectionProvider; - } - - @Override - public boolean authenticate(final String key, final String password) throws SearchException { - return authenticateImpl(key, password); - } - - private boolean authenticateImpl(final String key, final String password) throws SearchException { - Instant startTime = OperationDurationUtil.instance().now(); - - boolean result = false; - if (password != null) { - JsonObject entry = lookup(key, null, USER_PASSWORD); - Object userPasswordObj = entry.get(USER_PASSWORD); - - String userPassword = null; - if (userPasswordObj instanceof JsonArray) { - userPassword = ((JsonArray) userPasswordObj).getString(0); - } else if (userPasswordObj instanceof String) { - userPassword = (String) userPasswordObj; - } - - if (userPassword != null) { - if (persistenceExtension == null) { - result = PasswordEncryptionHelper.compareCredentials(password, userPassword); - } else { - result = persistenceExtension.compareHashedPasswords(password, userPassword); - } - } - } - - Duration duration = OperationDurationUtil.instance().duration(startTime); - - BucketMapping bucketMapping = connectionProvider.getBucketMappingByKey(key); - OperationDurationUtil.instance().logDebug("Couchbase operation: bind, duration: {}, bucket: {}, key: {}", duration, bucketMapping.getBucketName(), key); - - return result; - } - - @Override - public boolean addEntry(String key, JsonObject jsonObject) throws DuplicateEntryException, PersistenceException { - return addEntry(key, jsonObject, 0); - } - - @Override - public boolean addEntry(String key, JsonObject jsonObject, Integer expiration) throws DuplicateEntryException, PersistenceException { - Instant startTime = OperationDurationUtil.instance().now(); - - BucketMapping bucketMapping = connectionProvider.getBucketMappingByKey(key); - boolean result = addEntryImpl(bucketMapping, key, jsonObject, expiration); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("Couchbase operation: add, duration: {}, bucket: {}, key: {}, json: {}", duration, bucketMapping.getBucketName(), key, jsonObject); - - return result; - } - - private boolean addEntryImpl(BucketMapping bucketMapping, String key, JsonObject jsonObject, Integer expiration) throws PersistenceException { - try { - JsonDocument jsonDocument; - if (expiration == null) { - jsonDocument = JsonDocument.create(key, jsonObject); - } else { - jsonDocument = JsonDocument.create(key, expiration, jsonObject); - } - - JsonDocument result = bucketMapping.getBucket().upsert(jsonDocument); - if (result != null) { - return true; - } - - } catch (CouchbaseException ex) { - throw new PersistenceException("Failed to add entry", ex); - } - - return false; - } - - @Deprecated - protected boolean updateEntry(String key, JsonObject attrs) throws UnsupportedOperationException, SearchException { - List mods = new ArrayList(); - - for (Entry attrEntry : attrs.toMap().entrySet()) { - String attributeName = attrEntry.getKey(); - Object attributeValue = attrEntry.getValue(); - if (attributeName.equalsIgnoreCase(CouchbaseOperationService.OBJECT_CLASS) || attributeName.equalsIgnoreCase(CouchbaseOperationService.DN) - || attributeName.equalsIgnoreCase(CouchbaseOperationService.USER_PASSWORD)) { - continue; - } else { - if (attributeValue != null) { - mods.add(new MutationSpec(Mutation.REPLACE, attributeName, attributeValue)); - } - } - } - - return updateEntry(key, mods, null); - } - - @Override - public boolean updateEntry(String key, List mods, Integer expiration) throws UnsupportedOperationException, SearchException { - Instant startTime = OperationDurationUtil.instance().now(); - - BucketMapping bucketMapping = connectionProvider.getBucketMappingByKey(key); - boolean result = updateEntryImpl(bucketMapping, key, mods, expiration); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("Couchbase operation: modify, duration: {}, bucket: {}, key: {}, mods: {}", duration, bucketMapping.getBucketName(), key, mods); - - return result; - } - - private boolean updateEntryImpl(BucketMapping bucketMapping, String key, List mods, Integer expiration) throws SearchException { - try { - MutateInBuilder builder = bucketMapping.getBucket().mutateIn(key); - if (expiration != null) { - builder = builder.withExpiry(expiration); - } - - return modifyEntry(builder, mods); - } catch (final CouchbaseException ex) { - throw new SearchException("Failed to update entry", ex); - } - } - - protected boolean modifyEntry(MutateInBuilder builder, List mods) throws UnsupportedOperationException, SearchException { - try { - for (MutationSpec mod : mods) { - Mutation type = mod.type(); - if (Mutation.DICT_ADD == type) { - builder.insert(mod.path(), mod.fragment()); - } else if (Mutation.REPLACE == type) { - builder.replace(mod.path(), mod.fragment()); - } else if (Mutation.DELETE == type) { - builder.remove(mod.path()); - } else { - throw new UnsupportedOperationException("Operation type '" + type + "' is not implemented"); - } - } - - DocumentFragment result = builder.execute(); - if (result.size() > 0) { - return result.status(0).isSuccess(); - } - - return false; - } catch (final CouchbaseException ex) { - throw new SearchException("Failed to update entry", ex); - } - } - - @Override - public boolean delete(String key) throws EntryNotFoundException { - Instant startTime = OperationDurationUtil.instance().now(); - - BucketMapping bucketMapping = connectionProvider.getBucketMappingByKey(key); - boolean result = deleteImpl(bucketMapping, key); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("Couchbase operation: delete, duration: {}, bucket: {}, key: {}", duration, bucketMapping.getBucketName(), key); - - return result; - } - - private boolean deleteImpl(BucketMapping bucketMapping, String key) throws EntryNotFoundException { - try { - JsonDocument result = bucketMapping.getBucket().remove(key); - - return (result != null) && (result.id() != null); - } catch (CouchbaseException ex) { - throw new EntryNotFoundException("Failed to delete entry", ex); - } - } - - @Override - public int delete(String key, ScanConsistency scanConsistency, Expression expression, int count) throws DeleteException { - Instant startTime = OperationDurationUtil.instance().now(); - - BucketMapping bucketMapping = connectionProvider.getBucketMappingByKey(key); - ScanConsistency useScanConsistency = getScanConsistency(scanConsistency, false); - - int result = deleteImpl(bucketMapping, key, useScanConsistency, expression, count); - - String attemptInfo = getScanAttemptLogInfo(scanConsistency, useScanConsistency, false); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("Couchbase operation: delete_search, duration: {}, bucket: {}, key: {}, expression: {}, count: {}, consistency: {}{}", duration, bucketMapping.getBucketName(), key, expression, count, useScanConsistency, attemptInfo); - - return result; - } - - private int deleteImpl(BucketMapping bucketMapping, String key, ScanConsistency scanConsistency, Expression expression, int count) throws DeleteException { - Bucket bucket = bucketMapping.getBucket(); - - Expression finalExpression = expression; - if (enableScopeSupport) { - Expression scopeExpression = Expression.path("META().id").like(Expression.s(key + "%")); - finalExpression = scopeExpression.and(expression); - } - - MutateLimitPath deleteQuery = Delete.deleteFrom(Expression.i(bucketMapping.getBucketName())).where(finalExpression); - ReturningPath query = deleteQuery.limit(count); - LOG.debug("Execution query: '" + query + "'"); - - N1qlQueryResult result = bucket.query(N1qlQuery.simple(query, N1qlParams.build().consistency(scanConsistency))); - if (!result.finalSuccess()) { - throw new DeleteException(String.format("Failed to delete entries. Query: '%s'. Error: '%s', Error count: '%d'", query, result.errors(), - result.info().errorCount()), result.errors().get(0).getInt("code")); - } - - return result.info().mutationCount(); - } - - @Override - public boolean deleteRecursively(String key) throws EntryNotFoundException, SearchException { - Instant startTime = OperationDurationUtil.instance().now(); - - BucketMapping bucketMapping = connectionProvider.getBucketMappingByKey(key); - boolean result = deleteRecursivelyImpl(bucketMapping, key); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("Couchbase operation: delete_tree, duration: {}, bucket: {}, key: {}", duration, bucketMapping.getBucketName(), key); - - return result; - } - - private boolean deleteRecursivelyImpl(BucketMapping bucketMapping, String key) throws SearchException, EntryNotFoundException { - try { - if (enableScopeSupport) { - MutateLimitPath deleteQuery = Delete.deleteFrom(Expression.i(bucketMapping.getBucketName())) - .where(Expression.path("META().id").like(Expression.s(key + "%"))); - - N1qlQueryResult result = bucketMapping.getBucket().query(deleteQuery); - if (!result.finalSuccess()) { - throw new SearchException(String.format("Failed to delete entries. Query: '%s'. Error: '%s', Error count: '%d'", deleteQuery, result.errors(), - result.info().errorCount()), result.errors().get(0).getInt("code")); - } - } else { - LOG.warn("Removing only base key without sub-tree: " + key); - delete(key); - } - - return true; - } catch (CouchbaseException ex) { - throw new EntryNotFoundException("Failed to delete entry", ex); - } - } - - @Override - public JsonObject lookup(String key, ScanConsistency scanConsistency, String... attributes) throws SearchException { - Instant startTime = OperationDurationUtil.instance().now(); - - BucketMapping bucketMapping = connectionProvider.getBucketMappingByKey(key); - - boolean secondTry = false; - ScanConsistency useScanConsistency = getScanConsistency(scanConsistency, attemptWithoutAttributeScanConsistency); - JsonObject result = null; - SearchException lastException = null; - try { - result = lookupImpl(bucketMapping, key, useScanConsistency, attributes); - } catch (SearchException ex) { - lastException = ex; - } - if ((result == null) || result.isEmpty()) { - ScanConsistency useScanConsistency2 = getScanConsistency(scanConsistency, false); - if (!useScanConsistency2.equals(useScanConsistency)) { - useScanConsistency = useScanConsistency2; - secondTry = true; - result = lookupImpl(bucketMapping, key, useScanConsistency, attributes); - } else { - if (lastException != null) { - throw lastException; - } - } - } - - String attemptInfo = getScanAttemptLogInfo(scanConsistency, useScanConsistency, secondTry); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("Couchbase operation: lookup, duration: {}, bucket: {}, key: {}, attributes: {}, consistency: {}{}", duration, bucketMapping.getBucketName(), key, attributes, useScanConsistency, attemptInfo); - - return result; - } - - private JsonObject lookupImpl(BucketMapping bucketMapping, String key, ScanConsistency scanConsistency, String... attributes) throws SearchException { - try { - Bucket bucket = bucketMapping.getBucket(); - if (ArrayHelper.isEmpty(attributes)) { - JsonDocument doc = bucket.get(key); - if (doc != null) { - return doc.content(); - } - - } else { - JsonDocument doc = bucket.get(key); - if (doc != null) { - Set docAtributesKeep = new HashSet(Arrays.asList(attributes)); - - for (Iterator it = doc.content().getNames().iterator(); it.hasNext();) { - String docAtribute = (String) it.next(); - if (!docAtributesKeep.contains(docAtribute)) { - it.remove(); - } - } - - return doc.content(); - } - -// N1qlParams params = N1qlParams.build().consistency(scanConsistency); -// OffsetPath select = Select.select(attributes).from(Expression.i(bucketMapping.getBucketName())).useKeys(Expression.s(key)).limit(1); -// N1qlQueryResult result = bucket.query(N1qlQuery.simple(select, params)); -// if (!result.finalSuccess()) { -// throw new SearchException(String.format("Failed to lookup entry. Errors: %s", result.errors()), result.info().errorCount()); -// } -// -// if (result.allRows().size() == 1) { -// return result.allRows().get(0).value(); -// } - - } - } catch (CouchbaseException ex) { - throw new SearchException("Failed to lookup entry", ex); - } - - throw new SearchException("Failed to lookup entry"); - } - - @Override - public PagedResult search(String key, ScanConsistency scanConsistency, Expression expression, SearchScope scope, String[] attributes, Sort[] orderBy, - CouchbaseBatchOperationWraper batchOperationWraper, SearchReturnDataType returnDataType, int start, int count, int pageSize) throws SearchException { - Instant startTime = OperationDurationUtil.instance().now(); - - BucketMapping bucketMapping = connectionProvider.getBucketMappingByKey(key); - - boolean secondTry = false; - ScanConsistency useScanConsistency = getScanConsistency(scanConsistency, attemptWithoutAttributeScanConsistency); - PagedResult result = null; - int attemps = 20; - do { - attemps--; - try { - result = searchImpl(bucketMapping, key, useScanConsistency, expression, scope, attributes, orderBy, batchOperationWraper, - returnDataType, start, count, pageSize); - break; - } catch (SearchException ex) { - if (ex.getErrorCode() != 5000) { - throw ex; - } - - LOG.warn("Waiting for Indexer Warmup..."); - try { - Thread.sleep(2000); - } catch (InterruptedException ex2) {} - } - } while (attemps > 0); - if ((result == null) || (result.getEntriesCount() == 0)) { - ScanConsistency useScanConsistency2 = getScanConsistency(scanConsistency, false); - if (!useScanConsistency2.equals(useScanConsistency)) { - useScanConsistency = useScanConsistency2; - result = searchImpl(bucketMapping, key, useScanConsistency, expression, scope, attributes, orderBy, batchOperationWraper, returnDataType, start, count, pageSize); - secondTry = true; - } - } - - String attemptInfo = getScanAttemptLogInfo(scanConsistency, useScanConsistency, secondTry); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("Couchbase operation: search, duration: {}, bucket: {}, key: {}, expression: {}, scope: {}, attributes: {}, orderBy: {}, batchOperationWraper: {}, returnDataType: {}, start: {}, count: {}, pageSize: {}, consistency: {}{}", duration, bucketMapping.getBucketName(), key, expression, scope, attributes, orderBy, batchOperationWraper, returnDataType, start, count, pageSize, useScanConsistency, attemptInfo); - - return result; - } - - private PagedResult searchImpl(BucketMapping bucketMapping, String key, ScanConsistency scanConsistency, Expression expression, SearchScope scope, String[] attributes, Sort[] orderBy, - CouchbaseBatchOperationWraper batchOperationWraper, SearchReturnDataType returnDataType, int start, int count, int pageSize) throws SearchException { - Bucket bucket = bucketMapping.getBucket(); - - BatchOperation ldapBatchOperation = null; - if (batchOperationWraper != null) { - ldapBatchOperation = (BatchOperation) batchOperationWraper.getBatchOperation(); - } - - if (LOG.isTraceEnabled()) { - // Find whole DB search - if (StringHelper.equalsIgnoreCase(key, "_")) { - LOG.trace("Search in whole DB tree", new Exception()); - } - } - - Expression finalExpression = expression; - if (enableScopeSupport) { - Expression scopeExpression; - if (scope == null) { - scopeExpression = null; - } else if (SearchScope.BASE == scope) { - scopeExpression = Expression.path("META().id").like(Expression.s(key + "%")) - .and(Expression.path("META().id").notLike(Expression.s(key + "\\\\_%\\\\_"))); - } else { - scopeExpression = Expression.path("META().id").like(Expression.s(key + "%")); - } - - if (scopeExpression != null) { - finalExpression = scopeExpression.and(expression); - } - } else { - if (scope != null) { - LOG.debug("Ignoring scope '" + scope + " for expression: " + expression); - } - } - - String[] select = attributes; - if (select == null) { - select = new String[] { "gluu_doc.*", CouchbaseOperationService.DN }; - } else if ((select.length == 1) && StringHelper.isEmpty(select[0])) { - // Compatibility with Couchbase persistence layer when application pass filter new String[] { "" } - select = new String[] { CouchbaseOperationService.DN }; - } else { - boolean hasDn = Arrays.asList(select).contains(CouchbaseOperationService.DN); - if (!hasDn) { - select = ArrayHelper.arrayMerge(select, new String[] { CouchbaseOperationService.DN }); - } - } - GroupByPath selectQuery = Select.select(select).from(Expression.i(bucketMapping.getBucketName())).as("gluu_doc").where(finalExpression); - - LimitPath baseQuery = selectQuery; - if (orderBy != null) { - baseQuery = selectQuery.orderBy(orderBy); - } - - List searchResultList = new ArrayList(); - - if ((SearchReturnDataType.SEARCH == returnDataType) || (SearchReturnDataType.SEARCH_COUNT == returnDataType)) { - N1qlQueryResult lastResult = null; - if (pageSize > 0) { - boolean collectSearchResult; - - Statement query = null; - int currentLimit; - try { - List lastSearchResultList; - int resultCount = 0; - do { - collectSearchResult = true; - - currentLimit = pageSize; - if (count > 0) { - currentLimit = Math.min(pageSize, count - resultCount); - } - - query = baseQuery.limit(currentLimit).offset(start + resultCount); - LOG.debug("Execution query: '" + query + "'"); - lastResult = bucket.query(N1qlQuery.simple(query, N1qlParams.build().consistency(scanConsistency))); - if (!lastResult.finalSuccess()) { - throw new SearchException(String.format("Failed to search entries. Query: '%s'. Error: '%s', Error count: '%d'", query, lastResult.errors(), - lastResult.info().errorCount()), lastResult.errors().get(0).getInt("code")); - } - - lastSearchResultList = lastResult.allRows(); - - if (ldapBatchOperation != null) { - collectSearchResult = ldapBatchOperation.collectSearchResult(lastSearchResultList.size()); - } - if (collectSearchResult) { - searchResultList.addAll(lastSearchResultList); - } - - if (ldapBatchOperation != null) { - List entries = batchOperationWraper.createEntities(lastSearchResultList); - ldapBatchOperation.performAction(entries); - } - - resultCount += lastSearchResultList.size(); - - if ((count > 0) && (resultCount >= count)) { - break; - } - } while (lastSearchResultList.size() > 0); - } catch (CouchbaseException ex) { - throw new SearchException("Failed to search entries. Query: '" + query + "'", ex); - } - } else { - try { - Statement query = baseQuery; - if (count > 0) { - query = ((LimitPath) query).limit(count); - } - if (start > 0) { - query = ((OffsetPath) query).offset(start); - } - - LOG.debug("Execution query: '" + query + "'"); - lastResult = bucket.query(N1qlQuery.simple(query, N1qlParams.build().consistency(scanConsistency))); - if (!lastResult.finalSuccess()) { - throw new SearchException(String.format("Failed to search entries. Query: '%s'. Error: '%s', Error count: '%d'", baseQuery, lastResult.errors(), - lastResult.info().errorCount()), lastResult.errors().get(0).getInt("code")); - } - - searchResultList.addAll(lastResult.allRows()); - } catch (CouchbaseException ex) { - throw new SearchException("Failed to search entries. Query: '" + baseQuery.toString() + "'", ex); - } - } - } - - List resultRows = new ArrayList(searchResultList.size()); - for (N1qlQueryRow row : searchResultList) { - resultRows.add(row.value()); - } - - PagedResult result = new PagedResult(); - result.setEntries(resultRows); - result.setEntriesCount(resultRows.size()); - result.setStart(start); - - if ((SearchReturnDataType.COUNT == returnDataType) || (SearchReturnDataType.SEARCH_COUNT == returnDataType)) { - GroupByPath selectCountQuery = Select.select("COUNT(*) as TOTAL").from(Expression.i(bucketMapping.getBucketName())) - .where(finalExpression); - try { - LOG.debug("Calculating count. Execution query: '" + selectCountQuery + "'"); - N1qlQueryResult countResult = bucket.query(N1qlQuery.simple(selectCountQuery, N1qlParams.build().consistency(scanConsistency))); - if (!countResult.finalSuccess() || (countResult.info().resultCount() != 1)) { - throw new SearchException(String.format("Failed to calculate count entries. Query: '%s'. Error: '%s', Error count: '%d'", selectCountQuery, countResult.errors(), - countResult.info().errorCount()), countResult.errors().get(0).getInt("code")); - } - result.setTotalEntriesCount(countResult.allRows().get(0).value().getInt("TOTAL")); - } catch (CouchbaseException ex) { - throw new SearchException("Failed to calculate count entries. Query: '" + selectCountQuery.toString() + "'", ex); - } - } - - return result; - } - - public String[] createStoragePassword(String[] passwords) { - if (ArrayHelper.isEmpty(passwords)) { - return passwords; - } - - String[] results = new String[passwords.length]; - for (int i = 0; i < passwords.length; i++) { - if (persistenceExtension == null) { - results[i] = PasswordEncryptionHelper.createStoragePassword(passwords[i], connectionProvider.getPasswordEncryptionMethod()); - } else { - results[i] = persistenceExtension.createHashedPassword(passwords[i]); - } - } - - return results; - } - - @Override - public boolean isBinaryAttribute(String attribute) { - return this.connectionProvider.isBinaryAttribute(attribute); - } - - @Override - public boolean isCertificateAttribute(String attribute) { - return this.connectionProvider.isCertificateAttribute(attribute); - } - - private ScanConsistency getScanConsistency(ScanConsistency operationScanConsistency, boolean ignore) { - if (ignore) { - return scanConsistency; - } - - if (ignoreAttributeScanConsistency) { - return scanConsistency; - } - - if (operationScanConsistency != null) { - return operationScanConsistency; - } - - return scanConsistency; - } - - public ScanConsistency getScanConsistency() { - return scanConsistency; - } - - public boolean isDisableAttributeMapping() { - return disableAttributeMapping; - } - - @Override - public boolean destroy() { - boolean result = true; - - if (connectionProvider != null) { - try { - connectionProvider.destory(); - } catch (Exception ex) { - LOG.error("Failed to destory provider correctly"); - result = false; - } - } - - return result; - } - - @Override - public boolean isConnected() { - return connectionProvider.isConnected(); - } - - protected String getScanAttemptLogInfo(ScanConsistency scanConsistency, ScanConsistency usedScanConsistency, boolean secondTry) { - String attemptInfo = ""; - if (secondTry) { - attemptInfo = ", attempt: second"; - } else { - ScanConsistency useScanConsistency2 = getScanConsistency(scanConsistency, false); - if (!useScanConsistency2.equals(usedScanConsistency)) { - attemptInfo = ", attempt: first"; - } - } - - return attemptInfo; - } - - @Override - public void setPersistenceExtension(PersistenceExtension persistenceExtension) { - this.persistenceExtension = persistenceExtension; - } - -} diff --git a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/watch/OperationDurationUtil.java b/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/watch/OperationDurationUtil.java deleted file mode 100644 index 6554c96c..00000000 --- a/persistence-couchbase/src/main/java/org/gluu/persist/couchbase/operation/watch/OperationDurationUtil.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.gluu.persist.couchbase.operation.watch; - -import org.gluu.persist.watch.DurationUtil; - -/** - * Simple Couchbase operation duration calculator helper - * - * @author Yuriy Movchan Date: 04/08/2019 - */ -public class OperationDurationUtil extends DurationUtil { - - private static OperationDurationUtil instance = new OperationDurationUtil(); - - public static DurationUtil instance() { - return instance; - } - - public void logDebug(String format, Object... arguments) { - if (log.isDebugEnabled()) { - log.debug(format, arguments); - } - } - -} diff --git a/persistence-couchbase/src/main/resources/META-INF/beans.xml b/persistence-couchbase/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 2f4f7e27..00000000 --- a/persistence-couchbase/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/persistence-couchbase/src/test/java/org/gluu/test/.gitignore b/persistence-couchbase/src/test/java/org/gluu/test/.gitignore deleted file mode 100644 index 4a5e9327..00000000 --- a/persistence-couchbase/src/test/java/org/gluu/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/dev/ diff --git a/persistence-couchbase/src/test/java/org/gluu/test/dev/.gitignore b/persistence-couchbase/src/test/java/org/gluu/test/dev/.gitignore deleted file mode 100644 index c06add60..00000000 --- a/persistence-couchbase/src/test/java/org/gluu/test/dev/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/TestCouchbaseOperationsService.java diff --git a/persistence-filter/pom.xml b/persistence-filter/pom.xml deleted file mode 100644 index e186942b..00000000 --- a/persistence-filter/pom.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - 4.0.0 - oxcore-persistence-filter - jar - persistence-filter - - - org.gluu - oxcore - 5.0.0-SNAPSHOT - - - - - org.gluu - oxcore-util - - - - \ No newline at end of file diff --git a/persistence-filter/src/main/java/org/gluu/search/filter/Filter.java b/persistence-filter/src/main/java/org/gluu/search/filter/Filter.java deleted file mode 100644 index e9a77ecd..00000000 --- a/persistence-filter/src/main/java/org/gluu/search/filter/Filter.java +++ /dev/null @@ -1,286 +0,0 @@ -package org.gluu.search.filter; - -import java.util.List; - -import org.gluu.util.ArrayHelper; - -/** - * Simple filter without dependency to specific persistence filter mechanism - * - * @author Yuriy Movchan Date: 2017/12/12 - */ -public class Filter { - - private FilterType type; - - private Filter[] filters; - - private String filterString; - private String attributeName; - private Object assertionValue; - - private String subInitial; - private String[] subAny; - private String subFinal; - - private Boolean multiValued; - - public Filter(FilterType type) { - this.type = type; - } - - public Filter(FilterType type, Filter... filters) { - this(type); - this.filters = filters; - } - - public Filter(FilterType type, String filterString) { - this(type); - this.filterString = filterString; - } - - public Filter(FilterType type, Filter filter, Object assertionValue) { - this(type); - this.filters = new Filter[] { filter }; - this.assertionValue = assertionValue; - } - - public Filter(FilterType type, String attributeName, Object assertionValue) { - this(type); - this.attributeName = attributeName; - this.assertionValue = assertionValue; - } - - public Filter(FilterType type, String attributeName, String subInitial, String[] subAny, String subFinal) { - this(type); - this.attributeName = attributeName; - this.subInitial = subInitial; - this.subAny = subAny; - this.subFinal = subFinal; - } - - /* - * This method force filter to use specific syntax. It's not useful when we need - * to support different persistent mechanisms - */ - @Deprecated - public static Filter create(final String filterString) { - return new Filter(FilterType.RAW, filterString); - } - - public static Filter createPresenceFilter(final String attributeName) { - return new Filter(FilterType.PRESENCE, attributeName, null); - } - - public static Filter createEqualityFilter(final String attributeName, final Object assertionValue) { - return new Filter(FilterType.EQUALITY, attributeName, assertionValue); - } - - public static Filter createEqualityFilter(final Filter filter, final Object assertionValue) { - return new Filter(FilterType.EQUALITY, filter, assertionValue); - } - - public static Filter createNOTFilter(final Filter filter) { - return new Filter(FilterType.NOT, filter); - } - - public static Filter createLowercaseFilter(final String attributeName) { - return new Filter(FilterType.LOWERCASE, attributeName, null); - } - - public static Filter createLessOrEqualFilter(final String attributeName, final Object assertionValue) { - return new Filter(FilterType.LESS_OR_EQUAL, attributeName, assertionValue); - } - - public static Filter createGreaterOrEqualFilter(final String attributeName, final Object assertionValue) { - return new Filter(FilterType.GREATER_OR_EQUAL, attributeName, assertionValue); - } - - public static Filter createApproximateMatchFilter(final String attributeName, final String assertionValue) { - return new Filter(FilterType.APPROXIMATE_MATCH, attributeName, assertionValue); - } - - public static Filter createSubstringFilter(final String attributeName, final String subInitial, - final String[] subAny, final String subFinal) { - return new Filter(FilterType.SUBSTRING, attributeName, subInitial, subAny, subFinal); - } - - public static Filter createORFilter(final Filter... filters) { - return new Filter(FilterType.OR, filters); - } - - public static Filter createORFilter(final List filters) { - return new Filter(FilterType.OR, filters.toArray(new Filter[0])); - } - - public static Filter createANDFilter(final Filter... filters) { - return new Filter(FilterType.AND, filters); - } - - public static Filter createANDFilter(final List filters) { - return new Filter(FilterType.AND, filters.toArray(new Filter[0])); - } - - public final FilterType getType() { - return type; - } - - public final void setType(FilterType type) { - this.type = type; - } - - public final Filter[] getFilters() { - return filters; - } - - public final void setFilters(Filter[] filters) { - this.filters = filters; - } - - public final String getFilterString() { - return filterString; - } - - public final void setFilterString(String filterString) { - this.filterString = filterString; - } - - public final String getAttributeName() { - return attributeName; - } - - public final void setAttributeName(String attributeName) { - this.attributeName = attributeName; - } - - public final Object getAssertionValue() { - return assertionValue; - } - - public final void setAssertionValue(Object assertionValue) { - this.assertionValue = assertionValue; - } - - public final String getSubInitial() { - return subInitial; - } - - public final void setSubInitial(String subInitial) { - this.subInitial = subInitial; - } - - public final String[] getSubAny() { - return subAny; - } - - public final void setSubAny(String[] subAny) { - this.subAny = subAny; - } - - public final String getSubFinal() { - return subFinal; - } - - public final void setSubFinal(String subFinal) { - this.subFinal = subFinal; - } - - public final Boolean getMultiValued() { - return multiValued; - } - - public Filter multiValued() { - this.multiValued = Boolean.TRUE; - return this; - } - - public Filter multiValued(Boolean multiValued) { - this.multiValued = multiValued; - return this; - } - - @Override - protected Filter clone() { - Filter clonedFilter = new Filter(type); - - clonedFilter.filters = this.filters; - clonedFilter.filterString = this.filterString; - clonedFilter.attributeName = this.attributeName; - clonedFilter.assertionValue = this.assertionValue; - clonedFilter.subInitial = this.subInitial; - clonedFilter.subAny = this.subAny; - clonedFilter.subFinal = this.subFinal; - clonedFilter.multiValued = this.multiValued; - - return clonedFilter; - } - - @Override - public String toString() { - if (FilterType.RAW == this.type) { - return this.filterString; - } - - StringBuilder sb = new StringBuilder("("); - - if ((FilterType.NOT == this.type) || (FilterType.AND == this.type) || (FilterType.OR == this.type)) { - if (this.filters != null) { - sb.append(this.type.getSign()); - for (Filter filter : filters) { - sb.append(filter.toString()); - } - sb.append(")"); - - return sb.toString(); - } - } - if ((FilterType.EQUALITY == this.type) || (FilterType.LESS_OR_EQUAL == this.type) - || (FilterType.GREATER_OR_EQUAL == this.type)) { - if (ArrayHelper.isNotEmpty(this.filters)) { - return sb.append(this.filters[0].toString()).append(this.type.getSign()).append(this.assertionValue).append(')') - .toString(); - } else { - return sb.append(this.attributeName).append(this.type.getSign()).append(this.assertionValue).append(')') - .toString(); - } - } - - if (FilterType.PRESENCE == this.type) { - return sb.append(this.attributeName).append("=").append(this.type.getSign()).append(')').toString(); - } - - if (FilterType.APPROXIMATE_MATCH == this.type) { - return sb.append(this.attributeName).append(this.type.getSign()).append("=").append(this.assertionValue) - .append(')').toString(); - } - - if (FilterType.SUBSTRING == this.type) { - sb.append(this.attributeName).append(this.type.getSign()); - if (this.subInitial != null) { - sb.append(this.subInitial); - sb.append('*'); - } - if (this.subAny != null) { - sb.append('*'); - for (final String s : subAny) { - sb.append(s); - sb.append('*'); - } - } - if (this.subFinal != null) { - sb.append('*'); - sb.append(this.subFinal); - } - sb.append(')'); - - return sb.toString().replaceAll("\\*\\*","*"); - } - - if (FilterType.LOWERCASE == this.type) { - return sb.append("lower(\"").append(this.attributeName).append("\")").toString(); - } - - return super.toString(); - } - -} diff --git a/persistence-filter/src/main/java/org/gluu/search/filter/FilterType.java b/persistence-filter/src/main/java/org/gluu/search/filter/FilterType.java deleted file mode 100644 index b0a0cda9..00000000 --- a/persistence-filter/src/main/java/org/gluu/search/filter/FilterType.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.gluu.search.filter; - -/** - * Filter operation types - * - * @author Yuriy Movchan Date: 2017/12/13 - */ -public enum FilterType { - - RAW(""), PRESENCE("*"), EQUALITY("="), LESS_OR_EQUAL("<="), GREATER_OR_EQUAL(">="), APPROXIMATE_MATCH("~"), SUBSTRING("="), NOT("!"), - OR("|"), AND("&"), LOWERCASE("lowercase"); - - private String sign; - - FilterType(String sign) { - this.sign = sign; - } - - public final String getSign() { - return sign; - } - -} diff --git a/persistence-hybrid/pom.xml b/persistence-hybrid/pom.xml deleted file mode 100644 index 7f4cea83..00000000 --- a/persistence-hybrid/pom.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - 4.0.0 - oxcore-persistence-hybrid - jar - persistence-hybrid - - - org.gluu - oxcore - 5.0.0-SNAPSHOT - - - - - - src/main/resources - true - - **/*.xml - **/services/* - **/*.properties - - - - - - - - - org.gluu - oxcore-util - - - org.gluu - oxcore-persistence-core - - - org.gluu - oxcore-persistence-cdi - - - - - javax.enterprise - cdi-api - provided - - - javax.inject - javax.inject - - - - - \ No newline at end of file diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java deleted file mode 100644 index bda530d1..00000000 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManager.java +++ /dev/null @@ -1,441 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.hybrid.impl; - -import java.io.Serializable; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; - -import org.gluu.persist.PersistenceEntryManager; -import org.gluu.persist.event.DeleteNotifier; -import org.gluu.persist.exception.KeyConversionException; -import org.gluu.persist.exception.MappingException; -import org.gluu.persist.exception.operation.ConfigurationException; -import org.gluu.persist.impl.BaseEntryManager; -import org.gluu.persist.key.impl.GenericKeyConverter; -import org.gluu.persist.key.impl.model.ParsedKey; -import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; -import org.gluu.persist.model.AttributeData; -import org.gluu.persist.model.AttributeDataModification; -import org.gluu.persist.model.BatchOperation; -import org.gluu.persist.model.PagedResult; -import org.gluu.persist.model.SearchScope; -import org.gluu.persist.model.SortOrder; -import org.gluu.persist.reflect.property.PropertyAnnotation; -import org.gluu.search.filter.Filter; -import org.gluu.util.ArrayHelper; -import org.gluu.util.StringHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Hybrid Entry Manager - * - * @author Yuriy Movchan Date: 07/10/2019 - */ -public class HybridEntryManager extends BaseEntryManager implements Serializable { - - private static final long serialVersionUID = -1544664410881103105L; - - private static final Logger LOG = LoggerFactory.getLogger(HybridEntryManager.class); - - private static final GenericKeyConverter KEY_CONVERTER = new GenericKeyConverter(); - - private Properties mappingProperties; - private HashMap persistenceEntryManagers; - private HybridPersistenceOperationService operationService; - - private PersistenceEntryManager defaultPersistenceEntryManager; - private HashMap baseNameToEntryManagerMapping; - - public HybridEntryManager() { - } - - public HybridEntryManager(Properties mappingProperties, HashMap persistenceEntryManagers, HybridPersistenceOperationService operationService) { - this.mappingProperties = mappingProperties; - this.persistenceEntryManagers = persistenceEntryManagers; - this.operationService = operationService; - - init(); - } - - protected void init() { - String defaultPersistenceType = mappingProperties.getProperty("storage.default", null); - if (StringHelper.isEmpty(defaultPersistenceType) || (persistenceEntryManagers.get(defaultPersistenceType) == null)) { - throw new ConfigurationException("Default persistence type is not defined!"); - } - this.defaultPersistenceEntryManager = persistenceEntryManagers.get(defaultPersistenceType); - - this.baseNameToEntryManagerMapping = new HashMap(); - for (Entry persistenceTypeEntry : persistenceEntryManagers.entrySet()) { - String mapping = mappingProperties.getProperty(String.format("storage.%s.mapping", persistenceTypeEntry.getKey()), ""); - String[] baseNames = StringHelper.split(mapping, ","); - for (String baseName : baseNames) { - baseNameToEntryManagerMapping.put(baseName, persistenceTypeEntry.getValue()); - } - } - } - - @Override - public void addDeleteSubscriber(DeleteNotifier subscriber) { - if (this.persistenceEntryManagers == null) { - return; - } - - for (PersistenceEntryManager persistenceEntryManager : persistenceEntryManagers.values()) { - persistenceEntryManager.addDeleteSubscriber(subscriber); - } - } - - @Override - public boolean authenticate(String bindDn, String password) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(bindDn); - return persistenceEntryManager.authenticate(bindDn, password); - } - - @Override - public boolean authenticate(String baseDN, Class entryClass, String userName, String password) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.authenticate(baseDN, entryClass, userName, password); - } - - @Override - public boolean contains(Object entry) { - Class entryClass = entry.getClass(); - Object dnValue = getDNValue(entry, entryClass); - - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(dnValue); - return persistenceEntryManager.contains(entry); - } - - @Override - public boolean contains(String primaryKey, Class entryClass) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(primaryKey); - return persistenceEntryManager.contains(primaryKey, entryClass); - } - @Override - public boolean contains(String baseDN, Class entryClass, Filter filter) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.contains(baseDN, entryClass, filter); - } - - @Override - public int countEntries(Object entry) { - Class entryClass = entry.getClass(); - Object dnValue = getDNValue(entry, entryClass); - - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(dnValue); - return persistenceEntryManager.countEntries(entry); - } - - @Override - public int countEntries(String baseDN, Class entryClass, Filter filter) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.countEntries(baseDN, entryClass, filter); - } - - @Override - public int countEntries(String baseDN, Class entryClass, Filter filter, SearchScope scope) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.countEntries(baseDN, entryClass, filter, scope); - } - - @Override - public Date decodeTime(String baseDN, String date) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.decodeTime(baseDN, date); - } - - @Override - public boolean destroy() { - if (this.persistenceEntryManagers == null) { - return true; - } - - boolean result = true; - for (PersistenceEntryManager persistenceEntryManager : persistenceEntryManagers.values()) { - try { - result &= persistenceEntryManager.destroy(); - } catch (Exception ex) { - LOG.error("Faild to destroy Persistence Entry Manager", ex); - } - } - - return result; - } - - @Override - public String encodeTime(String baseDN, Date date) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.encodeTime(baseDN, date); - } - - @Override - public List exportEntry(String dn) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(dn); - return persistenceEntryManager.exportEntry(dn); - } - - @Override - public void importEntry(String dn, List data) { - throw new UnsupportedOperationException("Method not implemented."); - } - - @Override - public T find(Class entryClass, Object primaryKey) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(primaryKey); - return persistenceEntryManager.find(entryClass, primaryKey); - } - - @Override - public T find(Object primaryKey, Class entryClass, String[] ldapReturnAttributes) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(primaryKey); - return persistenceEntryManager.find(primaryKey, entryClass, ldapReturnAttributes); - } - - @Override - public List findEntries(Object entry) { - Class entryClass = entry.getClass(); - Object dnValue = getDNValue(entry, entryClass); - - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(dnValue); - return persistenceEntryManager.findEntries(entry); - } - - @Override - public List findEntries(Object entry, int count) { - Class entryClass = entry.getClass(); - Object dnValue = getDNValue(entry, entryClass); - - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(dnValue); - return persistenceEntryManager.findEntries(entry, count); - } - - @Override - public List findEntries(String baseDN, Class entryClass, Filter filter) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.findEntries(baseDN, entryClass, filter); - } - - @Override - public List findEntries(String baseDN, Class entryClass, Filter filter, int count) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.findEntries(baseDN, entryClass, filter, count); - } - - @Override - public List findEntries(String baseDN, Class entryClass, Filter filter, SearchScope scope, String[] ldapReturnAttributes, - BatchOperation batchOperation, int start, int count, int chunkSize) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.findEntries(baseDN, entryClass, filter, scope, ldapReturnAttributes, batchOperation, start, count, - chunkSize); - } - - @Override - public List findEntries(String baseDN, Class entryClass, Filter filter, SearchScope scope, String[] ldapReturnAttributes, - int start, int count, int chunkSize) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.findEntries(baseDN, entryClass, filter, scope, ldapReturnAttributes, start, count, chunkSize); - } - - @Override - public List findEntries(String baseDN, Class entryClass, Filter filter, String[] ldapReturnAttributes) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.findEntries(baseDN, entryClass, filter, ldapReturnAttributes); - } - - @Override - public List findEntries(String baseDN, Class entryClass, Filter filter, String[] ldapReturnAttributes, int count) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.findEntries(baseDN, entryClass, filter, ldapReturnAttributes, count); - } - - @Override - public PagedResult findPagedEntries(String baseDN, Class entryClass, Filter filter, String[] ldapReturnAttributes, String sortBy, - SortOrder sortOrder, int start, int count, int chunkSize) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(baseDN); - return persistenceEntryManager.findPagedEntries(baseDN, entryClass, filter, ldapReturnAttributes, sortBy, - sortOrder, start, count, chunkSize); - } - - @Override - public boolean hasBranchesSupport(String dn) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(dn); - return persistenceEntryManager.hasBranchesSupport(dn); - } - - @Override - public boolean hasExpirationSupport(String dn) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(dn); - return persistenceEntryManager.hasExpirationSupport(dn); - } - - @Override - public String getPersistenceType() { - return HybridEntryManagerFactory.PERSISTENCE_TYPE; - } - - @Override - public String getPersistenceType(String primaryKey) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(primaryKey); - return persistenceEntryManager.getPersistenceType(primaryKey); - } - - @Override - public PersistenceEntryManager getPersistenceEntryManager(String persistenceType) { - PersistenceEntryManager persistenceEntryManager = persistenceEntryManagers.get(persistenceType); - if (persistenceEntryManager != null) { - return persistenceEntryManager; - } - - if (HybridEntryManagerFactory.PERSISTENCE_TYPE.equals(persistenceType)) { - return this; - } - - return null; - } - - private PersistenceEntryManager getPersistenceEntryManagerByKey(String key) { - if ("_".equals(key)) { - return defaultPersistenceEntryManager; - } - - String[] baseNameParts = key.split("_"); - if (ArrayHelper.isEmpty(baseNameParts)) { - throw new KeyConversionException("Failed to determine base key part!"); - } - - PersistenceEntryManager persistenceEntryManager = baseNameToEntryManagerMapping.get(baseNameParts[0]); - if (persistenceEntryManager != null) { - return persistenceEntryManager; - } - - return defaultPersistenceEntryManager; - } - - private PersistenceEntryManager getEntryManagerForDn(Object baseDn) { - if (StringHelper.isEmptyString(baseDn)) { - throw new MappingException("Entry DN is null"); - } - - return getEntryManagerForDn(baseDn.toString()); - } - - private PersistenceEntryManager getEntryManagerForDn(String baseDn) { - if (StringHelper.isEmpty(baseDn)) { - throw new MappingException("Entry DN is null"); - } - - ParsedKey parsedKey = KEY_CONVERTER.convertToKey(baseDn); - return getPersistenceEntryManagerByKey(parsedKey.getKey()); - } - - public HybridPersistenceOperationService getOperationService() { - return operationService; - } - - @Override - public Void merge(Object entry) { - Class entryClass = entry.getClass(); - Object dnValue = getDNValue(entry, entryClass); - - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(dnValue); - return persistenceEntryManager.merge(entry); - } - - @Override - public void persist(Object entry) { - Class entryClass = entry.getClass(); - Object dnValue = getDNValue(entry, entryClass); - - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(dnValue); - persistenceEntryManager.persist(entry); - } - - @Override - public void remove(Object entry) { - Class entryClass = entry.getClass(); - Object dnValue = getDNValue(entry, entryClass); - - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(dnValue); - persistenceEntryManager.remove(entry); - } - - @Override - public void remove(String primaryKey) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(primaryKey); - persistenceEntryManager.remove(primaryKey); - } - - @Override - public int remove(String primaryKey, Class entryClass, Filter filter, int count) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(primaryKey); - return persistenceEntryManager.remove(primaryKey, entryClass, filter, count); - } - - @Override - public void removeDeleteSubscriber(DeleteNotifier subscriber) { - if (this.persistenceEntryManagers == null) { - return; - } - - for (PersistenceEntryManager persistenceEntryManager : persistenceEntryManagers.values()) { - persistenceEntryManager.removeDeleteSubscriber(subscriber); - } - } - - @Override - public void removeRecursively(String dn) { - PersistenceEntryManager persistenceEntryManager = getEntryManagerForDn(dn); - persistenceEntryManager.removeRecursively(dn); - } - - //************************************************************************* - // Internal methods which not needed in Hybrid Entry Manager - //************************************************************************* - - @Override - protected void persist(String dn, List attributes, Integer expiration) { - throw new UnsupportedOperationException("Method not implemented."); - } - - @Override - protected void merge(String dn, List attributeDataModifications, Integer expiration) { - throw new UnsupportedOperationException("Method not implemented."); - } - - @Override - protected List find(String dn, Map propertiesAnnotationsMap, String... ldapReturnAttributes) { - throw new UnsupportedOperationException("Method not implemented."); - } - - @Override - protected boolean contains(String baseDN, Class entryClass, List propertiesAnnotations, Filter filter, String[] objectClasses, String[] ldapReturnAttributes) { - throw new UnsupportedOperationException("Method not implemented."); - } - - @Override - protected Date decodeTime(String date) { - throw new UnsupportedOperationException("Method not implemented."); - } - - @Override - protected String encodeTime(Date date) { - throw new UnsupportedOperationException("Method not implemented."); - } - - @Override - protected void updateMergeChanges(String baseDn, T entry, boolean isConfigurationUpdate, Class entryClass, - Map attributesFromLdapMap, List attributeDataModifications) { - throw new UnsupportedOperationException("Method not implemented."); - } - -} diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManagerFactory.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManagerFactory.java deleted file mode 100644 index 2a98e43d..00000000 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridEntryManagerFactory.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.gluu.persist.hybrid.impl; - -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import javax.enterprise.context.ApplicationScoped; -import javax.inject.Inject; - -import org.gluu.persist.PersistenceEntryManager; -import org.gluu.persist.PersistenceEntryManagerFactory; -import org.gluu.persist.exception.operation.ConfigurationException; -import org.gluu.persist.operation.PersistenceOperationService; -import org.gluu.persist.service.BaseFactoryService; -import org.gluu.util.PropertiesHelper; -import org.gluu.util.StringHelper; -import org.gluu.util.properties.FileConfiguration; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Hybrid Entry Manager Factory - * - * @author Yuriy Movchan Date: 05/13/2018 - */ -@ApplicationScoped -public class HybridEntryManagerFactory implements PersistenceEntryManagerFactory { - static { - if (System.getProperty("gluu.base") != null) { - BASE_DIR = System.getProperty("gluu.base"); - } else if ((System.getProperty("catalina.base") != null) && (System.getProperty("catalina.base.ignore") == null)) { - BASE_DIR = System.getProperty("catalina.base"); - } else if (System.getProperty("catalina.home") != null) { - BASE_DIR = System.getProperty("catalina.home"); - } else if (System.getProperty("jboss.home.dir") != null) { - BASE_DIR = System.getProperty("jboss.home.dir"); - } else { - BASE_DIR = null; - } - } - - public static final String BASE_DIR; - public static final String DIR = BASE_DIR + File.separator + "conf" + File.separator; - - public static final String PERSISTENCE_TYPE = "hybrid"; - public static final String PROPERTIES_FILE = "gluu-hybrid.properties"; - - private static final Logger LOG = LoggerFactory.getLogger(HybridEntryManagerFactory.class); - - @Inject - private BaseFactoryService persistanceFactoryService; - - private String[] persistenceTypes; - - private Properties hybridMappingProperties; - - @Override - public String getPersistenceType() { - return PERSISTENCE_TYPE; - } - - @Override - public HashMap getConfigurationFileNames() { - HashMap confs = new HashMap(); - confs.put(PERSISTENCE_TYPE, PROPERTIES_FILE); - - HashMap allConfs = getAllConfigurationFileNames(PROPERTIES_FILE); - confs.putAll(allConfs); - - return confs; - } - - private HashMap getAllConfigurationFileNames(String confFileName) { - HashMap allConfs = new HashMap(); - - FileConfiguration fileConf = new FileConfiguration(DIR + confFileName); - if (!fileConf.isLoaded()) { - LOG.error("Unable to load configuration file '{}'", DIR + confFileName); - throw new ConfigurationException(String.format("Unable to load configuration file: '%s'", fileConf)); - } - - String storagesList = fileConf.getString("storages", null); - if (StringHelper.isEmpty(storagesList)) { - throw new ConfigurationException("'storages' key not exists or value is empty!"); - } - - this.persistenceTypes = StringHelper.split(storagesList, ","); - for (String persistenceType : persistenceTypes) { - PersistenceEntryManagerFactory persistenceEntryManagerFactory = persistanceFactoryService.getPersistenceEntryManagerFactory(persistenceType); - if (persistenceEntryManagerFactory == null) { - throw new ConfigurationException(String.format("Unable to get Persistence Entry Manager Factory by type '%s'", persistenceType)); - } - - Map confs = persistenceEntryManagerFactory.getConfigurationFileNames(); - allConfs.putAll(confs); - } - - return allConfs; - } - - @Override - public HybridEntryManager createEntryManager(Properties conf) { - HashMap сonnectionProperties = new HashMap(); - - HashMap persistenceEntryManagers = new HashMap(); - List operationServices = new ArrayList(); - - for (String persistenceType : persistenceTypes) { - PersistenceEntryManagerFactory persistenceEntryManagerFactory = persistanceFactoryService.getPersistenceEntryManagerFactory(persistenceType); - if (persistenceEntryManagerFactory == null) { - throw new ConfigurationException(String.format("Unable to get Persistence Entry Manager Factory by type '%s'", persistenceType)); - } - - Properties entryManagerConf = PropertiesHelper.findProperties(conf, persistenceType); - PersistenceEntryManager persistenceEntryManager = persistenceEntryManagerFactory.createEntryManager(entryManagerConf); - - persistenceEntryManagers.put(persistenceType, persistenceEntryManager); - operationServices.add(persistenceEntryManager.getOperationService()); - - сonnectionProperties.put(persistenceType, entryManagerConf); - } - - this.hybridMappingProperties = PropertiesHelper.filterProperties(conf, PERSISTENCE_TYPE); - - HybridPersistenceOperationService hybridOperationService = new HybridPersistenceOperationService(operationServices); - - HybridEntryManager hybridEntryManager = new HybridEntryManager(hybridMappingProperties, persistenceEntryManagers, hybridOperationService); - LOG.info("Created HybridEntryManager: {}", hybridOperationService); - - return hybridEntryManager; - } - - @Override - public void initStandalone(BaseFactoryService persistanceFactoryService) { - this.persistanceFactoryService = persistanceFactoryService; - } - -} diff --git a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridPersistenceOperationService.java b/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridPersistenceOperationService.java deleted file mode 100644 index 4578e9a4..00000000 --- a/persistence-hybrid/src/main/java/org/gluu/persist/hybrid/impl/HybridPersistenceOperationService.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.gluu.persist.hybrid.impl; - -import java.util.List; - -import org.gluu.persist.exception.extension.PersistenceExtension; -import org.gluu.persist.operation.PersistenceOperationService; - -/** - * Hybrid Operation Service - * - * @author Yuriy Movchan Date: 05/13/2018 - */ -public class HybridPersistenceOperationService implements PersistenceOperationService { - - private List persistenceOperationServices; - - public HybridPersistenceOperationService(List persistenceOperationServices) { - this.persistenceOperationServices = persistenceOperationServices; - } - - @Override - public boolean isConnected() { - for(PersistenceOperationService persistenceOperationService : persistenceOperationServices) { - if (!persistenceOperationService.isConnected()) { - return false; - } - } - - return true; - } - - public List getPersistenceOperationServices() { - return persistenceOperationServices; - } - - @Override - public void setPersistenceExtension(PersistenceExtension persistenceExtension) { - for(PersistenceOperationService persistenceOperationService : persistenceOperationServices) { - persistenceOperationService.setPersistenceExtension(persistenceExtension); - } - } - -} diff --git a/persistence-hybrid/src/main/resources/META-INF/beans.xml b/persistence-hybrid/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 2f4f7e27..00000000 --- a/persistence-hybrid/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/persistence-ldap-sample/pom.xml b/persistence-ldap-sample/pom.xml deleted file mode 100644 index cda15b64..00000000 --- a/persistence-ldap-sample/pom.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - 4.0.0 - oxcore-persistence-ldap-sample - persistence-ldapSample - Sample project to show persistence-ldap functionality - - - org.gluu - oxcore - 5.0.0-SNAPSHOT - - - - ${maven.min-version} - - - - - org.gluu - oxcore-persistence-ldap - - - org.gluu - oxcore-persistence-annotation - - - - \ No newline at end of file diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSample.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSample.java deleted file mode 100644 index 27c2d7d0..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSample.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.gluu.ldap; - -import java.util.List; - -import org.apache.log4j.Logger; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.status.StatusLogger; -import org.gluu.ldap.model.SimpleAttribute; -import org.gluu.ldap.model.SimpleGrant; -import org.gluu.ldap.model.SimpleSession; -import org.gluu.ldap.model.SimpleUser; -import org.gluu.log.LoggingHelper; -import org.gluu.persist.ldap.impl.LdapEntryManager; -import org.gluu.persist.model.PagedResult; -import org.gluu.persist.model.SearchScope; -import org.gluu.persist.model.SortOrder; -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.search.filter.Filter; - -/** - * @author Yuriy Movchan Date: 11/03/2016 - */ -public final class LdapSample { - - private static final Logger LOG; - - static { - StatusLogger.getLogger().setLevel(Level.OFF); - LoggingHelper.configureConsoleAppender(); - LOG = Logger.getLogger(LdapSample.class); - } - - private LdapSample() { - } - - public static void main(String[] args) { - // Prepare sample connection details - LdapSampleEntryManager ldapSampleEntryManager = new LdapSampleEntryManager(); - - // Create LDAP entry manager - LdapEntryManager ldapEntryManager = ldapSampleEntryManager.createLdapEntryManager(); - - // Find all users which have specified object classes defined in SimpleUser - List users = ldapEntryManager.findEntries("o=gluu", SimpleUser.class, null); - for (SimpleUser user : users) { - LOG.debug("User with uid: " + user.getUserId()); - } - - if (users.size() > 0) { - // Add attribute "streetAddress" to first user - SimpleUser user = users.get(0); - user.getCustomAttributes().add(new CustomAttribute("streetAddress", "Somewhere: " + System.currentTimeMillis())); - - ldapEntryManager.merge(user); - } - - Filter filter = Filter.createEqualityFilter("gluuStatus", "active"); - List attributes = ldapEntryManager.findEntries("o=gluu", SimpleAttribute.class, filter, SearchScope.SUB, null, null, 10, 0, - 0); - for (SimpleAttribute attribute : attributes) { - LOG.debug("Attribute with displayName: " + attribute.getCustomAttributes().get(1)); - } - - List sessions = ldapEntryManager.findEntries("o=gluu", SimpleSession.class, filter, SearchScope.SUB, null, null, 10, 0, 0); - LOG.debug("Found sessions: " + sessions.size()); - - List grants = ldapEntryManager.findEntries("o=gluu", SimpleGrant.class, null, SearchScope.SUB, new String[] { "grtId" }, - null, 10, 0, 0); - LOG.debug("Found grants: " + grants.size()); - - try { - PagedResult vlvResponse = ldapEntryManager.findPagedEntries("o=gluu", SimpleUser.class, null, - new String[] { "uid", "displayName", "gluuStatus" }, "displayName", SortOrder.ASCENDING, 10, 100000, 1000); - - LOG.debug("Found persons: " + vlvResponse.getTotalEntriesCount()); - System.out.println(vlvResponse.getEntries().size()); - } catch (Exception ex) { - LOG.error("Failed to search", ex); - } - } - -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleBatchJob.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleBatchJob.java deleted file mode 100644 index e9302dac..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleBatchJob.java +++ /dev/null @@ -1,152 +0,0 @@ -package org.gluu.ldap; - -import com.unboundid.util.StaticUtils; -import org.apache.log4j.Logger; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.status.StatusLogger; -import org.gluu.ldap.model.SimpleClient; -import org.gluu.ldap.model.SimpleSession; -import org.gluu.ldap.model.SimpleTokenLdap; -import org.gluu.log.LoggingHelper; -import org.gluu.persist.exception.EntryPersistenceException; -import org.gluu.persist.ldap.impl.LdapEntryManager; -import org.gluu.persist.model.BatchOperation; -import org.gluu.persist.model.DefaultBatchOperation; -import org.gluu.persist.model.ProcessBatchOperation; -import org.gluu.persist.model.SearchScope; -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.search.filter.Filter; - -import java.text.ParseException; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Date; -import java.util.List; - -/** - * Created by eugeniuparvan on 1/12/17. - */ -public final class LdapSampleBatchJob { - private static final Logger LOG; - - static { - StatusLogger.getLogger().setLevel(Level.OFF); - LoggingHelper.configureConsoleAppender(); - LOG = Logger.getLogger(LdapSample.class); - } - - private LdapSampleBatchJob() { } - - public static void main(String[] args) { - // Prepare sample connection details - LdapSampleEntryManager ldapSampleEntryManager = new LdapSampleEntryManager(); - - // Create LDAP entry manager - final LdapEntryManager ldapEntryManager = ldapSampleEntryManager.createLdapEntryManager(); - - BatchOperation tokenLdapBatchOperation = new ProcessBatchOperation() { - private int processedCount = 0; - - @Override - public void performAction(List objects) { - for (SimpleTokenLdap simpleTokenLdap : objects) { - try { - CustomAttribute customAttribute = getUpdatedAttribute(ldapEntryManager, simpleTokenLdap.getDn(), "exp", - simpleTokenLdap.getAttribute("exp")); - simpleTokenLdap.setCustomAttributes(Arrays.asList(new CustomAttribute[] {customAttribute})); - ldapEntryManager.merge(simpleTokenLdap); - processedCount++; - } catch (EntryPersistenceException ex) { - LOG.error("Failed to update entry", ex); - } - } - - LOG.info("Total processed: " + processedCount); - } - }; - - final Filter filter1 = Filter.createPresenceFilter("exp"); - ldapEntryManager.findEntries("o=gluu", SimpleTokenLdap.class, filter1, SearchScope.SUB, new String[] {"exp"}, - tokenLdapBatchOperation, 0, 0, 100); - - BatchOperation sessionBatchOperation = new ProcessBatchOperation() { - private int processedCount = 0; - - @Override - public void performAction(List objects) { - for (SimpleSession simpleSession : objects) { - try { - CustomAttribute customAttribute = getUpdatedAttribute(ldapEntryManager, simpleSession.getDn(), "oxLastAccessTime", - simpleSession.getAttribute("oxLastAccessTime")); - simpleSession.setCustomAttributes(Arrays.asList(new CustomAttribute[] {customAttribute})); - ldapEntryManager.merge(simpleSession); - processedCount++; - } catch (EntryPersistenceException ex) { - LOG.error("Failed to update entry", ex); - } - } - - LOG.info("Total processed: " + processedCount); - } - }; - - final Filter filter2 = Filter.createPresenceFilter("oxLastAccessTime"); - ldapEntryManager.findEntries("o=gluu", SimpleSession.class, filter2, SearchScope.SUB, new String[] {"oxLastAccessTime"}, - sessionBatchOperation, 0, 0, 100); - - BatchOperation clientBatchOperation = new ProcessBatchOperation() { - private int processedCount = 0; - - @Override - public void performAction(List objects) { - for (SimpleClient simpleClient : objects) { - processedCount++; - } - - LOG.info("Total processed: " + processedCount); - } - }; - - final Filter filter3 = Filter.createPresenceFilter("exp"); - List result3 = ldapEntryManager.findEntries("o=gluu", SimpleClient.class, filter3, SearchScope.SUB, - new String[] {"exp"}, clientBatchOperation, 0, 0, 1000); - - LOG.info("Result count (without collecting results): " + result3.size()); - - BatchOperation clientBatchOperation2 = new DefaultBatchOperation() { - private int processedCount = 0; - - @Override - public void performAction(List objects) { - for (SimpleClient simpleClient : objects) { - processedCount++; - } - - LOG.info("Total processed: " + processedCount); - } - }; - - final Filter filter4 = Filter.createPresenceFilter("exp"); - List result4 = ldapEntryManager.findEntries("o=gluu", SimpleClient.class, filter4, SearchScope.SUB, - new String[] {"exp"}, clientBatchOperation2, 0, 0, 1000); - - LOG.info("Result count (with collecting results): " + result4.size()); - } - - private static CustomAttribute getUpdatedAttribute(LdapEntryManager ldapEntryManager, String baseDn, String attributeName, String attributeValue) { - try { - Calendar calendar = Calendar.getInstance(); - Date oxLastAccessTimeDate = StaticUtils.decodeGeneralizedTime(attributeValue); - calendar.setTime(oxLastAccessTimeDate); - calendar.add(Calendar.SECOND, -1); - - CustomAttribute customAttribute = new CustomAttribute(); - customAttribute.setName(attributeName); - customAttribute.setValue(ldapEntryManager.encodeTime(baseDn, calendar.getTime())); - return customAttribute; - } catch (ParseException e) { - LOG.error("Can't parse attribute", e); - } - return null; - } -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleDelete.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleDelete.java deleted file mode 100644 index b8e7cf13..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleDelete.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.gluu.ldap; - -import org.apache.log4j.Logger; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.status.StatusLogger; -import org.gluu.log.LoggingHelper; -import org.gluu.persist.ldap.impl.LdapEntryManager; -import org.gluu.persist.model.base.DeletableEntity; -import org.gluu.search.filter.Filter; - -import java.util.Date; - -/** - * @author Yuriy Movchan Date: 11/03/2016 - */ -public final class LdapSampleDelete { - - private static final Logger LOG; - - static { - StatusLogger.getLogger().setLevel(Level.OFF); - LoggingHelper.configureConsoleAppender(); - LOG = Logger.getLogger(LdapSampleDelete.class); - } - - private LdapSampleDelete() { - } - - public static void main(String[] args) { - // Prepare sample connection details - LdapSampleEntryManager ldapSampleEntryManager = new LdapSampleEntryManager(); - - // Create LDAP entry manager - LdapEntryManager ldapEntryManager = ldapSampleEntryManager.createLdapEntryManager(); - - String baseDn = "ou=cache,o=gluu"; - Filter filter = Filter.createANDFilter( - Filter.createEqualityFilter("del", true), - Filter.createLessOrEqualFilter("exp", ldapEntryManager.encodeTime(baseDn, new Date(System.currentTimeMillis() + 2 * 24 * 60 * 60 * 1000))) - ); - - int result = ldapEntryManager.remove(baseDn, DeletableEntity.class, filter, 100); - System.out.println(result); - } - -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleEntryManager.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleEntryManager.java deleted file mode 100644 index 3f65fd8c..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleEntryManager.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.gluu.ldap; - -import java.util.Properties; - -import org.apache.log4j.Logger; -import org.gluu.persist.ldap.impl.LdapEntryManager; -import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; - -/** - * @author Yuriy Movchan - * Date: 01/13/2017 - */ -public class LdapSampleEntryManager { - - private static final Logger LOG = Logger.getLogger(LdapSampleEntryManager.class); - - private Properties getSampleConnectionProperties() { - Properties connectionProperties = new Properties(); - - connectionProperties.put("ldap.bindDN", "cn=Directory Manager"); - connectionProperties.put("ldap.bindPassword", "test"); - connectionProperties.put("ldap.servers", "localhost:1636"); - connectionProperties.put("ldap.useSSL", "true"); - connectionProperties.put("ldap.maxconnections", "3"); - - return connectionProperties; - } - - public LdapEntryManager createLdapEntryManager() { - LdapEntryManagerFactory ldapEntryManagerFactory = new LdapEntryManagerFactory(); - Properties connectionProperties = getSampleConnectionProperties(); - - LdapEntryManager ldapEntryManager = ldapEntryManagerFactory.createEntryManager(connectionProperties); - LOG.debug("Created LdapEntryManager: " + ldapEntryManager); - - return ldapEntryManager; - } - -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleSimpleSessionSample.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleSimpleSessionSample.java deleted file mode 100644 index 920b9797..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/LdapSampleSimpleSessionSample.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.gluu.ldap; - -import java.util.Date; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; - -import org.apache.log4j.Logger; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.status.StatusLogger; -import org.gluu.ldap.model.SimpleSessionState; -import org.gluu.log.LoggingHelper; -import org.gluu.persist.ldap.impl.LdapEntryManager; - -/** - * @author Yuriy Movchan Date: 01/25/2016 - */ -public final class LdapSampleSimpleSessionSample { - - private static final Logger LOG; - - static { - StatusLogger.getLogger().setLevel(Level.OFF); - LoggingHelper.configureConsoleAppender(); - LOG = Logger.getLogger(LdapSampleSimpleSessionSample.class); - } - - private LdapSampleSimpleSessionSample() { - } - - public static void main(String[] args) throws InterruptedException { - // Prepare sample connection details - LdapSampleEntryManager ldapSampleEntryManager = new LdapSampleEntryManager(); - final LdapEntryManager ldapEntryManager = ldapSampleEntryManager.createLdapEntryManager(); - - try { - - // Create LDAP entry manager - String sessionId = "xyzcyzxy-a41a-45ad-8a83-61485dbad561"; - final String sessionDn = "uniqueIdentifier=" + sessionId + ",ou=session,o=gluu"; - final String userDn = - "inum=@!E8F2.853B.1E7B.ACE2!0001!39A4.C163!0000!A8F2.DE1E.D7FB,ou=people,o=gluu"; - - final SimpleSessionState simpleSessionState = new SimpleSessionState(); - simpleSessionState.setDn(sessionDn); - simpleSessionState.setId(sessionId); - simpleSessionState.setLastUsedAt(new Date()); - - ldapEntryManager.persist(simpleSessionState); - System.out.println("Persisted"); - - int threadCount = 500; - ExecutorService executorService = Executors.newFixedThreadPool(threadCount, daemonThreadFactory()); - for (int i = 0; i < threadCount; i++) { - final int count = i; - executorService.execute(new Runnable() { - @Override - public void run() { - final SimpleSessionState simpleSessionStateFromLdap = ldapEntryManager.find(SimpleSessionState.class, sessionDn); - String beforeUserDn = simpleSessionStateFromLdap.getUserDn(); - String randomUserDn = count % 2 == 0 ? userDn : ""; - - try { - simpleSessionStateFromLdap.setUserDn(randomUserDn); - simpleSessionStateFromLdap.setLastUsedAt(new Date()); - ldapEntryManager.merge(simpleSessionStateFromLdap); - System.out.println("Merged thread: " + count + ", userDn: " + randomUserDn + ", before userDn: " + beforeUserDn); - } catch (Throwable e) { - System.out.println("ERROR !!!, thread: " + count + ", userDn: " + randomUserDn + ", before userDn: " + beforeUserDn - + ", error:" + e.getMessage()); - // e.printStackTrace(); - } - } - }); - } - - Thread.sleep(5000L); - } finally { - ldapEntryManager.getOperationService().getConnectionPool().close(); - } - } - - public static ThreadFactory daemonThreadFactory() { - return new ThreadFactory() { - public Thread newThread(Runnable runnable) { - Thread thread = new Thread(runnable); - thread.setDaemon(true); - return thread; - } - }; - } - -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/MailUniquenessConfigurationSample.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/MailUniquenessConfigurationSample.java deleted file mode 100644 index 9d67bfae..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/MailUniquenessConfigurationSample.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.gluu.ldap; - -import java.util.List; - -import org.apache.log4j.Logger; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.status.StatusLogger; -import org.gluu.ldap.model.MailUniquenessConfiguration; -import org.gluu.ldap.model.SimpleAttribute; -import org.gluu.ldap.model.SimpleGrant; -import org.gluu.ldap.model.SimpleSession; -import org.gluu.ldap.model.SimpleUser; -import org.gluu.log.LoggingHelper; -import org.gluu.persist.ldap.impl.LdapEntryManager; -import org.gluu.persist.model.PagedResult; -import org.gluu.persist.model.SearchScope; -import org.gluu.persist.model.SortOrder; -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.search.filter.Filter; - -/** - * @author Yuriy Movchan Date: 11/03/2016 - */ -public final class MailUniquenessConfigurationSample { - - private static final Logger LOG; - - static { - StatusLogger.getLogger().setLevel(Level.OFF); - LoggingHelper.configureConsoleAppender(); - LOG = Logger.getLogger(MailUniquenessConfigurationSample.class); - } - - private MailUniquenessConfigurationSample() { - } - - public static void main(String[] args) { - // Prepare sample connection details - LdapSampleEntryManager ldapSampleEntryManager = new LdapSampleEntryManager(); - - // Create LDAP entry manager - LdapEntryManager ldapEntryManager = ldapSampleEntryManager.createLdapEntryManager(); - - MailUniquenessConfiguration conf = ldapEntryManager.find("cn=Unique mail address,cn=Plugins,cn=config", MailUniquenessConfiguration.class, null); - System.out.println("Current mail uniqueness: " + conf.isEnabled()); - - conf.setEnabled(!conf.isEnabled()); - - // Upate configuration in LDAP - ldapEntryManager.merge(conf); - - MailUniquenessConfiguration conf2 = ldapEntryManager.find("cn=Unique mail address,cn=Plugins,cn=config", MailUniquenessConfiguration.class, null); - System.out.println("After update mail uniqueness: " + conf2.isEnabled()); - } - -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/MailUniquenessConfiguration.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/MailUniquenessConfiguration.java deleted file mode 100644 index 71dcb243..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/MailUniquenessConfiguration.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.ldap.model; - -import java.io.Serializable; - -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; - -/** - * @author Yuriy Movchan - * Date: 12/17/2019 - */ -@DataEntry(configurationDefinition = true) -@ObjectClass(value = "ds-cfg-plugin") -public class MailUniquenessConfiguration implements Serializable { - - private static final long serialVersionUID = -1634191420188575733L; - - @DN - private String dn; - - @AttributeName(name = "ds-cfg-enabled") - private boolean enabled; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public boolean isEnabled() { - return enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleAttribute.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleAttribute.java deleted file mode 100644 index 6f3ee866..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleAttribute.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.ldap.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.util.StringHelper; - -/** - * @author Yuriy Movchan - * Date: 12/30/2016 - */ -@DataEntry -@ObjectClass(value = "gluuAttribute") -public class SimpleAttribute implements Serializable { - - private static final long serialVersionUID = -1634191420188575733L; - - @DN - private String dn; - - @AttributesList(name = "name", value = "values", sortByName = true) - private List customAttributes = new ArrayList(); - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String getAttribute(String ldapAttribute) { - String attribute = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(ldapAttribute)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String ldapAttribute) { - List values = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), ldapAttribute)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleClient.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleClient.java deleted file mode 100644 index f3418c6c..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleClient.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.ldap.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.util.StringHelper; - -/** - * @author Yuriy Movchan - * Date: 02/08/2018 - */ -@DataEntry -@ObjectClass(value = "oxAuthClient") -public class SimpleClient implements Serializable { - - private static final long serialVersionUID = -2534191420188575733L; - - @DN - private String dn; - - @AttributesList(name = "name", value = "values", sortByName = true) - private List customAttributes = new ArrayList(); - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String getAttribute(String ldapAttribute) { - String attribute = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(ldapAttribute)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String ldapAttribute) { - List values = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), ldapAttribute)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleGrant.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleGrant.java deleted file mode 100644 index 1ef8638c..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleGrant.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.ldap.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.util.StringHelper; - -/** - * @author Yuriy Movchan - * Date: 12/30/2016 - */ -@DataEntry -@ObjectClass(value = "oxAuthGrant") -public class SimpleGrant implements Serializable { - - private static final long serialVersionUID = -1234191420188575733L; - - @DN - private String dn; - - @AttributesList(name = "name", value = "values", sortByName = true) - private List customAttributes = new ArrayList(); - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String getAttribute(String ldapAttribute) { - String attribute = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(ldapAttribute)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String ldapAttribute) { - List values = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), ldapAttribute)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleSession.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleSession.java deleted file mode 100644 index 53b33daf..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleSession.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.ldap.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.util.StringHelper; - -/** - * @author Yuriy Movchan - * Date: 12/30/2016 - */ -@DataEntry -@ObjectClass(value = "oxAuthSessionId") -public class SimpleSession implements Serializable { - - private static final long serialVersionUID = -1534191420188575733L; - - @DN - private String dn; - - @AttributesList(name = "name", value = "values", sortByName = true) - private List customAttributes = new ArrayList(); - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String getAttribute(String ldapAttribute) { - String attribute = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(ldapAttribute)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String ldapAttribute) { - List values = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), ldapAttribute)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleSessionState.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleSessionState.java deleted file mode 100644 index 9f03df61..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleSessionState.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.ldap.model; - -import java.io.Serializable; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; - -import javax.persistence.Transient; - -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.JsonObject; -import org.gluu.persist.annotation.ObjectClass; - -/** - * @author Yuriy Zabrovarnyy - * @author Javier Rojas Blum - * @version December 15, 2015 - */ -@DataEntry -@ObjectClass(value = "oxAuthSessionId") -public class SimpleSessionState implements Serializable { - - private static final long serialVersionUID = -237476411915686378L; - - @DN - private String dn; - - @AttributeName(name = "uniqueIdentifier") - private String id; - - @AttributeName(name = "oxLastAccessTime") - private Date lastUsedAt; - - @AttributeName(name = "oxAuthUserDN") - private String userDn; - - @AttributeName(name = "authnTime") - private Date authenticationTime; - - @AttributeName(name = "oxAuthSessionState") - private Boolean permissionGranted; - - @AttributeName(name = "oxAsJwt") - private Boolean isJwt = false; - - @AttributeName(name = "oxJwt") - private String jwt; - - @JsonObject - @AttributeName(name = "oxAuthSessionAttribute") - private Map sessionAttributes; - - @Transient - private transient boolean persisted; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public String getJwt() { - return jwt; - } - - public void setJwt(String jwt) { - this.jwt = jwt; - } - - public Boolean getIsJwt() { - return isJwt; - } - - public void setIsJwt(Boolean isJwt) { - this.isJwt = isJwt; - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public Date getLastUsedAt() { - return lastUsedAt != null ? new Date(lastUsedAt.getTime()) : null; - } - - public void setLastUsedAt(Date lastUsedAt) { - this.lastUsedAt = lastUsedAt != null ? new Date(lastUsedAt.getTime()) : null; - } - - public String getUserDn() { - return userDn; - } - - public void setUserDn(String userDn) { - this.userDn = userDn != null ? userDn : ""; - } - - public Date getAuthenticationTime() { - return authenticationTime != null ? new Date(authenticationTime.getTime()) : null; - } - - public void setAuthenticationTime(Date authenticationTime) { - this.authenticationTime = authenticationTime != null ? new Date(authenticationTime.getTime()) : null; - } - - public Boolean getPermissionGranted() { - return permissionGranted; - } - - public void setPermissionGranted(Boolean permissionGranted) { - this.permissionGranted = permissionGranted; - } - - public Map getSessionAttributes() { - if (sessionAttributes == null) { - sessionAttributes = new HashMap(); - } - return sessionAttributes; - } - - public void setSessionAttributes(Map sessionAttributes) { - this.sessionAttributes = sessionAttributes; - } - - public boolean isPersisted() { - return persisted; - } - - public void setPersisted(boolean persisted) { - this.persisted = persisted; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - SimpleSessionState id1 = (SimpleSessionState) o; - - return !(id != null ? !id.equals(id1.id) : id1.id != null); - } - - @Override - public int hashCode() { - return id != null ? id.hashCode() : 0; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(); - sb.append("SessionState"); - sb.append(", dn='").append(dn).append('\''); - sb.append(", id='").append(id).append('\''); - sb.append(", isJwt=").append(isJwt); - sb.append(", lastUsedAt=").append(lastUsedAt); - sb.append(", userDn='").append(userDn).append('\''); - sb.append(", authenticationTime=").append(authenticationTime); - sb.append(", permissionGranted=").append(permissionGranted); - sb.append(", sessionAttributes=").append(sessionAttributes); - sb.append(", persisted=").append(persisted); - sb.append('}'); - return sb.toString(); - } - -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleTokenLdap.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleTokenLdap.java deleted file mode 100644 index 75098892..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleTokenLdap.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.gluu.ldap.model; - -import org.gluu.persist.annotation.*; -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.util.StringHelper; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -/** - * Created by eugeniuparvan on 1/12/17. - */ -@DataEntry -@ObjectClass(value = "token") -public class SimpleTokenLdap implements Serializable { - - @AttributesList(name = "name", value = "values", sortByName = true) - private List customAttributes = new ArrayList(); - - @DN - private String dn; - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String getAttribute(String ldapAttribute) { - String attribute = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(ldapAttribute)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String ldapAttribute) { - List values = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), ldapAttribute)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleUser.java b/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleUser.java deleted file mode 100644 index 4dc9516f..00000000 --- a/persistence-ldap-sample/src/main/java/org/gluu/ldap/model/SimpleUser.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.ldap.model; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.model.base.CustomAttribute; -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.util.StringHelper; - -/** - * @author Yuriy Movchan - * Date: 11/03/2016 - */ -@DataEntry(sortBy = { "userId" }) -@ObjectClass(value = "gluuPerson") -public class SimpleUser implements Serializable { - - private static final long serialVersionUID = -1634191420188575733L; - - @DN - private String dn; - - @AttributeName(name = "uid") - private String userId; - - @AttributesList(name = "name", value = "values", sortByName = true) - private List customAttributes = new ArrayList(); - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String getAttribute(String ldapAttribute) { - String attribute = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(ldapAttribute)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String ldapAttribute) { - List values = null; - if (ldapAttribute != null && !ldapAttribute.isEmpty()) { - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), ldapAttribute)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-ldap/pom.xml b/persistence-ldap/pom.xml deleted file mode 100644 index 55bbc150..00000000 --- a/persistence-ldap/pom.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - 4.0.0 - oxcore-persistence-ldap - jar - persistence-ldap - - - org.gluu - oxcore - 5.0.0-SNAPSHOT - - - - - - src/main/resources - true - - **/*.xml - **/services/* - **/*.properties - - - - - - - - - org.gluu - oxcore-util - - - org.gluu - oxcore-persistence-filter - - - org.gluu - oxcore-persistence-core - - - org.gluu - oxcore-persistence-annotation - - - - com.unboundid - unboundid-ldapsdk - - - - - javax.enterprise - cdi-api - provided - - - javax.inject - javax.inject - - - - - \ No newline at end of file diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/exception/InvalidSimplePageControlException.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/exception/InvalidSimplePageControlException.java deleted file mode 100644 index 94197b0f..00000000 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/exception/InvalidSimplePageControlException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.ldap.exception; - -import org.gluu.persist.exception.operation.PersistenceException; - -import com.unboundid.ldap.sdk.ResultCode; - -/** - * Invalid page control LDAP exception -- thrown when Simple Page Control returns result without cookie - * - * @author Yuriy Movchan Date: 12/30/2016 - */ -public class InvalidSimplePageControlException extends PersistenceException { - - private static final long serialVersionUID = 1756816743469359856L; - - private ResultCode resultCode; - - public InvalidSimplePageControlException(String message) { - super(message); - } - - public InvalidSimplePageControlException(ResultCode resultCode, String message) { - super(message); - - this.resultCode = resultCode; - } - - public ResultCode getResultCode() { - return resultCode; - } - -} diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapBatchOperationWraper.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapBatchOperationWraper.java deleted file mode 100644 index f7116a4a..00000000 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapBatchOperationWraper.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.gluu.persist.ldap.impl; - -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.model.BatchOperation; -import org.gluu.persist.reflect.property.PropertyAnnotation; - -import com.unboundid.ldap.sdk.SearchResult; -import com.unboundid.ldap.sdk.SearchResultEntry; - -/** - * LDAP batch operation wrapper - * - * @author Yuriy Movchan Date: 02/07/2010 - */ -public class LdapBatchOperationWraper { - - private LdapEntryManager ldapEntryManager; - private Class entryClass; - private List propertiesAnnotations; - - private BatchOperation batchOperation; - - public LdapBatchOperationWraper(BatchOperation batchOperation) { - this.batchOperation = batchOperation; - } - - public LdapBatchOperationWraper(BatchOperation batchOperation, LdapEntryManager ldapEntryManager, Class entryClass, - List propertiesAnnotations) { - this.batchOperation = batchOperation; - this.ldapEntryManager = ldapEntryManager; - this.entryClass = entryClass; - this.propertiesAnnotations = propertiesAnnotations; - } - - public final BatchOperation getBatchOperation() { - return batchOperation; - } - - public List createEntities(SearchResult searchResult) { - if (ldapEntryManager == null) { - return new ArrayList(0); - } - SearchResultEntry[] searchResultEntry = searchResult.getSearchEntries() - .toArray(new SearchResultEntry[searchResult.getSearchEntries().size()]); - - return ldapEntryManager.createEntities(entryClass, propertiesAnnotations, searchResultEntry); - } - -} diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java deleted file mode 100644 index b42915dc..00000000 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManager.java +++ /dev/null @@ -1,1008 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.ldap.impl; - -import java.io.Serializable; -import java.text.ParseException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.commons.codec.binary.Base64; -import org.gluu.persist.PersistenceEntryManager; -import org.gluu.persist.event.DeleteNotifier; -import org.gluu.persist.exception.AuthenticationException; -import org.gluu.persist.exception.EntryDeleteException; -import org.gluu.persist.exception.EntryPersistenceException; -import org.gluu.persist.exception.MappingException; -import org.gluu.persist.exception.operation.ConnectionException; -import org.gluu.persist.exception.operation.SearchException; -import org.gluu.persist.exception.operation.SearchScopeException; -import org.gluu.persist.impl.BaseEntryManager; -import org.gluu.persist.ldap.operation.LdapOperationService; -import org.gluu.persist.ldap.operation.impl.LdapOperationServiceImpl; -import org.gluu.persist.model.AttributeData; -import org.gluu.persist.model.AttributeDataModification; -import org.gluu.persist.model.AttributeDataModification.AttributeModificationType; -import org.gluu.persist.model.BatchOperation; -import org.gluu.persist.model.DefaultBatchOperation; -import org.gluu.persist.model.PagedResult; -import org.gluu.persist.model.SearchScope; -import org.gluu.persist.model.SortOrder; -import org.gluu.persist.reflect.property.PropertyAnnotation; -import org.gluu.search.filter.Filter; -import org.gluu.util.ArrayHelper; -import org.gluu.util.StringHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.unboundid.ldap.sdk.Attribute; -import com.unboundid.ldap.sdk.LDAPConnection; -import com.unboundid.ldap.sdk.Modification; -import com.unboundid.ldap.sdk.ModificationType; -import com.unboundid.ldap.sdk.ResultCode; -import com.unboundid.ldap.sdk.SearchResult; -import com.unboundid.ldap.sdk.SearchResultEntry; -import com.unboundid.util.StaticUtils; - -/** - * LDAP Entry Manager - * - * @author Yuriy Movchan Date: 10.07.2010 - */ -public class LdapEntryManager extends BaseEntryManager implements Serializable { - - private static final long serialVersionUID = -2544614410981223105L; - - private static final Logger LOG = LoggerFactory.getLogger(LdapEntryManager.class); - - private static final LdapFilterConverter LDAP_FILTER_CONVERTER = new LdapFilterConverter(); - private static final LdapSearchScopeConverter LDAP_SEARCH_SCOPE_CONVERTER = new LdapSearchScopeConverter(); - - private List subscribers; - - public LdapEntryManager() { - } - - public LdapEntryManager(LdapOperationServiceImpl operationService) { - this.operationService = operationService; - this.subscribers = new LinkedList(); - } - - @Override - public boolean destroy() { - if (this.operationService == null) { - return true; - } - - return getOperationService().destroy(); - } - - public LdapOperationServiceImpl getOperationService() { - return (LdapOperationServiceImpl) operationService; - } - - @Override - public void addDeleteSubscriber(DeleteNotifier subscriber) { - subscribers.add(subscriber); - } - - @Override - public void removeDeleteSubscriber(DeleteNotifier subscriber) { - subscribers.remove(subscriber); - } - - @Override - public Void merge(Object entry) { - Class entryClass = entry.getClass(); - checkEntryClass(entryClass, true); - if (isSchemaEntry(entryClass)) { - if (getSupportedLDAPVersion() > 2) { - return merge(entry, true, false, AttributeModificationType.ADD); - } else { - throw new UnsupportedOperationException("Server doesn't support dynamic schema modifications"); - } - } else { - boolean configurationEntry = isConfigurationEntry(entryClass); - return merge(entry, false, configurationEntry, null); - } - } - - @Override - protected void updateMergeChanges(String baseDn, T entry, boolean isConfigurationUpdate, Class entryClass, Map attributesFromLdapMap, - List attributeDataModifications) { - // Update object classes if entry contains custom object classes - if (getSupportedLDAPVersion() > 2) { - if (!isConfigurationUpdate) { - String[] objectClasses = getObjectClasses(entry, entryClass); - String[] objectClassesFromLdap = attributesFromLdapMap.get(OBJECT_CLASS.toLowerCase()).getStringValues(); - - if (!Arrays.equals(objectClassesFromLdap, objectClasses)) { - attributeDataModifications.add(new AttributeDataModification(AttributeModificationType.REPLACE, - new AttributeData(OBJECT_CLASS, objectClasses), new AttributeData(OBJECT_CLASS, objectClassesFromLdap))); - } - } - } - } - - @Override - public void remove(Object entry) { - Class entryClass = entry.getClass(); - checkEntryClass(entryClass, true); - if (isSchemaEntry(entryClass)) { - if (getSupportedLDAPVersion() > 2) { - merge(entry, true, false, AttributeModificationType.REMOVE); - } else { - throw new UnsupportedOperationException("Server doesn't support dynamic schema modifications"); - } - return; - } - - Object dnValue = getDNValue(entry, entryClass); - - LOG.debug(String.format("LDAP entry to remove: %s", dnValue.toString())); - - remove(dnValue.toString()); - } - - protected void persist(String dn, List attributes) { - persist(dn, attributes); - } - - @Override - protected void persist(String dn, List attributes, Integer expiration) { - List ldapAttributes = new ArrayList(attributes.size()); - for (AttributeData attribute : attributes) { - String attributeName = attribute.getName(); - String[] attributeValues = attribute.getStringValues(); - - if (ArrayHelper.isNotEmpty(attributeValues) && StringHelper.isNotEmpty(attributeValues[0])) { - if (getOperationService().isCertificateAttribute(attributeName)) { - byte[][] binaryValues = toBinaryValues(attributeValues); - - ldapAttributes.add(new Attribute(attributeName + ";binary", binaryValues)); - } else { - ldapAttributes.add(new Attribute(attributeName, attributeValues)); - } - } - } - - // Persist entry - try { - boolean result = getOperationService().addEntry(dn, ldapAttributes); - if (!result) { - throw new EntryPersistenceException(String.format("Failed to persist entry: %s", dn)); - } - } catch (ConnectionException ex) { - throw new EntryPersistenceException(String.format("Failed to persist entry: %s", dn), ex.getCause()); - } catch (Exception ex) { - throw new EntryPersistenceException(String.format("Failed to persist entry: %s", dn), ex); - } - } - - @Override - public void merge(String dn, List attributeDataModifications, Integer expiration) { - // Update entry - try { - List modifications = new ArrayList(attributeDataModifications.size()); - for (AttributeDataModification attributeDataModification : attributeDataModifications) { - AttributeData attribute = attributeDataModification.getAttribute(); - AttributeData oldAttribute = attributeDataModification.getOldAttribute(); - - String attributeName = null; - String[] attributeValues = null; - if (attribute != null) { - attributeName = attribute.getName(); - attributeValues = attribute.getStringValues(); - } - - String oldAttributeName = null; - String[] oldAttributeValues = null; - if (oldAttribute != null) { - oldAttributeName = oldAttribute.getName(); - oldAttributeValues = oldAttribute.getStringValues(); - } - - Modification modification = null; - if (AttributeModificationType.ADD.equals(attributeDataModification.getModificationType())) { - modification = createModification(ModificationType.ADD, attributeName, attributeValues); - } else { - if (AttributeModificationType.REMOVE.equals(attributeDataModification.getModificationType())) { - modification = createModification(ModificationType.DELETE, oldAttributeName, oldAttributeValues); - } else if (AttributeModificationType.REPLACE.equals(attributeDataModification.getModificationType())) { - if (attributeValues.length == 1) { - modification = createModification(ModificationType.REPLACE, attributeName, attributeValues); - } else { - String[] oldValues = ArrayHelper.arrayClone(oldAttributeValues); - String[] newValues = ArrayHelper.arrayClone(attributeValues); - - Arrays.sort(oldValues); - Arrays.sort(newValues); - - boolean[] retainOldValues = new boolean[oldValues.length]; - Arrays.fill(retainOldValues, false); - - List addValues = new ArrayList(); - List removeValues = new ArrayList(); - - // Add new values - for (String value : newValues) { - int idx = Arrays.binarySearch(oldValues, value, new Comparator() { - @Override - public int compare(String o1, String o2) { - return o1.toLowerCase().compareTo(o2.toLowerCase()); - } - }); - if (idx >= 0) { - // Old values array contains new value. Retain - // old value - retainOldValues[idx] = true; - } else { - // This is new value - addValues.add(value); - } - } - - // Remove values which we don't have in new values - for (int i = 0; i < oldValues.length; i++) { - if (!retainOldValues[i]) { - removeValues.add(oldValues[i]); - } - } - - if (removeValues.size() > 0) { - Modification removeModification = createModification(ModificationType.DELETE, attributeName, - removeValues.toArray(new String[removeValues.size()])); - modifications.add(removeModification); - } - - if (addValues.size() > 0) { - Modification addModification = createModification(ModificationType.ADD, attributeName, - addValues.toArray(new String[addValues.size()])); - modifications.add(addModification); - } - } - } - } - - if (modification != null) { - modifications.add(modification); - } - } - - if (modifications.size() > 0) { - boolean result = getOperationService().updateEntry(dn, modifications); - if (!result) { - throw new EntryPersistenceException(String.format("Failed to update entry: %s", dn)); - } - } - } catch (ConnectionException ex) { - throw new EntryPersistenceException(String.format("Failed to update entry: %s", dn), ex.getCause()); - } catch (Exception ex) { - throw new EntryPersistenceException(String.format("Failed to update entry: %s", dn), ex); - } - } - - @Override - public void remove(String dn) { - // Remove entry - try { - for (DeleteNotifier subscriber : subscribers) { - subscriber.onBeforeRemove(dn); - } - getOperationService().delete(dn); - for (DeleteNotifier subscriber : subscribers) { - subscriber.onAfterRemove(dn); - } - } catch (Exception ex) { - throw new EntryDeleteException(String.format("Failed to remove entry: %s", dn), ex); - } - } - - @Override - public int remove(String baseDN, Class entryClass, Filter filter, int count) { - if (StringHelper.isEmptyString(baseDN)) { - throw new MappingException("Base DN to find entries is null"); - } - - // Check entry class - checkEntryClass(entryClass, false); - String[] objectClasses = getTypeObjectClasses(entryClass); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - - // Find entries - Filter searchFilter; - if (objectClasses.length > 0) { - searchFilter = addObjectClassFilter(filter, objectClasses); - } else { - searchFilter = filter; - } - - DeleteBatchOperation batchOperation = new DeleteBatchOperation(this); - SearchResult searchResult = null; - try { - LdapBatchOperationWraper batchOperationWraper = new LdapBatchOperationWraper(batchOperation, this, entryClass, - propertiesAnnotations); - searchResult = getOperationService().search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(SearchScope.SUB), batchOperationWraper, - 0, 100, count, null, LdapOperationService.DN); - - } catch (Exception ex) { - throw new EntryDeleteException(String.format("Failed to delete entries with baseDN: %s, filter: %s", baseDN, searchFilter), ex); - } - - if (!ResultCode.SUCCESS.equals(searchResult.getResultCode())) { - throw new EntryDeleteException(String.format("Failed to delete entries with baseDN: %s, filter: %s", baseDN, searchFilter)); - } - - return batchOperation.getCountEntries(); - } - - @Override - public void removeRecursively(String dn) { - try { - if (getOperationService().getConnectionProvider().isSupportsSubtreeDeleteRequestControl()) { - for (DeleteNotifier subscriber : subscribers) { - subscriber.onBeforeRemove(dn); - } - getOperationService().deleteRecursively(dn); - for (DeleteNotifier subscriber : subscribers) { - subscriber.onAfterRemove(dn); - } - } else { - removeSubtreeThroughIteration(dn); - } - } catch (Exception ex) { - throw new EntryDeleteException(String.format("Failed to remove entry: %s", dn), ex); - } - } - - private void removeSubtreeThroughIteration(String dn) { - SearchScope scope = SearchScope.SUB; - - SearchResult searchResult = null; - try { - searchResult = getOperationService().search(dn, toLdapFilter(Filter.createPresenceFilter("objectClass")), toLdapSearchScope(scope), null, 0, 0, 0, null, "dn"); - if (!ResultCode.SUCCESS.equals(searchResult.getResultCode())) { - throw new EntryPersistenceException(String.format("Failed to find sub-entries of entry '%s' for removal", dn)); - } - } catch (SearchScopeException ex) { - throw new AuthenticationException(String.format("Failed to convert scope: %s", scope), ex); - } catch (SearchException ex) { - throw new EntryDeleteException(String.format("Failed to find sub-entries of entry '%s' for removal", dn), ex); - } - - List removeEntriesDn = new ArrayList(searchResult.getEntryCount()); - for (SearchResultEntry searchResultEntry : searchResult.getSearchEntries()) { - removeEntriesDn.add(searchResultEntry.getDN()); - } - - Collections.sort(removeEntriesDn, LINE_LENGHT_COMPARATOR); - - for (String removeEntryDn : removeEntriesDn) { - remove(removeEntryDn); - } - } - - @Override - protected List find(String dn, Map propertiesAnnotationsMap, String... ldapReturnAttributes) { - try { - // Load entry - SearchResultEntry entry = getOperationService().lookup(dn, ldapReturnAttributes); - List result = getAttributeDataList(entry); - if (result != null) { - return result; - } - } catch (Exception ex) { - throw new EntryPersistenceException(String.format("Failed to find entry: %s", dn), ex); - } - - throw new EntryPersistenceException(String.format("Failed to find entry: %s", dn)); - } - - @Override - public List findEntries(String baseDN, Class entryClass, Filter filter, SearchScope scope, String[] ldapReturnAttributes, - BatchOperation batchOperation, int start, int count, int chunkSize) { - if (StringHelper.isEmptyString(baseDN)) { - throw new MappingException("Base DN to find entries is null"); - } - - // Check entry class - checkEntryClass(entryClass, false); - String[] objectClasses = getTypeObjectClasses(entryClass); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - String[] currentLdapReturnAttributes = ldapReturnAttributes; - if (ArrayHelper.isEmpty(currentLdapReturnAttributes)) { - currentLdapReturnAttributes = getAttributes(null, propertiesAnnotations, false); - } - - // Find entries - Filter searchFilter; - if (objectClasses.length > 0) { - searchFilter = addObjectClassFilter(filter, objectClasses); - } else { - searchFilter = filter; - } - SearchResult searchResult = null; - try { - LdapBatchOperationWraper batchOperationWraper = new LdapBatchOperationWraper(batchOperation, this, entryClass, - propertiesAnnotations); - searchResult = getOperationService().search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(scope), batchOperationWraper, - start, chunkSize, count, null, currentLdapReturnAttributes); - } catch (Exception ex) { - throw new EntryPersistenceException(String.format("Failed to find entries with baseDN: %s, filter: %s", baseDN, searchFilter), ex); - } - - if (!ResultCode.SUCCESS.equals(searchResult.getResultCode())) { - throw new EntryPersistenceException(String.format("Failed to find entries with baseDN: %s, filter: %s", baseDN, searchFilter)); - } - - if (searchResult.getEntryCount() == 0) { - return new ArrayList(0); - } - - List entries = createEntities(entryClass, propertiesAnnotations, - searchResult.getSearchEntries().toArray(new SearchResultEntry[searchResult.getSearchEntries().size()])); - - // Default sort if needed - sortEntriesIfNeeded(entryClass, entries); - - return entries; - } - - @Override - public PagedResult findPagedEntries(String baseDN, Class entryClass, Filter filter, String[] ldapReturnAttributes, String sortBy, - SortOrder sortOrder, int start, int count, int chunkSize) { - if (StringHelper.isEmptyString(baseDN)) { - throw new MappingException("Base DN to find entries is null"); - } - - // Check entry class - checkEntryClass(entryClass, false); - String[] objectClasses = getTypeObjectClasses(entryClass); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - String[] currentLdapReturnAttributes = ldapReturnAttributes; - if (ArrayHelper.isEmpty(currentLdapReturnAttributes)) { - currentLdapReturnAttributes = getAttributes(null, propertiesAnnotations, false); - } - - // Find entries - Filter searchFilter; - if (objectClasses.length > 0) { - searchFilter = addObjectClassFilter(filter, objectClasses); - } else { - searchFilter = filter; - } - - List searchResultEntries; - PagedResult vlvResponse = new PagedResult(); - try { - searchResultEntries = getOperationService().searchSearchResultEntryList(baseDN, toLdapFilter(searchFilter), - toLdapSearchScope(SearchScope.SUB), start, count, chunkSize, sortBy, sortOrder, vlvResponse, currentLdapReturnAttributes); - } catch (Exception ex) { - throw new EntryPersistenceException(String.format("Failed to find entries with baseDN: %s, filter: %s", baseDN, searchFilter), ex); - } - - List entries = new ArrayList(0); - if (searchResultEntries.size() > 0) { - entries = createEntitiesVirtualListView(entryClass, propertiesAnnotations, searchResultEntries.toArray(new SearchResultEntry[]{})); - } - vlvResponse.setEntries(entries); - - return vlvResponse; - - } - - @Deprecated - public List findEntriesVirtualListView(String baseDN, Class entryClass, Filter filter, int start, int count, String sortBy, - SortOrder sortOrder, PagedResult vlvResponse, String[] ldapReturnAttributes) { - - if (StringHelper.isEmptyString(baseDN)) { - throw new MappingException("Base DN to find entries is null"); - } - - // Check entry class - checkEntryClass(entryClass, false); - String[] objectClasses = getTypeObjectClasses(entryClass); - List propertiesAnnotations = getEntryPropertyAnnotations(entryClass); - String[] currentLdapReturnAttributes = ldapReturnAttributes; - if (ArrayHelper.isEmpty(currentLdapReturnAttributes)) { - currentLdapReturnAttributes = getAttributes(null, propertiesAnnotations, false); - } - - // Find entries - Filter searchFilter; - if (objectClasses.length > 0) { - searchFilter = addObjectClassFilter(filter, objectClasses); - } else { - searchFilter = filter; - } - - SearchResult searchResult = null; - try { - - searchResult = getOperationService().searchVirtualListView(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(SearchScope.SUB), - start, count, sortBy, sortOrder, vlvResponse, currentLdapReturnAttributes); - - if (!ResultCode.SUCCESS.equals(searchResult.getResultCode())) { - throw new EntryPersistenceException(String.format("Failed to find entries with baseDN: %s, filter: %s", baseDN, searchFilter)); - } - - } catch (Exception ex) { - throw new EntryPersistenceException(String.format("Failed to find entries with baseDN: %s, filter: %s", baseDN, searchFilter), ex); - } - - if (searchResult.getEntryCount() == 0) { - return new ArrayList(0); - } - - List entries = createEntitiesVirtualListView(entryClass, propertiesAnnotations, - searchResult.getSearchEntries().toArray(new SearchResultEntry[searchResult.getSearchEntries().size()])); - - return entries; - } - - @Override - protected boolean contains(String baseDN, Class entryClass, List propertiesAnnotations, Filter filter, String[] objectClasses, String[] ldapReturnAttributes) { - if (StringHelper.isEmptyString(baseDN)) { - throw new MappingException("Base DN to check contain entries is null"); - } - - // Create filter - Filter searchFilter; - if (objectClasses.length > 0) { - searchFilter = addObjectClassFilter(filter, objectClasses); - } else { - searchFilter = filter; - } - - SearchScope scope = SearchScope.SUB; - - SearchResult searchResult = null; - try { - searchResult = getOperationService().search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(scope), null, 0, 1, 1, null, ldapReturnAttributes); - if ((searchResult == null) || !ResultCode.SUCCESS.equals(searchResult.getResultCode())) { - throw new EntryPersistenceException(String.format("Failed to find entry with baseDN: %s, filter: %s", baseDN, searchFilter)); - } - } catch (SearchScopeException ex) { - throw new AuthenticationException(String.format("Failed to convert scope: %s", scope), ex); - } catch (SearchException ex) { - if (!(ResultCode.NO_SUCH_OBJECT_INT_VALUE == ex.getErrorCode())) { - throw new EntryPersistenceException(String.format("Failed to find entry with baseDN: %s, filter: %s", baseDN, searchFilter), ex); - } - } - - return (searchResult != null) && (searchResult.getEntryCount() > 0); - } - - protected List createEntities(Class entryClass, List propertiesAnnotations, - SearchResultEntry... searchResultEntries) { - List result = new ArrayList(searchResultEntries.length); - Map> entriesAttributes = new HashMap>(100); - - int count = 0; - for (int i = 0; i < searchResultEntries.length; i++) { - count++; - SearchResultEntry entry = searchResultEntries[i]; - entriesAttributes.put(entry.getDN(), getAttributeDataList(entry)); - - // Remove reference to allow java clean up object - searchResultEntries[i] = null; - - // Allow java to clean up temporary objects - if (count >= 100) { - List currentResult = createEntities(entryClass, propertiesAnnotations, entriesAttributes); - result.addAll(currentResult); - - entriesAttributes = new HashMap>(100); - count = 0; - } - } - - List currentResult = createEntities(entryClass, propertiesAnnotations, entriesAttributes); - result.addAll(currentResult); - - return result; - } - - @Deprecated - private List createEntitiesVirtualListView(Class entryClass, List propertiesAnnotations, - SearchResultEntry... searchResultEntries) { - - List result = new LinkedList(); - Map> entriesAttributes = new LinkedHashMap>(100); - - int count = 0; - for (int i = 0; i < searchResultEntries.length; i++) { - - count++; - - SearchResultEntry entry = searchResultEntries[i]; - - LinkedList attributeDataLinkedList = new LinkedList(); - attributeDataLinkedList.addAll(getAttributeDataList(entry)); - entriesAttributes.put(entry.getDN(), attributeDataLinkedList); - - // Remove reference to allow java clean up object - searchResultEntries[i] = null; - - // Allow java to clean up temporary objects - if (count >= 100) { - - List currentResult = new LinkedList(); - currentResult.addAll(createEntities(entryClass, propertiesAnnotations, entriesAttributes, false)); - result.addAll(currentResult); - - entriesAttributes = new LinkedHashMap>(100); - count = 0; - } - } - - List currentResult = createEntities(entryClass, propertiesAnnotations, entriesAttributes, false); - result.addAll(currentResult); - - return result; - } - - private List getAttributeDataList(SearchResultEntry entry) { - if (entry == null) { - return null; - } - - List result = new ArrayList(); - for (Attribute attribute : entry.getAttributes()) { - String[] attributeValueStrings = NO_STRINGS; - String attributeName = attribute.getName(); - if (LOG.isTraceEnabled()) { - if (attribute.needsBase64Encoding()) { - LOG.trace("Found binary attribute: " + attributeName + ". Is defined in LDAP config: " - + getOperationService().isBinaryAttribute(attributeName)); - } - } - - attributeValueStrings = attribute.getValues(); - if (attribute.needsBase64Encoding()) { - boolean binaryAttribute = getOperationService().isBinaryAttribute(attributeName); - boolean certificateAttribute = getOperationService().isCertificateAttribute(attributeName); - - if (binaryAttribute || certificateAttribute) { - byte[][] attributeValues = attribute.getValueByteArrays(); - if (attributeValues != null) { - attributeValueStrings = new String[attributeValues.length]; - for (int i = 0; i < attributeValues.length; i++) { - attributeValueStrings[i] = Base64.encodeBase64String(attributeValues[i]); - LOG.trace("Binary attribute: " + attribute.getName() + " value (hex): " - + org.apache.commons.codec.binary.Hex.encodeHexString(attributeValues[i]) + " value (base64): " - + attributeValueStrings[i]); - } - } - } - if (certificateAttribute) { - attributeName = getOperationService().getCertificateAttributeName(attributeName); - } - } - - boolean multiValued = attributeValueStrings.length > 1; - AttributeData tmpAttribute = new AttributeData(attributeName, attributeValueStrings, multiValued); - result.add(tmpAttribute); - } - - return result; - } - - @Override - public boolean authenticate(String baseDN, Class entryClass, String userName, String password) { - if (StringHelper.isEmptyString(baseDN)) { - throw new MappingException("Base DN to count entries is null"); - } - - // Check entry class - checkEntryClass(entryClass, false); - String[] objectClasses = getTypeObjectClasses(entryClass); - - // Find entries - Filter searchFilter = Filter.createEqualityFilter(LdapOperationService.UID, userName); - if (objectClasses.length > 0) { - searchFilter = addObjectClassFilter(searchFilter, objectClasses); - } - - SearchScope scope = SearchScope.SUB; - try { - SearchResult searchResult = getOperationService().search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(scope), null, 0, 1, 1, null, (String[]) null); - if ((searchResult == null) || (searchResult.getEntryCount() != 1)) { - return false; - } - - String bindDn = searchResult.getSearchEntries().get(0).getDN(); - - return getOperationService().authenticate(bindDn, password); - } catch (ConnectionException ex) { - throw new AuthenticationException(String.format("Failed to authenticate user: %s", userName), ex); - } catch (SearchScopeException ex) { - throw new AuthenticationException(String.format("Failed to convert scope: %s", scope), ex); - } catch (SearchException ex) { - throw new AuthenticationException(String.format("Failed to find user DN: %s", userName), ex); - } - } - - @Override - public boolean authenticate(String bindDn, String password) { - try { - return getOperationService().authenticate(bindDn, password); - } catch (ConnectionException ex) { - throw new AuthenticationException(String.format("Failed to authenticate DN: %s", bindDn), ex); - } - } - - @Override - public int countEntries(String baseDN, Class entryClass, Filter filter) { - return countEntries(baseDN, entryClass, filter, null); - } - - @Override - public int countEntries(String baseDN, Class entryClass, Filter filter, SearchScope scope) { - if (StringHelper.isEmptyString(baseDN)) { - throw new MappingException("Base DN to count entries is null"); - } - - // Check entry class - checkEntryClass(entryClass, false); - String[] objectClasses = getTypeObjectClasses(entryClass); - - // Find entries - Filter searchFilter; - if (objectClasses.length > 0) { - searchFilter = addObjectClassFilter(filter, objectClasses); - } else { - searchFilter = filter; - } - - SearchScope searchScope = scope; - if (searchScope == null) { - searchScope = SearchScope.SUB; - } - - String[] ldapReturnAttributes; - CountBatchOperation batchOperation; - if (SearchScope.BASE == searchScope) { - ldapReturnAttributes = new String[] { "numsubordinates" }; // Don't load attributes - batchOperation = null; - } else { - ldapReturnAttributes = new String[] { "" }; // Don't load attributes - batchOperation = new CountBatchOperation(); - } - - SearchResult searchResult; - try { - LdapBatchOperationWraper batchOperationWraper = null; - if (batchOperation != null) { - batchOperationWraper = new LdapBatchOperationWraper(batchOperation); - } - searchResult = getOperationService().search(baseDN, toLdapFilter(searchFilter), toLdapSearchScope(searchScope), batchOperationWraper, 0, 100, 0, null, - ldapReturnAttributes); - } catch (Exception ex) { - throw new EntryPersistenceException( - String.format("Failed to calculate the number of entries with baseDN: %s, filter: %s", baseDN, searchFilter), ex); - } - - if (SearchScope.BASE != searchScope) { - return batchOperation.getCountEntries(); - } - - if (searchResult.getEntryCount() != 1) { - throw new EntryPersistenceException(String.format("Failed to calculate the number of entries due to missing result entry with baseDN: %s, filter: %s", baseDN, searchFilter)); - } - - Long result = searchResult.getSearchEntries().get(0).getAttributeValueAsLong("numsubordinates"); - if (result == null) { - throw new EntryPersistenceException(String.format("Failed to calculate the number of entries due to missing attribute 'numsubordinates' with baseDN: %s, filter: %s", baseDN, searchFilter)); - } - - return result.intValue(); - } - - @Override - public String encodeTime(String baseDN, Date date) { - if (date == null) { - return null; - } - - return StaticUtils.encodeGeneralizedTime(date); - } - - @Override - protected String encodeTime(Date date) { - return encodeTime(null, date); - } - - @Override - public Date decodeTime(String baseDN, String date) { - if (date == null) { - return null; - } - - try { - return StaticUtils.decodeGeneralizedTime(date); - } catch (ParseException ex) { - LOG.error("Failed to parse generalized time {}", date, ex); - } - - return null; - } - - @Override - protected Date decodeTime(String date) { - return decodeTime(null, date); - } - - public boolean loadLdifFileContent(String ldifFileContent) { - LDAPConnection connection = null; - try { - connection = getOperationService().getConnection(); - ResultCode result = LdifDataUtility.instance().importLdifFileContent(connection, ldifFileContent); - return ResultCode.SUCCESS.equals(result); - } catch (Exception ex) { - LOG.error("Failed to load ldif file", ex); - return false; - } finally { - if (connection != null) { - getOperationService().releaseConnection(connection); - } - } - } - - @Override - public List exportEntry(String dn) { - try { - SearchResultEntry searchResultEntry = getOperationService().lookup(dn, (String[]) null); - - List result = getAttributeDataList(searchResultEntry); - if (result != null) { - return result; - } - - return null; - } catch (ConnectionException ex) { - throw new EntryPersistenceException(String.format("Failed to find entry: %s", dn), ex); - } - } - - @Override - public void importEntry(String dn, List data) { - persist(dn, data); - } - - public int getSupportedLDAPVersion() { - return getOperationService().getSupportedLDAPVersion(); - } - - private Modification createModification(final ModificationType modificationType, final String attributeName, final String... attributeValues) { - String realAttributeName = attributeName; - if (getOperationService().isCertificateAttribute(realAttributeName)) { - realAttributeName += ";binary"; - byte[][] binaryValues = toBinaryValues(attributeValues); - - return new Modification(modificationType, realAttributeName, binaryValues); - } - - return new Modification(modificationType, realAttributeName, attributeValues); - } - - private com.unboundid.ldap.sdk.Filter toLdapFilter(Filter genericFilter) throws SearchException { - return LDAP_FILTER_CONVERTER.convertToLdapFilter(genericFilter); - } - - private com.unboundid.ldap.sdk.SearchScope toLdapSearchScope(SearchScope scope) throws SearchScopeException { - return LDAP_SEARCH_SCOPE_CONVERTER.convertToLdapSearchScope(scope); - } - - @Override - public boolean hasBranchesSupport(String dn) { - return true; - } - - @Override - public boolean hasExpirationSupport(String primaryKey) { - return false; - } - - @Override - public String getPersistenceType() { - return LdapEntryManagerFactory.PERSISTENCE_TYPE; - } - - @Override - public String getPersistenceType(String primaryKey) { - return LdapEntryManagerFactory.PERSISTENCE_TYPE; - } - - @Override - public PersistenceEntryManager getPersistenceEntryManager(String persistenceType) { - if (LdapEntryManagerFactory.PERSISTENCE_TYPE.equals(persistenceType)) { - return this; - } - - return null; - } - - @Override - public String[] getObjectClasses(Object entry, Class entryClass) { - String[] ojectClasses = super.getObjectClasses(entry, entryClass); - - Set objecClassSet = new HashSet(); - - // Add in LDAP implementation "top" by default - objecClassSet.add("top"); - objecClassSet.addAll(Arrays.asList(ojectClasses)); - return objecClassSet.toArray(new String[0]); - } - - private static class CountBatchOperation extends DefaultBatchOperation { - - private int countEntries = 0; - - @Override - public void performAction(List entries) { - } - - @Override - public boolean collectSearchResult(int size) { - countEntries += size; - return false; - } - - public int getCountEntries() { - return countEntries; - } - } - - private static final class DeleteBatchOperation extends DefaultBatchOperation { - - private int countEntries = 0; - private LdapEntryManager ldapEntryManager; - - public DeleteBatchOperation(LdapEntryManager ldapEntryManager) { - this.ldapEntryManager = ldapEntryManager; - } - - @Override - public void performAction(List entries) { - for (T entity : entries) { - try { - String dnValue = ldapEntryManager.getDNValue(entity).toString(); - if (ldapEntryManager.hasBranchesSupport(dnValue)) { - ldapEntryManager.removeRecursively(dnValue); - } else { - ldapEntryManager.remove(dnValue); - } - LOG.trace("Removed {}", dnValue); - } catch (Exception e) { - LOG.error("Failed to remove entry, entity: " + entity, e); - } - } - } - - @Override - public boolean collectSearchResult(int size) { - countEntries += size; - return false; - } - - public int getCountEntries() { - return countEntries; - } - } - -} diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManagerFactory.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManagerFactory.java deleted file mode 100644 index dcb7f507..00000000 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapEntryManagerFactory.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.gluu.persist.ldap.impl; - -import java.util.HashMap; -import java.util.Properties; - -import javax.enterprise.context.ApplicationScoped; - -import org.gluu.persist.PersistenceEntryManagerFactory; -import org.gluu.persist.exception.operation.ConfigurationException; -import org.gluu.persist.ldap.operation.impl.LdapAuthConnectionProvider; -import org.gluu.persist.ldap.operation.impl.LdapConnectionProvider; -import org.gluu.persist.ldap.operation.impl.LdapOperationServiceImpl; -import org.gluu.persist.service.BaseFactoryService; -import org.gluu.util.PropertiesHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * LDAP Entry Manager Factory - * - * @author Yuriy Movchan Date: 02/02/2018 - */ -@ApplicationScoped -public class LdapEntryManagerFactory implements PersistenceEntryManagerFactory { - - public static final String PERSISTENCE_TYPE = "ldap"; - public static final String LDAP_DEFAULT_PROPERTIES_FILE = "gluu-ldap.properties"; - - private static final Logger LOG = LoggerFactory.getLogger(LdapEntryManagerFactory.class); - - @Override - public String getPersistenceType() { - return PERSISTENCE_TYPE; - } - - @Override - public HashMap getConfigurationFileNames() { - HashMap confs = new HashMap(); - confs.put(PERSISTENCE_TYPE, LDAP_DEFAULT_PROPERTIES_FILE); - - return confs; - } - - @Override - public LdapEntryManager createEntryManager(Properties conf) { - Properties entryManagerConf = PropertiesHelper.filterProperties(conf, PERSISTENCE_TYPE); - - LdapConnectionProvider connectionProvider = new LdapConnectionProvider(entryManagerConf); - if (!connectionProvider.isCreated()) { - throw new ConfigurationException( - String.format("Failed to create LDAP connection pool! Result code: '%s'", connectionProvider.getCreationResultCode())); - } - LOG.debug("Created connectionProvider '{}' with code '{}'", connectionProvider, connectionProvider.getCreationResultCode()); - - LdapConnectionProvider bindConnectionProvider = new LdapAuthConnectionProvider(entryManagerConf); - if (!bindConnectionProvider.isCreated()) { - throw new ConfigurationException( - String.format("Failed to create LDAP bind connection pool! Result code: '%s'", bindConnectionProvider.getCreationResultCode())); - } - LOG.debug("Created bindConnectionProvider '{}' with code '{}'", bindConnectionProvider, bindConnectionProvider.getCreationResultCode()); - - LdapEntryManager ldapEntryManager = new LdapEntryManager(new LdapOperationServiceImpl(connectionProvider, bindConnectionProvider)); - LOG.info("Created LdapEntryManager: {}", ldapEntryManager.getOperationService()); - - return ldapEntryManager; - } - - @Override - public void initStandalone(BaseFactoryService persistanceFactoryService) {} - -} diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapFilterConverter.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapFilterConverter.java deleted file mode 100644 index 18272eb6..00000000 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapFilterConverter.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.gluu.persist.ldap.impl; - -import javax.enterprise.context.ApplicationScoped; - -import org.gluu.persist.exception.operation.SearchException; -import org.gluu.search.filter.Filter; -import org.gluu.search.filter.FilterType; -import org.gluu.util.ArrayHelper; - -/** - * Filter to LDAP filter convert - * - * @author Yuriy Movchan Date: 12/15/2017 - */ -@ApplicationScoped -public class LdapFilterConverter { - - public com.unboundid.ldap.sdk.Filter convertToLdapFilter(Filter genericFilter) throws SearchException { - FilterType type = genericFilter.getType(); - if (FilterType.RAW == type) { - try { - return com.unboundid.ldap.sdk.Filter.create(genericFilter.getFilterString()); - } catch (com.unboundid.ldap.sdk.LDAPException ex) { - throw new SearchException("Failed to parse RAW Ldap filter", ex, ex.getResultCode().intValue()); - } - } - - if ((FilterType.NOT == type) || (FilterType.AND == type) || (FilterType.OR == type)) { - Filter[] genericFilters = genericFilter.getFilters(); - com.unboundid.ldap.sdk.Filter[] ldapFilters = new com.unboundid.ldap.sdk.Filter[genericFilters.length]; - - if (genericFilters != null) { - for (int i = 0; i < genericFilters.length; i++) { - ldapFilters[i] = convertToLdapFilter(genericFilters[i]); - } - - if (FilterType.NOT == type) { - return com.unboundid.ldap.sdk.Filter.createNOTFilter(ldapFilters[0]); - } else if (FilterType.AND == type) { - return com.unboundid.ldap.sdk.Filter.createANDFilter(ldapFilters); - } else if (FilterType.OR == type) { - return com.unboundid.ldap.sdk.Filter.createORFilter(ldapFilters); - } - } - } - - if (FilterType.EQUALITY == type) { - String attributeName; - if (ArrayHelper.isEmpty(genericFilter.getFilters())) { - attributeName = genericFilter.getAttributeName(); - } else { - attributeName = convertToLdapFilter(genericFilter.getFilters()[0]).getAttributeName(); - } - return com.unboundid.ldap.sdk.Filter.createEqualityFilter(attributeName, String.valueOf(genericFilter.getAssertionValue())); - } - - if (FilterType.LESS_OR_EQUAL == type) { - return com.unboundid.ldap.sdk.Filter.createLessOrEqualFilter(genericFilter.getAttributeName(), String.valueOf(genericFilter.getAssertionValue())); - } - - if (FilterType.GREATER_OR_EQUAL == type) { - return com.unboundid.ldap.sdk.Filter.createGreaterOrEqualFilter(genericFilter.getAttributeName(), String.valueOf(genericFilter.getAssertionValue())); - } - - if (FilterType.PRESENCE == type) { - return com.unboundid.ldap.sdk.Filter.createPresenceFilter(genericFilter.getAttributeName()); - } - - if (FilterType.APPROXIMATE_MATCH == type) { - return com.unboundid.ldap.sdk.Filter.createApproximateMatchFilter(genericFilter.getAttributeName(), String.valueOf(genericFilter.getAssertionValue())); - } - - if (FilterType.SUBSTRING == type) { - return com.unboundid.ldap.sdk.Filter.createSubstringFilter(genericFilter.getAttributeName(), genericFilter.getSubInitial(), - genericFilter.getSubAny(), genericFilter.getSubFinal()); - } - - if (FilterType.LOWERCASE == type) { - // Return Dummy filter because case sensitivity is defined at LDAP schema level - return com.unboundid.ldap.sdk.Filter.createPresenceFilter(genericFilter.getAttributeName()); - } - - throw new SearchException(String.format("Unknown filter type '%s'", type), com.unboundid.ldap.sdk.ResultCode.PROTOCOL_ERROR_INT_VALUE); - } - - public Filter convertRawLdapFilterToFilter(String rawFilter) throws SearchException { - com.unboundid.ldap.sdk.Filter ldapFilter; - try { - ldapFilter = com.unboundid.ldap.sdk.Filter.create(rawFilter); - } catch (com.unboundid.ldap.sdk.LDAPException ex) { - throw new SearchException("Failed to parse RAW Ldap filter", ex, ex.getResultCode().intValue()); - } - - return convertRawLdapFilterToFilterImpl(ldapFilter); - } - - protected Filter convertRawLdapFilterToFilterImpl(com.unboundid.ldap.sdk.Filter ldapFilter) throws SearchException { - byte type = ldapFilter.getFilterType(); - - if ((com.unboundid.ldap.sdk.Filter.FILTER_TYPE_NOT == type) || (com.unboundid.ldap.sdk.Filter.FILTER_TYPE_AND == type) || (com.unboundid.ldap.sdk.Filter.FILTER_TYPE_OR == type)) { - com.unboundid.ldap.sdk.Filter[] ldapFilters = ldapFilter.getComponents(); - Filter[] genericFilters = new Filter[ldapFilters.length]; - - if (ldapFilters != null) { - for (int i = 0; i < ldapFilters.length; i++) { - genericFilters[i] = convertRawLdapFilterToFilterImpl(ldapFilters[i]); - } - - if (com.unboundid.ldap.sdk.Filter.FILTER_TYPE_NOT == type) { - return Filter.createNOTFilter(genericFilters[0]); - } else if (com.unboundid.ldap.sdk.Filter.FILTER_TYPE_AND == type) { - return Filter.createANDFilter(genericFilters); - } else if (com.unboundid.ldap.sdk.Filter.FILTER_TYPE_OR == type) { - return Filter.createORFilter(genericFilters); - } - } - } - - if (com.unboundid.ldap.sdk.Filter.FILTER_TYPE_EQUALITY == type) { - return Filter.createEqualityFilter(ldapFilter.getAttributeName(), ldapFilter.getAssertionValue()); - } - - if (com.unboundid.ldap.sdk.Filter.FILTER_TYPE_LESS_OR_EQUAL == type) { - return Filter.createLessOrEqualFilter(ldapFilter.getAttributeName(), ldapFilter.getAssertionValue()); - } - - if (com.unboundid.ldap.sdk.Filter.FILTER_TYPE_GREATER_OR_EQUAL == type) { - return Filter.createGreaterOrEqualFilter(ldapFilter.getAttributeName(), ldapFilter.getAssertionValue()); - } - - if (com.unboundid.ldap.sdk.Filter.FILTER_TYPE_PRESENCE == type) { - return Filter.createPresenceFilter(ldapFilter.getAttributeName()); - } - - if (com.unboundid.ldap.sdk.Filter.FILTER_TYPE_APPROXIMATE_MATCH == type) { - return Filter.createApproximateMatchFilter(ldapFilter.getAttributeName(), ldapFilter.getAssertionValue()); - } - - if (com.unboundid.ldap.sdk.Filter.FILTER_TYPE_SUBSTRING == type) { - return Filter.createSubstringFilter(ldapFilter.getAttributeName(), ldapFilter.getSubInitialString(), - ldapFilter.getSubAnyStrings(), ldapFilter.getSubFinalString()); - } - - throw new SearchException(String.format("Unknown filter type '%s'", type), com.unboundid.ldap.sdk.ResultCode.PROTOCOL_ERROR_INT_VALUE); - } - -} diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapSearchScopeConverter.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapSearchScopeConverter.java deleted file mode 100644 index e6b1ca7a..00000000 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdapSearchScopeConverter.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.gluu.persist.ldap.impl; - -import org.gluu.persist.exception.operation.SearchScopeException; -import org.gluu.persist.model.SearchScope; - -/** - * Simple filter without dependency to specific persistence filter mechanism - * - * @author Yuriy Movchan Date: 12/15/2017 - */ -public class LdapSearchScopeConverter { - - public com.unboundid.ldap.sdk.SearchScope convertToLdapSearchScope(SearchScope searchScope) throws SearchScopeException { - if (SearchScope.BASE == searchScope) { - return com.unboundid.ldap.sdk.SearchScope.BASE; - } - if (SearchScope.ONE == searchScope) { - return com.unboundid.ldap.sdk.SearchScope.ONE; - } - if (SearchScope.SUB == searchScope) { - return com.unboundid.ldap.sdk.SearchScope.SUB; - } - - throw new SearchScopeException(String.format("Unknown search scope '%s'", searchScope)); - } - -} diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdifDataUtility.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdifDataUtility.java deleted file mode 100644 index 1d06fead..00000000 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/impl/LdifDataUtility.java +++ /dev/null @@ -1,346 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.ldap.impl; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.ListIterator; - -import org.apache.commons.io.IOUtils; -import org.gluu.util.StringHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.unboundid.ldap.sdk.ChangeType; -import com.unboundid.ldap.sdk.Entry; -import com.unboundid.ldap.sdk.Filter; -import com.unboundid.ldap.sdk.LDAPConnection; -import com.unboundid.ldap.sdk.LDAPException; -import com.unboundid.ldap.sdk.LDAPSearchException; -import com.unboundid.ldap.sdk.ResultCode; -import com.unboundid.ldap.sdk.SearchResult; -import com.unboundid.ldap.sdk.SearchResultEntry; -import com.unboundid.ldap.sdk.SearchScope; -import com.unboundid.ldif.LDIFChangeRecord; -import com.unboundid.ldif.LDIFException; -import com.unboundid.ldif.LDIFReader; - -/** - * Utility class to import ldif file to LDAP. - * - * @author Yuriy Movchan Date: 08.06.2010 - */ -public final class LdifDataUtility { - - private static final Logger LOG = LoggerFactory.getLogger(LdifDataUtility.class); - - // Just define the singleton as a static field in a separate class. - // The semantics of Java guarantee that the field will not be initialized until - // the field is referenced, - // and that any thread which accesses the field will see all of the writes - // resulting from initializing that field. - // http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html - private static class Holder { - private static LdifDataUtility INSTANCE = new LdifDataUtility(); - } - - private LdifDataUtility() { - } - - public static LdifDataUtility instance() { - return Holder.INSTANCE; - } - - /** - * Performs ldif file import - * - * @param connection - * Connection to LDAP server - * @param ldifFileName - * LDIF file - * @return The result code for the processing that was performed - */ - public ResultCode importLdifFile(LDAPConnection connection, String ldifFileName) { - LDIFReader ldifReader = createLdifReader(ldifFileName); - if (ldifReader == null) { - return ResultCode.LOCAL_ERROR; - } - try { - return importLdifFile(connection, ldifReader); - } finally { - disposeLdifReader(ldifReader); - } - } - - /** - * Performs ldif file conent import - * - * @param connection - * Connection to LDAP server - * @param ldifFileContent - * LDIF file - * @return The result code for the processing that was performed - */ - public ResultCode importLdifFileContent(LDAPConnection connection, String ldifFileContent) { - BufferedReader is = null; - LDIFReader ldifReader = null; - try { - is = new BufferedReader(new StringReader(ldifFileContent)); - ldifReader = new LDIFReader(is); - - return importLdifFile(connection, ldifReader); - } finally { - IOUtils.closeQuietly(is); - if (ldifReader != null) { - disposeLdifReader(ldifReader); - } - } - } - - /** - * Performs ldif file import - * - * @param connection - * Connection to LDAP server - * @param ldifReader - * LDIF reader - * @return The result code for the processing that was performed - */ - public ResultCode importLdifFile(LDAPConnection connection, LDIFReader ldifReader) { - // Attempt to process and apply the changes to the server - ResultCode resultCode = ResultCode.SUCCESS; - while (true) { - // Read the next change to process - LDIFChangeRecord ldifRecord = null; - try { - ldifRecord = ldifReader.readChangeRecord(true); - } catch (LDIFException le) { - LOG.error("Malformed ldif record", le); - if (!le.mayContinueReading()) { - resultCode = ResultCode.DECODING_ERROR; - break; - } - } catch (IOException ioe) { - LOG.error("I/O error encountered while reading a change record", ioe); - resultCode = ResultCode.LOCAL_ERROR; - break; - } - - // If the change record was null, then it means there are no more - // changes to be processed. - if (ldifRecord == null) { - break; - } - - // Apply the target change to the server. - try { - ldifRecord.processChange(connection); - } catch (LDAPException le) { - if (ResultCode.ENTRY_ALREADY_EXISTS.equals(le.getResultCode())) { - continue; - } - if (ldifRecord.getChangeType().equals(ChangeType.DELETE)) { - continue; - } - - LOG.error("Failed to inserting ldif record", le); - } - } - - return resultCode; - } - - /** - * Check if DS has at least one DN simular to specified in ldif file. - * - * @param connection - * Connection to LDAP server - * @param ldifFileName - * LDIF file - * @return true if server contains at least one DN simular to specified in ldif - * file. - */ - public boolean checkIfSerrverHasEntryFromLDIFFile(LDAPConnection connection, String ldifFileName) { - // Set up the LDIF reader that will be used to read the changes to apply - LDIFReader ldifReader = createLdifReader(ldifFileName); - if (ldifReader == null) { - return true; - } - - // Check all ldif entries - while (true) { - // Read the next change to process. - Entry entry = null; - try { - entry = ldifReader.readEntry(); - } catch (LDIFException le) { - LOG.error("Malformed ldif record", le); - if (!le.mayContinueReading()) { - return true; - } - } catch (IOException ioe) { - LOG.error("I/O error encountered while reading a change record", ioe); - return true; - } - - // If the change record was null, then it means there are no more - // changes to be processed. - if (entry == null) { - break; - } - - // Search entry in the server. - try { - SearchResult sr = connection.search(entry.getDN(), SearchScope.BASE, "objectClass=*"); - if ((sr != null) && (sr.getEntryCount() > 0)) { - return true; - } - } catch (LDAPException le) { - if (le.getResultCode() != ResultCode.NO_SUCH_OBJECT) { - LOG.error("Failed to search ldif record", le); - return true; - } - } - } - - disposeLdifReader(ldifReader); - - return false; - } - - /** - * Remove base entry with all sub entries - * - * @param connection - * Connection to LDAP server - * @param baseDN - * Base DN entry - * @return The result code for the processing that was performed. - */ - public ResultCode deleteEntryWithAllSubs(LDAPConnection connection, String baseDN) { - ResultCode resultCode = ResultCode.SUCCESS; - SearchResult searchResult = null; - try { - searchResult = connection.search(baseDN, SearchScope.SUB, "objectClass=*"); - if ((searchResult == null) || (searchResult.getEntryCount() == 0)) { - return ResultCode.LOCAL_ERROR; - } - } catch (LDAPSearchException le) { - LOG.error("Failed to search subordinate entries", le); - return ResultCode.LOCAL_ERROR; - } - - LinkedList dns = new LinkedList(); - for (SearchResultEntry entry : searchResult.getSearchEntries()) { - dns.add(entry.getDN()); - } - - ListIterator listIterator = dns.listIterator(dns.size()); - while (listIterator.hasPrevious()) { - try { - connection.delete(listIterator.previous()); - } catch (LDAPException le) { - LOG.error("Failed to delete entry", le); - resultCode = ResultCode.LOCAL_ERROR; - break; - } - } - - return resultCode; - } - - private LDIFReader createLdifReader(String ldifFileNamePath) { - // Set up the LDIF reader that will be used to read the changes to apply - File ldifFile = new File(ldifFileNamePath); - LDIFReader ldifReader; - try { - if (!ldifFile.exists()) { - return null; - } - ldifReader = new LDIFReader(ldifFile); - } catch (IOException ex) { - LOG.error("I/O error creating the LDIF reader", ex); - return null; - } - - return ldifReader; - } - - private void disposeLdifReader(LDIFReader ldifReader) { - if (ldifReader != null) { - try { - ldifReader.close(); - } catch (IOException ex) { - } - } - } - - public ResultCode validateLDIF(LDIFReader ldifReader, String dn) { - String baseDn = dn.toLowerCase(); - ResultCode resultCode = ResultCode.SUCCESS; - while (true) { - // Read the next change to process - LDIFChangeRecord ldifRecord = null; - try { - ldifRecord = ldifReader.readChangeRecord(true); - if (ldifRecord != null) { - if (StringHelper.isNotEmpty(baseDn)) { - if (!ldifRecord.getDN().toLowerCase().endsWith(baseDn)) { - resultCode = ResultCode.NOT_SUPPORTED; - break; - } - } - } - - } catch (LDIFException le) { - LOG.info("Malformed ldif record " + ldifRecord); - LOG.error("Malformed ldif record", le); - resultCode = ResultCode.DECODING_ERROR; - break; - } catch (IOException ioe) { - LOG.error("I/O error encountered while reading a change record", ioe); - resultCode = ResultCode.LOCAL_ERROR; - break; - } - - // If the change record was null, then it means there are no more - // changes to be processed. - if (ldifRecord == null) { - break; - } - } - - return resultCode; - } - - public List getAttributeResultEntryLDIF(LDAPConnection connection, List patterns, String baseDN) { - List searchResultEntryList = new ArrayList(); - try { - for (String pattern : patterns) { - String[] targetArray = new String[] {pattern}; - Filter inumFilter = Filter.createSubstringFilter("inum", null, targetArray, null); - Filter searchFilter = Filter.createORFilter(inumFilter); - SearchResultEntry sr = connection.searchForEntry(baseDN, SearchScope.SUB, searchFilter, null); - searchResultEntryList.add(sr); - } - - return searchResultEntryList; - } catch (LDAPException le) { - if (le.getResultCode() != ResultCode.NO_SUCH_OBJECT) { - LOG.error("Failed to search ldif record", le); - return null; - } - } - return null; - } - -} diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/LdapOperationService.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/LdapOperationService.java deleted file mode 100644 index 8449c967..00000000 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/LdapOperationService.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.gluu.persist.ldap.operation; - -import java.util.Collection; -import java.util.List; - -import org.gluu.persist.exception.operation.ConnectionException; -import org.gluu.persist.exception.operation.DuplicateEntryException; -import org.gluu.persist.exception.operation.SearchException; -import org.gluu.persist.ldap.impl.LdapBatchOperationWraper; -import org.gluu.persist.ldap.operation.impl.LdapConnectionProvider; -import org.gluu.persist.model.PagedResult; -import org.gluu.persist.model.SortOrder; -import org.gluu.persist.operation.PersistenceOperationService; - -import com.unboundid.ldap.sdk.Attribute; -import com.unboundid.ldap.sdk.Control; -import com.unboundid.ldap.sdk.Filter; -import com.unboundid.ldap.sdk.LDAPConnection; -import com.unboundid.ldap.sdk.LDAPConnectionPool; -import com.unboundid.ldap.sdk.LDAPException; -import com.unboundid.ldap.sdk.Modification; -import com.unboundid.ldap.sdk.SearchResult; -import com.unboundid.ldap.sdk.SearchResultEntry; -import com.unboundid.ldap.sdk.SearchScope; -import com.unboundid.ldif.LDIFChangeRecord; - -public interface LdapOperationService extends PersistenceOperationService { - - static final String DN = "dn"; - static final String UID = "uid"; - static final String SUCCESS = "success"; - static final String USER_PASSWORD = "userPassword"; - static final String OBJECT_CLASS = "objectClass"; - - LdapConnectionProvider getConnectionProvider(); - - void setConnectionProvider(LdapConnectionProvider connectionProvider); - - LdapConnectionProvider getBindConnectionProvider(); - - void setBindConnectionProvider(LdapConnectionProvider bindConnectionProvider); - - LDAPConnectionPool getConnectionPool(); - - LDAPConnection getConnection() throws LDAPException; - - void releaseConnection(LDAPConnection connection); - - boolean authenticate(String bindDn, String password) throws ConnectionException; - - SearchResult search(String dn, Filter filter, SearchScope scope, LdapBatchOperationWraper batchOperationWraper, int start, - int searchLimit, int count, Control[] controls, String... attributes) throws SearchException; - - List searchSearchResultEntryList(String dn, Filter filter, SearchScope scope, int startIndex, - int count, int pageSize, String sortBy, SortOrder sortOrder, - PagedResult vlvResponse, String... attributes) throws Exception; - - SearchResult searchVirtualListView(String dn, Filter filter, SearchScope scope, int start, int count, - String sortBy, SortOrder sortOrder, PagedResult vlvResponse, String... attributes) - throws Exception; - - /** - * Lookup entry in the directory - * - * @param dn - * @param attributes - * @return SearchResultEntry - * @throws ConnectionException - */ - SearchResultEntry lookup(String dn, String... attributes) throws ConnectionException; - - /** - * Use this method to add new entry - * - * @param dn - * for entry - * @param atts - * attributes for entry - * @return true if successfully added - * @throws DuplicateEntryException - * @throws ConnectionException - * @throws DuplicateEntryException - * @throws ConnectionException - * @throws LDAPException - */ - boolean addEntry(String dn, Collection atts) throws DuplicateEntryException, ConnectionException; - - /** - * This method is used to update set of attributes for an entry - * - * @param dn - * @param modifications - * @return - * @throws ConnectionException - * @throws DuplicateEntryException - */ - boolean updateEntry(String dn, List modifications) throws DuplicateEntryException, ConnectionException; - - /** - * Delete entry from the directory - * - * @param dn - * @throws ConnectionException - */ - boolean delete(String dn) throws ConnectionException; - - /** - * Delete entry from the directory - * - * @param dn - * @return - * @throws ConnectionException - */ - boolean deleteRecursively(String dn) throws ConnectionException; - - boolean processChange(LDIFChangeRecord ldifRecord) throws LDAPException; - - int getSupportedLDAPVersion(); - - String getSubschemaSubentry(); - - boolean destroy(); - - boolean isBinaryAttribute(String attributeName); - - boolean isCertificateAttribute(String attributeName); - - String getCertificateAttributeName(String attributeName); - - List sortListByAttributes(List searchResultEntries, Class cls, boolean caseSensitive, boolean ascending, String... sortByAttributes); - -} diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapAuthConnectionProvider.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapAuthConnectionProvider.java deleted file mode 100644 index 75088d5d..00000000 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapAuthConnectionProvider.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.gluu.persist.ldap.operation.impl; - -import java.util.Properties; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.unboundid.ldap.sdk.ResultCode; - -/** - * Authentication connection provider - * - * @author Yuriy Movchan Date: 12/29/2017 - */ -public class LdapAuthConnectionProvider extends LdapConnectionProvider { - - private static final Logger LOG = LoggerFactory.getLogger(LdapAuthConnectionProvider.class); - - public LdapAuthConnectionProvider(Properties connectionProperties) { - Properties bindConnectionProperties = prepareBindConnectionProperties(connectionProperties); - create(bindConnectionProperties); - if (ResultCode.INAPPROPRIATE_AUTHENTICATION.equals(getCreationResultCode())) { - LOG.warn("It's not possible to create authentication LDAP connection pool using anonymous bind. " - + "Attempting to create it using binDN/bindPassword"); - create(connectionProperties); - } - } - - private Properties prepareBindConnectionProperties(Properties connectionProperties) { - Properties bindProperties = (Properties) connectionProperties.clone(); - bindProperties.remove("bindDN"); - bindProperties.remove("bindPassword"); - - return bindProperties; - } - -} diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapConnectionProvider.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapConnectionProvider.java deleted file mode 100644 index 37c32085..00000000 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapConnectionProvider.java +++ /dev/null @@ -1,551 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.ldap.operation.impl; - -import java.security.GeneralSecurityException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Properties; - -import org.gluu.persist.exception.operation.ConfigurationException; -import org.gluu.persist.operation.auth.PasswordEncryptionMethod; -import org.gluu.util.ArrayHelper; -import org.gluu.util.StringHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.unboundid.ldap.sdk.BindRequest; -import com.unboundid.ldap.sdk.FailoverServerSet; -import com.unboundid.ldap.sdk.GetEntryLDAPConnectionPoolHealthCheck; -import com.unboundid.ldap.sdk.LDAPConnection; -import com.unboundid.ldap.sdk.LDAPConnectionOptions; -import com.unboundid.ldap.sdk.LDAPConnectionPool; -import com.unboundid.ldap.sdk.LDAPException; -import com.unboundid.ldap.sdk.ResultCode; -import com.unboundid.ldap.sdk.SimpleBindRequest; -import com.unboundid.util.ssl.SSLUtil; -import com.unboundid.util.ssl.TrustAllTrustManager; -import com.unboundid.util.ssl.TrustStoreTrustManager; - -/** - * @author Yuriy Movchan - */ -public class LdapConnectionProvider { - - private static final Logger LOG = LoggerFactory.getLogger(LdapConnectionProvider.class); - - private static final int DEFAULT_SUPPORTED_LDAP_VERSION = 2; - private static final String DEFAULT_SUBSCHEMA_SUBENTRY = "cn=schema"; - - private static final String[] SSL_PROTOCOLS = {"TLSv1.2", "TLSv1.1", "TLSv1", "SSLv3"}; - - private LDAPConnectionPool connectionPool; - private ResultCode creationResultCode; - - private int supportedLDAPVersion = DEFAULT_SUPPORTED_LDAP_VERSION; - private String subschemaSubentry = DEFAULT_SUBSCHEMA_SUBENTRY; - - private String[] servers; - private String[] addresses; - private int[] ports; - - private String bindDn; - private String bindPassword; - private boolean useSSL; - - private ArrayList additionalPasswordMethods; - private ArrayList binaryAttributes, certificateAttributes; - - private boolean supportsSubtreeDeleteRequestControl; - - - protected LdapConnectionProvider() { - } - - public LdapConnectionProvider(Properties props) { - create(props); - } - - protected void create(Properties props) { - try { - init(props); - } catch (LDAPException ex) { - creationResultCode = ex.getResultCode(); - - Properties clonedProperties = (Properties) props.clone(); - if (clonedProperties.getProperty("bindPassword") != null) { - clonedProperties.setProperty("bindPassword", "REDACTED"); - } - LOG.error("Failed to create connection pool with properties: " + clonedProperties, ex); - } catch (Exception ex) { - Properties clonedProperties = (Properties) props.clone(); - if (clonedProperties.getProperty("bindPassword") != null) { - clonedProperties.setProperty("bindPassword", "REDACTED"); - } - LOG.error("Failed to create connection pool with properties: " + clonedProperties, ex); - } - } - - /** - * This method is used to create LDAPConnectionPool - * - * @throws NumberFormatException - * @throws LDAPException - * @throws GeneralSecurityException - * @throws EncryptionException - * @throws EncryptionException - */ - protected void init(Properties props) throws NumberFormatException, LDAPException, GeneralSecurityException { - String serverProp = props.getProperty("servers"); - this.servers = serverProp.split(","); - this.addresses = new String[this.servers.length]; - this.ports = new int[this.servers.length]; - for (int i = 0; i < this.servers.length; i++) { - String str = this.servers[i]; - int idx = str.indexOf(":"); - if (idx == -1) { - throw new ConfigurationException("Ldap server settings should be in format server:port"); - } - this.addresses[i] = str.substring(0, idx).trim(); - this.ports[i] = Integer.parseInt(str.substring(str.indexOf(":") + 1, str.length())); - } - - BindRequest bindRequest = null; - if (StringHelper.isEmpty(props.getProperty("bindDN"))) { - this.bindDn = null; - this.bindPassword = null; - bindRequest = new SimpleBindRequest(); - } else { - this.bindDn = props.getProperty("bindDN"); - this.bindPassword = props.getProperty("bindPassword"); - bindRequest = new SimpleBindRequest(this.bindDn, this.bindPassword); - } - - LDAPConnectionOptions connectionOptions = new LDAPConnectionOptions(); - connectionOptions.setConnectTimeoutMillis(100 * 1000); - connectionOptions.setAutoReconnect(true); - - this.useSSL = Boolean.valueOf(props.getProperty("useSSL")).booleanValue(); - - SSLUtil sslUtil = null; - FailoverServerSet failoverSet; - if (this.useSSL) { - String sslTrustStoreFile = props.getProperty("ssl.trustStoreFile"); - String sslTrustStorePin = props.getProperty("ssl.trustStorePin"); - String sslTrustStoreFormat = props.getProperty("ssl.trustStoreFormat"); - - if (StringHelper.isEmpty(sslTrustStoreFile) && StringHelper.isEmpty(sslTrustStorePin)) { - sslUtil = new SSLUtil(new TrustAllTrustManager()); - } else { - TrustStoreTrustManager trustStoreTrustManager = new TrustStoreTrustManager(sslTrustStoreFile, sslTrustStorePin.toCharArray(), - sslTrustStoreFormat, true); - sslUtil = new SSLUtil(trustStoreTrustManager); - } - - failoverSet = new FailoverServerSet(this.addresses, this.ports, sslUtil.createSSLSocketFactory(SSL_PROTOCOLS[0]), connectionOptions); - } else { - failoverSet = new FailoverServerSet(this.addresses, this.ports, connectionOptions); - } - - int maxConnections = StringHelper.toInt(props.getProperty("maxconnections"), 10); - this.connectionPool = createConnectionPoolWithWaitImpl(props, failoverSet, bindRequest, connectionOptions, maxConnections, sslUtil); - if (this.connectionPool != null) { - this.connectionPool.setCreateIfNecessary(true); - String connectionMaxWaitTime = props.getProperty("connection.max-wait-time-millis"); - if (StringHelper.isNotEmpty(connectionMaxWaitTime)) { - this.connectionPool.setMaxWaitTimeMillis(Long.parseLong(connectionMaxWaitTime)); - } - String maxConnectionAge = props.getProperty("connection.max-age-time-millis"); - if (StringHelper.isNotEmpty(connectionMaxWaitTime)) { - this.connectionPool.setMaxConnectionAgeMillis(Long.parseLong(maxConnectionAge)); - } - boolean onCheckoutHealthCheckEnabled = StringHelper.toBoolean(props.getProperty("connection-pool.health-check.on-checkout.enabled"), false); - long healthCheckIntervalMillis = StringHelper.toLong(props.getProperty("connection-pool.health-check.interval-millis"), 0); - long healthCheckMaxResponsetimeMillis = StringHelper.toLong(props.getProperty("connection-pool.health-check.max-response-time-millis"), 0); - boolean backgroundHealthCheckEnabled = !onCheckoutHealthCheckEnabled && (healthCheckIntervalMillis > 0); - // Because otherwise it has no effect anyway - if (backgroundHealthCheckEnabled) { - this.connectionPool.setHealthCheckIntervalMillis(healthCheckIntervalMillis); - } - if (onCheckoutHealthCheckEnabled || backgroundHealthCheckEnabled) { - GetEntryLDAPConnectionPoolHealthCheck healthChecker = new GetEntryLDAPConnectionPoolHealthCheck(// entryDN (null means root DSE) - null, // maxResponseTime - healthCheckMaxResponsetimeMillis, // invokeOnCreate - false, // invokeOnCheckout - onCheckoutHealthCheckEnabled, // invokeOnRelease - false, // invokeForBackgroundChecks - backgroundHealthCheckEnabled, // invokeOnException - false); - - this.connectionPool.setHealthCheck(healthChecker); - } - } - - this.additionalPasswordMethods = new ArrayList(); - if (props.containsKey("additionalPasswordMethods")) { - String[] additionalPasswordMethodsArray = StringHelper.split(props.get("additionalPasswordMethods").toString(), ","); - for (String additionalPasswordMethod : additionalPasswordMethodsArray) { - PasswordEncryptionMethod passwordEncryptionMethod = PasswordEncryptionMethod.getMethod(additionalPasswordMethod); - if (passwordEncryptionMethod != null) { - this.additionalPasswordMethods.add(passwordEncryptionMethod); - } - } - } - LOG.debug("Adding support for password methods: " + this.additionalPasswordMethods); - - this.binaryAttributes = new ArrayList(); - if (props.containsKey("binaryAttributes")) { - String[] binaryAttrs = StringHelper.split(props.get("binaryAttributes").toString().toLowerCase(), ","); - this.binaryAttributes.addAll(Arrays.asList(binaryAttrs)); - } - LOG.debug("Using next binary attributes: " + this.binaryAttributes); - - this.certificateAttributes = new ArrayList(); - if (props.containsKey("certificateAttributes")) { - String[] binaryAttrs = StringHelper.split(props.get("certificateAttributes").toString().toLowerCase(), ","); - this.certificateAttributes.addAll(Arrays.asList(binaryAttrs)); - } - LOG.debug("Using next binary certificateAttributes: " + this.certificateAttributes); - - this.supportedLDAPVersion = determineSupportedLdapVersion(); - this.subschemaSubentry = determineSubschemaSubentry(); - this.supportsSubtreeDeleteRequestControl = supportsSubtreeDeleteRequestControl(); - this.creationResultCode = ResultCode.SUCCESS; - } - - private LDAPConnectionPool createConnectionPoolWithWaitImpl(Properties props, FailoverServerSet failoverSet, BindRequest bindRequest, - LDAPConnectionOptions connectionOptions, int maxConnections, SSLUtil sslUtil) throws LDAPException { - int connectionPoolMaxWaitTimeSeconds = StringHelper.toInt(props.getProperty("connection-pool-max-wait-time"), 30); - LOG.debug("Using LDAP connection pool timeout: '" + connectionPoolMaxWaitTimeSeconds + "'"); - - LDAPConnectionPool createdConnectionPool = null; - LDAPException lastException = null; - - int attempt = 0; - long currentTime = System.currentTimeMillis(); - long maxWaitTime = currentTime + connectionPoolMaxWaitTimeSeconds * 1000; - do { - attempt++; - if (attempt > 0) { - LOG.info("Attempting to create connection pool: " + attempt); - } - - try { - createdConnectionPool = createConnectionPoolImpl(failoverSet, bindRequest, connectionOptions, maxConnections, sslUtil); - break; - } catch (LDAPException ex) { - if (ex.getResultCode().intValue() != ResultCode.CONNECT_ERROR_INT_VALUE) { - throw ex; - } - lastException = ex; - } - - try { - Thread.sleep(5000); - } catch (InterruptedException ex) { - LOG.error("Exception happened in sleep", ex); - return null; - } - currentTime = System.currentTimeMillis(); - } while (maxWaitTime > currentTime); - - if ((createdConnectionPool == null) && (lastException != null)) { - throw lastException; - } - - return createdConnectionPool; - } - - private LDAPConnectionPool createConnectionPoolImpl(FailoverServerSet failoverSet, BindRequest bindRequest, - LDAPConnectionOptions connectionOptions, int maxConnections, SSLUtil sslUtil) throws LDAPException { - - LDAPConnectionPool createdConnectionPool; - try { - createdConnectionPool = new LDAPConnectionPool(failoverSet, bindRequest, maxConnections); - } catch (LDAPException ex) { - if (!this.useSSL) { - throw ex; - } - - // Error when LDAP server not supports specified encryption - if (ex.getResultCode() != ResultCode.SERVER_DOWN) { - throw ex; - } - - LOG.info("Attempting to use older SSL protocols", ex); - createdConnectionPool = createSSLConnectionPoolWithPreviousProtocols(sslUtil, bindRequest, connectionOptions, maxConnections); - if (createdConnectionPool == null) { - throw ex; - } - } - - return createdConnectionPool; - } - - private LDAPConnectionPool createSSLConnectionPoolWithPreviousProtocols(SSLUtil sslUtil, BindRequest bindRequest, - LDAPConnectionOptions connectionOptions, int maxConnections) throws LDAPException { - for (int i = 1; i < SSL_PROTOCOLS.length; i++) { - String protocol = SSL_PROTOCOLS[i]; - try { - FailoverServerSet failoverSet = new FailoverServerSet(this.addresses, this.ports, sslUtil.createSSLSocketFactory(protocol), - connectionOptions); - LDAPConnectionPool connectionPool = new LDAPConnectionPool(failoverSet, bindRequest, maxConnections); - - LOG.info("Server supports: '" + protocol + "'"); - return connectionPool; - } catch (GeneralSecurityException ex) { - LOG.debug("Server not supports: '" + protocol + "'", ex); - } catch (LDAPException ex) { - // Error when LDAP server not supports specified encryption - if (ex.getResultCode() != ResultCode.SERVER_DOWN) { - throw ex; - } - LOG.debug("Server not supports: '" + protocol + "'", ex); - } - } - - return null; - } - - private int determineSupportedLdapVersion() { - int resultSupportedLDAPVersion = LdapConnectionProvider.DEFAULT_SUPPORTED_LDAP_VERSION; - - boolean validConnection = isValidConnection(); - if (!validConnection) { - return resultSupportedLDAPVersion; - } - - try { - String[] supportedLDAPVersions = connectionPool.getRootDSE().getAttributeValues("supportedLDAPVersion"); - if (ArrayHelper.isEmpty(supportedLDAPVersions)) { - return resultSupportedLDAPVersion; - } - - for (String supportedLDAPVersion : supportedLDAPVersions) { - resultSupportedLDAPVersion = Math.max(resultSupportedLDAPVersion, Integer.parseInt(supportedLDAPVersion)); - } - } catch (Exception ex) { - LOG.error("Failed to determine supportedLDAPVersion", ex); - } - - return resultSupportedLDAPVersion; - } - - private String determineSubschemaSubentry() { - String resultSubschemaSubentry = LdapConnectionProvider.DEFAULT_SUBSCHEMA_SUBENTRY; - - boolean validConnection = isValidConnection(); - if (!validConnection) { - return resultSubschemaSubentry; - } - - try { - String subschemaSubentry = connectionPool.getRootDSE().getAttributeValue("subschemaSubentry"); - if (StringHelper.isEmpty(subschemaSubentry)) { - return resultSubschemaSubentry; - } - resultSubschemaSubentry = subschemaSubentry; - } catch (Exception ex) { - LOG.error("Failed to determine subschemaSubentry", ex); - } - - return resultSubschemaSubentry; - } - - private boolean supportsSubtreeDeleteRequestControl() { - boolean supportsSubtreeDeleteRequestControl = false; - - boolean validConnection = isValidConnection(); - if (!validConnection) { - return supportsSubtreeDeleteRequestControl; - } - - try { - supportsSubtreeDeleteRequestControl = connectionPool.getRootDSE() - .supportsControl(com.unboundid.ldap.sdk.controls.SubtreeDeleteRequestControl.SUBTREE_DELETE_REQUEST_OID); - } catch (Exception ex) { - LOG.error("Failed to determine if LDAP server supports Subtree Delete Request Control", ex); - } - - return supportsSubtreeDeleteRequestControl; - } - - private boolean isValidConnection() { - if (StringHelper.isEmptyString(bindDn) || StringHelper.isEmptyString(bindPassword)) { - return false; - } - - if (connectionPool == null) { - return false; - } - - return true; - } - - public int getSupportedLDAPVersion() { - return supportedLDAPVersion; - } - - public String getSubschemaSubentry() { - return subschemaSubentry; - } - - public boolean isSupportsSubtreeDeleteRequestControl() { - return supportsSubtreeDeleteRequestControl; - } - - /** - * This method is used to get LDAP connection from connectionPool if the - * connection is not available it will return new connection - * - * @return LDAPConnection from the connectionPool - * @throws LDAPException - */ - public LDAPConnection getConnection() throws LDAPException { - return connectionPool.getConnection(); - } - - /** - * Use this method to get connection pool instance; - * - * @return LDAPConnectionPool - * @throws LDAPException - * @throws NumberFormatException - */ - - /** - * Use this static method to release LDAPconnection to LDAPConnectionpool - * - * @param connection - */ - public void releaseConnection(LDAPConnection connection) { - connectionPool.releaseConnection(connection); - } - - /** - * This method to release back the connection after a exception occured - * - * @param connection - * @param ex - * (LDAPException) - */ - public void releaseConnection(LDAPConnection connection, LDAPException ex) { - connectionPool.releaseConnectionAfterException(connection, ex); - } - - /** - * This method is used to release back a connection that is no longer been used - * or fit to be used - * - * @param connection - */ - public void closeDefunctConnection(LDAPConnection connection) { - connectionPool.releaseDefunctConnection(connection); - } - - public LDAPConnectionPool getConnectionPool() { - return connectionPool; - } - - public void closeConnectionPool() { - connectionPool.close(); - } - - public boolean isConnected() { - if (connectionPool == null) { - return false; - } - - boolean isConnected = false; - try { - LDAPConnection connection = getConnection(); - try { - isConnected = connection.isConnected(); - } finally { - releaseConnection(connection); - } - } catch (LDAPException ex) { - } - - return isConnected; - } - - public ResultCode getCreationResultCode() { - return creationResultCode; - } - - public void setCreationResultCode(ResultCode creationResultCode) { - this.creationResultCode = creationResultCode; - } - - public boolean isCreated() { - return ResultCode.SUCCESS == this.creationResultCode; - } - - public String[] getServers() { - return servers; - } - - public String[] getAddresses() { - return addresses; - } - - public int[] getPorts() { - return ports; - } - - public String getBindDn() { - return bindDn; - } - - public String getBindPassword() { - return bindPassword; - } - - public boolean isUseSSL() { - return useSSL; - } - - public final ArrayList getAdditionalPasswordMethods() { - return additionalPasswordMethods; - } - - public ArrayList getBinaryAttributes() { - return binaryAttributes; - } - - public ArrayList getCertificateAttributes() { - return certificateAttributes; - } - - public boolean isBinaryAttribute(String attributeName) { - if (StringHelper.isEmpty(attributeName)) { - return false; - } - - return binaryAttributes.contains(attributeName.toLowerCase()); - } - - public boolean isCertificateAttribute(String attributeName) { - String realAttributeName = getCertificateAttributeName(attributeName); - - return certificateAttributes.contains(realAttributeName.toLowerCase()); - } - - public String getCertificateAttributeName(String attributeName) { - if (StringHelper.isEmpty(attributeName)) { - return attributeName; - } - - if (attributeName.endsWith(";binary")) { - return attributeName.substring(0, attributeName.length() - 7); - } - - return attributeName; - } - -} diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java deleted file mode 100644 index 12d072c0..00000000 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/impl/LdapOperationServiceImpl.java +++ /dev/null @@ -1,1252 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.ldap.operation.impl; - -import java.io.Serializable; -import java.time.Duration; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.apache.commons.lang.StringUtils; -import org.gluu.persist.exception.MappingException; -import org.gluu.persist.exception.extension.PersistenceExtension; -import org.gluu.persist.exception.operation.ConnectionException; -import org.gluu.persist.exception.operation.DuplicateEntryException; -import org.gluu.persist.exception.operation.SearchException; -import org.gluu.persist.ldap.exception.InvalidSimplePageControlException; -import org.gluu.persist.ldap.impl.LdapBatchOperationWraper; -import org.gluu.persist.ldap.operation.LdapOperationService; -import org.gluu.persist.ldap.operation.watch.OperationDurationUtil; -import org.gluu.persist.model.BatchOperation; -import org.gluu.persist.model.PagedResult; -import org.gluu.persist.model.SortOrder; -import org.gluu.persist.operation.auth.PasswordEncryptionHelper; -import org.gluu.persist.operation.auth.PasswordEncryptionMethod; -import org.gluu.util.ArrayHelper; -import org.gluu.util.Pair; -import org.gluu.util.StringHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.unboundid.asn1.ASN1OctetString; -import com.unboundid.ldap.sdk.Attribute; -import com.unboundid.ldap.sdk.BindResult; -import com.unboundid.ldap.sdk.Control; -import com.unboundid.ldap.sdk.DeleteRequest; -import com.unboundid.ldap.sdk.Filter; -import com.unboundid.ldap.sdk.LDAPConnection; -import com.unboundid.ldap.sdk.LDAPConnectionPool; -import com.unboundid.ldap.sdk.LDAPException; -import com.unboundid.ldap.sdk.LDAPResult; -import com.unboundid.ldap.sdk.LDAPSearchException; -import com.unboundid.ldap.sdk.Modification; -import com.unboundid.ldap.sdk.ModificationType; -import com.unboundid.ldap.sdk.ModifyRequest; -import com.unboundid.ldap.sdk.ResultCode; -import com.unboundid.ldap.sdk.SearchRequest; -import com.unboundid.ldap.sdk.SearchResult; -import com.unboundid.ldap.sdk.SearchResultEntry; -import com.unboundid.ldap.sdk.SearchResultReference; -import com.unboundid.ldap.sdk.SearchScope; -import com.unboundid.ldap.sdk.controls.ServerSideSortRequestControl; -import com.unboundid.ldap.sdk.controls.SimplePagedResultsControl; -import com.unboundid.ldap.sdk.controls.SortKey; -import com.unboundid.ldap.sdk.controls.SubtreeDeleteRequestControl; -import com.unboundid.ldap.sdk.controls.VirtualListViewRequestControl; -import com.unboundid.ldap.sdk.controls.VirtualListViewResponseControl; -import com.unboundid.ldap.sdk.schema.AttributeTypeDefinition; -import com.unboundid.ldif.LDIFChangeRecord; - -/** - * OperationsFacade is the base class that performs all the ldap operations - * using connectionpool - * - * @author Pankaj - * @author Yuriy Movchan - */ -public class LdapOperationServiceImpl implements LdapOperationService { - - private static final Logger LOG = LoggerFactory.getLogger(LdapOperationServiceImpl.class); - - private LdapConnectionProvider connectionProvider; - private LdapConnectionProvider bindConnectionProvider; - - private PersistenceExtension persistenceExtension; - - private static Map> ATTRIBUTE_DATA_TYPES = new HashMap>(); - private static final Map> OID_SYNTAX_CLASS_MAPPING; - - static { - //Populates the mapping of syntaxes that will support comparison of attribute values. - //Only accounting for the most common and existing in Gluu Schema - OID_SYNTAX_CLASS_MAPPING = new HashMap>(); - //See RFC4517, section 3.3 - OID_SYNTAX_CLASS_MAPPING.put("1.3.6.1.4.1.1466.115.121.1.7", Boolean.class); - OID_SYNTAX_CLASS_MAPPING.put("1.3.6.1.4.1.1466.115.121.1.11", String.class); //Country String - OID_SYNTAX_CLASS_MAPPING.put("1.3.6.1.4.1.1466.115.121.1.15", String.class); //Directory String - OID_SYNTAX_CLASS_MAPPING.put("1.3.6.1.4.1.1466.115.121.1.12", String.class); //DN - OID_SYNTAX_CLASS_MAPPING.put("1.3.6.1.4.1.1466.115.121.1.22", String.class); //Facsimile - OID_SYNTAX_CLASS_MAPPING.put("1.3.6.1.4.1.1466.115.121.1.24", Date.class); //Generalized Time - OID_SYNTAX_CLASS_MAPPING.put("1.3.6.1.4.1.1466.115.121.1.26", String.class); //IA5 String (used in email) - OID_SYNTAX_CLASS_MAPPING.put("1.3.6.1.4.1.1466.115.121.1.27", Integer.class); - OID_SYNTAX_CLASS_MAPPING.put("1.3.6.1.4.1.1466.115.121.1.36", String.class); //Numeric string - OID_SYNTAX_CLASS_MAPPING.put("1.3.6.1.4.1.1466.115.121.1.41", String.class); //Postal address - OID_SYNTAX_CLASS_MAPPING.put("1.3.6.1.4.1.1466.115.121.1.50", String.class); //Telephone number - } - - @SuppressWarnings("unused") - private LdapOperationServiceImpl() { - } - - public LdapOperationServiceImpl(LdapConnectionProvider connectionProvider) { - this(connectionProvider, null); - populateAttributeDataTypesMapping(getSubschemaSubentry()); - } - - public LdapOperationServiceImpl(LdapConnectionProvider connectionProvider, LdapConnectionProvider bindConnectionProvider) { - this.connectionProvider = connectionProvider; - this.bindConnectionProvider = bindConnectionProvider; - populateAttributeDataTypesMapping(getSubschemaSubentry()); - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#getConnectionProvider() - */ - @Override - public LdapConnectionProvider getConnectionProvider() { - return connectionProvider; - } - - /* - * (non-Javadoc) - * - * @see - * org.gluu.site.ldap.PlatformOperationFacade#setConnectionProvider(org.gluu. - * site.ldap.LdapConnectionProvider) - */ - @Override - public void setConnectionProvider(LdapConnectionProvider connectionProvider) { - this.connectionProvider = connectionProvider; - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#getBindConnectionProvider() - */ - @Override - public LdapConnectionProvider getBindConnectionProvider() { - return bindConnectionProvider; - } - - /* - * (non-Javadoc) - * - * @see - * org.gluu.site.ldap.PlatformOperationFacade#setBindConnectionProvider(org.gluu - * .site.ldap.LdapConnectionProvider) - */ - @Override - public void setBindConnectionProvider(LdapConnectionProvider bindConnectionProvider) { - this.bindConnectionProvider = bindConnectionProvider; - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#getConnectionPool() - */ - @Override - public LDAPConnectionPool getConnectionPool() { - return connectionProvider.getConnectionPool(); - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#getConnection() - */ - @Override - public LDAPConnection getConnection() throws LDAPException { - return connectionProvider.getConnection(); - } - - /* - * (non-Javadoc) - * - * @see - * org.gluu.site.ldap.PlatformOperationFacade#releaseConnection(com.unboundid. - * ldap.sdk.LDAPConnection) - */ - @Override - public void releaseConnection(LDAPConnection connection) { - connectionProvider.releaseConnection(connection); - } - - /* - * (non-Javadoc) - * - * @see - * org.gluu.site.ldap.PlatformOperationFacade#authenticate(java.lang.String, - * java.lang.String) - */ - @Override - public boolean authenticate(final String bindDn, final String password) throws ConnectionException { - try { - return authenticateImpl(bindDn, password); - } catch (LDAPException ex) { - throw new ConnectionException("Failed to authenticate dn", ex); - } - } - - private boolean authenticateImpl(final String bindDn, final String password) throws LDAPException, ConnectionException { - Instant startTime = OperationDurationUtil.instance().now(); - - boolean result = false; - - // Try to authenticate if the password was encrypted with additional mechanism - List additionalPasswordMethods = this.connectionProvider.getAdditionalPasswordMethods(); - if ((persistenceExtension != null) || !additionalPasswordMethods.isEmpty()) { - SearchResultEntry searchResult = lookup(bindDn, USER_PASSWORD); - if (searchResult == null) { - throw new ConnectionException("Failed to find use by dn"); - } - - String userPassword = searchResult.getAttribute(USER_PASSWORD).getValue(); - if (userPassword != null) { - if (persistenceExtension != null) { - result = persistenceExtension.compareHashedPasswords(password, userPassword); - } else { - PasswordEncryptionMethod storedPasswordMethod = PasswordEncryptionHelper.findAlgorithm(userPassword); - if (additionalPasswordMethods.contains(storedPasswordMethod)) { - LOG.debug("Authenticating '{}' using internal authentication mechanism '{}'", bindDn, storedPasswordMethod); - result = PasswordEncryptionHelper.compareCredentials(password, userPassword); - } - } - } - } else { - if (this.bindConnectionProvider == null) { - result = authenticateConnectionPoolImpl(bindDn, password); - } else { - result = authenticateBindConnectionPoolImpl(bindDn, password); - } - } - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("LDAP operation: bind, duration: {}, dn: {}", duration, bindDn); - - return result; - } - - private boolean authenticateConnectionPoolImpl(final String bindDn, final String password) throws LDAPException, ConnectionException { - boolean loggedIn = false; - - if (bindDn == null) { - return loggedIn; - } - - boolean closeConnection = false; - LDAPConnection connection = connectionProvider.getConnection(); - try { - closeConnection = true; - BindResult r = connection.bind(bindDn, password); - if (r.getResultCode() == ResultCode.SUCCESS) { - loggedIn = true; - } - } finally { - connectionProvider.releaseConnection(connection); - // We can't use connection which binded as ordinary user - if (closeConnection) { - connectionProvider.closeDefunctConnection(connection); - } - } - - return loggedIn; - } - - private boolean authenticateBindConnectionPoolImpl(final String bindDn, final String password) throws LDAPException, ConnectionException { - if (bindDn == null) { - return false; - } - - LDAPConnection connection = bindConnectionProvider.getConnection(); - try { - BindResult r = connection.bind(bindDn, password); - return r.getResultCode() == ResultCode.SUCCESS; - } finally { - bindConnectionProvider.releaseConnection(connection); - } - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#search(java.lang.String, - * com.unboundid.ldap.sdk.Filter, org.gluu.ldap.model.SearchScope, - * org.gluu.site.ldap.persistence.BatchOperation, int, int, int, - * com.unboundid.ldap.sdk.Control[], java.lang.String) - */ - @Override - public SearchResult search(String dn, Filter filter, SearchScope scope, LdapBatchOperationWraper batchOperationWraper, int start, - int searchLimit, int count, Control[] controls, String... attributes) throws SearchException { - Instant startTime = OperationDurationUtil.instance().now(); - - SearchResult result = searchImpl(dn, filter, scope, batchOperationWraper, start, searchLimit, count, controls, attributes); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("LDAP operation: search, duration: {}, dn: {}, filter: {}, scope: {}, batchOperationWraper: {}, start: {}, searchLimit: {}, count: {}, controls: {}, attributes: {}", duration, dn, filter, scope, batchOperationWraper, start, searchLimit, count, controls, attributes); - - return result; - } - - private SearchResult searchImpl(String dn, Filter filter, SearchScope scope, LdapBatchOperationWraper batchOperationWraper, int start, - int searchLimit, int count, Control[] controls, String... attributes) throws SearchException { - SearchRequest searchRequest; - - BatchOperation ldapBatchOperation = null; - if (batchOperationWraper != null) { - ldapBatchOperation = (BatchOperation) batchOperationWraper.getBatchOperation(); - } - - if (LOG.isTraceEnabled()) { - // Find whole tree search. This can be very slow - if (StringHelper.equalsIgnoreCase(dn, "o=gluu")) { - LOG.trace("Search in whole LDAP tree", new Exception()); - } - } - - if (attributes == null) { - searchRequest = new SearchRequest(dn, scope, filter); - } else { - searchRequest = new SearchRequest(dn, scope, filter, attributes); - } - - boolean useSizeLimit = count > 0; - - if (useSizeLimit) { - // Use paged result to limit search - searchLimit = count; - } - - SearchResult searchResult = null; - List searchResultList = new ArrayList(); - List searchResultEntries = new ArrayList(); - List searchResultReferences = new ArrayList(); - - if ((searchLimit > 0) || (start > 0)) { - if (searchLimit == 0) { - // Default page size - searchLimit = 100; - } - - boolean collectSearchResult; - - LDAPConnection ldapConnection = null; - try { - ldapConnection = getConnectionPool().getConnection(); - ASN1OctetString cookie = null; - SimplePagedResponse simplePagedResponse = null; - if (start > 0) { - try { - simplePagedResponse = scrollSimplePagedResultsControl(ldapConnection, dn, filter, scope, controls, start); - cookie = simplePagedResponse.getCookie(); - } catch (InvalidSimplePageControlException ex) { - throw new LDAPSearchException(ex.getResultCode(), "Failed to scroll to specified start", ex); - } catch (LDAPException ex) { - throw new LDAPSearchException(ex.getResultCode(), "Failed to scroll to specified start", ex); - } - } - - if ((cookie != null) && (cookie.getValueLength() == 0)) { - SearchResult searchResultTemp = simplePagedResponse.getLastSearchResult(); - return new SearchResult(searchResultTemp.getMessageID(), searchResultTemp.getResultCode(), searchResultTemp.getDiagnosticMessage(), - searchResultTemp.getMatchedDN(), searchResultTemp.getReferralURLs(), searchResultEntries, searchResultReferences, - searchResultEntries.size(), searchResultReferences.size(), searchResultTemp.getResponseControls()); - } - - do { - collectSearchResult = true; - searchRequest.setControls(new Control[] {new SimplePagedResultsControl(searchLimit, cookie)}); - setControls(searchRequest, controls); - searchResult = ldapConnection.search(searchRequest); - - if (ldapBatchOperation != null) { - collectSearchResult = ldapBatchOperation.collectSearchResult(searchResult.getEntryCount()); - } - if (collectSearchResult) { - searchResultList.add(searchResult); - searchResultEntries.addAll(searchResult.getSearchEntries()); - searchResultReferences.addAll(searchResult.getSearchReferences()); - } - - if (ldapBatchOperation != null) { - List entries = batchOperationWraper.createEntities(searchResult); - ldapBatchOperation.performAction(entries); - } - cookie = null; - try { - SimplePagedResultsControl c = SimplePagedResultsControl.get(searchResult); - if (c != null) { - cookie = c.getCookie(); - } - } catch (LDAPException ex) { - LOG.error("Error while accessing cookies" + ex.getMessage()); - } - - if (useSizeLimit) { - break; - } - } while ((cookie != null) && (cookie.getValueLength() > 0)); - } catch (LDAPException ex) { - throw new SearchException("Failed to scroll to specified start", ex, ex.getResultCode().intValue()); - } finally { - if (ldapConnection != null) { - getConnectionPool().releaseConnection(ldapConnection); - } - } - - if (!collectSearchResult) { - return new SearchResult(searchResult.getMessageID(), searchResult.getResultCode(), searchResult.getDiagnosticMessage(), - searchResult.getMatchedDN(), searchResult.getReferralURLs(), searchResultEntries, searchResultReferences, - searchResultEntries.size(), searchResultReferences.size(), searchResult.getResponseControls()); - } - - if (!searchResultList.isEmpty()) { - SearchResult searchResultTemp = searchResultList.get(0); - return new SearchResult(searchResultTemp.getMessageID(), searchResultTemp.getResultCode(), searchResultTemp.getDiagnosticMessage(), - searchResultTemp.getMatchedDN(), searchResultTemp.getReferralURLs(), searchResultEntries, searchResultReferences, - searchResultEntries.size(), searchResultReferences.size(), searchResultTemp.getResponseControls()); - } - } else { - setControls(searchRequest, controls); - try { - searchResult = getConnectionPool().search(searchRequest); - } catch (LDAPSearchException ex) { - throw new SearchException(ex.getMessage(), ex, ex.getResultCode().intValue()); - } - } - - return searchResult; - } - - private SimplePagedResponse scrollSimplePagedResultsControl(LDAPConnection ldapConnection, String dn, Filter filter, SearchScope scope, - Control[] controls, int start) throws LDAPException, InvalidSimplePageControlException { - SearchRequest searchRequest = new SearchRequest(dn, scope, filter, "dn"); - - int currentStartIndex = start; - ASN1OctetString cookie = null; - SearchResult searchResult = null; - do { - int pageSize = Math.min(currentStartIndex, 100); - searchRequest.setControls(new Control[] {new SimplePagedResultsControl(pageSize, cookie, true)}); - setControls(searchRequest, controls); - searchResult = ldapConnection.search(searchRequest); - - currentStartIndex -= searchResult.getEntryCount(); - try { - SimplePagedResultsControl c = SimplePagedResultsControl.get(searchResult); - if (c != null) { - cookie = c.getCookie(); - } - } catch (LDAPException ex) { - LOG.error("Error while accessing cookie", ex); - throw new InvalidSimplePageControlException(ex.getResultCode(), "Error while accessing cookie"); - } - } while ((cookie != null) && (cookie.getValueLength() > 0) && (currentStartIndex > 0)); - - return new SimplePagedResponse(cookie, searchResult); - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#searchSearchResult(java.lang. - * String, com.unboundid.ldap.sdk.Filter, org.gluu.ldap.model.SearchScope, int, - * int, int, java.lang.String, org.gluu.ldap.model.SortOrder, - * org.gluu.ldap.model.VirtualListViewResponse, java.lang.String) - */ - @Override - public List searchSearchResultEntryList(String dn, Filter filter, SearchScope scope, int startIndex, - int count, int pageSize, String sortBy, SortOrder sortOrder, - PagedResult vlvResponse, String... attributes) throws Exception { - Instant startTime = OperationDurationUtil.instance().now(); - - List result = searchSearchResultEntryListImpl(dn, filter, scope, startIndex, count, pageSize, sortBy, sortOrder, vlvResponse, attributes); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("LDAP operation: search_result_list, duration: {}, dn: {}, filter: {}, scope: {}, startIndex: {}, count: {}, pageSize: {}, sortBy: {}, sortOrder: {}, vlvResponse: {}, attributes: {}", duration, dn, filter, scope, startIndex, count, pageSize, sortBy, sortOrder, vlvResponse, attributes); - - return result; - } - - private List searchSearchResultEntryListImpl(String dn, Filter filter, SearchScope scope, int start, int count, - int pageSize, String sortBy, SortOrder sortOrder, PagedResult vlvResponse, String... attributes) throws LDAPException, Exception { - //This method does not assume that count <= pageSize as occurs in SCIM, but it's more general - - //Why this? - if (StringHelper.equalsIgnoreCase(dn, "o=gluu")) { - (new Exception()).printStackTrace(); - } - - List searchEntries; - ASN1OctetString resumeCookie = null; - LDAPConnection conn = getConnection(); - SearchRequest searchRequest = new SearchRequest(dn, scope, filter, attributes); - - int totalResults = 0; - - do { - //Keep searching while we reach start index... - SearchResult searchResult = nextSearchResult(conn, searchRequest, pageSize, resumeCookie); - searchEntries = searchResult.getSearchEntries(); - totalResults += searchEntries.size(); - - resumeCookie = getSearchResultCookie(searchResult); - } while (totalResults < start && resumeCookie != null); - - List searchResultEntryList = new ArrayList(); - - if (totalResults > start) { - //Take the interesting ones, ie. skip [0, start) interval - int lowerBound = searchEntries.size() - (totalResults - start); - int upperBound = Math.min(searchEntries.size(), lowerBound + count); - searchResultEntryList.addAll(searchEntries.subList(lowerBound, upperBound)); - } - - //Continue adding results till reaching count if needed - while (resumeCookie != null && totalResults < count + start) { - SearchResult searchResult = nextSearchResult(conn, searchRequest, pageSize, resumeCookie); - searchEntries = searchResult.getSearchEntries(); - searchResultEntryList.addAll(searchEntries); - totalResults += searchEntries.size(); - - resumeCookie = getSearchResultCookie(searchResult); - } - - if (totalResults > count + start) { - //Remove the uninteresting tail - searchResultEntryList = searchResultEntryList.subList(0, count); - } - - //skip the rest and update the number of total results only - while (resumeCookie != null) { - SearchResult searchResult = nextSearchResult(conn, searchRequest, pageSize, resumeCookie); - searchEntries = searchResult.getSearchEntries(); - totalResults += searchEntries.size(); - - resumeCookie = getSearchResultCookie(searchResult); - } - - if (StringUtils.isNotEmpty(sortBy)) { - boolean ascending = sortOrder == null || sortOrder.equals(SortOrder.ASCENDING); - searchResultEntryList = sortListByAttributes(searchResultEntryList, SearchResultEntry.class, false, ascending, sortBy); - } - - // Get results info - vlvResponse.setEntriesCount(searchResultEntryList.size()); - vlvResponse.setTotalEntriesCount(totalResults); - vlvResponse.setStart(start); - - releaseConnection(conn); - return searchResultEntryList; - } - - private ASN1OctetString getSearchResultCookie(SearchResult searchResult) throws Exception { - SimplePagedResultsControl responseControl = SimplePagedResultsControl.get(searchResult); - return responseControl.moreResultsToReturn() ? responseControl.getCookie() : null; - } - - private SearchResult nextSearchResult(LDAPConnection connection, SearchRequest searchRequest, int pageSize, - ASN1OctetString resumeCookie) throws Exception { - - searchRequest.setControls(new SimplePagedResultsControl(pageSize, resumeCookie)); - SearchResult result = connection.search(searchRequest); - - if (!ResultCode.SUCCESS.equals(result.getResultCode())) { - String msgErr = "Search operation returned: " + result.getResultCode(); - LOG.error(msgErr); - throw new Exception(msgErr); - } - return result; - - } - - /* - * (non-Javadoc) - * - * @see - * org.gluu.site.ldap.PlatformOperationFacade#searchVirtualListView(java.lang. - * String, com.unboundid.ldap.sdk.Filter, org.gluu.ldap.model.SearchScope, int, - * int, java.lang.String, org.gluu.ldap.model.SortOrder, - * org.gluu.ldap.model.VirtualListViewResponse, java.lang.String) - */ - @Deprecated - public SearchResult searchVirtualListView(String dn, Filter filter, SearchScope scope, int start, int count, String sortBy, - SortOrder sortOrder, PagedResult vlvResponse, String... attributes) throws Exception { - Instant startTime = OperationDurationUtil.instance().now(); - - SearchResult result = searchVirtualListViewImpl(dn, filter, scope, start, count, sortBy, sortOrder, vlvResponse, attributes); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("LDAP operation: search_virtual_list_view, duration: {}, dn: {}, filter: {}, scope: {}, start: {}, count: {}, sortBy: {}, sortOrder: {}, vlvResponse: {}, attributes: {}", duration, dn, filter, scope, start, count, sortBy, sortOrder, vlvResponse, attributes); - - return result; - } - - private SearchResult searchVirtualListViewImpl(String dn, Filter filter, SearchScope scope, int start, int count, String sortBy, - SortOrder sortOrder, PagedResult vlvResponse, String... attributes) throws LDAPSearchException, LDAPException { - if (StringHelper.equalsIgnoreCase(dn, "o=gluu")) { - (new Exception()).printStackTrace(); - } - - SearchRequest searchRequest; - - if (attributes == null) { - searchRequest = new SearchRequest(dn, scope, filter); - } else { - searchRequest = new SearchRequest(dn, scope, filter, attributes); - } - - // start and count should be "cleansed" before arriving here - int targetOffset = start; - int beforeCount = 0; - int afterCount = (count > 0) ? (count - 1) : 0; - int contentCount = 0; - - boolean reverseOrder = false; - if (sortOrder != null) { - reverseOrder = sortOrder.equals(SortOrder.DESCENDING) ? true : false; - } - - // Note that the VLV control always requires the server-side sort control. - searchRequest.setControls(new ServerSideSortRequestControl(new SortKey(sortBy, reverseOrder)), - new VirtualListViewRequestControl(targetOffset, beforeCount, afterCount, contentCount, null)); - - SearchResult searchResult = getConnectionPool().search(searchRequest); - - /* - * for (SearchResultEntry searchResultEntry : searchResult.getSearchEntries()) { - * log.info("##### searchResultEntry = " + searchResultEntry.toString()); } - */ - - // LDAPTestUtils.assertHasControl(searchResult, - // VirtualListViewResponseControl.VIRTUAL_LIST_VIEW_RESPONSE_OID); - - VirtualListViewResponseControl vlvResponseControl = VirtualListViewResponseControl.get(searchResult); - - // Get results info - vlvResponse.setEntriesCount(searchResult.getEntryCount()); - vlvResponse.setTotalEntriesCount(vlvResponseControl.getContentCount()); - vlvResponse.setStart(vlvResponseControl.getTargetPosition()); - - return searchResult; - } - - private void setControls(SearchRequest searchRequest, Control... controls) { - if (!ArrayHelper.isEmpty(controls)) { - Control[] newControls; - if (ArrayHelper.isEmpty(searchRequest.getControls())) { - newControls = controls; - } else { - newControls = ArrayHelper.arrayMerge(searchRequest.getControls(), controls); - } - - searchRequest.setControls(newControls); - } - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#lookup(java.lang.String, - * java.lang.String) - */ - @Override - public SearchResultEntry lookup(String dn, String... attributes) throws ConnectionException { - Instant startTime = OperationDurationUtil.instance().now(); - - SearchResultEntry result = lookupImpl(dn, attributes); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("LDAP operation: lookup, duration: {}, dn: {}, attributes: {}", duration, dn, attributes); - - return result; - } - - private SearchResultEntry lookupImpl(String dn, String... attributes) { - try { - if (attributes == null) { - return getConnectionPool().getEntry(dn); - } else { - return getConnectionPool().getEntry(dn, attributes); - } - } catch (Exception ex) { - throw new ConnectionException("Failed to lookup entry", ex); - } - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#addEntry(java.lang.String, - * java.util.Collection) - */ - @Override - public boolean addEntry(String dn, Collection attributes) throws DuplicateEntryException, ConnectionException { - Instant startTime = OperationDurationUtil.instance().now(); - - boolean result = addEntryImpl(dn, attributes); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("LDAP operation: add, duration: {}, dn: {}, attributes: {}", duration, dn, attributes); - - return result; - } - - private boolean addEntryImpl(String dn, Collection attributes) throws DuplicateEntryException { - if (this.persistenceExtension != null) { - updateUserPasswordAttribute(attributes); - } - - try { - LDAPResult result = getConnectionPool().add(dn, attributes); - if (result.getResultCode().getName().equalsIgnoreCase(SUCCESS)) { - return true; - } - } catch (final LDAPException ex) { - int errorCode = ex.getResultCode().intValue(); - if (errorCode == ResultCode.ENTRY_ALREADY_EXISTS_INT_VALUE) { - throw new DuplicateEntryException(); - } - if (errorCode == ResultCode.INSUFFICIENT_ACCESS_RIGHTS_INT_VALUE) { - throw new ConnectionException("LDAP config error: insufficient access rights.", ex); - } - if (errorCode == ResultCode.TIME_LIMIT_EXCEEDED_INT_VALUE) { - throw new ConnectionException("LDAP Error: time limit exceeded", ex); - } - if (errorCode == ResultCode.OBJECT_CLASS_VIOLATION_INT_VALUE) { - throw new ConnectionException("LDAP config error: schema violation contact LDAP admin.", ex); - } - - throw new ConnectionException("Error adding entry to directory. LDAP error number " + errorCode, ex); - } - - return false; - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#updateEntry(java.lang.String, - * java.util.Collection) - */ - @Deprecated - protected boolean updateEntry(String dn, Collection attrs) throws DuplicateEntryException, ConnectionException { - List mods = new ArrayList(); - - for (Attribute attribute : attrs) { - String attributeName = attribute.getName(); - String attributeValue = attribute.getValue(); - if (attributeName.equalsIgnoreCase(OBJECT_CLASS) - || attributeName.equalsIgnoreCase(DN) - || attributeName.equalsIgnoreCase(USER_PASSWORD)) { - continue; - } else { - if (attributeValue != null) { - mods.add(new Modification(ModificationType.REPLACE, attributeName, attributeValue)); - } - } - } - - return updateEntry(dn, mods); - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#updateEntry(java.lang.String, - * java.util.List) - */ - @Override - public boolean updateEntry(String dn, List modifications) throws DuplicateEntryException, ConnectionException { - Instant startTime = OperationDurationUtil.instance().now(); - - boolean result = updateEntryImpl(dn, modifications); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("LDAP operation: modify, duration: {}, dn: {}, modifications: {}", duration, dn, modifications); - - return result; - } - - private boolean updateEntryImpl(String dn, List modifications) throws DuplicateEntryException { - if (this.persistenceExtension != null) { - updateUserPasswordModification(modifications); - } - - ModifyRequest modifyRequest = new ModifyRequest(dn, modifications); - return modifyEntry(modifyRequest); - } - - /** - * Use this method to add / replace / delete attribute from entry - * - * @param modifyRequest - * @return true if modification is successful - * @throws DuplicateEntryException - * @throws ConnectionException - */ - protected boolean modifyEntry(ModifyRequest modifyRequest) throws DuplicateEntryException, ConnectionException { - LDAPResult modifyResult = null; - try { - modifyResult = getConnectionPool().modify(modifyRequest); - return ResultCode.SUCCESS.equals(modifyResult.getResultCode()); - } catch (final LDAPException ex) { - int errorCode = ex.getResultCode().intValue(); - if (errorCode == ResultCode.INSUFFICIENT_ACCESS_RIGHTS_INT_VALUE) { - throw new ConnectionException("LDAP config error: insufficient access rights.", ex); - } - if (errorCode == ResultCode.TIME_LIMIT_EXCEEDED_INT_VALUE) { - throw new ConnectionException("LDAP Error: time limit exceeded", ex); - } - if (errorCode == ResultCode.OBJECT_CLASS_VIOLATION_INT_VALUE) { - throw new ConnectionException("LDAP config error: schema violation contact LDAP admin.", ex); - } - - throw new ConnectionException("Error updating entry in directory. LDAP error number " + errorCode, ex); - } - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#delete(java.lang.String) - */ - @Override - public boolean delete(String dn) throws ConnectionException { - Instant startTime = OperationDurationUtil.instance().now(); - - boolean result = deleteImpl(dn); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("LDAP operation: delete, duration: {}, dn: {}", duration, dn); - - return result; - } - - private boolean deleteImpl(String dn) { - try { - LDAPResult result = getConnectionPool().delete(dn); - - return ResultCode.SUCCESS.equals(result.getResultCode()); - } catch (Exception ex) { - throw new ConnectionException("Failed to delete entry", ex); - } - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#deleteWithSubtree(java.lang. - * String) - */ - @Override - public boolean deleteRecursively(String dn) throws ConnectionException { - Instant startTime = OperationDurationUtil.instance().now(); - - boolean result = deleteRecursivelyImpl(dn); - - Duration duration = OperationDurationUtil.instance().duration(startTime); - OperationDurationUtil.instance().logDebug("LDAP operation: delete_tree, duration: {}, dn: {}", duration, dn); - - return result; - } - - protected boolean deleteRecursivelyImpl(String dn) { - try { - final DeleteRequest deleteRequest = new DeleteRequest(dn); - deleteRequest.addControl(new SubtreeDeleteRequestControl()); - LDAPResult result = getConnectionPool().delete(deleteRequest); - - return ResultCode.SUCCESS.equals(result.getResultCode()); - } catch (Exception ex) { - throw new ConnectionException("Failed to delete entry", ex); - } - } - - /* - * (non-Javadoc) - * - * @see - * org.gluu.site.ldap.PlatformOperationFacade#processChange(com.unboundid.ldif. - * LDIFChangeRecord) - */ - @Override - public boolean processChange(LDIFChangeRecord ldifRecord) throws LDAPException { - LDAPConnection connection = getConnection(); - try { - LDAPResult ldapResult = ldifRecord.processChange(connection); - - return ResultCode.SUCCESS.equals(ldapResult.getResultCode()); - } finally { - releaseConnection(connection); - } - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#getSupportedLDAPVersion() - */ - @Override - public int getSupportedLDAPVersion() { - return this.connectionProvider.getSupportedLDAPVersion(); - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#getSubschemaSubentry() - */ - @Override - public String getSubschemaSubentry() { - return this.connectionProvider.getSubschemaSubentry(); - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#destroy() - */ - @Override - public boolean destroy() { - boolean result = true; - - if (connectionProvider != null) { - try { - connectionProvider.closeConnectionPool(); - } catch (Exception ex) { - LOG.error("Failed to close connection pool correctly"); - result = false; - } - } - - if (bindConnectionProvider != null) { - try { - bindConnectionProvider.closeConnectionPool(); - } catch (Exception ex) { - LOG.error("Failed to close bind connection pool correctly"); - result = false; - } - } - - return result; - } - - /* - * (non-Javadoc) - * - * @see org.gluu.site.ldap.PlatformOperationFacade#isBinaryAttribute(java.lang. - * String) - */ - @Override - public boolean isBinaryAttribute(String attributeName) { - return this.connectionProvider.isBinaryAttribute(attributeName); - } - - /* - * (non-Javadoc) - * - * @see - * org.gluu.site.ldap.PlatformOperationFacade#isCertificateAttribute(java.lang. - * String) - */ - @Override - public boolean isCertificateAttribute(String attributeName) { - return this.connectionProvider.isCertificateAttribute(attributeName); - } - - /* - * (non-Javadoc) - * - * @see - * org.gluu.site.ldap.PlatformOperationFacade#getCertificateAttributeName(java. - * lang.String) - */ - @Override - public String getCertificateAttributeName(String attributeName) { - return this.connectionProvider.getCertificateAttributeName(attributeName); - } - - private void updateUserPasswordAttribute(Collection attributes) { - for (Iterator it = attributes.iterator(); it.hasNext();) { - Attribute attribute = (Attribute) it.next(); - if (StringHelper.equals(LdapOperationService.USER_PASSWORD, attribute.getName())) { - it.remove(); - Attribute newAttribute = new Attribute(attribute.getName(), - createStoragePassword(attribute.getValues())); - attributes.add(newAttribute); - break; - } - } - } - - private void updateUserPasswordModification(List modifications) { - for (Iterator it = modifications.iterator(); it.hasNext();) { - Modification modification = (Modification) it.next(); - if (StringHelper.equals(LdapOperationService.USER_PASSWORD, modification.getAttributeName())) { - it.remove(); - Modification newModification = new Modification(modification.getModificationType(), - modification.getAttributeName(), - createStoragePassword(modification.getValues())); - modifications.add(newModification); - break; - } - } - } - - public String[] createStoragePassword(String[] passwords) { - if (ArrayHelper.isEmpty(passwords)) { - return passwords; - } - - String[] results = new String[passwords.length]; - for (int i = 0; i < passwords.length; i++) { - if (persistenceExtension != null) { - results[i] = persistenceExtension.createHashedPassword(passwords[i]); - } - } - - return results; - } - - @Override - public List sortListByAttributes(List searchResultEntries, Class cls, boolean caseSensitive, - boolean ascending, String... sortByAttributes) { - // Check input parameters - if (searchResultEntries == null) { - throw new MappingException("Entries list to sort is null"); - } - - if (searchResultEntries.size() == 0) { - return searchResultEntries; - } - - SearchResultEntryComparator comparator = new SearchResultEntryComparator(sortByAttributes, caseSensitive, ascending); - - //The following line does not work because of type erasure - //T array[]=(T[])searchResultEntries.toArray(); - - //Converting the list to an array gets rid of unmodifiable list problem, see issue #68 - T[] dummyArr = (T[]) java.lang.reflect.Array.newInstance(cls, 0); - T[] array = searchResultEntries.toArray(dummyArr); - Arrays.sort(array, comparator); - return Arrays.asList(array); - - } - - private void populateAttributeDataTypesMapping(String schemaEntryDn) { - - try { - if (ATTRIBUTE_DATA_TYPES.size() == 0) { - //schemaEntryDn="ou=schema"; - SearchResultEntry entry = lookup(schemaEntryDn, "attributeTypes"); - Attribute attrAttributeTypes = entry.getAttribute("attributeTypes"); - - Map> tmpMap = new HashMap>(); - - for (String strAttributeType : attrAttributeTypes.getValues()) { - AttributeTypeDefinition attrTypeDef = new AttributeTypeDefinition(strAttributeType); - String[] names = attrTypeDef.getNames(); - - if (names != null) { - for (String name : names) { - tmpMap.put(name, new Pair(attrTypeDef.getBaseSyntaxOID(), attrTypeDef.getSuperiorType())); - } - } - } - - //Fill missing values - for (String name : tmpMap.keySet()) { - Pair currPair = tmpMap.get(name); - String sup = currPair.getSecond(); - - if (currPair.getFirst() == null && sup != null) { //No OID syntax? - //Try to lookup superior type - Pair pair = tmpMap.get(sup); - if (pair != null) { - currPair.setFirst(pair.getFirst()); - } - } - } - - //Populate map of attribute names vs. Java classes - for (String name : tmpMap.keySet()) { - String syntaxOID = tmpMap.get(name).getFirst(); - - if (syntaxOID != null) { - Class cls = OID_SYNTAX_CLASS_MAPPING.get(syntaxOID); - if (cls != null) { - ATTRIBUTE_DATA_TYPES.put(name, cls); - } - } - } - } - } catch (Exception e) { - LOG.error(e.getMessage(), e); - } - - } - - - private static final class SearchResultEntryComparator implements Comparator, Serializable { - - private static final long serialVersionUID = 574848841116711467L; - private String[] sortByAttributes; - private boolean caseSensitive; - private boolean ascending; - - private SearchResultEntryComparator(String[] sortByAttributes, boolean caseSensitive, boolean ascending) { - this.sortByAttributes = sortByAttributes; - this.caseSensitive = caseSensitive; - this.ascending = ascending; - } - - public int compare(T entry1, T entry2) { - - int result = 0; - - if (entry1 == null) { - if (entry2 == null) { - result = 0; - } else { - result = -1; - } - } else { - if (entry2 == null) { - result = 1; - } else { - for (String currSortByAttribute : sortByAttributes) { - result = compare(entry1, entry2, currSortByAttribute); - if (result != 0) { - break; - } - } - } - } - - if (!ascending) { - result *= -1; - } - - return result; - - } - - //This comparison assumes a default sort order of "ascending" - public int compare(T entry1, T entry2, String attributeName) { - - int result = 0; - try { - - if (entry1 instanceof SearchResultEntry) { - - SearchResultEntry resultEntry1 = (SearchResultEntry) entry1; - SearchResultEntry resultEntry2 = (SearchResultEntry) entry2; - - //Obtain a string representation first and do nulls treatments - String value1 = resultEntry1.getAttributeValue(attributeName); - String value2 = resultEntry2.getAttributeValue(attributeName); - - if (value1 == null) { - if (value2 == null) { - result = 0; - } else { - result = -1; - } - } else { - if (value2 == null) { - result = 1; - } else { - Class cls = ATTRIBUTE_DATA_TYPES.get(attributeName); - - if (cls != null) { - if (cls.equals(String.class)) { - if (caseSensitive) { - result = value1.compareTo(value2); - } else { - result = value1.toLowerCase().compareTo(value2.toLowerCase()); - } - } else - if (cls.equals(Integer.class)) { - result = resultEntry1.getAttributeValueAsInteger(attributeName) - .compareTo(resultEntry2.getAttributeValueAsInteger(attributeName)); - } else - if (cls.equals(Boolean.class)) { - result = resultEntry1.getAttributeValueAsBoolean(attributeName) - .compareTo(resultEntry2.getAttributeValueAsBoolean(attributeName)); - } else - if (cls.equals(Date.class)) { - result = resultEntry1.getAttributeValueAsDate(attributeName) - .compareTo(resultEntry2.getAttributeValueAsDate(attributeName)); - } - } - } - } - } - } catch (Exception e) { - LOG.error("Error occurred when comparing entries with SearchResultEntryComparator"); - LOG.error(e.getMessage(), e); - } - return result; - - } - - } - - @Override - public boolean isConnected() { - return connectionProvider.isConnected(); - } - - @Override - public void setPersistenceExtension(PersistenceExtension persistenceExtension) { - this.persistenceExtension = persistenceExtension; - } - - private class SimplePagedResponse { - - private ASN1OctetString cookie; - private SearchResult lastSearchResult; - - public SimplePagedResponse(ASN1OctetString cookie, SearchResult lastSearchResult) { - this.cookie = cookie; - this.lastSearchResult = lastSearchResult; - } - - public ASN1OctetString getCookie() { - return cookie; - } - - public SearchResult getLastSearchResult() { - return lastSearchResult; - } - - } - -} - diff --git a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/watch/OperationDurationUtil.java b/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/watch/OperationDurationUtil.java deleted file mode 100644 index 7444cb8b..00000000 --- a/persistence-ldap/src/main/java/org/gluu/persist/ldap/operation/watch/OperationDurationUtil.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.gluu.persist.ldap.operation.watch; - -import org.gluu.persist.watch.DurationUtil; - -/** - * Simple LDAP operation duration calculator helper - * - * @author Yuriy Movchan Date: 04/08/2019 - */ -public class OperationDurationUtil extends DurationUtil { - - private static OperationDurationUtil instance = new OperationDurationUtil(); - - public static DurationUtil instance() { - return instance; - } - - public void logDebug(String format, Object... arguments) { - if (log.isDebugEnabled()) { - log.debug(format, arguments); - } - } - -} diff --git a/persistence-ldap/src/main/resources/META-INF/beans.xml b/persistence-ldap/src/main/resources/META-INF/beans.xml deleted file mode 100644 index 2f4f7e27..00000000 --- a/persistence-ldap/src/main/resources/META-INF/beans.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - diff --git a/persistence-model/pom.xml b/persistence-model/pom.xml deleted file mode 100644 index af57a1bf..00000000 --- a/persistence-model/pom.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - 4.0.0 - oxcore-persistence-model - jar - persistence-model - - - org.gluu - oxcore - 5.0.0-SNAPSHOT - - - - - org.gluu - oxcore-persistence-annotation - - - org.gluu - oxcore-util - - - - \ No newline at end of file diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/BaseEntry.java b/persistence-model/src/main/java/org/gluu/persist/model/base/BaseEntry.java deleted file mode 100644 index 1b054964..00000000 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/BaseEntry.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model.base; - -import org.gluu.persist.annotation.DN; - -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Provides DN attribute - * - * @author Yuriy Movchan Date: 10.07.2010 - */ -public class BaseEntry { - - @DN - private String dn; - - public BaseEntry() { - } - - public BaseEntry(String dn) { - super(); - this.dn = dn; - } - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public String getBaseDn() { - return dn; - } - - public void setBaseDn(String dn) { - this.dn = dn; - } - - @Override - public String toString() { - return String.format("BaseEntry [dn=%s]", dn); - } - - public static List getDNs(Collection collection) { - return collection.stream().map(BaseEntry::getDn).collect(Collectors.toList()); - } -} diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/CustomAttribute.java b/persistence-model/src/main/java/org/gluu/persist/model/base/CustomAttribute.java deleted file mode 100644 index 3966acd7..00000000 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/CustomAttribute.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model.base; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -/** - * @author Javier Rojas Date: 12.5.2011 - * @author Yuriy Movchan Date: 04/08/2014 -*/ -public class CustomAttribute implements Serializable, Comparable { - - private static final long serialVersionUID = 1468450094325306154L; - - private String name; - private boolean multiValued; - private List values; - - public CustomAttribute() { - } - - public CustomAttribute(String name) { - this.name = name; - } - - public CustomAttribute(String name, String value) { - this.name = name; - setValue(value); - this.multiValued = false; - } - - public CustomAttribute(String name, List values) { - this.name = name; - this.values = values; - } - - public String getValue() { - if (this.values == null) { - return null; - } - - if (this.values.size() > 0) { - return String.valueOf(this.values.get(0)); - } - - return null; - } - - public void setValue(String value) { - this.values = new ArrayList(); - this.values.add(value); - this.multiValued = false; - } - - public List getValues() { - return values; - } - - public void setValues(List values) { - this.values = values; - this.multiValued = (values != null) && (values.size() > 1); - } - - public final String getName() { - return name; - } - - public final void setName(String name) { - this.name = name; - } - - public boolean isMultiValued() { - return multiValued; - } - - public CustomAttribute setMultiValued(boolean multiValued) { - this.multiValued = multiValued; - - return this; - } - - public String getDisplayValue() { - if (values == null) { - return ""; - } - - if (values.size() == 1) { - return values.get(0); - } - - StringBuilder sb = new StringBuilder(values.get(0)); - for (int i = 1; i < values.size(); i++) { - sb.append(", ").append(values.get(i)); - } - - return sb.toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - CustomAttribute that = (CustomAttribute) o; - - if (name != null ? !name.equals(that.name) : that.name != null) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - return name != null ? name.hashCode() : 0; - } - - @Override - public String toString() { - return String.format("Attribute [name=%s, multiValued=%s, value=%s]", name, multiValued, values); - } - - public int compareTo(CustomAttribute o) { - return name.compareTo(o.name); - } -} diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/CustomEntry.java b/persistence-model/src/main/java/org/gluu/persist/model/base/CustomEntry.java deleted file mode 100644 index df1c7a21..00000000 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/CustomEntry.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model.base; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.util.StringHelper; - -/** - * @author Yuriy Movchan Date: 04/08/2014 - */ -@DataEntry -public class CustomEntry extends BaseEntry implements Serializable { - - private static final long serialVersionUID = -7686468010219068788L; - - @AttributesList(name = "name", value = "values", sortByName = true) - private List customAttributes = new ArrayList(); - - @CustomObjectClass - private String[] customObjectClasses; - - public List getCustomAttributes() { - return customAttributes; - } - - public String getCustomAttributeValue(String attributeName) { - if (customAttributes == null) { - return null; - } - - for (CustomAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(attributeName, customAttribute.getName())) { - return customAttribute.getValue(); - } - } - - return null; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/CustomObjectAttribute.java b/persistence-model/src/main/java/org/gluu/persist/model/base/CustomObjectAttribute.java deleted file mode 100644 index cfb04c9b..00000000 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/CustomObjectAttribute.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model.base; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -/** - * @author Yuriy Movchan Date: 09/16/2019 -*/ -public class CustomObjectAttribute implements Serializable, Comparable { - - private static final long serialVersionUID = -1238450094325306154L; - - private String name; - private boolean multiValued; - private List values; - - public CustomObjectAttribute() { - } - - public CustomObjectAttribute(String name) { - this.name = name; - } - - public CustomObjectAttribute(String name, Object value) { - this.name = name; - setValue(value); - this.multiValued = false; - } - - public CustomObjectAttribute(String name, List values) { - this.name = name; - setValues(values); - } - - public Object getValue() { - if (this.values == null) { - return null; - } - - if (this.values.size() > 0) { - return this.values.get(0); - } - - return null; - } - - public void setValue(Object value) { - this.values = new ArrayList(); - this.values.add(value); - this.multiValued = false; - } - - public List getValues() { - return values; - } - - public void setValues(List values) { - this.values = values; - this.multiValued = (values != null) && (values.size() > 1); - } - - public final String getName() { - return name; - } - - public final void setName(String name) { - this.name = name; - } - - public boolean isMultiValued() { - return multiValued; - } - - public CustomObjectAttribute setMultiValued(boolean multiValued) { - this.multiValued = multiValued; - - return this; - } - - public String getDisplayValue() { - if (values == null) { - return ""; - } - - if (values.size() == 1) { - return values.get(0).toString(); - } - - StringBuilder sb = new StringBuilder(values.get(0).toString()); - for (int i = 1; i < values.size(); i++) { - sb.append(", ").append(values.get(i).toString()); - } - - return sb.toString(); - } - - private String toStringValue() { - if (values == null) { - return ""; - } - - if (values.size() == 1) { - if (multiValued) { - return "[" + values.get(0).toString() + "]"; - } - return values.get(0).toString(); - } - - StringBuilder sb = new StringBuilder("["); - for (int i = 0; i < values.size(); i++) { - if (i > 0) { - sb.append(", "); - } - sb.append(values.get(i).toString()); - } - sb.append("]"); - - return sb.toString(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - CustomObjectAttribute that = (CustomObjectAttribute) o; - - if (name != null ? !name.equals(that.name) : that.name != null) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - return name != null ? name.hashCode() : 0; - } - - @Override - public String toString() { - return String.format("Attribute [name=%s, multiValued=%s, value=%s]", name, multiValued, toStringValue()); - } - - public int compareTo(CustomObjectAttribute o) { - return name.compareTo(o.name); - } -} diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/Deletable.java b/persistence-model/src/main/java/org/gluu/persist/model/base/Deletable.java deleted file mode 100644 index b5a151ce..00000000 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/Deletable.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.gluu.persist.model.base; - -/** - * @author Yuriy Zabrovarnyy - */ -public interface Deletable { - Boolean isDeletable(); -} diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java b/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java deleted file mode 100644 index 373c014c..00000000 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/DeletableEntity.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.gluu.persist.model.base; - -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.DataEntry; - -import java.util.Date; - -/** - * @author Yuriy Zabrovarnyy - */ -@DataEntry -public class DeletableEntity extends BaseEntry implements Deletable { - - @AttributeName(name = "exp") - private Date expirationDate; - @AttributeName(name = "del") - private Boolean deletable; - - @Override - public Boolean isDeletable() { - return deletable; - } - - public void setDeletable(Boolean deletable) { - this.deletable = deletable; - } - - public Date getExpirationDate() { - return expirationDate; - } - - public void setExpirationDate(Date expirationDate) { - this.expirationDate = expirationDate; - } - - public boolean canDelete() { - return canDelete(new Date()); - } - - public boolean canDelete(Date now) { - Date exp = expirationDate != null ? expirationDate : null; - return deletable != null && deletable && (exp == null || exp.before(now)); - } - - @Override - public String toString() { - Date exp = expirationDate != null ? expirationDate : null; - return "DeletableEntity{" + - "expirationDate=" + exp + - ", deletable=" + deletable + - "} " + super.toString(); - } -} diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/DummyEntry.java b/persistence-model/src/main/java/org/gluu/persist/model/base/DummyEntry.java deleted file mode 100644 index 7b16abb4..00000000 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/DummyEntry.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model.base; - -import java.io.Serializable; - -import org.gluu.persist.annotation.DataEntry; - -/** - * Dummy entry - * - * @author Yuriy Movchan Date: 07.13.2011 - */ -@DataEntry -public class DummyEntry extends BaseEntry implements Serializable { - - private static final long serialVersionUID = -1111582184398161100L; - -} diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/Entry.java b/persistence-model/src/main/java/org/gluu/persist/model/base/Entry.java deleted file mode 100644 index 1fb35dce..00000000 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/Entry.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model.base; - -import java.io.Serializable; - -import org.gluu.persist.annotation.DN; - -/** - * Provides DN attribute - * - * @author Yuriy Movchan Date: 07/10/2010 - */ -public class Entry implements Serializable, Cloneable { - - private static final long serialVersionUID = 6602706707181973761L; - - @DN - private String dn; - - public Entry() { - } - - public Entry(String dn) { - super(); - this.dn = dn; - } - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public String getBaseDn() { - return dn; - } - - public void setBaseDn(String dn) { - this.dn = dn; - } - - @Override - public String toString() { - return String.format("Entry [dn=%s]", dn); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((dn == null) ? 0 : dn.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - Entry other = (Entry) obj; - if (dn == null) { - if (other.dn != null) { - return false; - } - } else if (!dn.equals(other.dn)) { - return false; - } - - return true; - } - -} diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/GluuBoolean.java b/persistence-model/src/main/java/org/gluu/persist/model/base/GluuBoolean.java deleted file mode 100644 index 7d971306..00000000 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/GluuBoolean.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model.base; - -import java.util.HashMap; -import java.util.Map; - -import org.gluu.persist.annotation.AttributeEnum; - -/** - * Boolean value - * - * @author Yuriy Movchan Date: 11.20.2010 - */ - -@Deprecated // We need ot remove true/false from it at -public enum GluuBoolean implements AttributeEnum { - - DISABLED(false, "disabled", "Disabled"), ENABLED(true, "enabled", "Enabled"), FALSE(false, "false", "False"), TRUE(true, "true", "True"), - INACTIVE(false, "inactive", "Inactive"), ACTIVE(true, "active", "Active"); - - private boolean booleanValue; - private String value; - private String displayName; - - private static Map MAP_BY_VALUES = new HashMap(); - - static { - for (GluuBoolean enumType : values()) { - MAP_BY_VALUES.put(enumType.getValue(), enumType); - } - } - - GluuBoolean(boolean booleanValue, String value, String displayName) { - this.booleanValue = booleanValue; - this.value = value; - this.displayName = displayName; - } - - public String getValue() { - return value; - } - - public boolean isBooleanValue() { - return booleanValue; - } - - public static GluuBoolean getByValue(String value) { - return MAP_BY_VALUES.get(value); - } - - public String getDisplayName() { - return displayName; - } - - public Enum resolveByValue(String value) { - return getByValue(value); - } - - @Override - public String toString() { - return value; - } - -} diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/GluuDummyEntry.java b/persistence-model/src/main/java/org/gluu/persist/model/base/GluuDummyEntry.java deleted file mode 100644 index 14f42905..00000000 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/GluuDummyEntry.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model.base; - -import java.io.Serializable; - -import org.gluu.persist.annotation.DataEntry; - -/** - * Person with custom attributes - * - * @author Yuriy Movchan Date: 07.13.2011 - */ -@DataEntry -public class GluuDummyEntry extends Entry implements Serializable { - - private static final long serialVersionUID = -1111582184398161100L; - -} diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/InumEntry.java b/persistence-model/src/main/java/org/gluu/persist/model/base/InumEntry.java deleted file mode 100644 index 524ac93b..00000000 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/InumEntry.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model.base; - -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; - -/** - * Provides global inum search ability. - * - * @author Oleksiy Tataryn - */ -@DataEntry -@ObjectClass -public class InumEntry extends Entry { - - @AttributeName(ignoreDuringUpdate = true) - private String inum; - - /** - * @param inum - * the inum to set - */ - public void setInum(String inum) { - this.inum = inum; - } - - /** - * @return the inum - */ - public String getInum() { - return inum; - } - - @Override - public String toString() { - return String.format("Entry [dn=%s, inum=%s]", getDn(), getInum()); - } - -} diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleBranch.java b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleBranch.java deleted file mode 100644 index 5d2b1412..00000000 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleBranch.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model.base; - -import java.io.Serializable; - -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; - -/** - * Model for simple branch - * - * @author Yuriy Movchan Date: 11.01.2010 - */ -@DataEntry -@ObjectClass(value = "organizationalUnit") -public class SimpleBranch extends BaseEntry implements Serializable { - - private static final long serialVersionUID = -1311006812730222719L; - - @AttributeName(name = "ou") - private String organizationalUnitName; - - public SimpleBranch() { - } - - public SimpleBranch(String dn) { - setDn(dn); - } - - public SimpleBranch(String dn, String organizationalUnitName) { - this(dn); - this.organizationalUnitName = organizationalUnitName; - } - - public String getOrganizationalUnitName() { - return organizationalUnitName; - } - - public void setOrganizationalUnitName(String organizationalUnitName) { - this.organizationalUnitName = organizationalUnitName; - } - - @Override - public String toString() { - return String.format("SimpleBranch [organizationalUnitName=%s, toString()=%s]", organizationalUnitName, super.toString()); - } - -} diff --git a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java b/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java deleted file mode 100644 index 59a99fcb..00000000 --- a/persistence-model/src/main/java/org/gluu/persist/model/base/SimpleUser.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.persist.model.base; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.AttributesList; -import org.gluu.persist.annotation.CustomObjectClass; -import org.gluu.persist.annotation.DN; -import org.gluu.persist.annotation.DataEntry; -import org.gluu.persist.annotation.ObjectClass; -import org.gluu.util.StringHelper; - -/** - * @author Javier Rojas Blum Date: 11.25.2011 - */ -@DataEntry -@ObjectClass -public class SimpleUser implements Serializable { - - private static final long serialVersionUID = -1634191420188575733L; - - @DN - private String dn; - - @AttributeName(name = "uid", consistency = true) - private String userId; - - @AttributeName - private Date updatedAt; - - @AttributeName(name = "oxCreationTimestamp") - private Date createdAt; - - @AttributeName(name = "oxAuthPersistentJWT") - private String[] oxAuthPersistentJwt; - - @AttributesList(name = "name", value = "values", multiValued = "multiValued", sortByName = true) - protected List customAttributes = new ArrayList(); - - @CustomObjectClass - private String[] customObjectClasses; - - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } - - public String[] getOxAuthPersistentJwt() { - return oxAuthPersistentJwt; - } - - public void setOxAuthPersistentJwt(String[] oxAuthPersistentJwt) { - this.oxAuthPersistentJwt = oxAuthPersistentJwt; - } - - public Date getUpdatedAt() { - return updatedAt; - } - - public void setUpdatedAt(Date updatedAt) { - this.updatedAt = updatedAt; - } - - public Date getCreatedAt() { - return createdAt; - } - - public void setCreatedAt(Date createdAt) { - this.createdAt = createdAt; - } - - public List getCustomAttributes() { - return customAttributes; - } - - public void setCustomAttributes(List customAttributes) { - this.customAttributes = customAttributes; - } - - public String getAttribute(String attributeName) { - Object objectAttribute = getAttributeObject(attributeName); - - return StringHelper.toString(objectAttribute); - } - - public Object getAttributeObject(String attributeName) { - Object attribute = null; - if (attributeName != null && !attributeName.isEmpty()) { - for (CustomObjectAttribute customAttribute : customAttributes) { - if (customAttribute.getName().equals(attributeName)) { - attribute = customAttribute.getValue(); - break; - } - } - } - - return attribute; - } - - public List getAttributeValues(String attributeName) { - List objectValues = getAttributeObjectValues(attributeName); - if (objectValues == null) { - return null; - } - - List values = new ArrayList(objectValues.size()); - for (Object objectValue : objectValues) { - values.add(StringHelper.toString(objectValue)); - } - - return values; - } - - public List getAttributeObjectValues(String attributeName) { - List values = null; - if (attributeName != null && !attributeName.isEmpty()) { - for (CustomObjectAttribute customAttribute : customAttributes) { - if (StringHelper.equalsIgnoreCase(customAttribute.getName(), attributeName)) { - values = customAttribute.getValues(); - break; - } - } - } - - return values; - } - - public String[] getCustomObjectClasses() { - return customObjectClasses; - } - - public void setCustomObjectClasses(String[] customObjectClasses) { - this.customObjectClasses = customObjectClasses; - } - -} diff --git a/persistence-standalone/pom.xml b/persistence-standalone/pom.xml deleted file mode 100644 index ea880666..00000000 --- a/persistence-standalone/pom.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - 4.0.0 - oxcore-persistence-standalone - Persistence standalone services - - - org.gluu - oxcore - 5.0.0-SNAPSHOT - - - - ${maven.min-version} - - - - - - src/main/resources - true - - **/*.xml - **/services/* - **/*.properties - - - - - - - - org.gluu - oxcore-persistence-cdi - - - org.reflections - reflections - - - - - javax.enterprise - cdi-api - provided - - - - \ No newline at end of file diff --git a/persistence-standalone/src/main/java/org/gluu/persist/service/StandalonePersistanceFactoryService.java b/persistence-standalone/src/main/java/org/gluu/persist/service/StandalonePersistanceFactoryService.java deleted file mode 100644 index 365ac3a3..00000000 --- a/persistence-standalone/src/main/java/org/gluu/persist/service/StandalonePersistanceFactoryService.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.gluu.persist.service; - -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Set; - -import org.gluu.persist.PersistenceEntryManagerFactory; -import org.gluu.persist.exception.PropertyNotFoundException; -import org.gluu.persist.exception.operation.ConfigurationException; -import org.gluu.persist.model.PersistenceConfiguration; -import org.gluu.persist.reflect.util.ReflectHelper; - -/** - * Factory which creates Persistence Entry Manager - * - * @author Yuriy Movchan Date: 05/10/2019 - */ -public class StandalonePersistanceFactoryService extends PersistanceFactoryService { - - private HashMap persistenceEntryManagerFactoryNames; - private HashMap, PersistenceEntryManagerFactory> persistenceEntryManagerFactoryTypes; - - @Override - public PersistenceEntryManagerFactory getPersistenceEntryManagerFactory(PersistenceConfiguration persistenceConfiguration) { - return getPersistenceEntryManagerFactory(persistenceConfiguration.getEntryManagerFactoryType()); - } - - @Override - public PersistenceEntryManagerFactory getPersistenceEntryManagerFactory(Class persistenceEntryManagerFactoryClass) { - if (this.persistenceEntryManagerFactoryTypes == null) { - initPersistenceManagerMaps(); - } - - PersistenceEntryManagerFactory persistenceEntryManagerFactory = this.persistenceEntryManagerFactoryTypes - .get(persistenceEntryManagerFactoryClass); - - return persistenceEntryManagerFactory; - } - - @Override - public PersistenceEntryManagerFactory getPersistenceEntryManagerFactory(String persistenceType) { - if (this.persistenceEntryManagerFactoryNames == null) { - initPersistenceManagerMaps(); - } - - PersistenceEntryManagerFactory persistenceEntryManagerFactory = this.persistenceEntryManagerFactoryNames.get(persistenceType); - - return persistenceEntryManagerFactory; - } - - private void initPersistenceManagerMaps() { - this.persistenceEntryManagerFactoryNames = new HashMap(); - this.persistenceEntryManagerFactoryTypes = new HashMap, PersistenceEntryManagerFactory>(); - - org.reflections.Reflections reflections = new org.reflections.Reflections(new org.reflections.util.ConfigurationBuilder() - .setUrls(org.reflections.util.ClasspathHelper.forPackage("org.gluu.persist")) - .setScanners(new org.reflections.scanners.SubTypesScanner())); - Set> classes = reflections.getSubTypesOf(PersistenceEntryManagerFactory.class); - - getLog().info("Found '{}' PersistenceEntryManagerFactory", classes.size()); - - List> classesList = new ArrayList>(classes); - for (Class clazz : classesList) { - getLog().info("Found PersistenceEntryManagerFactory '{}'", clazz); - PersistenceEntryManagerFactory persistenceEntryManagerFactory = createPersistenceEntryManagerFactoryImpl(clazz); - persistenceEntryManagerFactoryNames.put(persistenceEntryManagerFactory.getPersistenceType(), persistenceEntryManagerFactory); - persistenceEntryManagerFactoryTypes.put(clazz, persistenceEntryManagerFactory); - } - } - - private PersistenceEntryManagerFactory createPersistenceEntryManagerFactoryImpl(Class persistenceEntryManagerFactoryClass) { - PersistenceEntryManagerFactory persistenceEntryManagerFactory; - try { - persistenceEntryManagerFactory = ReflectHelper.createObjectByDefaultConstructor(persistenceEntryManagerFactoryClass); - persistenceEntryManagerFactory.initStandalone(this); - } catch (PropertyNotFoundException | IllegalArgumentException | InstantiationException | IllegalAccessException - | InvocationTargetException e) { - throw new ConfigurationException( - String.format("Failed to create PersistenceEntryManagerFactory by type '%s'!", persistenceEntryManagerFactoryClass)); - } - - return persistenceEntryManagerFactory; - } - -} diff --git a/persistence-standalone/src/test/java/org/gluu/persist/service/test/.gitignore b/persistence-standalone/src/test/java/org/gluu/persist/service/test/.gitignore deleted file mode 100644 index eabb0d0d..00000000 --- a/persistence-standalone/src/test/java/org/gluu/persist/service/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/manual/ diff --git a/pom.xml b/pom.xml index a1ff6685..10aafa7e 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.gluu oxcore pom - 5.0.0-SNAPSHOT + 4.3.0.Final oxCore http://ox.gluu.org @@ -27,17 +27,6 @@ oxUtil - persistence-filter - persistence-model - persistence-core - persistence-ldap - persistence-annotation - persistence-couchbase - persistence-hybrid - persistence-cdi - persistence-standalone - persistence-ldap-sample - persistence-couchbase-sample oxModel core-cache core-document-store @@ -61,7 +50,7 @@ org.gluu gluu-core-bom - 5.0.0-SNAPSHOT + 4.3.0.Final import pom diff --git a/security-extension-cdi/pom.xml b/security-extension-cdi/pom.xml index f12563ac..79928458 100644 --- a/security-extension-cdi/pom.xml +++ b/security-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final @@ -54,11 +54,6 @@ weld-core-impl provided - - org.jboss.spec.javax.ejb - jboss-ejb-api_3.2_spec - provided - diff --git a/security-extension-cdi/src/main/java/org/gluu/service/security/SecurityEvaluationException.java b/security-extension-cdi/src/main/java/org/gluu/service/security/SecurityEvaluationException.java index e740e056..9184e7f9 100644 --- a/security-extension-cdi/src/main/java/org/gluu/service/security/SecurityEvaluationException.java +++ b/security-extension-cdi/src/main/java/org/gluu/service/security/SecurityEvaluationException.java @@ -1,11 +1,8 @@ package org.gluu.service.security; -import javax.ejb.ApplicationException; - /** * @author Yuriy Movchan Date: 05/22/2017 */ -@ApplicationException(rollback = true) public class SecurityEvaluationException extends RuntimeException { private static final long serialVersionUID = 7115786700134354355L; diff --git a/server/pom.xml b/server/pom.xml index 593c8051..7a2f025a 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 5.0.0-SNAPSHOT + 4.3.0.Final From 6c0d15602a634e1a2a9097ca66c96cdfbeed1bcc Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 5 Oct 2021 12:04:06 +0300 Subject: [PATCH 249/362] Version 4.3.1-SNAPSHOT --- core-cache/pom.xml | 2 +- core-cdi/pom.xml | 2 +- core-document-store/pom.xml | 2 +- core-java-ext/pom.xml | 2 +- core-script/pom.xml | 2 +- core-standalone/pom.xml | 2 +- core-timer-weld/pom.xml | 2 +- demo-cdi/pom.xml | 2 +- exception-extension-cdi/pom.xml | 2 +- oxJsfUtil/pom.xml | 2 +- oxModel/pom.xml | 2 +- oxRadius/pom.xml | 2 +- oxSaml/pom.xml | 2 +- oxService/pom.xml | 2 +- oxUtil/pom.xml | 2 +- pom.xml | 4 ++-- security-extension-cdi/pom.xml | 2 +- server/pom.xml | 2 +- 18 files changed, 19 insertions(+), 19 deletions(-) diff --git a/core-cache/pom.xml b/core-cache/pom.xml index 56d99693..349ff08b 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/core-cdi/pom.xml b/core-cdi/pom.xml index 71b98c66..37653495 100644 --- a/core-cdi/pom.xml +++ b/core-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index 9543ca57..cad1f589 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/core-java-ext/pom.xml b/core-java-ext/pom.xml index 2f313b48..fe4a9991 100644 --- a/core-java-ext/pom.xml +++ b/core-java-ext/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/core-script/pom.xml b/core-script/pom.xml index 54382e9b..534599bd 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/core-standalone/pom.xml b/core-standalone/pom.xml index b4a189ce..d16769f4 100644 --- a/core-standalone/pom.xml +++ b/core-standalone/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/core-timer-weld/pom.xml b/core-timer-weld/pom.xml index 3b9ec6e1..efaf81ad 100644 --- a/core-timer-weld/pom.xml +++ b/core-timer-weld/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index f0a958b9..e65df6e7 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/exception-extension-cdi/pom.xml b/exception-extension-cdi/pom.xml index 7dd63717..cc1c1e17 100644 --- a/exception-extension-cdi/pom.xml +++ b/exception-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index dd3017ee..163920dd 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/oxModel/pom.xml b/oxModel/pom.xml index b367f9de..1cb72a22 100644 --- a/oxModel/pom.xml +++ b/oxModel/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/oxRadius/pom.xml b/oxRadius/pom.xml index 46dfa093..01f8c134 100644 --- a/oxRadius/pom.xml +++ b/oxRadius/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index e8850911..b3cb783a 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/oxService/pom.xml b/oxService/pom.xml index 8ec15de1..71ce6c71 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index 80fb228d..9e9a66b4 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/pom.xml b/pom.xml index 10aafa7e..ac9e4ca3 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.gluu oxcore pom - 4.3.0.Final + 4.3.1-SNAPSHOT oxCore http://ox.gluu.org @@ -50,7 +50,7 @@ org.gluu gluu-core-bom - 4.3.0.Final + 4.3.1-SNAPSHOT import pom diff --git a/security-extension-cdi/pom.xml b/security-extension-cdi/pom.xml index 79928458..57bc86ac 100644 --- a/security-extension-cdi/pom.xml +++ b/security-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT diff --git a/server/pom.xml b/server/pom.xml index 7a2f025a..27d274b9 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.0.Final + 4.3.1-SNAPSHOT From 6b7619eafe33a8376de0477d3ef72f579d00fe0f Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 5 Oct 2021 20:33:10 +0300 Subject: [PATCH 250/362] feat: upate jython --- core-script/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-script/pom.xml b/core-script/pom.xml index 534599bd..6e4c9a50 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -54,7 +54,7 @@ - org.python + org.gluufederation jython-standalone From 520199cc8f4b8ed4fc1e99fc4ece9f040f5dbb30 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 8 Oct 2021 21:00:46 +0300 Subject: [PATCH 251/362] fix: try to exclude library not-yet-commons-ssl --- oxSaml/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index b3cb783a..b89ef349 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -66,6 +66,12 @@ org.opensaml opensaml + + + ca.juliusdavies + not-yet-commons-ssl + + jakarta.xml.bind From b8852faf33cc4c2e8a57ed6e760a8e049dbe0fff Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 20 Oct 2021 16:49:35 +0300 Subject: [PATCH 252/362] feat: Add method to postAuthentication to IDP script IDP # 15 --- .../org/gluu/model/custom/script/type/idp/DummyIdpType.java | 5 +++++ .../java/org/gluu/model/custom/script/type/idp/IdpType.java | 2 ++ 2 files changed, 7 insertions(+) diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/idp/DummyIdpType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/idp/DummyIdpType.java index f8efb778..c8d722d6 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/idp/DummyIdpType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/idp/DummyIdpType.java @@ -45,4 +45,9 @@ public boolean updateAttributes(Object context, Map configurationAttributes) { + return true; + } + } diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/idp/IdpType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/idp/IdpType.java index 4b9de9f6..3a1869e0 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/idp/IdpType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/idp/IdpType.java @@ -22,4 +22,6 @@ public interface IdpType extends BaseExternalType { boolean updateAttributes(Object context, Map configurationAttributes); + boolean postAuthentication(Object context, Map configurationAttributes); + } From 516add28116c6ae77af4e5ede3398f8cee1b7c9e Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 25 Oct 2021 13:49:11 +0300 Subject: [PATCH 253/362] faet: fix after libs update --- .../document/store/provider/WebDavDocumentStoreProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java index ac7f498b..a0e6a993 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java @@ -10,6 +10,7 @@ import javax.inject.Inject; import javax.jcr.RepositoryException; +import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; @@ -39,7 +40,6 @@ import org.apache.http.protocol.HttpContext; import org.apache.http.util.Args; import org.apache.jackrabbit.webdav.client.methods.HttpMkcol; -import org.apache.tika.io.IOUtils; import org.gluu.service.document.store.conf.DocumentStoreConfiguration; import org.gluu.service.document.store.conf.DocumentStoreType; import org.gluu.service.document.store.conf.WebDavDocumentStoreConfiguration; From ecbb31a65508fc8dd2509ab5d9ebc09b9677bab4 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 26 Oct 2021 18:52:10 +0300 Subject: [PATCH 254/362] chore: fix compilation issue --- .../java/org/gluu/service/cache/RedisSentinelProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java index 2a7fb4e6..f179c8e9 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java @@ -11,6 +11,7 @@ import redis.clients.jedis.Protocol; import java.io.Serializable; +import java.util.Set; /** * Important : keep it weld free. It's reused by oxd ! @@ -35,7 +36,7 @@ public void create() { String password = redisConfiguration.getPassword(); pool = new JedisSentinelPool( getRedisConfiguration().getSentinelMasterGroupName(), - Sets.newHashSet(StringUtils.split(getRedisConfiguration().getServers().trim(), ",")), + Set.of(StringUtils.split(getRedisConfiguration().getServers().trim(), ",")), poolConfig, redisConfiguration.getConnectionTimeout(), redisConfiguration.getSoTimeout(), From c9e5b3a26c4d57be36c5f5c08aef3592622ac3ff Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 26 Oct 2021 19:00:40 +0300 Subject: [PATCH 255/362] fix: remove wrong imports --- .../org/gluu/service/cache/RedisSentinelProvider.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java index f179c8e9..14186589 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java @@ -1,18 +1,18 @@ package org.gluu.service.cache; -import com.google.common.collect.Sets; +import java.io.Serializable; +import java.util.Set; + import org.apache.commons.lang.SerializationUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisSentinelPool; import redis.clients.jedis.Protocol; -import java.io.Serializable; -import java.util.Set; - /** * Important : keep it weld free. It's reused by oxd ! * From 49abf909a2b5428de1366bd52c859b58fe0eede2 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 26 Oct 2021 19:04:33 +0300 Subject: [PATCH 256/362] fix: add missing dependency --- core-script/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core-script/pom.xml b/core-script/pom.xml index 6e4c9a50..0be863c4 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -75,6 +75,12 @@ provided + + + com.google.guava + guava + + org.slf4j From 5f469e152236c0312a16a8981f9d78907910b3cb Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 26 Oct 2021 22:38:21 +0300 Subject: [PATCH 257/362] chore: remove resteasy-jaxrs 3 --- demo-cdi/pom.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index e65df6e7..5c615587 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -43,13 +43,6 @@ cdi-api provided - - - - org.jboss.resteasy - resteasy-jaxrs - provided - \ No newline at end of file From d8d10ee864c348ac9e03aaba495d21a1377be4e5 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 27 Oct 2021 07:26:46 +0300 Subject: [PATCH 258/362] chore: add missing resteasy-cdi library --- demo-cdi/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index 5c615587..b8855f19 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -43,6 +43,12 @@ cdi-api provided + + + + org.jboss.resteasy + resteasy-cdi + \ No newline at end of file From 10663d08fa047a5768092c1257b4dac4c8886708 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 9 Nov 2021 20:28:33 +0300 Subject: [PATCH 259/362] Branch for version 4.4.0 --- core-cache/pom.xml | 2 +- core-cdi/pom.xml | 2 +- core-document-store/pom.xml | 2 +- core-java-ext/pom.xml | 2 +- core-script/pom.xml | 2 +- core-standalone/pom.xml | 2 +- core-timer-weld/pom.xml | 2 +- demo-cdi/pom.xml | 2 +- exception-extension-cdi/pom.xml | 2 +- oxJsfUtil/pom.xml | 2 +- oxModel/pom.xml | 2 +- oxRadius/pom.xml | 2 +- oxSaml/pom.xml | 2 +- oxService/pom.xml | 2 +- oxUtil/pom.xml | 2 +- pom.xml | 4 ++-- security-extension-cdi/pom.xml | 2 +- server/pom.xml | 2 +- 18 files changed, 19 insertions(+), 19 deletions(-) diff --git a/core-cache/pom.xml b/core-cache/pom.xml index 349ff08b..99b40a2a 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/core-cdi/pom.xml b/core-cdi/pom.xml index 37653495..7dded74c 100644 --- a/core-cdi/pom.xml +++ b/core-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index cad1f589..b5aeb318 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/core-java-ext/pom.xml b/core-java-ext/pom.xml index fe4a9991..d37c5b95 100644 --- a/core-java-ext/pom.xml +++ b/core-java-ext/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/core-script/pom.xml b/core-script/pom.xml index 0be863c4..215a9f9e 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/core-standalone/pom.xml b/core-standalone/pom.xml index d16769f4..cdec4641 100644 --- a/core-standalone/pom.xml +++ b/core-standalone/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/core-timer-weld/pom.xml b/core-timer-weld/pom.xml index efaf81ad..b28e1cf4 100644 --- a/core-timer-weld/pom.xml +++ b/core-timer-weld/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index b8855f19..ef7306fd 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/exception-extension-cdi/pom.xml b/exception-extension-cdi/pom.xml index cc1c1e17..80e08c03 100644 --- a/exception-extension-cdi/pom.xml +++ b/exception-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index 163920dd..ad83a2b9 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/oxModel/pom.xml b/oxModel/pom.xml index 1cb72a22..78e268ff 100644 --- a/oxModel/pom.xml +++ b/oxModel/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/oxRadius/pom.xml b/oxRadius/pom.xml index 01f8c134..b2021937 100644 --- a/oxRadius/pom.xml +++ b/oxRadius/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index b89ef349..0c5a7e9b 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/oxService/pom.xml b/oxService/pom.xml index 71ce6c71..0e09639c 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index 9e9a66b4..0d60190d 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/pom.xml b/pom.xml index ac9e4ca3..1d254e1c 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.gluu oxcore pom - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT oxCore http://ox.gluu.org @@ -50,7 +50,7 @@ org.gluu gluu-core-bom - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT import pom diff --git a/security-extension-cdi/pom.xml b/security-extension-cdi/pom.xml index 57bc86ac..8d100db3 100644 --- a/security-extension-cdi/pom.xml +++ b/security-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT diff --git a/server/pom.xml b/server/pom.xml index 27d274b9..9534050e 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.3.1-SNAPSHOT + 4.4.0-SNAPSHOT From 64fa4e930f1cdc43b09c135a895237026f9154ee Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 9 Nov 2021 20:33:18 +0300 Subject: [PATCH 260/362] Update Gluu maven repository --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1d254e1c..8f58a107 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ pom 4.4.0-SNAPSHOT oxCore - http://ox.gluu.org + http://www.gluu.org ${maven.min-version} From 0be43cd86811c3a307f91da5db8db2050cbb9300 Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 9 Nov 2021 21:18:30 +0300 Subject: [PATCH 261/362] Update Gluu maven repository --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8f58a107..cc6b4798 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ pom 4.4.0-SNAPSHOT oxCore - http://www.gluu.org + https://www.gluu.org ${maven.min-version} From 117cb9b9380b0e8cd8da7a8477aa89013c70802a Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 8 Nov 2021 21:21:56 +0300 Subject: [PATCH 262/362] chore: add missing library --- oxService/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/oxService/pom.xml b/oxService/pom.xml index 0e09639c..0b3f6e4d 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -155,6 +155,11 @@ com.sun.mail jakarta.mail + + com.fasterxml + aalto-xml + 1.2.1 + \ No newline at end of file From 152d4b1406f515b5cacae4d0770219b493251eaf Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 16 Nov 2021 12:20:19 +0300 Subject: [PATCH 263/362] chore: add missing repos --- pom.xml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pom.xml b/pom.xml index cc6b4798..95875e8a 100644 --- a/pom.xml +++ b/pom.xml @@ -185,4 +185,22 @@ + + + + mavencentral + maven central + https://repo1.maven.org/maven2 + + + bouncycastle + Bouncy Castle + https://repo2.maven.org/maven2/org/bouncycastle + + + gluu + Gluu project repository + https://maven.gluu.org/maven + + \ No newline at end of file From 3418492f8d39f8799aaf3b30d7a10f28a56edad9 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 29 Nov 2021 13:37:46 +0300 Subject: [PATCH 264/362] chore: add method to look up entries when DB is MySQL --- .../java/org/gluu/service/LookupService.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/LookupService.java b/oxService/src/main/java/org/gluu/service/LookupService.java index a408f263..de4f608d 100644 --- a/oxService/src/main/java/org/gluu/service/LookupService.java +++ b/oxService/src/main/java/org/gluu/service/LookupService.java @@ -47,11 +47,11 @@ public class LookupService implements Serializable { * display name * @return DisplayNameEntry object */ - public DisplayNameEntry getDisplayNameEntry(String dn) throws Exception { + public T getDisplayNameEntry(String dn, Class entryClass) throws Exception { String key = "l_" + dn; - DisplayNameEntry entry = (DisplayNameEntry) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); + T entry = (T) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); if (entry == null) { - entry = persistenceEntryManager.find(dn, DisplayNameEntry.class, null); + entry = persistenceEntryManager.find(dn, entryClass, null); cacheService.put(OxConstants.CACHE_LOOKUP_NAME, key, entry); } @@ -59,6 +59,10 @@ public DisplayNameEntry getDisplayNameEntry(String dn) throws Exception { return entry; } + public DisplayNameEntry getDisplayNameEntry(String dn) throws Exception { + return getDisplayNameEntry(dn, DisplayNameEntry.class); + } + /** * Returns DisplayNameEntry based on display name * @@ -93,22 +97,26 @@ public Object getTypedEntry(String dn, String clazz) throws Exception { * @return list of DisplayNameEntry objects */ @SuppressWarnings("unchecked") - public List getDisplayNameEntries(String baseDn, List dns) { + public List getDisplayNameEntries(String baseDn, Class entryClass, List dns) { List inums = getInumsFromDns(dns); if (inums.size() == 0) { return null; } String key = getCompoundKey(inums); - List entries = (List) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); + List entries = (List) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); if (entries == null) { Filter searchFilter = buildInumFilter(inums); - entries = persistenceEntryManager.findEntries(baseDn, DisplayNameEntry.class, searchFilter); + entries = persistenceEntryManager.findEntries(baseDn, entryClass, searchFilter); cacheService.put(OxConstants.CACHE_LOOKUP_NAME, key, entries); } return entries; } + public List getDisplayNameEntries(String baseDn, List dns) { + return getDisplayNameEntries(baseDn, DisplayNameEntry.class, dns); + } + public Filter buildInumFilter(List inums) { List inumFilters = new ArrayList(inums.size()); for (String inum : inums) { @@ -156,12 +164,15 @@ public List getDisplayNameEntriesByEntries(String baseDn, List return null; } + Class objectClass = DisplayNameEntry.class; List dns = new ArrayList(entries.size()); for (Entry entry : entries) { dns.add(entry.getDn()); + objectClass = objectClass.getClass(); } + - return getDisplayNameEntries(baseDn, dns); + return getDisplayNameEntries(baseDn, objectClass, dns); } /** From 58b3cb010b5e5b72f03646bc5e4690811790de01 Mon Sep 17 00:00:00 2001 From: yurem Date: Mon, 29 Nov 2021 23:01:23 +0300 Subject: [PATCH 265/362] chore: allow to lookup entry by dn and objectClass --- .../java/org/gluu/model/DisplayNameEntry.java | 12 ++++++++ .../java/org/gluu/service/LookupService.java | 30 +++++++++++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/oxService/src/main/java/org/gluu/model/DisplayNameEntry.java b/oxService/src/main/java/org/gluu/model/DisplayNameEntry.java index 283fd9fa..c9a2f1c2 100644 --- a/oxService/src/main/java/org/gluu/model/DisplayNameEntry.java +++ b/oxService/src/main/java/org/gluu/model/DisplayNameEntry.java @@ -10,6 +10,7 @@ import org.gluu.persist.model.base.Entry; import org.gluu.persist.annotation.AttributeName; +import org.gluu.persist.annotation.CustomObjectClass; import org.gluu.persist.annotation.DataEntry; /** @@ -31,6 +32,9 @@ public DisplayNameEntry(String dn, String inum, String displayName) { this.displayName = displayName; } + @CustomObjectClass + private String[] customObjectClasses; + @AttributeName(ignoreDuringUpdate = true) private String inum; @@ -76,4 +80,12 @@ public String getUid() { return uid; } + public String[] getCustomObjectClasses() { + return customObjectClasses; + } + + public void setCustomObjectClasses(String[] customObjectClasses) { + this.customObjectClasses = customObjectClasses; + } + } diff --git a/oxService/src/main/java/org/gluu/service/LookupService.java b/oxService/src/main/java/org/gluu/service/LookupService.java index de4f608d..0b47d4a7 100644 --- a/oxService/src/main/java/org/gluu/service/LookupService.java +++ b/oxService/src/main/java/org/gluu/service/LookupService.java @@ -47,8 +47,28 @@ public class LookupService implements Serializable { * display name * @return DisplayNameEntry object */ + public DisplayNameEntry getDisplayNameEntry(String dn, String objectClass) throws Exception { + String key = "l_" + objectClass + "_" + dn; + DisplayNameEntry entry = (DisplayNameEntry) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); + if (entry == null) { + // Prepare sample for search + DisplayNameEntry sample = new DisplayNameEntry(); + sample.setBaseDn(dn); + sample.setCustomObjectClasses(new String[] { objectClass }); + + List entries = persistenceEntryManager.findEntries(sample, 1); + if (entries.size() == 1) { + entry = entries.get(0); + } + + cacheService.put(OxConstants.CACHE_LOOKUP_NAME, key, entry); + } + + return entry; + } + public T getDisplayNameEntry(String dn, Class entryClass) throws Exception { - String key = "l_" + dn; + String key = "l_" + entryClass.getSimpleName() + "_" + dn; T entry = (T) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); if (entry == null) { entry = persistenceEntryManager.find(dn, entryClass, null); @@ -76,7 +96,7 @@ public Object getTypedEntry(String dn, String clazz) throws Exception { } Class entryClass = Class.class.forName(clazz); - String key = "l_" + dn; + String key = "l_" + entryClass.getSimpleName() + "_" + dn; Object entry = cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); if (entry == null) { entry = persistenceEntryManager.find(entryClass, dn); @@ -103,7 +123,7 @@ public List getDisplayNameEntries(String baseDn, Class entryClass, Lis return null; } - String key = getCompoundKey(inums); + String key = getCompoundKey(entryClass, inums); List entries = (List) cacheService.get(OxConstants.CACHE_LOOKUP_NAME, key); if (entries == null) { Filter searchFilter = buildInumFilter(inums); @@ -144,13 +164,13 @@ public List getInumsFromDns(List dns) { return inums; } - private String getCompoundKey(List inums) { + private String getCompoundKey(Class entryClass, List inums) { StringBuilder compoundKey = new StringBuilder(); for (String inum : inums) { if (compoundKey.length() > 0) { compoundKey.append("_"); } else { - compoundKey.append("l_"); + compoundKey.append("l_" + entryClass.getSimpleName() + "_"); } compoundKey.append(inum); } From 9bd24689face8a9b157180243118e09d74da56aa Mon Sep 17 00:00:00 2001 From: Milton Ch Date: Mon, 6 Dec 2021 10:17:54 -0400 Subject: [PATCH 266/362] fix: compability with java 8 for sets --- .../java/org/gluu/service/cache/RedisSentinelProvider.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java index 14186589..110a6bab 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java @@ -1,6 +1,8 @@ package org.gluu.service.cache; import java.io.Serializable; +import java.util.Arrays; +import java.util.HashSet; import java.util.Set; import org.apache.commons.lang.SerializationUtils; @@ -36,7 +38,7 @@ public void create() { String password = redisConfiguration.getPassword(); pool = new JedisSentinelPool( getRedisConfiguration().getSentinelMasterGroupName(), - Set.of(StringUtils.split(getRedisConfiguration().getServers().trim(), ",")), + new HashSet(Arrays.asList(StringUtils.split(getRedisConfiguration().getServers().trim(), ","))), poolConfig, redisConfiguration.getConnectionTimeout(), redisConfiguration.getSoTimeout(), From 35a55ae96fbeeffe3d7cc7ebe5b5449189af348d Mon Sep 17 00:00:00 2001 From: Milton Ch <86965029+Milton-Ch@users.noreply.github.com> Date: Tue, 21 Dec 2021 14:36:45 -0400 Subject: [PATCH 267/362] feat: updated redis providers to support ssl connection (#221) --- .../service/cache/RedisClusterProvider.java | 24 +++++---- .../service/cache/RedisConfiguration.java | 31 +++++++++++ .../service/cache/RedisProviderFactory.java | 52 +++++++++++-------- .../service/cache/RedisSentinelProvider.java | 38 +++++++------- .../gluu/service/cache/RedisSetParams.java | 2 +- .../service/cache/RedisShardedProvider.java | 18 ++++--- .../cache/RedisStandaloneProvider.java | 29 +++++------ 7 files changed, 121 insertions(+), 73 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java index f70064dc..9230a456 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisClusterProvider.java @@ -7,10 +7,11 @@ import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPoolConfig; -import java.io.IOException; + import java.io.Serializable; import java.util.HashSet; import java.util.Set; +import java.util.UUID; /** * Important : keep it weld free. It's reused by oxd ! @@ -33,12 +34,22 @@ public void create() { JedisPoolConfig poolConfig = createPoolConfig(); String password = redisConfiguration.getPassword(); - pool = new JedisCluster(hosts(getRedisConfiguration().getServers()), redisConfiguration.getConnectionTimeout(), redisConfiguration.getSoTimeout(), redisConfiguration.getMaxRetryAttempts(), password, poolConfig); + + if (redisConfiguration.getUseSSL()) { + RedisProviderFactory.setSSLSystemProperties(redisConfiguration); + + pool = new JedisCluster(hosts(getRedisConfiguration().getServers()), redisConfiguration.getConnectionTimeout(), + redisConfiguration.getSoTimeout(), redisConfiguration.getMaxRetryAttempts(), + password, UUID.randomUUID().toString(), poolConfig, true); + } else { + pool = new JedisCluster(hosts(getRedisConfiguration().getServers()), redisConfiguration.getConnectionTimeout(), + redisConfiguration.getSoTimeout(), redisConfiguration.getMaxRetryAttempts(), password, poolConfig); + } testConnection(); LOG.debug("RedisClusterProvider started."); } catch (Exception e) { - LOG.error("Failed to start RedisClusterProvider."); + LOG.error("Failed to start RedisClusterProvider.", e); throw new IllegalStateException("Error starting RedisClusterProvider", e); } } @@ -59,12 +70,7 @@ public static Set hosts(String servers) { public void destroy() { LOG.debug("Destroying RedisClusterProvider"); - try { - pool.close(); - } catch (IOException e) { - LOG.error("Failed to destroy RedisClusterProvider", e); - return; - } + pool.close(); LOG.debug("Destroyed RedisClusterProvider"); } diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java b/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java index 4d5c8f98..bd4ac11b 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisConfiguration.java @@ -27,6 +27,12 @@ public class RedisConfiguration implements Serializable { private String sslTrustStoreFilePath = ""; + private String sslTrustStorePassword = ""; + + private String sslKeyStoreFilePath = ""; + + private String sslKeyStorePassword = ""; + /** * The cap on the number of "idle" instances in the pool. If maxIdle * is set too low on heavily loaded systems it is possible you will see @@ -140,6 +146,30 @@ public void setSslTrustStoreFilePath(String sslTrustStoreFilePath) { this.sslTrustStoreFilePath = sslTrustStoreFilePath; } + public String getSslTrustStorePassword() { + return sslTrustStorePassword; + } + + public void setSslTrustStorePassword(String sslTrustStorePassword) { + this.sslTrustStorePassword = sslTrustStorePassword; + } + + public String getSslKeyStoreFilePath() { + return sslKeyStoreFilePath; + } + + public void setSslKeyStoreFilePath(String sslKeyStoreFilePath) { + this.sslKeyStoreFilePath = sslKeyStoreFilePath; + } + + public String getSslKeyStorePassword() { + return sslKeyStorePassword; + } + + public void setSslKeyStorePassword(String sslKeyStorePassword) { + this.sslKeyStorePassword = sslKeyStorePassword; + } + public String getSentinelMasterGroupName() { return sentinelMasterGroupName; } @@ -156,6 +186,7 @@ public String toString() { ", redisProviderType=" + redisProviderType + ", useSSL=" + useSSL + ", sslTrustStoreFilePath=" + sslTrustStoreFilePath + + ", sslKeyStoreFilePath=" + sslKeyStoreFilePath + ", sentinelMasterGroupName=" + sentinelMasterGroupName + ", maxIdleConnections=" + maxIdleConnections + ", maxTotalConnections=" + maxTotalConnections + diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisProviderFactory.java b/core-cache/src/main/java/org/gluu/service/cache/RedisProviderFactory.java index 11df4a6d..ea19df73 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisProviderFactory.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisProviderFactory.java @@ -1,19 +1,16 @@ package org.gluu.service.cache; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.security.KeyStore; -import java.security.SecureRandom; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; - -import org.apache.commons.io.IOUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import java.io.FileInputStream; +import java.security.KeyStore; +import java.security.SecureRandom; /** * Important : keep it weld free. It's reused by oxd ! @@ -66,23 +63,34 @@ public static void destroySilently(AbstractRedisProvider provider) { } } - public static SSLSocketFactory createTrustStoreSslSocketFactory(File keystoreFile) throws Exception { - + public static SSLSocketFactory createSslSocketFactory(RedisConfiguration redisConfiguration) throws Exception { KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); - InputStream inputStream = null; - try { - inputStream = new FileInputStream(keystoreFile); - trustStore.load(inputStream, null); - } finally { - IOUtils.closeQuietly(inputStream); - } - + trustStore.load(new FileInputStream(redisConfiguration.getSslTrustStoreFilePath()), + redisConfiguration.getSslTrustStorePassword().toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(trustStore); - TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); + + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(new FileInputStream(redisConfiguration.getSslKeyStoreFilePath()), + redisConfiguration.getSslKeyStorePassword().toCharArray()); + KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + keyManagerFactory.init(keyStore, redisConfiguration.getSslKeyStorePassword().toCharArray()); SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, trustManagers, new SecureRandom()); + sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom()); + return sslContext.getSocketFactory(); } + + public static void setSSLSystemProperties(RedisConfiguration redisConfiguration) { + if (StringUtils.isNotBlank(redisConfiguration.getSslKeyStoreFilePath())) { + System.setProperty("javax.net.ssl.keyStore", redisConfiguration.getSslKeyStoreFilePath()); + System.setProperty("javax.net.ssl.keyStorePassword", redisConfiguration.getSslKeyStorePassword()); + } + + if (StringUtils.isNotBlank(redisConfiguration.getSslTrustStoreFilePath())) { + System.setProperty("javax.net.ssl.trustStore", redisConfiguration.getSslTrustStoreFilePath()); + System.setProperty("javax.net.ssl.trustStorePassword", redisConfiguration.getSslTrustStorePassword()); + } + } } diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java index 110a6bab..3cd57218 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisSentinelProvider.java @@ -1,19 +1,13 @@ package org.gluu.service.cache; -import java.io.Serializable; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - import org.apache.commons.lang.SerializationUtils; -import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import redis.clients.jedis.*; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPoolConfig; -import redis.clients.jedis.JedisSentinelPool; -import redis.clients.jedis.Protocol; +import java.io.Serializable; + +import static org.gluu.service.cache.RedisClusterProvider.hosts; /** * Important : keep it weld free. It's reused by oxd ! @@ -34,20 +28,24 @@ public void create() { try { LOG.debug("Starting RedisSentinelProvider ... configuration:" + getRedisConfiguration()); - JedisPoolConfig poolConfig = createPoolConfig(); String password = redisConfiguration.getPassword(); - pool = new JedisSentinelPool( - getRedisConfiguration().getSentinelMasterGroupName(), - new HashSet(Arrays.asList(StringUtils.split(getRedisConfiguration().getServers().trim(), ","))), - poolConfig, - redisConfiguration.getConnectionTimeout(), - redisConfiguration.getSoTimeout(), - password, - Protocol.DEFAULT_DATABASE); + JedisPoolConfig poolConfig = createPoolConfig(); + JedisClientConfig jedisClientConfig; + + if (redisConfiguration.getUseSSL()) { + RedisProviderFactory.setSSLSystemProperties(redisConfiguration); + jedisClientConfig = DefaultJedisClientConfig.builder().ssl(true).password(password).build(); + } else { + jedisClientConfig = DefaultJedisClientConfig.builder().ssl(false).password(password).build(); + } + + pool = new JedisSentinelPool(getRedisConfiguration().getSentinelMasterGroupName(), + hosts(getRedisConfiguration().getServers()), poolConfig, jedisClientConfig, jedisClientConfig); + testConnection(); LOG.debug("RedisSentinelProvider started."); } catch (Exception e) { - LOG.error("Failed to start RedisSentinelProvider."); + LOG.error("Failed to start RedisSentinelProvider.", e); throw new IllegalStateException("Error starting RedisSentinelProvider", e); } } diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisSetParams.java b/core-cache/src/main/java/org/gluu/service/cache/RedisSetParams.java index a3f51125..22cb32a8 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisSetParams.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisSetParams.java @@ -3,7 +3,7 @@ import java.util.ArrayList; import redis.clients.jedis.params.Params; -import redis.clients.util.SafeEncoder; +import redis.clients.jedis.util.SafeEncoder; /** * Taken from here diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java index eaa17943..e25fd656 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisShardedProvider.java @@ -2,13 +2,15 @@ import org.apache.commons.lang.SerializationUtils; import org.apache.commons.lang.StringUtils; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.apache.http.conn.ssl.DefaultHostnameVerifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import redis.clients.jedis.*; +import redis.clients.jedis.JedisShardInfo; +import redis.clients.jedis.ShardedJedis; +import redis.clients.jedis.ShardedJedisPool; import javax.net.ssl.SSLParameters; -import java.io.File; import java.io.Serializable; import java.util.ArrayList; import java.util.List; @@ -32,14 +34,17 @@ public void create() { try { LOG.debug("Starting RedisShardedProvider ... configuration:" + redisConfiguration); - JedisPoolConfig poolConfig = createPoolConfig(); + GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig<>(); + poolConfig.setMaxTotal(redisConfiguration.getMaxTotalConnections()); + poolConfig.setMaxIdle(redisConfiguration.getMaxIdleConnections()); + poolConfig.setMinIdle(2); pool = new ShardedJedisPool(poolConfig, shards(redisConfiguration)); testConnection(); LOG.debug("RedisShardedProvider started."); } catch (Exception e) { - LOG.error("Failed to start RedisShardedProvider."); + LOG.error("Failed to start RedisShardedProvider.", e); throw new IllegalStateException("Error starting RedisShardedProvider", e); } } @@ -58,9 +63,10 @@ private static List shards(RedisConfiguration configuration) { try { final JedisShardInfo shardInfo; if (configuration.getUseSSL()) { - if (StringUtils.isNotBlank(configuration.getSslTrustStoreFilePath())) { + if (StringUtils.isNotBlank(configuration.getSslTrustStoreFilePath()) + && StringUtils.isNotBlank(configuration.getSslKeyStoreFilePath())) { shardInfo = new JedisShardInfo(host, port, true, - RedisProviderFactory.createTrustStoreSslSocketFactory(new File(configuration.getSslTrustStoreFilePath())), + RedisProviderFactory.createSslSocketFactory(configuration), new SSLParameters(), new DefaultHostnameVerifier()); } else { shardInfo = new JedisShardInfo(host, port, true); diff --git a/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java b/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java index 1448019c..d980ba62 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java +++ b/core-cache/src/main/java/org/gluu/service/cache/RedisStandaloneProvider.java @@ -5,11 +5,14 @@ import org.apache.http.conn.ssl.DefaultHostnameVerifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import redis.clients.jedis.*; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.JedisPoolConfig; import javax.annotation.PreDestroy; import javax.net.ssl.SSLParameters; -import java.io.File; +import javax.net.ssl.SSLSocketFactory; import java.io.Serializable; /** @@ -35,20 +38,15 @@ public void create() { HostAndPort hostAndPort = RedisClusterProvider.hosts(redisConfiguration.getServers()).iterator().next(); String password = redisConfiguration.getPassword(); if (redisConfiguration.getUseSSL()) { - if (StringUtils.isNotBlank(redisConfiguration.getSslTrustStoreFilePath())) { - if (StringUtils.isBlank(password)) { - pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), true, - RedisProviderFactory.createTrustStoreSslSocketFactory(new File(redisConfiguration.getSslTrustStoreFilePath())), new SSLParameters(), new DefaultHostnameVerifier()); - } else { - pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), redisConfiguration.getConnectionTimeout(), password, true, - RedisProviderFactory.createTrustStoreSslSocketFactory(new File(redisConfiguration.getSslTrustStoreFilePath())), new SSLParameters(), new DefaultHostnameVerifier()); - } + if (StringUtils.isNotBlank(redisConfiguration.getSslTrustStoreFilePath()) + && StringUtils.isNotBlank(redisConfiguration.getSslKeyStoreFilePath())) { + SSLSocketFactory sslSocketFactory = RedisProviderFactory.createSslSocketFactory(redisConfiguration); + + pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), true, + sslSocketFactory, new SSLParameters(), new DefaultHostnameVerifier()); } else { - if (StringUtils.isBlank(password)) { - pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), true); - } else { - pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), redisConfiguration.getConnectionTimeout(), password, true); - } + pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), + redisConfiguration.getConnectionTimeout(), password, true); } } else { pool = new JedisPool(poolConfig, hostAndPort.getHost(), hostAndPort.getPort(), redisConfiguration.getConnectionTimeout(), password); @@ -57,6 +55,7 @@ public void create() { testConnection(); LOG.debug("RedisStandaloneProvider started."); } catch (Exception e) { + LOG.error("Problems connecting with Redis", e); throw new IllegalStateException("Error starting RedisStandaloneProvider", e); } } From aa6ea6818208654053578d7ec249a71809fda706 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 12 Jan 2022 18:35:07 +0300 Subject: [PATCH 268/362] chore: allow to specify empty root for doc store is OS is Windows --- .../document/store/provider/LocalDocumentStoreProvider.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java index 13ff776c..c51f1e0b 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java @@ -50,6 +50,11 @@ public void create() { log.debug("Starting LocalDocumentStoreProvider ..."); if (StringHelper.isEmpty(localDocumentStoreConfiguration.getBaseLocation())) { + String osName = System.getProperty("os.name"); + if (StringHelper.isNotEmpty(osName) && osName.toLowerCase().startsWith("windows")) { + baseLocation = ""; + return; + } throw new IllegalArgumentException("Base location should not be empty"); } From 93b8ac5e4bc7a71a4a21eb9d68e77de5ba0b25bc Mon Sep 17 00:00:00 2001 From: yurem Date: Sat, 5 Feb 2022 10:24:09 +0300 Subject: [PATCH 269/362] chore; allow to reuse security provider utility --- .../security/SecurityProviderUtility.java | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java diff --git a/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java b/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java new file mode 100644 index 00000000..d3f2f33f --- /dev/null +++ b/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java @@ -0,0 +1,159 @@ +/* + * oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.util.security; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.util.List; + +import javax.crypto.Cipher; + +import org.apache.commons.io.IOUtils; +import org.gluu.util.StringHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Provider installation utility + * + * @author Yuriy Movchan + * @author madhumitas + */ +public class SecurityProviderUtility { + + private static final Logger LOG = LoggerFactory.getLogger(SecurityProviderUtility.class); + + public static final String BC_PROVIDER_NAME = "BC"; + public static final String BC_FIPS_PROVIDER_NAME = "BCFIPS"; + + public static boolean USE_FIPS_CHECK_COMMAND = false; + + private static boolean isFipsMode = false; + + private static Provider bouncyCastleProvider; + + private static final String BC_GENERIC_PROVIDER_CLASS_NAME = "org.bouncycastle.jce.provider.BouncyCastleProvider"; + private static final String BC_FIPS_PROVIDER_CLASS_NAME = "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider"; + + public static void installBCProvider(boolean silent) { + String providerName = BC_PROVIDER_NAME; + String className = BC_GENERIC_PROVIDER_CLASS_NAME; + + isFipsMode = checkFipsMode(); + if (isFipsMode) { + LOG.info("Fips mode is enabled"); + + providerName = BC_FIPS_PROVIDER_NAME; + className = BC_FIPS_PROVIDER_CLASS_NAME; + } + +// // Remove current providers in case on web container restart +// Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME); +// Security.removeProvider(BouncyCastleFipsProvider.PROVIDER_NAME); + + try { + installBCProvider(providerName, className, silent); + } catch (Exception e) { + LOG.error( + "Security provider '{}' doesn't exists in class path. Please deploy correct war for this environment!"); + LOG.error(e.getMessage(), e); + } + } + + public static void installBCProvider() { + installBCProvider(false); + } + + public static void installBCProvider(String providerName, String providerClassName, boolean silent) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException { + bouncyCastleProvider = Security.getProvider(providerName); + if (bouncyCastleProvider == null) { + if (!silent) { + LOG.info("Adding Bouncy Castle Provider"); + } + + bouncyCastleProvider = (Provider) Class.forName(providerClassName).getConstructor().newInstance(); + Security.addProvider(bouncyCastleProvider); + LOG.info("Provider '{}' with version {} is added", bouncyCastleProvider.getName(), bouncyCastleProvider.getVersionStr()); + } else { + if (!silent) { + LOG.info("Bouncy Castle Provider was added already"); + } + } + } + + /** + * A check that the server is running in FIPS-approved-only mode. This is a part + * of compliance to ensure that the server is really FIPS compliant + * + * @return boolean value + */ + private static boolean checkFipsMode() { + try { + // First check if there are FIPS provider libs + Class.forName(BC_FIPS_PROVIDER_CLASS_NAME); + } catch (ClassNotFoundException e) { + LOG.trace("BC Fips provider is not available", e); + return false; + } + + if (USE_FIPS_CHECK_COMMAND) { + String osName = System.getProperty("os.name"); + if (StringHelper.isNotEmpty(osName) && osName.toLowerCase().startsWith("windows")) { + return false; + } + + try { + // Check if FIPS is enabled + Process process = Runtime.getRuntime().exec("fips-mode-setup --check"); + List result = IOUtils.readLines(process.getInputStream(), StandardCharsets.UTF_8); + if ((result.size() > 0) && StringHelper.equalsIgnoreCase(result.get(0), "FIPS mode is enabled.")) { + return true; + } + } catch (IOException e) { + LOG.error("Failed to check if FIPS mode was enabled", e); + return false; + } + + return false; + } + + return true; + } + + /** + * Determines if cryptography restrictions apply. + * Restrictions apply if the value of {@link Cipher#getMaxAllowedKeyLength(String)} returns a value smaller than {@link Integer#MAX_VALUE} if there are any restrictions according to the JavaDoc of the method. + * This method is used with the transform "AES/CBC/PKCS5Padding" as this is an often used algorithm that is an implementation requirement for Java SE. + * + * @return true if restrictions apply, false otherwise + * https://stackoverflow.com/posts/33849265/edit, author Maarten Bodewes + */ + public static boolean checkRestrictedCryptography() { + try { + return Cipher.getMaxAllowedKeyLength("AES/CBC/PKCS5Padding") < Integer.MAX_VALUE; + } catch (final NoSuchAlgorithmException e) { + throw new IllegalStateException("The transform \"AES/CBC/PKCS5Padding\" is not available (the availability of this algorithm is mandatory for Java SE implementations)", e); + } + } + + public static String getBCProviderName() { + return bouncyCastleProvider.getName(); + } + + public static Provider getBCProvider() { + return bouncyCastleProvider; + } + + public static boolean isFipsMode() { + return isFipsMode; + } + +} \ No newline at end of file From 2834bb2d27c1faf69a16ba38072e06816b5cfd20 Mon Sep 17 00:00:00 2001 From: SMan Date: Fri, 11 Mar 2022 05:28:04 -0600 Subject: [PATCH 270/362] feat: security_mode_type has been added to the security_provider_utility; (#225) --- .../security/SecurityProviderUtility.java | 282 +++++++++++------- 1 file changed, 174 insertions(+), 108 deletions(-) diff --git a/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java b/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java index d3f2f33f..10ee7d4a 100644 --- a/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java +++ b/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java @@ -29,104 +29,167 @@ */ public class SecurityProviderUtility { - private static final Logger LOG = LoggerFactory.getLogger(SecurityProviderUtility.class); - - public static final String BC_PROVIDER_NAME = "BC"; - public static final String BC_FIPS_PROVIDER_NAME = "BCFIPS"; - - public static boolean USE_FIPS_CHECK_COMMAND = false; - - private static boolean isFipsMode = false; - - private static Provider bouncyCastleProvider; - - private static final String BC_GENERIC_PROVIDER_CLASS_NAME = "org.bouncycastle.jce.provider.BouncyCastleProvider"; - private static final String BC_FIPS_PROVIDER_CLASS_NAME = "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider"; - - public static void installBCProvider(boolean silent) { - String providerName = BC_PROVIDER_NAME; - String className = BC_GENERIC_PROVIDER_CLASS_NAME; - - isFipsMode = checkFipsMode(); - if (isFipsMode) { - LOG.info("Fips mode is enabled"); - - providerName = BC_FIPS_PROVIDER_NAME; - className = BC_FIPS_PROVIDER_CLASS_NAME; - } - -// // Remove current providers in case on web container restart -// Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME); -// Security.removeProvider(BouncyCastleFipsProvider.PROVIDER_NAME); - - try { - installBCProvider(providerName, className, silent); - } catch (Exception e) { - LOG.error( - "Security provider '{}' doesn't exists in class path. Please deploy correct war for this environment!"); - LOG.error(e.getMessage(), e); - } - } - - public static void installBCProvider() { - installBCProvider(false); - } - - public static void installBCProvider(String providerName, String providerClassName, boolean silent) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException { - bouncyCastleProvider = Security.getProvider(providerName); - if (bouncyCastleProvider == null) { - if (!silent) { - LOG.info("Adding Bouncy Castle Provider"); - } - - bouncyCastleProvider = (Provider) Class.forName(providerClassName).getConstructor().newInstance(); - Security.addProvider(bouncyCastleProvider); - LOG.info("Provider '{}' with version {} is added", bouncyCastleProvider.getName(), bouncyCastleProvider.getVersionStr()); - } else { - if (!silent) { - LOG.info("Bouncy Castle Provider was added already"); - } - } - } - - /** - * A check that the server is running in FIPS-approved-only mode. This is a part - * of compliance to ensure that the server is really FIPS compliant - * - * @return boolean value - */ - private static boolean checkFipsMode() { - try { - // First check if there are FIPS provider libs - Class.forName(BC_FIPS_PROVIDER_CLASS_NAME); - } catch (ClassNotFoundException e) { - LOG.trace("BC Fips provider is not available", e); - return false; - } - - if (USE_FIPS_CHECK_COMMAND) { - String osName = System.getProperty("os.name"); - if (StringHelper.isNotEmpty(osName) && osName.toLowerCase().startsWith("windows")) { - return false; - } - - try { - // Check if FIPS is enabled - Process process = Runtime.getRuntime().exec("fips-mode-setup --check"); - List result = IOUtils.readLines(process.getInputStream(), StandardCharsets.UTF_8); - if ((result.size() > 0) && StringHelper.equalsIgnoreCase(result.get(0), "FIPS mode is enabled.")) { - return true; - } - } catch (IOException e) { - LOG.error("Failed to check if FIPS mode was enabled", e); - return false; - } - - return false; - } - - return true; - } + public static final String DEF_JKS = "jks"; + public static final String DEF_PKCS12 = "pkcs12"; + public static final String DEF_BCFKS = "bcfks"; + + /** + * Security Mode Type + * + * @author Sergey Manoylo + * @version March 11, 2022 + */ + public static enum SecurityModeType { + + JKS_SECURITY_MODE (DEF_JKS), + PKCS12_SECURITY_MODE (DEF_PKCS12), + BCFKS_SECURITY_MODE (DEF_BCFKS); + + private final String value; + + /** + * Constructor + * + * @param value string value, that defines Security Mode Type + */ + SecurityModeType(String value) { + this.value = value; + } + + /** + * Creates/parses SecurityModeType from String value + * + * @param param string value, that defines Security Mode Type + * @return SecurityModeType + */ + public static SecurityModeType fromString(String param) { + switch(param) { + case DEF_JKS: { + return JKS_SECURITY_MODE; + } + case DEF_PKCS12: { + return PKCS12_SECURITY_MODE; + } + case DEF_BCFKS: { + return BCFKS_SECURITY_MODE; + } + } + return null; + } + + /** + * Returns a string representation of the object. In this case the parameter name for the default scope. + */ + @Override + public String toString() { + return value; + } + } + + private static final Logger LOG = LoggerFactory.getLogger(SecurityProviderUtility.class); + + public static final String BC_PROVIDER_NAME = "BC"; + public static final String BC_FIPS_PROVIDER_NAME = "BCFIPS"; + + public static boolean USE_FIPS_CHECK_COMMAND = false; + + private static SecurityModeType securityMode = null; + + private static Provider bouncyCastleProvider; + + private static final String BC_GENERIC_PROVIDER_CLASS_NAME = "org.bouncycastle.jce.provider.BouncyCastleProvider"; + private static final String BC_FIPS_PROVIDER_CLASS_NAME = "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider"; + + public static void installBCProvider(boolean silent) { + String providerName = BC_PROVIDER_NAME; + String className = BC_GENERIC_PROVIDER_CLASS_NAME; + + if (securityMode == null || securityMode == SecurityModeType.BCFKS_SECURITY_MODE) { + System.out.println("securityMode == null || securityMode == SecurityModeType.BCFKS_SECURITY_MODE"); + boolean isFipsMode = checkFipsMode(); + if (isFipsMode) { + LOG.info("Fips mode is enabled"); + + providerName = BC_FIPS_PROVIDER_NAME; + className = BC_FIPS_PROVIDER_CLASS_NAME; + + securityMode = SecurityModeType.BCFKS_SECURITY_MODE; + } + else { + securityMode = SecurityModeType.JKS_SECURITY_MODE; + } + } + + try { + installBCProvider(providerName, className, silent); + } catch (Exception e) { + LOG.error( + "Security provider '{}' doesn't exists in class path. Please deploy correct war for this environment!"); + LOG.error(e.getMessage(), e); + } + } + + public static void installBCProvider() { + installBCProvider(false); + } + + public static void installBCProvider(String providerName, String providerClassName, boolean silent) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException { + bouncyCastleProvider = Security.getProvider(providerName); + if (bouncyCastleProvider == null) { + if (!silent) { + LOG.info("Adding Bouncy Castle Provider"); + } + + bouncyCastleProvider = (Provider) Class.forName(providerClassName).getConstructor().newInstance(); + Security.addProvider(bouncyCastleProvider); + LOG.info("Provider '{}' with version {} is added", bouncyCastleProvider.getName(), bouncyCastleProvider.getVersionStr()); + } else { + if (!silent) { + LOG.info("Bouncy Castle Provider was added already"); + } + } + } + + /** + * A check that the server is running in FIPS-approved-only mode. This is a part + * of compliance to ensure that the server is really FIPS compliant + * + * @return boolean value + */ + private static boolean checkFipsMode() { + try { + // First check if there are FIPS provider libs + Class.forName(BC_FIPS_PROVIDER_CLASS_NAME); + } catch (ClassNotFoundException e) { + System.out.println("BC Fips provider is not available"); + LOG.trace("BC Fips provider is not available", e); + return false; + } + + System.out.println("USE_FIPS_CHECK_COMMAND = " + USE_FIPS_CHECK_COMMAND); + + if (USE_FIPS_CHECK_COMMAND) { + String osName = System.getProperty("os.name"); + if (StringHelper.isNotEmpty(osName) && osName.toLowerCase().startsWith("windows")) { + return false; + } + + try { + // Check if FIPS is enabled + Process process = Runtime.getRuntime().exec("fips-mode-setup --check"); + List result = IOUtils.readLines(process.getInputStream(), StandardCharsets.UTF_8); + if ((result.size() > 0) && StringHelper.equalsIgnoreCase(result.get(0), "FIPS mode is enabled.")) { + return true; + } + } catch (IOException e) { + LOG.error("Failed to check if FIPS mode was enabled", e); + return false; + } + return false; + } + + return true; + } /** * Determines if cryptography restrictions apply. @@ -144,16 +207,19 @@ public static boolean checkRestrictedCryptography() { } } - public static String getBCProviderName() { - return bouncyCastleProvider.getName(); - } + public static String getBCProviderName() { + return bouncyCastleProvider.getName(); + } - public static Provider getBCProvider() { - return bouncyCastleProvider; - } + public static Provider getBCProvider() { + return bouncyCastleProvider; + } - public static boolean isFipsMode() { - return isFipsMode; - } + public static SecurityModeType getSecurityMode() { + return securityMode; + } -} \ No newline at end of file + public static void setSecurityMode(SecurityModeType securityModeIn) { + securityMode = securityModeIn; + } +} From d25870a0a21ff5478149983f33baa08ddaf695e0 Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Mon, 14 Mar 2022 10:04:21 +0200 Subject: [PATCH 271/362] fix(master): removed duplicated dn field https://github.com/GluuFederation/oxAuth/issues/1651 --- .../service/cache/NativePersistenceCacheEntity.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java index debed376..7a5dc58e 100644 --- a/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java +++ b/core-cache/src/main/java/org/gluu/service/cache/NativePersistenceCacheEntity.java @@ -11,8 +11,6 @@ @ObjectClass(value = "cache") public class NativePersistenceCacheEntity extends DeletableEntity implements Serializable, Deletable { - @DN - private String dn; @Expiration private Integer ttl; @AttributeName(name = "uuid") @@ -22,14 +20,6 @@ public class NativePersistenceCacheEntity extends DeletableEntity implements Ser @AttributeName(name = "dat") private String data; - public String getDn() { - return dn; - } - - public void setDn(String dn) { - this.dn = dn; - } - public Integer getTtl() { return ttl; } @@ -64,7 +54,7 @@ public void setData(String data) { @Override public String toString() { - return "NativePersistenceCacheEntity [dn=" + dn + ", ttl=" + ttl + ", id=" + id + ", creationDate=" + creationDate + ", data=" + return "NativePersistenceCacheEntity [dn=" + getDn() + ", ttl=" + ttl + ", id=" + id + ", creationDate=" + creationDate + ", data=" + data + "]"; } } From d23943c5903b325b3b8f5e666a37c3025660b216 Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 18 Mar 2022 17:49:07 +0300 Subject: [PATCH 272/362] chore: deprecated old methods --- oxService/src/main/java/org/gluu/service/LookupService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/oxService/src/main/java/org/gluu/service/LookupService.java b/oxService/src/main/java/org/gluu/service/LookupService.java index 0b47d4a7..18997be2 100644 --- a/oxService/src/main/java/org/gluu/service/LookupService.java +++ b/oxService/src/main/java/org/gluu/service/LookupService.java @@ -79,6 +79,7 @@ public T getDisplayNameEntry(String dn, Class entryClass) throws Exceptio return entry; } + @Deprecated public DisplayNameEntry getDisplayNameEntry(String dn) throws Exception { return getDisplayNameEntry(dn, DisplayNameEntry.class); } @@ -133,6 +134,7 @@ public List getDisplayNameEntries(String baseDn, Class entryClass, Lis return entries; } + @Deprecated public List getDisplayNameEntries(String baseDn, List dns) { return getDisplayNameEntries(baseDn, DisplayNameEntry.class, dns); } From 988484eaedbbfa91ef7c9ecf268e7ee1c3b720de Mon Sep 17 00:00:00 2001 From: yurem Date: Tue, 22 Mar 2022 22:35:46 +0300 Subject: [PATCH 273/362] feat: optimization --- oxUtil/src/main/java/org/gluu/util/StringHelper.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/oxUtil/src/main/java/org/gluu/util/StringHelper.java b/oxUtil/src/main/java/org/gluu/util/StringHelper.java index 35e8211b..c61546da 100644 --- a/oxUtil/src/main/java/org/gluu/util/StringHelper.java +++ b/oxUtil/src/main/java/org/gluu/util/StringHelper.java @@ -136,7 +136,7 @@ public static String[] toStringArray(Object[] array) { String[] result = new String[array.length]; for (int i = 0; i < result.length; i++) { - result[i] = String.valueOf(array[i]); + result[i] = toString(array[i]); } return result; @@ -518,7 +518,11 @@ public static boolean isNotEmptyString(Object string) { } public static String toString(Object object) { - return (object == null) ? null : object.toString(); + if (object instanceof String) { + return (String) object; + } + + return (object == null) ? null : object.toString(); } public static String qualify(final String prefix, String name) { From fabb5c5281b92c803a780a1de706959d0b5ea898 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 24 Mar 2022 21:01:03 +0300 Subject: [PATCH 274/362] chore: use logger instead system output --- .../org/gluu/util/security/SecurityProviderUtility.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java b/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java index 10ee7d4a..56b42597 100644 --- a/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java +++ b/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java @@ -29,6 +29,8 @@ */ public class SecurityProviderUtility { + private static final Logger LOG = LoggerFactory.getLogger(SecurityProviderUtility.class); + public static final String DEF_JKS = "jks"; public static final String DEF_PKCS12 = "pkcs12"; public static final String DEF_BCFKS = "bcfks"; @@ -86,8 +88,6 @@ public String toString() { } } - private static final Logger LOG = LoggerFactory.getLogger(SecurityProviderUtility.class); - public static final String BC_PROVIDER_NAME = "BC"; public static final String BC_FIPS_PROVIDER_NAME = "BCFIPS"; @@ -105,7 +105,7 @@ public static void installBCProvider(boolean silent) { String className = BC_GENERIC_PROVIDER_CLASS_NAME; if (securityMode == null || securityMode == SecurityModeType.BCFKS_SECURITY_MODE) { - System.out.println("securityMode == null || securityMode == SecurityModeType.BCFKS_SECURITY_MODE"); + LOG.trace("securityMode == null || securityMode == SecurityModeType.BCFKS_SECURITY_MODE"); boolean isFipsMode = checkFipsMode(); if (isFipsMode) { LOG.info("Fips mode is enabled"); @@ -166,7 +166,7 @@ private static boolean checkFipsMode() { return false; } - System.out.println("USE_FIPS_CHECK_COMMAND = " + USE_FIPS_CHECK_COMMAND); + LOG.trace("USE_FIPS_CHECK_COMMAND = " + USE_FIPS_CHECK_COMMAND); if (USE_FIPS_CHECK_COMMAND) { String osName = System.getProperty("os.name"); From fe7ee5e424a553067db63f7489070a4d38d5b3ed Mon Sep 17 00:00:00 2001 From: yurem Date: Fri, 25 Mar 2022 18:31:46 +0300 Subject: [PATCH 275/362] chore: remove unused uid attribute from display entry bean --- .../java/org/gluu/model/DisplayNameEntry.java | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/oxService/src/main/java/org/gluu/model/DisplayNameEntry.java b/oxService/src/main/java/org/gluu/model/DisplayNameEntry.java index c9a2f1c2..efeb8e3d 100644 --- a/oxService/src/main/java/org/gluu/model/DisplayNameEntry.java +++ b/oxService/src/main/java/org/gluu/model/DisplayNameEntry.java @@ -41,9 +41,6 @@ public DisplayNameEntry(String dn, String inum, String displayName) { @AttributeName private String displayName; - @AttributeName - private String uid; - public String getInum() { return inum; } @@ -65,21 +62,6 @@ public String toString() { return String.format("DisplayNameEntry [displayName=%s, inum=%s, toString()=%s]", displayName, inum, super.toString()); } - /** - * @param uid - * the uid to set - */ - public void setUid(String uid) { - this.uid = uid; - } - - /** - * @return the uid - */ - public String getUid() { - return uid; - } - public String[] getCustomObjectClasses() { return customObjectClasses; } From a81646d80433754ce154e7476b85e80a9e201ec7 Mon Sep 17 00:00:00 2001 From: SMan Date: Tue, 5 Apr 2022 09:59:17 -0500 Subject: [PATCH 276/362] Security mode type (#226) * feat: security_mode_type has been added to the security_provider_utility; * fix: comments have been removed; --- .../org/gluu/util/security/SecurityProviderUtility.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java b/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java index 56b42597..4f5c5ed5 100644 --- a/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java +++ b/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java @@ -29,8 +29,6 @@ */ public class SecurityProviderUtility { - private static final Logger LOG = LoggerFactory.getLogger(SecurityProviderUtility.class); - public static final String DEF_JKS = "jks"; public static final String DEF_PKCS12 = "pkcs12"; public static final String DEF_BCFKS = "bcfks"; @@ -88,6 +86,8 @@ public String toString() { } } + private static final Logger LOG = LoggerFactory.getLogger(SecurityProviderUtility.class); + public static final String BC_PROVIDER_NAME = "BC"; public static final String BC_FIPS_PROVIDER_NAME = "BCFIPS"; @@ -105,7 +105,6 @@ public static void installBCProvider(boolean silent) { String className = BC_GENERIC_PROVIDER_CLASS_NAME; if (securityMode == null || securityMode == SecurityModeType.BCFKS_SECURITY_MODE) { - LOG.trace("securityMode == null || securityMode == SecurityModeType.BCFKS_SECURITY_MODE"); boolean isFipsMode = checkFipsMode(); if (isFipsMode) { LOG.info("Fips mode is enabled"); @@ -124,7 +123,7 @@ public static void installBCProvider(boolean silent) { installBCProvider(providerName, className, silent); } catch (Exception e) { LOG.error( - "Security provider '{}' doesn't exists in class path. Please deploy correct war for this environment!"); + "Security provider '{}' doesn't exists in class path. Please deploy correct war for this environment!", providerName); LOG.error(e.getMessage(), e); } } @@ -166,8 +165,6 @@ private static boolean checkFipsMode() { return false; } - LOG.trace("USE_FIPS_CHECK_COMMAND = " + USE_FIPS_CHECK_COMMAND); - if (USE_FIPS_CHECK_COMMAND) { String osName = System.getProperty("os.name"); if (StringHelper.isNotEmpty(osName) && osName.toLowerCase().startsWith("windows")) { From 1bf6d29abab19a27c7224285e9f249f0a1ef2892 Mon Sep 17 00:00:00 2001 From: SMan Date: Fri, 8 Apr 2022 04:04:01 -0500 Subject: [PATCH 277/362] Unnecessary out has been removed; (#227) * feat: security_mode_type has been added to the security_provider_utility; * fix: comments have been removed; * fix: unnecessary out has been removed; --- .../java/org/gluu/util/security/SecurityProviderUtility.java | 1 - 1 file changed, 1 deletion(-) diff --git a/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java b/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java index 4f5c5ed5..7277aeae 100644 --- a/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java +++ b/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java @@ -160,7 +160,6 @@ private static boolean checkFipsMode() { // First check if there are FIPS provider libs Class.forName(BC_FIPS_PROVIDER_CLASS_NAME); } catch (ClassNotFoundException e) { - System.out.println("BC Fips provider is not available"); LOG.trace("BC Fips provider is not available", e); return false; } From 700db9dfc487b4c2bd78a7e1ef6025ef711ba75c Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Mon, 25 Apr 2022 21:04:07 +0530 Subject: [PATCH 278/362] fix: changed ui person authentication script python to jython --- oxUtil/src/main/java/org/gluu/model/ProgrammingLanguage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxUtil/src/main/java/org/gluu/model/ProgrammingLanguage.java b/oxUtil/src/main/java/org/gluu/model/ProgrammingLanguage.java index 6d559844..ce042531 100644 --- a/oxUtil/src/main/java/org/gluu/model/ProgrammingLanguage.java +++ b/oxUtil/src/main/java/org/gluu/model/ProgrammingLanguage.java @@ -18,7 +18,7 @@ */ public enum ProgrammingLanguage implements AttributeEnum { - PYTHON("python", "Python"), JAVA_SCRIPT("javascript", "JavaScript"); + PYTHON("python", "Jython"), JAVA_SCRIPT("javascript", "JavaScript"); private String value; private String displayName; From 7b2da878793cb163e19e0a87e23f7438bc2771d4 Mon Sep 17 00:00:00 2001 From: SMan Date: Tue, 26 Apr 2022 02:48:23 -0500 Subject: [PATCH 279/362] feat: security_mode_type and key_storage_type have been added; --- .../security/SecurityProviderUtility.java | 181 ++++++++++++++++-- 1 file changed, 163 insertions(+), 18 deletions(-) diff --git a/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java b/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java index 7277aeae..9ad58d4f 100644 --- a/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java +++ b/oxUtil/src/main/java/org/gluu/util/security/SecurityProviderUtility.java @@ -26,12 +26,34 @@ * * @author Yuriy Movchan * @author madhumitas + * @author Sergey Manoylo + * @version April 26, 2022 */ public class SecurityProviderUtility { - public static final String DEF_JKS = "jks"; - public static final String DEF_PKCS12 = "pkcs12"; - public static final String DEF_BCFKS = "bcfks"; + // security mode + public static final String DEF_MODE_BCPROV = "BCPROV"; + public static final String DEF_MODE_BCFIPS = "BCFIPS"; + + // keystorage type + public static final String DEF_KS_JKS = "JKS"; + public static final String DEF_KS_PKCS12 = "PKCS12"; + public static final String DEF_KS_BCFKS = "BCFKS"; + + // JKS additional extensions + public static final String DEF_EXT_JKS = "jks"; + public static final String DEF_EXT_KEYSTORE = "keystore"; + public static final String DEF_EXT_KS = "ks"; + + // PKCS12 additional extensions + public static final String DEF_EXT_PKCS12 = "pkcs12"; + public static final String DEF_EXT_P12 = "p12"; + public static final String DEF_EXT_PFX = "pfx"; + + // BCFKS additional extensions + public static final String DEF_EXT_BCFKS = "bcfks"; + public static final String DEF_EXT_BCF = "bcf"; + public static final String DEF_EXT_BCFIPS = "bcfips"; /** * Security Mode Type @@ -41,10 +63,9 @@ public class SecurityProviderUtility { */ public static enum SecurityModeType { - JKS_SECURITY_MODE (DEF_JKS), - PKCS12_SECURITY_MODE (DEF_PKCS12), - BCFKS_SECURITY_MODE (DEF_BCFKS); - + BCPROV_SECURITY_MODE (DEF_MODE_BCPROV), + BCFIPS_SECURITY_MODE (DEF_MODE_BCFIPS); + private final String value; /** @@ -63,15 +84,12 @@ public static enum SecurityModeType { * @return SecurityModeType */ public static SecurityModeType fromString(String param) { - switch(param) { - case DEF_JKS: { - return JKS_SECURITY_MODE; + switch(param.toUpperCase()) { + case DEF_MODE_BCPROV: { + return BCPROV_SECURITY_MODE; } - case DEF_PKCS12: { - return PKCS12_SECURITY_MODE; - } - case DEF_BCFKS: { - return BCFKS_SECURITY_MODE; + case DEF_MODE_BCFIPS: { + return BCFIPS_SECURITY_MODE; } } return null; @@ -84,8 +102,135 @@ public static SecurityModeType fromString(String param) { public String toString() { return value; } + + /** + * + * @return + */ + public KeyStorageType[] getKeystorageTypes() { + KeyStorageType [] keystorages = null; + if (this == BCPROV_SECURITY_MODE) { + keystorages = new KeyStorageType[] { KeyStorageType.JKS_KS, KeyStorageType.PKCS12_KS }; + } + else if (this == BCFIPS_SECURITY_MODE) { + keystorages = new KeyStorageType[] { KeyStorageType.BCFKS_KS }; + } + return keystorages; + } } + /** + * Security Mode Type + * + * @author Sergey Manoylo + * @version March 11, 2022 + */ + public static enum KeyStorageType { + + JKS_KS (DEF_KS_JKS), + PKCS12_KS (DEF_KS_PKCS12), + BCFKS_KS (DEF_KS_BCFKS); + + private final String value; + + /** + * Constructor + * + * @param value string value, that defines Security Mode Type + */ + KeyStorageType(String value) { + this.value = value; + } + + /** + * Creates/parses SecurityModeType from String value + * + * @param param string value, that defines Security Mode Type + * @return SecurityModeType + */ + public static KeyStorageType fromString(String param) { + switch(param.toUpperCase()) { + case DEF_KS_JKS: { + return JKS_KS; + } + case DEF_KS_PKCS12: { + return PKCS12_KS; + } + case DEF_KS_BCFKS: { + return BCFKS_KS; + } + } + return null; + } + + /** + * Returns a string representation of the object. In this case the parameter name for the default scope. + */ + @Override + public String toString() { + return value; + } + + /** + * + * @return + */ + public String[] getExtensions() { + String[] extensions = null; + if (this == JKS_KS) { + extensions = new String[] { DEF_EXT_JKS, DEF_EXT_KEYSTORE, DEF_EXT_KS }; + } + else if(this == PKCS12_KS) { + extensions = new String[] { DEF_EXT_PKCS12, DEF_EXT_P12, DEF_EXT_P12 }; + } + else if(this == BCFKS_KS) { + extensions = new String[] { DEF_EXT_BCFKS, DEF_EXT_BCF, DEF_EXT_BCFIPS }; + } + return extensions; + } + + /** + * + * @return + */ + public SecurityModeType getSecurityMode() { + SecurityModeType securityModeType = null; + if (this == JKS_KS || this == PKCS12_KS) { + securityModeType = SecurityModeType.BCPROV_SECURITY_MODE; + } + else if(this == BCFKS_KS) { + securityModeType = SecurityModeType.BCFIPS_SECURITY_MODE; + } + return securityModeType; + } + + /** + * + * @param extension + * @return + */ + public static KeyStorageType fromExtension(String extension) { + switch(extension.toLowerCase()) { + case DEF_EXT_JKS: + case DEF_EXT_KEYSTORE: + case DEF_EXT_KS: { + return JKS_KS; + } + case DEF_EXT_PKCS12: + case DEF_EXT_P12: + case DEF_EXT_PFX: { + return PKCS12_KS; + } + case DEF_EXT_BCFKS: + case DEF_EXT_BCF: + case DEF_EXT_BCFIPS: { + return BCFKS_KS; + } + } + return null; + } + } + private static final Logger LOG = LoggerFactory.getLogger(SecurityProviderUtility.class); public static final String BC_PROVIDER_NAME = "BC"; @@ -104,7 +249,7 @@ public static void installBCProvider(boolean silent) { String providerName = BC_PROVIDER_NAME; String className = BC_GENERIC_PROVIDER_CLASS_NAME; - if (securityMode == null || securityMode == SecurityModeType.BCFKS_SECURITY_MODE) { + if (securityMode == null || securityMode == SecurityModeType.BCFIPS_SECURITY_MODE) { boolean isFipsMode = checkFipsMode(); if (isFipsMode) { LOG.info("Fips mode is enabled"); @@ -112,10 +257,10 @@ public static void installBCProvider(boolean silent) { providerName = BC_FIPS_PROVIDER_NAME; className = BC_FIPS_PROVIDER_CLASS_NAME; - securityMode = SecurityModeType.BCFKS_SECURITY_MODE; + securityMode = SecurityModeType.BCFIPS_SECURITY_MODE; } else { - securityMode = SecurityModeType.JKS_SECURITY_MODE; + securityMode = SecurityModeType.BCPROV_SECURITY_MODE; } } From 6a731d5ce0b312158adb9911487bff723b04cc71 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 27 Apr 2022 12:24:15 +0300 Subject: [PATCH 280/362] Branch for version 4.5.0 --- core-cache/pom.xml | 2 +- core-cdi/pom.xml | 2 +- core-document-store/pom.xml | 2 +- core-java-ext/pom.xml | 2 +- core-script/pom.xml | 2 +- core-standalone/pom.xml | 2 +- core-timer-weld/pom.xml | 2 +- demo-cdi/pom.xml | 2 +- exception-extension-cdi/pom.xml | 2 +- oxJsfUtil/pom.xml | 2 +- oxModel/pom.xml | 2 +- oxRadius/pom.xml | 2 +- oxSaml/pom.xml | 2 +- oxService/pom.xml | 2 +- oxUtil/pom.xml | 2 +- pom.xml | 4 ++-- security-extension-cdi/pom.xml | 2 +- server/pom.xml | 2 +- 18 files changed, 19 insertions(+), 19 deletions(-) diff --git a/core-cache/pom.xml b/core-cache/pom.xml index 99b40a2a..4f859785 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/core-cdi/pom.xml b/core-cdi/pom.xml index 7dded74c..ffb04be8 100644 --- a/core-cdi/pom.xml +++ b/core-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index b5aeb318..e0a2c2f0 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/core-java-ext/pom.xml b/core-java-ext/pom.xml index d37c5b95..04eac55d 100644 --- a/core-java-ext/pom.xml +++ b/core-java-ext/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/core-script/pom.xml b/core-script/pom.xml index 215a9f9e..79980813 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/core-standalone/pom.xml b/core-standalone/pom.xml index cdec4641..242c6928 100644 --- a/core-standalone/pom.xml +++ b/core-standalone/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/core-timer-weld/pom.xml b/core-timer-weld/pom.xml index b28e1cf4..d91bf860 100644 --- a/core-timer-weld/pom.xml +++ b/core-timer-weld/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index ef7306fd..1e6dd0fd 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/exception-extension-cdi/pom.xml b/exception-extension-cdi/pom.xml index 80e08c03..58d92692 100644 --- a/exception-extension-cdi/pom.xml +++ b/exception-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index ad83a2b9..c09fe435 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/oxModel/pom.xml b/oxModel/pom.xml index 78e268ff..60dbf61d 100644 --- a/oxModel/pom.xml +++ b/oxModel/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/oxRadius/pom.xml b/oxRadius/pom.xml index b2021937..b8269a68 100644 --- a/oxRadius/pom.xml +++ b/oxRadius/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index 0c5a7e9b..bc302c14 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/oxService/pom.xml b/oxService/pom.xml index 0b3f6e4d..3080fc1f 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index 0d60190d..baf7d4e5 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/pom.xml b/pom.xml index 95875e8a..cf8eb286 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.gluu oxcore pom - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT oxCore https://www.gluu.org @@ -50,7 +50,7 @@ org.gluu gluu-core-bom - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT import pom diff --git a/security-extension-cdi/pom.xml b/security-extension-cdi/pom.xml index 8d100db3..d32d6dd2 100644 --- a/security-extension-cdi/pom.xml +++ b/security-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT diff --git a/server/pom.xml b/server/pom.xml index 9534050e..e5b2b315 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.4.0-SNAPSHOT + 4.5.0-SNAPSHOT From 0ba5eca3fef74f1a969cb55e5e4225ee168ba65e Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Wed, 27 Apr 2022 19:50:28 +0530 Subject: [PATCH 281/362] feat: to save the files in db --- ...tandaloneDocumentStoreProviderFactory.java | 12 + .../store/conf/DocumentStoreType.java | 2 +- .../provider/DBDocumentStoreProvider.java | 186 ++++++++++++++++ .../store/service/DBDocumentService.java | 209 ++++++++++++++++++ .../document/store/service/OxDocument.java | 144 ++++++++++++ 5 files changed, 552 insertions(+), 1 deletion(-) create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/service/DBDocumentService.java create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java index 72d0b022..529ded97 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java @@ -2,6 +2,7 @@ import org.gluu.service.document.store.conf.DocumentStoreConfiguration; import org.gluu.service.document.store.conf.DocumentStoreType; +import org.gluu.service.document.store.provider.DBDocumentStoreProvider; import org.gluu.service.document.store.provider.DocumentStoreProvider; import org.gluu.service.document.store.provider.JcaDocumentStoreProvider; import org.gluu.service.document.store.provider.LocalDocumentStoreProvider; @@ -22,6 +23,9 @@ public class StandaloneDocumentStoreProviderFactory { public StandaloneDocumentStoreProviderFactory(StringEncrypter stringEncrypter) { this.stringEncrypter = stringEncrypter; } + public StandaloneDocumentStoreProviderFactory() { + + } public DocumentStoreProvider getDocumentStoreProvider(DocumentStoreConfiguration documentStoreConfiguration) { DocumentStoreType documentStoreType = documentStoreConfiguration.getDocumentStoreType(); @@ -63,7 +67,15 @@ public DocumentStoreProvider getDocumentStoreProvider(DocumentStoreConfiguration documentStoreProvider = webDavDocumentStoreProvider; break; + case DB: + DBDocumentStoreProvider dbDocumentStoreProvider = new DBDocumentStoreProvider(); + //webDavDocumentStoreProvider.configure(documentStoreConfiguration, stringEncrypter); + //webDavDocumentStoreProvider.init(); + + documentStoreProvider = dbDocumentStoreProvider; + break; } + if (documentStoreProvider == null) { throw new RuntimeException( diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreType.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreType.java index 0b3de6ba..e941823f 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreType.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreType.java @@ -7,5 +7,5 @@ */ @XmlEnum(String.class) public enum DocumentStoreType { - LOCAL, JCA, WEB_DAV + LOCAL, JCA, WEB_DAV, DB } diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java new file mode 100644 index 00000000..e3abf83b --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -0,0 +1,186 @@ +package org.gluu.service.document.store.provider; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.util.Base64; +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import org.apache.commons.io.IOUtils; +import org.gluu.service.document.store.conf.DocumentStoreType; +import org.gluu.service.document.store.service.DBDocumentService; +import org.gluu.service.document.store.service.OxDocument; +import org.gluu.util.StringHelper; +import org.slf4j.Logger; + +/** + * @author Shekhar L. on 26/04/2022 + */ +@ApplicationScoped +public class DBDocumentStoreProvider extends DocumentStoreProvider { + + @Inject + private Logger log; + + + @Inject + private DBDocumentService documentService; + + public DBDocumentStoreProvider() { + } + + public DocumentStoreType getProviderType() { + return DocumentStoreType.DB; + } + + @Override + public boolean hasDocument(String path) { + log.debug("Has document: '{}'", path); + if (StringHelper.isEmpty(path)) { + throw new IllegalArgumentException("Specified path should not be empty!"); + } + OxDocument oxDocument = null; + try { + oxDocument = documentService.getOxDocumentByDisplayName(path); + } catch (Exception e) { + log.error("Failed to check if path '" + path + "' exists in repository", e); + } + + return oxDocument != null; + } + + @Override + public boolean saveDocument(String name, String documentContent, Charset charset) { + log.debug("Save document: '{}'", name); + OxDocument oxDocument = new OxDocument(); + oxDocument.setDocument(documentContent); + oxDocument.setDisplayName(name); + try { + try { + oxDocument.setInum(documentService.generateInumForNewOxDocument()); + documentService.addOxDocument(oxDocument); + //persistenceEntryManager.persist(oxDocument); + return true; + } finally { + } + } catch (Exception ex) { + log.error("Failed to write document to file '{}'", name, ex); + } + + return false; + } + + @Override + public boolean saveDocumentStream(String name, InputStream documentStream) { + + //log.debug("Save document from stream: '{}'", name); + OxDocument oxDocument = new OxDocument(); + oxDocument.setDisplayName(name); + + try { + String documentContent = Base64.getEncoder().encodeToString(IOUtils.toByteArray(documentStream)); + oxDocument.setDocument(documentContent); + oxDocument.setInum(documentService.generateInumForNewOxDocument()); + documentService.addOxDocument(oxDocument); + return true; + } catch (IOException e) { + log.error("Failed to write document from stream to file '{}'", name, e); + }catch (Exception e) { + log.error("Failed to write document from stream to file '{}'", name, e); + } + + return false; + } + + + @Override + public String readDocument(String inum, Charset charset) { + log.debug("Read document: '{}'", inum); + OxDocument oxDocument; + try { + oxDocument = documentService.getOxDocumentByInum(inum); + if(oxDocument != null) { + return oxDocument.getDocument(); + } + } catch (Exception e) { + log.error("Failed to read document as stream from file '{}'", inum, e); + e.printStackTrace(); + } + return null; + } + + @Override + public InputStream readDocumentAsStream(String inum) { + log.debug("Read document as stream: '{}'", inum); + String filecontecnt = readDocument(inum, null); + if (filecontecnt == null) { + log.error("Document file '{}' isn't exist", inum); + return null; + } + + InputStream InputStream = new ByteArrayInputStream(Base64.getDecoder().decode(filecontecnt)); + return InputStream; + } + + @Override + public boolean renameDocument(String currentDisplayName, String destinationDisplayName) { + log.debug("Rename document: '{}' -> '{}'", currentDisplayName, destinationDisplayName); + OxDocument oxDocument; + try { + oxDocument = documentService.getOxDocumentByDisplayName(currentDisplayName); + if (oxDocument == null) { + log.error("Document doesn't Exist with the name '{}'", currentDisplayName); + return false; + } + oxDocument.setDisplayName(destinationDisplayName); + documentService.updateOxDocument(oxDocument); + OxDocument oxDocumentDestination = documentService.getOxDocumentByDisplayName(destinationDisplayName); + if(oxDocumentDestination == null) { + log.error("Failed to rename to destination file '{}'", destinationDisplayName); + return false; + } + } catch (Exception e) { + log.error("Failed to rename to destination file '{}'", destinationDisplayName); + e.printStackTrace(); + } + return true; + } + + @Override + public boolean removeDocument(String inum) { + log.debug("Remove document: '{}'", inum); + OxDocument oxDocument; + try { + oxDocument = documentService.getOxDocumentByInum(inum); + if(oxDocument == null) { + log.error(" document not exist file '{}'", inum); + return false; + } + + documentService.removeOxDocument(oxDocument); + OxDocument checkOxDocument = documentService.getOxDocumentByInum(inum); + if(checkOxDocument == null) { + return true; + } + return false; + } catch (Exception e) { + log.error("Failed to remove document file '{}'", inum, e); + e.printStackTrace(); + } + return false; + } + + @Override + public void create() { + // TODO Auto-generated method stub + + } + + @Override + public void destroy() { + // TODO Auto-generated method stub + + } + +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/service/DBDocumentService.java b/core-document-store/src/main/java/org/gluu/service/document/store/service/DBDocumentService.java new file mode 100644 index 00000000..a42c6b8a --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/service/DBDocumentService.java @@ -0,0 +1,209 @@ +/* + * oxTrust is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.service.document.store.service; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +import javax.enterprise.context.ApplicationScoped; +import javax.inject.Inject; +import javax.inject.Named; + +import org.gluu.persist.PersistenceEntryManager; +import org.gluu.search.filter.Filter; +import org.gluu.util.StringHelper; +import org.slf4j.Logger; + +/** + * Provides operations with OxDocument + * + * @author Shekhar L. Date : 04 April 2022 + */ +@ApplicationScoped +@Named("DBDocumentService") +public class DBDocumentService implements Serializable { + + private static final long serialVersionUID = 65734145678106186L; + + @Inject + private PersistenceEntryManager persistenceEntryManager; + + @Inject + private Logger logger; + + public static final String inum = "inum"; + public static final String displayName = "displayName"; + public static final String description = "description"; + + /** + * Add new OxDocument entry + * + * @param OxDocument + * OxDocument + */ + public void addOxDocument(OxDocument oxDocument) throws Exception { + persistenceEntryManager.persist(oxDocument); + } + + /** + * Remove OxDocument entry + * + * @param OxDocument + * OxDocument + */ + public void removeOxDocument(OxDocument oxDocument) throws Exception { + + persistenceEntryManager.remove(oxDocument); + } + + /** + * Get OxDocument by inum + * + * @param inum + * OxDocument Inum + * @return OxDocument + */ + public OxDocument getOxDocumentByInum(String inum) throws Exception { + OxDocument result = null; + try { + result = persistenceEntryManager.find(OxDocument.class, getDnForOxDocument(inum)); + } catch (Exception e) { + logger.debug("", e); + } + return result; + } + + /** + * Build DN string for OxDocument + * + * @param inum + * OxDocument Inum + * @return DN string for specified scope or DN for OxDocument branch if inum is null + * @throws Exception + */ + public String getDnForOxDocument(String inum) throws Exception { + if (StringHelper.isEmpty(inum)) { + return String.format("ou=document,%s", "o=gluu"); + } + return String.format("inum=%s,ou=document,%s", inum, "o=gluu"); + } + + /** + * Update OxDocument entry + * + * @param OxDocument + * OxDocument + */ + public void updateOxDocument(OxDocument oxDocument) throws Exception { + persistenceEntryManager.merge(oxDocument); + } + + /** + * Generate new inum for OxDocument + * + * @return New inum for OxDocument + */ + public String generateInumForNewOxDocument() throws Exception { + OxDocument oxDocument = new OxDocument(); + String newInum = null; + String newDn = null; + //do { + newInum = generateInumForNewOxDocumentImpl(); + newDn = getDnForOxDocument(newInum); + oxDocument.setDn(newDn); + //} while (persistenceEntryManager.contains(newDn, OxDocument.class)); + return newInum; + } + + /** + * Search scopes by pattern + * + * @param pattern + * Pattern + * @param sizeLimit + * Maximum count of results + * @return List of OxDocument + * @throws Exception + */ + public List searchOxDocuments(String pattern, int sizeLimit) { + Filter searchFilter = null; + if (StringHelper.isNotEmpty(pattern)) { + String[] targetArray = new String[] { pattern }; + Filter displayNameFilter = Filter.createSubstringFilter(displayName, null, targetArray, + null); + Filter descriptionFilter = Filter.createSubstringFilter(description, null, targetArray, + null); + searchFilter = Filter.createORFilter(displayNameFilter, descriptionFilter); + } + List result = new ArrayList<>(); + try { + result = persistenceEntryManager.findEntries(getDnForOxDocument(null), OxDocument.class, searchFilter, sizeLimit); + return result; + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + /** + * Generate new inum for oxDocument + * + * @return New inum for oxDocument + * @throws Exception + */ + private String generateInumForNewOxDocumentImpl() throws Exception { + return UUID.randomUUID().toString(); + } + + public List getAllOxDocumentsList(int size) { + try { + List oxDocuments = persistenceEntryManager.findEntries(getDnForOxDocument(null), OxDocument.class, null, size); + return oxDocuments; + } catch (Exception e) { + logger.error("", e); + return new ArrayList<>(); + } + } + + /** + * returns oxDocuments by Dn + * + * @return oxDocuments + */ + + public OxDocument getOxDocumentByDn(String Dn) throws Exception { + return persistenceEntryManager.find(OxDocument.class, Dn); + } + + /** + * Get oxDocuments by DisplayName + * + * @param DisplayName + * @return oxDocuments + */ + public OxDocument getOxDocumentByDisplayName(String DisplayName) throws Exception { + OxDocument oxDocument = new OxDocument(); + oxDocument.setDisplayName(DisplayName); + List oxDocuments = persistenceEntryManager.findEntries(oxDocument); + if ((oxDocuments != null) && (oxDocuments.size() > 0)) { + return oxDocuments.get(0); + } + return null; + } + + /*private List filter(List oxDocument) { + if (oxDocument != null) { + return oxDocument.stream().filter(e -> !e.isUmaType()).collect(Collectors.toList()); + } else { + return new ArrayList<>(); + } + }*/ +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java b/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java new file mode 100644 index 00000000..aaf4b119 --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java @@ -0,0 +1,144 @@ +/* + * oxTrust is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.service.document.store.service; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import org.gluu.persist.model.base.Entry; +import org.gluu.persist.annotation.AttributeName; +import org.gluu.persist.annotation.AttributesList; +import org.gluu.persist.annotation.DataEntry; +import org.gluu.persist.annotation.ObjectClass; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +/** + * Group + * + * @author Yuriy Movchan Date: 11.02.2010 + */ +@DataEntry(sortBy = { "displayName" }) +@ObjectClass(value = "oxDocument") +@JsonInclude(Include.NON_NULL) +public class OxDocument extends Entry implements Serializable { + + private static final long serialVersionUID = -2812480357430436503L; + + private transient boolean selected; +//inum $ displayName $ description $ document $ oxModuleProperty $ oxLevel $ oxRevision $ oxEnabled $ oxAlias ) + @AttributeName(ignoreDuringUpdate = true) + private String inum; + + + @AttributeName + private String displayName; + + @AttributeName + private String description; + + @AttributeName + private String document; + + @AttributeName + private String oxModuleProperty; + + @AttributeName + private String oxLevel; + + @AttributeName + private String oxRevision; + + @AttributeName + private String oxEnabled; + + @AttributeName + private String oxAlias; + + public String getInum() { + return inum; + } + + public void setInum(String inum) { + this.inum = inum; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public boolean isSelected() { + return selected; + } + + public void setSelected(boolean selected) { + this.selected = selected; + } + + public String getDocument() { + return document; + } + + public void setDocument(String document) { + this.document = document; + } + + public String getOxModuleProperty() { + return oxModuleProperty; + } + + public void setOxModuleProperty(String oxModuleProperty) { + this.oxModuleProperty = oxModuleProperty; + } + + public String getOxLevel() { + return oxLevel; + } + + public void setOxLevel(String oxLevel) { + this.oxLevel = oxLevel; + } + + public String getOxRevision() { + return oxRevision; + } + + public void setOxRevision(String oxRevision) { + this.oxRevision = oxRevision; + } + + public String getOxEnabled() { + return oxEnabled; + } + + public void setOxEnabled(String oxEnabled) { + this.oxEnabled = oxEnabled; + } + + public String getOxAlias() { + return oxAlias; + } + + public void setOxAlias(String oxAlias) { + this.oxAlias = oxAlias; + } + +} From f72de5c7a89458b01025aaa6ffb1db199ae682bc Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Mon, 2 May 2022 20:10:56 +0530 Subject: [PATCH 282/362] feat: to save the files in db --- core-document-store/pom.xml | 5 + ...tandaloneDocumentStoreProviderFactory.java | 9 +- .../conf/DBDocumentStoreConfiguration.java | 90 ++++++++++++ .../conf/DocumentStoreConfiguration.java | 9 ++ .../provider/DBDocumentStoreProvider.java | 136 ++++++++++++++---- .../store/service/DBDocumentService.java | 31 +++- .../document/store/service/OxDocument.java | 16 ++- 7 files changed, 254 insertions(+), 42 deletions(-) create mode 100644 core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index e0a2c2f0..ea818c56 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -48,6 +48,11 @@ oxcore-util ${project.version} + + org.gluu + gluu-orm-ldap + ${project.version} + diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java index 529ded97..2dc0c002 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java @@ -23,8 +23,9 @@ public class StandaloneDocumentStoreProviderFactory { public StandaloneDocumentStoreProviderFactory(StringEncrypter stringEncrypter) { this.stringEncrypter = stringEncrypter; } + public StandaloneDocumentStoreProviderFactory() { - + super(); } public DocumentStoreProvider getDocumentStoreProvider(DocumentStoreConfiguration documentStoreConfiguration) { @@ -66,11 +67,11 @@ public DocumentStoreProvider getDocumentStoreProvider(DocumentStoreConfiguration webDavDocumentStoreProvider.init(); documentStoreProvider = webDavDocumentStoreProvider; - break; + break; case DB: DBDocumentStoreProvider dbDocumentStoreProvider = new DBDocumentStoreProvider(); - //webDavDocumentStoreProvider.configure(documentStoreConfiguration, stringEncrypter); - //webDavDocumentStoreProvider.init(); + dbDocumentStoreProvider.configure(documentStoreConfiguration, stringEncrypter); + dbDocumentStoreProvider.init(); documentStoreProvider = dbDocumentStoreProvider; break; diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java new file mode 100644 index 00000000..97e929aa --- /dev/null +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java @@ -0,0 +1,90 @@ +package org.gluu.service.document.store.conf; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.io.Serializable; + +import org.gluu.persist.PersistenceEntryManager; + +/** + * @author shekhar L. on 27/04/2022 + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class DBDocumentStoreConfiguration implements Serializable { + + private static final long serialVersionUID = 3380170170265842538L; + + private String server; // http://localhost:8080 + private String useSSL; + private int connectionTimeout; + private PersistenceEntryManager MANAGER = null; + private String maxconnections; + + private String userId; + private String password; + //private String decryptedPassword; + + + public int getConnectionTimeout() { + return connectionTimeout; + } + + public void setConnectionTimeout(int connectionTimeout) { + this.connectionTimeout = connectionTimeout; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public PersistenceEntryManager getMANAGER() { + return MANAGER; + } + + public void setMANAGER(PersistenceEntryManager mANAGER) { + MANAGER = mANAGER; + } + + public String getServer() { + return server; + } + + public void setServer(String server) { + this.server = server; + } + + public String getUseSSL() { + return useSSL; + } + + public void setUseSSL(String useSSL) { + this.useSSL = useSSL; + } + + public String getMaxconnections() { + return maxconnections; + } + + public void setMaxconnections(String maxconnections) { + this.maxconnections = maxconnections; + } + + @Override + public String toString() { + return "DBDocumentStoreConfiguration [serverUrl=" + server + ", connectionTimeout=" + + connectionTimeout + ", userId=" + userId + "]"; + } + +} diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java index c7f19636..23f0936b 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java @@ -22,6 +22,7 @@ public class DocumentStoreConfiguration implements Serializable { private JcaDocumentStoreConfiguration jcaConfiguration; private WebDavDocumentStoreConfiguration webDavConfiguration; + private DBDocumentStoreConfiguration dbDavConfiguration; public DocumentStoreType getDocumentStoreType() { return documentStoreType; @@ -55,6 +56,14 @@ public void setWebDavConfiguration(WebDavDocumentStoreConfiguration webDavConfig this.webDavConfiguration = webDavConfiguration; } + public DBDocumentStoreConfiguration getDbDavConfiguration() { + return dbDavConfiguration; + } + + public void setDbDavConfiguration(DBDocumentStoreConfiguration dbDavConfiguration) { + this.dbDavConfiguration = dbDavConfiguration; + } + @Override public String toString() { return "DocumentStoreConfiguration [documentStoreType=" + documentStoreType + ", localConfiguration=" + localConfiguration diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index e3abf83b..b731c376 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -5,14 +5,25 @@ import java.io.InputStream; import java.nio.charset.Charset; import java.util.Base64; +import java.util.Date; +import java.util.Properties; + +import javax.annotation.PostConstruct; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; import org.apache.commons.io.IOUtils; +import org.gluu.persist.PersistenceEntryManager; +import org.gluu.persist.ldap.impl.LdapEntryManager; +import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; +import org.gluu.service.document.store.conf.DBDocumentStoreConfiguration; +import org.gluu.service.document.store.conf.DocumentStoreConfiguration; import org.gluu.service.document.store.conf.DocumentStoreType; import org.gluu.service.document.store.service.DBDocumentService; import org.gluu.service.document.store.service.OxDocument; import org.gluu.util.StringHelper; +import org.gluu.util.security.StringEncrypter; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author Shekhar L. on 26/04/2022 @@ -26,6 +37,15 @@ public class DBDocumentStoreProvider extends DocumentStoreProvider oxDocuments = persistenceEntryManager.findEntries(oxDocument); if ((oxDocuments != null) && (oxDocuments.size() > 0)) { return oxDocuments.get(0); @@ -199,6 +210,14 @@ public OxDocument getOxDocumentByDisplayName(String DisplayName) throws Exceptio return null; } + public PersistenceEntryManager getPersistenceEntryManager() { + return persistenceEntryManager; + } + + public void setPersistenceEntryManager(PersistenceEntryManager persistenceEntryManager) { + this.persistenceEntryManager = persistenceEntryManager; + } + /*private List filter(List oxDocument) { if (oxDocument != null) { return oxDocument.stream().filter(e -> !e.isUmaType()).collect(Collectors.toList()); diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java b/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java index aaf4b119..bee87445 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java @@ -7,12 +7,9 @@ package org.gluu.service.document.store.service; import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - +import java.util.Date; import org.gluu.persist.model.base.Entry; import org.gluu.persist.annotation.AttributeName; -import org.gluu.persist.annotation.AttributesList; import org.gluu.persist.annotation.DataEntry; import org.gluu.persist.annotation.ObjectClass; @@ -46,6 +43,9 @@ public class OxDocument extends Entry implements Serializable { @AttributeName private String document; + @AttributeName + private Date creationDate; + @AttributeName private String oxModuleProperty; @@ -141,4 +141,12 @@ public void setOxAlias(String oxAlias) { this.oxAlias = oxAlias; } + public Date getCreationDate() { + return creationDate; + } + + public void setCreationDate(Date creationDate) { + this.creationDate = creationDate; + } + } From 19cf64b44577ff6a3619e8ed44a3021142256e72 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Thu, 26 May 2022 21:24:26 +0530 Subject: [PATCH 283/362] fix: added functionality to support internal and external persistenceManager --- ...tandaloneDocumentStoreProviderFactory.java | 2 +- .../conf/DBDocumentStoreConfiguration.java | 18 +++++++-------- .../conf/DocumentStoreConfiguration.java | 12 +++++----- .../provider/DBDocumentStoreProvider.java | 23 +++++++++++++------ 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java index 2dc0c002..bde52a6c 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java @@ -70,7 +70,7 @@ public DocumentStoreProvider getDocumentStoreProvider(DocumentStoreConfiguration break; case DB: DBDocumentStoreProvider dbDocumentStoreProvider = new DBDocumentStoreProvider(); - dbDocumentStoreProvider.configure(documentStoreConfiguration, stringEncrypter); + dbDocumentStoreProvider.configure(documentStoreConfiguration); dbDocumentStoreProvider.init(); documentStoreProvider = dbDocumentStoreProvider; diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java index 97e929aa..37fcd840 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java @@ -17,7 +17,7 @@ public class DBDocumentStoreConfiguration implements Serializable { private String server; // http://localhost:8080 private String useSSL; private int connectionTimeout; - private PersistenceEntryManager MANAGER = null; + private PersistenceEntryManager persistenceEntryManager = null; private String maxconnections; private String userId; @@ -49,14 +49,6 @@ public void setPassword(String password) { this.password = password; } - public PersistenceEntryManager getMANAGER() { - return MANAGER; - } - - public void setMANAGER(PersistenceEntryManager mANAGER) { - MANAGER = mANAGER; - } - public String getServer() { return server; } @@ -81,6 +73,14 @@ public void setMaxconnections(String maxconnections) { this.maxconnections = maxconnections; } + public PersistenceEntryManager getPersistenceEntryManager() { + return persistenceEntryManager; + } + + public void setPersistenceEntryManager(PersistenceEntryManager persistenceEntryManager) { + this.persistenceEntryManager = persistenceEntryManager; + } + @Override public String toString() { return "DBDocumentStoreConfiguration [serverUrl=" + server + ", connectionTimeout=" diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java index 23f0936b..54d1aa36 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DocumentStoreConfiguration.java @@ -22,7 +22,7 @@ public class DocumentStoreConfiguration implements Serializable { private JcaDocumentStoreConfiguration jcaConfiguration; private WebDavDocumentStoreConfiguration webDavConfiguration; - private DBDocumentStoreConfiguration dbDavConfiguration; + private DBDocumentStoreConfiguration dbConfiguration; public DocumentStoreType getDocumentStoreType() { return documentStoreType; @@ -56,17 +56,17 @@ public void setWebDavConfiguration(WebDavDocumentStoreConfiguration webDavConfig this.webDavConfiguration = webDavConfiguration; } - public DBDocumentStoreConfiguration getDbDavConfiguration() { - return dbDavConfiguration; + public DBDocumentStoreConfiguration getDbConfiguration() { + return dbConfiguration; } - public void setDbDavConfiguration(DBDocumentStoreConfiguration dbDavConfiguration) { - this.dbDavConfiguration = dbDavConfiguration; + public void setDbConfiguration(DBDocumentStoreConfiguration dbDavConfiguration) { + this.dbConfiguration = dbDavConfiguration; } @Override public String toString() { return "DocumentStoreConfiguration [documentStoreType=" + documentStoreType + ", localConfiguration=" + localConfiguration - + ", jcaConfiguration=" + jcaConfiguration + ", webDavConfiguration=" + webDavConfiguration + "]"; + + ", jcaConfiguration=" + jcaConfiguration + ", webDavConfiguration=" + webDavConfiguration + ", DBConfiguration=" + dbConfiguration + "]"; } } diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index b731c376..e336726e 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -44,8 +44,10 @@ public class DBDocumentStoreProvider extends DocumentStoreProvider Date: Sun, 29 May 2022 17:58:59 +0530 Subject: [PATCH 284/362] fix: removed the external pm --- .../provider/DBDocumentStoreProvider.java | 54 ++----------------- 1 file changed, 4 insertions(+), 50 deletions(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index e336726e..29894983 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -46,8 +46,6 @@ public class DBDocumentStoreProvider extends DocumentStoreProvider Date: Tue, 31 May 2022 18:53:01 +0530 Subject: [PATCH 285/362] fix: changes for persistence manager,logger etc. --- ...tandaloneDocumentStoreProviderFactory.java | 2 +- .../conf/DBDocumentStoreConfiguration.java | 60 +------------------ .../provider/DBDocumentStoreProvider.java | 7 +-- .../store/service/DBDocumentService.java | 7 +-- 4 files changed, 7 insertions(+), 69 deletions(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java index bde52a6c..d2a214d5 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java @@ -70,7 +70,7 @@ public DocumentStoreProvider getDocumentStoreProvider(DocumentStoreConfiguration break; case DB: DBDocumentStoreProvider dbDocumentStoreProvider = new DBDocumentStoreProvider(); - dbDocumentStoreProvider.configure(documentStoreConfiguration); + dbDocumentStoreProvider.configure(documentStoreConfiguration,documentStoreConfiguration.getDbConfiguration().getPersistenceEntryManager()); dbDocumentStoreProvider.init(); documentStoreProvider = dbDocumentStoreProvider; diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java index 37fcd840..5b631ce3 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java @@ -14,64 +14,7 @@ public class DBDocumentStoreConfiguration implements Serializable { private static final long serialVersionUID = 3380170170265842538L; - private String server; // http://localhost:8080 - private String useSSL; - private int connectionTimeout; private PersistenceEntryManager persistenceEntryManager = null; - private String maxconnections; - - private String userId; - private String password; - //private String decryptedPassword; - - - public int getConnectionTimeout() { - return connectionTimeout; - } - - public void setConnectionTimeout(int connectionTimeout) { - this.connectionTimeout = connectionTimeout; - } - - public String getUserId() { - return userId; - } - - public void setUserId(String userId) { - this.userId = userId; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getServer() { - return server; - } - - public void setServer(String server) { - this.server = server; - } - - public String getUseSSL() { - return useSSL; - } - - public void setUseSSL(String useSSL) { - this.useSSL = useSSL; - } - - public String getMaxconnections() { - return maxconnections; - } - - public void setMaxconnections(String maxconnections) { - this.maxconnections = maxconnections; - } public PersistenceEntryManager getPersistenceEntryManager() { return persistenceEntryManager; @@ -83,8 +26,7 @@ public void setPersistenceEntryManager(PersistenceEntryManager persistenceEntryM @Override public String toString() { - return "DBDocumentStoreConfiguration [serverUrl=" + server + ", connectionTimeout=" - + connectionTimeout + ", userId=" + userId + "]"; + return "DBDocumentStoreConfiguration [persistenceEntryManager=" + persistenceEntryManager + "]"; } } diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index 29894983..35cce910 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -59,10 +59,10 @@ public void init() { this.dbDocumentStoreConfiguration = documentStoreConfiguration.getDbConfiguration(); } - public void configure(DocumentStoreConfiguration documentStoreConfiguration) { + public void configure(DocumentStoreConfiguration documentStoreConfiguration,PersistenceEntryManager persistenceManager) { this.log = LoggerFactory.getLogger(DBDocumentStoreProvider.class); this.documentStoreConfiguration = documentStoreConfiguration; - this.persistenceEntryManager = dbDocumentStoreConfiguration.getPersistenceEntryManager(); + this.persistenceEntryManager = persistenceManager; } @@ -160,7 +160,6 @@ public String readDocument(String name, Charset charset) { } } catch (Exception e) { log.error("Failed to read document as stream from file '{}'", name, e); - e.printStackTrace(); } return null; } @@ -197,7 +196,6 @@ public boolean renameDocument(String currentDisplayName, String destinationDispl } } catch (Exception e) { log.error("Failed to rename to destination file '{}'", destinationDisplayName); - e.printStackTrace(); } return true; } @@ -221,7 +219,6 @@ public boolean removeDocument(String inum) { return false; } catch (Exception e) { log.error("Failed to remove document file '{}'", inum, e); - e.printStackTrace(); } return false; } diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/service/DBDocumentService.java b/core-document-store/src/main/java/org/gluu/service/document/store/service/DBDocumentService.java index 821b3fad..05da3026 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/service/DBDocumentService.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/service/DBDocumentService.java @@ -87,8 +87,7 @@ public OxDocument getOxDocumentByInum(String inum) throws Exception { try { result = persistenceEntryManager.find(OxDocument.class, getDnForOxDocument(inum)); } catch (Exception e) { - System.out.print(e); - //logger.debug("", e); + logger.error("Not able to find the oxDocument. Here is the exception message ", e); } return result; } @@ -158,7 +157,7 @@ public List searchOxDocuments(String pattern, int sizeLimit) { result = persistenceEntryManager.findEntries(getDnForOxDocument(null), OxDocument.class, searchFilter, sizeLimit); return result; } catch (Exception e) { - e.printStackTrace(); + logger.error("Failed to find OxDocument : ", e); } return result; } @@ -178,7 +177,7 @@ public List getAllOxDocumentsList(int size) { List oxDocuments = persistenceEntryManager.findEntries(getDnForOxDocument(null), OxDocument.class, null, size); return oxDocuments; } catch (Exception e) { - logger.error("", e); + logger.error("Failed to find OxDocument: ", e); return new ArrayList<>(); } } From e33f6fcf93f539ef1f1f42703137218659210078 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Tue, 31 May 2022 23:54:48 +0530 Subject: [PATCH 286/362] fix added orm core dependency to support all db orms --- core-document-store/pom.xml | 12 ++++++++++-- .../store/provider/DBDocumentStoreProvider.java | 2 -- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index ea818c56..42175940 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -50,10 +50,18 @@ org.gluu - gluu-orm-ldap + gluu-orm-core + ${project.version} + + + org.gluu + gluu-orm-core + ${project.version} + + org.gluu + gluu-orm-annotation ${project.version} - javax.enterprise diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index 35cce910..3e720d82 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -13,8 +13,6 @@ import javax.inject.Inject; import org.apache.commons.io.IOUtils; import org.gluu.persist.PersistenceEntryManager; -import org.gluu.persist.ldap.impl.LdapEntryManager; -import org.gluu.persist.ldap.impl.LdapEntryManagerFactory; import org.gluu.service.document.store.conf.DBDocumentStoreConfiguration; import org.gluu.service.document.store.conf.DocumentStoreConfiguration; import org.gluu.service.document.store.conf.DocumentStoreType; From 512f5b038e1eb873532ec3ae9ccc695f9b66e0b7 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Wed, 1 Jun 2022 00:14:29 +0530 Subject: [PATCH 287/362] fix : remove duplicate dependencies --- core-document-store/pom.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index 42175940..2c1e9c11 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -54,10 +54,6 @@ ${project.version} - org.gluu - gluu-orm-core - ${project.version} - org.gluu gluu-orm-annotation ${project.version} From 308e93baf94612c1aaa7f9dcf0b8b2ac713799a9 Mon Sep 17 00:00:00 2001 From: yurem Date: Thu, 2 Jun 2022 14:00:51 +0300 Subject: [PATCH 288/362] feat: remove peristenceEntryManager from DB configuration --- .../StandaloneDocumentStoreProviderFactory.java | 11 ++++++++--- .../store/conf/DBDocumentStoreConfiguration.java | 16 ++-------------- .../store/provider/DBDocumentStoreProvider.java | 3 +-- 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java index d2a214d5..c1bb573b 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/StandaloneDocumentStoreProviderFactory.java @@ -1,5 +1,6 @@ package org.gluu.service.document.store; +import org.gluu.persist.PersistenceEntryManager; import org.gluu.service.document.store.conf.DocumentStoreConfiguration; import org.gluu.service.document.store.conf.DocumentStoreType; import org.gluu.service.document.store.provider.DBDocumentStoreProvider; @@ -19,13 +20,17 @@ public class StandaloneDocumentStoreProviderFactory { private static final Logger LOG = LoggerFactory.getLogger(StandaloneDocumentStoreProviderFactory.class); private StringEncrypter stringEncrypter; + private PersistenceEntryManager persistenceEntryManager; + + public StandaloneDocumentStoreProviderFactory() { + } public StandaloneDocumentStoreProviderFactory(StringEncrypter stringEncrypter) { this.stringEncrypter = stringEncrypter; } - public StandaloneDocumentStoreProviderFactory() { - super(); + public StandaloneDocumentStoreProviderFactory(PersistenceEntryManager persistenceEntryManager) { + this.persistenceEntryManager = persistenceEntryManager; } public DocumentStoreProvider getDocumentStoreProvider(DocumentStoreConfiguration documentStoreConfiguration) { @@ -70,7 +75,7 @@ public DocumentStoreProvider getDocumentStoreProvider(DocumentStoreConfiguration break; case DB: DBDocumentStoreProvider dbDocumentStoreProvider = new DBDocumentStoreProvider(); - dbDocumentStoreProvider.configure(documentStoreConfiguration,documentStoreConfiguration.getDbConfiguration().getPersistenceEntryManager()); + dbDocumentStoreProvider.configure(documentStoreConfiguration, persistenceEntryManager); dbDocumentStoreProvider.init(); documentStoreProvider = dbDocumentStoreProvider; diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java index 5b631ce3..1dbd11b0 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/conf/DBDocumentStoreConfiguration.java @@ -1,10 +1,8 @@ package org.gluu.service.document.store.conf; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - import java.io.Serializable; -import org.gluu.persist.PersistenceEntryManager; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; /** * @author shekhar L. on 27/04/2022 @@ -14,19 +12,9 @@ public class DBDocumentStoreConfiguration implements Serializable { private static final long serialVersionUID = 3380170170265842538L; - private PersistenceEntryManager persistenceEntryManager = null; - - public PersistenceEntryManager getPersistenceEntryManager() { - return persistenceEntryManager; - } - - public void setPersistenceEntryManager(PersistenceEntryManager persistenceEntryManager) { - this.persistenceEntryManager = persistenceEntryManager; - } - @Override public String toString() { - return "DBDocumentStoreConfiguration [persistenceEntryManager=" + persistenceEntryManager + "]"; + return "DBDocumentStoreConfiguration []"; } } diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index 3e720d82..21ac516a 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -41,7 +41,6 @@ public class DBDocumentStoreProvider extends DocumentStoreProvider Date: Sat, 4 Jun 2022 00:23:46 +0530 Subject: [PATCH 289/362] Fix : added instance initiation for standalone execution --- .../document/store/provider/DBDocumentStoreProvider.java | 2 ++ .../gluu/service/document/store/service/DBDocumentService.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index 21ac516a..3247f680 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -60,6 +60,8 @@ public void configure(DocumentStoreConfiguration documentStoreConfiguration, Per this.log = LoggerFactory.getLogger(DBDocumentStoreProvider.class); this.documentStoreConfiguration = documentStoreConfiguration; this.persistenceEntryManager = persistenceManager; + if(documentService == null) + this.documentService = new DBDocumentService(persistenceEntryManager); } diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/service/DBDocumentService.java b/core-document-store/src/main/java/org/gluu/service/document/store/service/DBDocumentService.java index 05da3026..5aaaaa90 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/service/DBDocumentService.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/service/DBDocumentService.java @@ -22,6 +22,7 @@ import org.gluu.search.filter.Filter; import org.gluu.util.StringHelper; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Provides operations with OxDocument @@ -47,6 +48,7 @@ public DBDocumentService() { public DBDocumentService(PersistenceEntryManager persistenceEntryManager) { super(); this.persistenceEntryManager = persistenceEntryManager; + this.logger = LoggerFactory.getLogger(DBDocumentService.class); } public static final String inum = "inum"; From ed6e9d7e0c6ddf6a23cdf2b64c2b7a1a8a912e76 Mon Sep 17 00:00:00 2001 From: yurem Date: Wed, 15 Jun 2022 00:03:06 +0300 Subject: [PATCH 290/362] feat: update to conform Couchbase SDK 3.x #24 --- .../model/custom/script/type/persistence/PersistenceType.java | 2 +- .../service/external/ExternalPersistenceExtensionService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java index 692c2239..32cbbb58 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/persistence/PersistenceType.java @@ -10,7 +10,7 @@ import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.type.BaseExternalType; -import org.gluu.persist.exception.extension.PersistenceExtension; +import org.gluu.persist.extension.PersistenceExtension; /** * Base interface for persistence script diff --git a/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java index 5f664f4f..184f0140 100644 --- a/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java +++ b/oxService/src/main/java/org/gluu/service/external/ExternalPersistenceExtensionService.java @@ -20,7 +20,7 @@ import org.gluu.model.custom.script.conf.CustomScriptConfiguration; import org.gluu.model.custom.script.type.persistence.PersistenceType; import org.gluu.persist.PersistenceEntryManager; -import org.gluu.persist.exception.extension.PersistenceExtension; +import org.gluu.persist.extension.PersistenceExtension; import org.gluu.service.custom.script.ExternalScriptService; import org.gluu.service.external.context.PersistenceExternalContext; From 370ebdc5dc33e9bee3c77ad109f9ee6df11ee336 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Tue, 21 Jun 2022 18:42:34 +0530 Subject: [PATCH 291/362] feat: add method for saml api --- .../saml/metadata/SAMLMetadataParser.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java index defa8f2a..6b05fc6a 100644 --- a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java +++ b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java @@ -5,6 +5,7 @@ */ package org.gluu.saml.metadata; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -18,6 +19,7 @@ import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.gluu.service.document.store.service.DocumentStoreService; import org.gluu.util.io.HTTPFileDownloader; @@ -55,6 +57,21 @@ public List getEntityIdFromMetadataFile(String metadataFile) { return null; } } + + public List getEntityIdFromMetadataFile(File metadataFile) { + if (!metadataFile.isFile()) { + return null; + } + EntityIDHandler handler = parseMetadata(metadataFile); + + List entityIds = handler.getEntityIDs(); + + if (entityIds == null || entityIds.isEmpty()) { + log.error("Failed to find entityId in metadata file: " + metadataFile.getAbsolutePath()); + } + + return entityIds; + } public List getSpEntityIdFromMetadataFile(String metadataFile) { EntityIDHandler handler = parseMetadata(metadataFile); @@ -90,6 +107,25 @@ public EntityIDHandler parseMetadata(String metadataFile) { IOUtils.closeQuietly(is); } } + + public EntityIDHandler parseMetadata(File metadataFile) { + if (!metadataFile.exists()) { + log.error("Failed to get entityId from metadata file: " + metadataFile.getAbsolutePath()); + return null; + } + + InputStream is = null; + try { + is = FileUtils.openInputStream(metadataFile); + + return parseMetadata(is); + } catch (IOException ex) { + log.error("Failed to read SAML metadata file: " + metadataFile.getAbsolutePath(), ex); + return null; + } finally { + IOUtils.closeQuietly(is); + } + } public EntityIDHandler parseMetadata(InputStream is) { InputStreamReader isr = null; From 0b173afb5e49ad4a47406422c03ce719f5f9290e Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Fri, 8 Jul 2022 23:15:00 +0300 Subject: [PATCH 292/362] fix: allow to use in casa --- .../provider/DBDocumentStoreProvider.java | 18 ++------ .../DocumentStoreProviderFactory.java | 4 ++ .../store/service/DBDocumentService.java | 46 ++++++++----------- 3 files changed, 26 insertions(+), 42 deletions(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index 3247f680..287ce5c1 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -5,12 +5,11 @@ import java.io.InputStream; import java.nio.charset.Charset; import java.util.Base64; -import java.util.Date; -import java.util.Properties; import javax.annotation.PostConstruct; import javax.enterprise.context.ApplicationScoped; import javax.inject.Inject; + import org.apache.commons.io.IOUtils; import org.gluu.persist.PersistenceEntryManager; import org.gluu.service.document.store.conf.DBDocumentStoreConfiguration; @@ -19,7 +18,6 @@ import org.gluu.service.document.store.service.DBDocumentService; import org.gluu.service.document.store.service.OxDocument; import org.gluu.util.StringHelper; -import org.gluu.util.security.StringEncrypter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,7 +29,6 @@ public class DBDocumentStoreProvider extends DocumentStoreProvider persistenceEntryManagerInstance; + + private PersistenceEntryManager persistenceEntryManager; + + public DBDocumentService() {} + public DBDocumentService(PersistenceEntryManager persistenceEntryManager) { - super(); this.persistenceEntryManager = persistenceEntryManager; - this.logger = LoggerFactory.getLogger(DBDocumentService.class); } public static final String inum = "inum"; public static final String displayName = "displayName"; public static final String description = "description"; + @PostConstruct + public void init() { + if (persistenceEntryManagerInstance.isResolvable()) { + this.persistenceEntryManager = persistenceEntryManagerInstance.get(); + } else { + this.persistenceEntryManager = null; + } + } + /** * Add new OxDocument entry * @@ -210,20 +216,4 @@ public OxDocument getOxDocumentByDisplayName(String DisplayName) throws Exceptio } return null; } - - public PersistenceEntryManager getPersistenceEntryManager() { - return persistenceEntryManager; - } - - public void setPersistenceEntryManager(PersistenceEntryManager persistenceEntryManager) { - this.persistenceEntryManager = persistenceEntryManager; - } - - /*private List filter(List oxDocument) { - if (oxDocument != null) { - return oxDocument.stream().filter(e -> !e.isUmaType()).collect(Collectors.toList()); - } else { - return new ArrayList<>(); - } - }*/ } From 424e509f5b903288ff1519da768bda3b6cd0bdbe Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Thu, 14 Jul 2022 21:03:56 +0530 Subject: [PATCH 293/362] chore: remove caCertsLocation, caCertsPassphrase properties --- .../gluu/config/oxtrust/AppConfiguration.java | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index 8faca14f..f6ee0a0f 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -74,8 +74,6 @@ public class AppConfiguration implements Configuration, Serializable { private String shibboleth3FederationRootDir; - private String caCertsLocation; - private String caCertsPassphrase; private String tempCertDir; private String certDir; @@ -409,22 +407,6 @@ public void setShibboleth3FederationRootDir(String shibboleth3FederationRootDir) this.shibboleth3FederationRootDir = shibboleth3FederationRootDir; } - public String getCaCertsLocation() { - return caCertsLocation; - } - - public void setCaCertsLocation(String caCertsLocation) { - this.caCertsLocation = caCertsLocation; - } - - public String getCaCertsPassphrase() { - return caCertsPassphrase; - } - - public void setCaCertsPassphrase(String caCertsPassphrase) { - this.caCertsPassphrase = caCertsPassphrase; - } - public String getTempCertDir() { return tempCertDir; } From cc32bc6321ef8667d30c1f26e9f9af31ac358dcd Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Fri, 15 Jul 2022 00:13:01 +0530 Subject: [PATCH 294/362] fix: fix for display name --- .../document/store/provider/DBDocumentStoreProvider.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index 287ce5c1..b81fa456 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -92,7 +92,7 @@ public boolean saveDocument(String name, String documentContent, Charset charset oxDocument.setInum(documentService.generateInumForNewOxDocument()); String dn = "inum="+ oxDocument.getInum() +",ou=document,o=gluu"; oxDocument.setDn(dn); - oxDocument.setDescription("Testing the document saving"); + oxDocument.setDescription(name); oxDocument.setOxEnabled("true"); oxDocument.setOxModuleProperty("oxtrusr server"); documentService.addOxDocument(oxDocument); @@ -121,8 +121,7 @@ public boolean saveDocumentStream(String name, InputStream documentStream) { oxDocument.setInum(inum); String dn = "inum="+ oxDocument.getInum() +",ou=document,o=gluu"; oxDocument.setDn(dn); - oxDocument.setDisplayName("Test"); - oxDocument.setDescription("Testing the document saving"); + oxDocument.setDescription(name); oxDocument.setOxEnabled("true"); oxDocument.setOxModuleProperty("oxtrusr server"); documentService.addOxDocument(oxDocument); From 56624cbb6b12513a69e6f6daca6b6687403bb76a Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Mon, 18 Jul 2022 21:15:59 +0300 Subject: [PATCH 295/362] fix: fix empty string validation method --- oxUtil/src/main/java/org/gluu/util/StringHelper.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/oxUtil/src/main/java/org/gluu/util/StringHelper.java b/oxUtil/src/main/java/org/gluu/util/StringHelper.java index c61546da..2ad36560 100644 --- a/oxUtil/src/main/java/org/gluu/util/StringHelper.java +++ b/oxUtil/src/main/java/org/gluu/util/StringHelper.java @@ -510,10 +510,18 @@ public static String addQuote(final String string) { } public static boolean isEmptyString(Object string) { + if (string == null) { + return false; + } + return !(string instanceof String) || isEmpty((String) string); } public static boolean isNotEmptyString(Object string) { + if (string == null) { + return false; + } + return !(string instanceof String) || isNotEmpty((String) string); } From 177de59477377d897bb7a53d1a6aeeab09911d94 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Tue, 19 Jul 2022 17:31:49 +0300 Subject: [PATCH 296/362] fix: remove unused uer property --- .../java/org/gluu/service/cache/SampleSessionId.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/oxService/src/test/java/org/gluu/service/cache/SampleSessionId.java b/oxService/src/test/java/org/gluu/service/cache/SampleSessionId.java index 4cece445..86863f6f 100644 --- a/oxService/src/test/java/org/gluu/service/cache/SampleSessionId.java +++ b/oxService/src/test/java/org/gluu/service/cache/SampleSessionId.java @@ -1,6 +1,5 @@ package org.gluu.service.cache; -import com.couchbase.client.java.cluster.User; import com.google.common.collect.Maps; import org.gluu.persist.annotation.AttributeName; import org.gluu.persist.annotation.DN; @@ -64,9 +63,6 @@ public class SampleSessionId implements Serializable { @Transient private transient boolean persisted; - @Transient - private User user; - public SampleSessionId() { } @@ -149,14 +145,6 @@ public void setUserDn(String p_userDn) { userDn = p_userDn != null ? p_userDn : ""; } - public User getUser() { - return user; - } - - public void setUser(User user) { - this.user = user; - } - public Date getAuthenticationTime() { return authenticationTime; } From c35e2127be35a533efc48e8acf4d3f06b72b63ac Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Tue, 19 Jul 2022 18:13:09 +0300 Subject: [PATCH 297/362] chore: try signuture --- checkstyle.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/checkstyle.xml b/checkstyle.xml index 6fbf532c..9281e722 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -187,4 +187,4 @@ - \ No newline at end of file + From 5662c085ec12eba958c8045edee7aa22aaadd4c0 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Mon, 25 Jul 2022 16:47:27 +0300 Subject: [PATCH 298/362] chore: sync with jans --- oxUtil/src/main/java/org/gluu/util/StringHelper.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/oxUtil/src/main/java/org/gluu/util/StringHelper.java b/oxUtil/src/main/java/org/gluu/util/StringHelper.java index 2ad36560..85eeb7ec 100644 --- a/oxUtil/src/main/java/org/gluu/util/StringHelper.java +++ b/oxUtil/src/main/java/org/gluu/util/StringHelper.java @@ -510,10 +510,6 @@ public static String addQuote(final String string) { } public static boolean isEmptyString(Object string) { - if (string == null) { - return false; - } - return !(string instanceof String) || isEmpty((String) string); } From 16902a4e5cc2f3c4b3dd310ac8f125a26d3e3a9b Mon Sep 17 00:00:00 2001 From: jgomer2001 Date: Mon, 25 Jul 2022 15:13:18 -0500 Subject: [PATCH 299/362] feat: update bean https://github.com/GluuFederation/scim/issues/54 --- .../gluu/config/oxtrust/ScimProperties.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/ScimProperties.java b/oxService/src/main/java/org/gluu/config/oxtrust/ScimProperties.java index 8e700fc1..5f8957d1 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/ScimProperties.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/ScimProperties.java @@ -4,7 +4,6 @@ import java.io.Serializable; - @JsonIgnoreProperties(ignoreUnknown = true) public class ScimProperties implements Serializable { @@ -14,6 +13,8 @@ public class ScimProperties implements Serializable { private static final long serialVersionUID = -5154249316054593386L; private int maxCount; + private int bulkMaxOperations; + private long bulkMaxPayloadSize; private ScimMode protectionMode; @@ -27,6 +28,22 @@ public void setMaxCount(int maxCount) { this.maxCount = maxCount; } + public int getBulkMaxOperations() { + return bulkMaxOperations; + } + + public void setBulkMaxOperations(int bulkMaxOperations) { + this.bulkMaxOperations = bulkMaxOperations; + } + + public long getBulkMaxPayloadSize() { + return bulkMaxPayloadSize; + } + + public void setBulkMaxPayloadSize(long bulkMaxPayloadSize) { + this.bulkMaxPayloadSize = bulkMaxPayloadSize; + } + public ScimMode getProtectionMode() { return protectionMode; } From 6e11514f2d2ef9a38b567ba6cab46d365e31f954 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Wed, 31 Aug 2022 00:41:53 +0530 Subject: [PATCH 300/362] feat: added locale in DB AppConfiguration oxtrust 2226 --- .../java/org/gluu/config/oxtrust/AppConfiguration.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index f6ee0a0f..2792367b 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -39,6 +39,8 @@ public class AppConfiguration implements Configuration, Serializable { private String personCustomObjectClass; private String[] personObjectClassDisplayNames; + private String[] oxTrustAdminUIlocalesSupported; + private String[] contactObjectClassTypes; private String[] contactObjectClassDisplayNames; @@ -945,4 +947,12 @@ public boolean isPassIdTokenHintToLogoutRedirectUri() { public void setPassIdTokenHintToLogoutRedirectUri(boolean passIdTokenHintToLogoutRedirectUri) { this.passIdTokenHintToLogoutRedirectUri = passIdTokenHintToLogoutRedirectUri; } + + public String[] getOxTrustAdminUIlocalesSupported() { + return oxTrustAdminUIlocalesSupported; + } + + public void setOxTrustAdminUIlocalesSupported(String[] oxTrustAdminUIlocalesSupported) { + this.oxTrustAdminUIlocalesSupported = oxTrustAdminUIlocalesSupported; + } } From 26eee7be14f4e280157065b62a5c010185ff0e68 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Wed, 31 Aug 2022 22:58:48 +0530 Subject: [PATCH 301/362] feat: adminUiLocaleSupported property rename and restructure --- .../gluu/config/oxtrust/AppConfiguration.java | 12 ++++---- .../java/org/gluu/model/LocaleSupported.java | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 6 deletions(-) create mode 100644 oxService/src/main/java/org/gluu/model/LocaleSupported.java diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index 2792367b..96e7a4bb 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -8,8 +8,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; - import javax.enterprise.inject.Vetoed; +import org.gluu.model.LocaleSupported; import java.io.Serializable; import java.util.Arrays; import java.util.List; @@ -39,7 +39,7 @@ public class AppConfiguration implements Configuration, Serializable { private String personCustomObjectClass; private String[] personObjectClassDisplayNames; - private String[] oxTrustAdminUIlocalesSupported; + private List adminUiLocaleSupported; private String[] contactObjectClassTypes; @@ -948,11 +948,11 @@ public void setPassIdTokenHintToLogoutRedirectUri(boolean passIdTokenHintToLogou this.passIdTokenHintToLogoutRedirectUri = passIdTokenHintToLogoutRedirectUri; } - public String[] getOxTrustAdminUIlocalesSupported() { - return oxTrustAdminUIlocalesSupported; + public List getAdminUiLocaleSupported() { + return adminUiLocaleSupported; } - public void setOxTrustAdminUIlocalesSupported(String[] oxTrustAdminUIlocalesSupported) { - this.oxTrustAdminUIlocalesSupported = oxTrustAdminUIlocalesSupported; + public void setAdminUiLocaleSupported(List adminUiLocaleSupported) { + this.adminUiLocaleSupported = adminUiLocaleSupported; } } diff --git a/oxService/src/main/java/org/gluu/model/LocaleSupported.java b/oxService/src/main/java/org/gluu/model/LocaleSupported.java new file mode 100644 index 00000000..41bc9e29 --- /dev/null +++ b/oxService/src/main/java/org/gluu/model/LocaleSupported.java @@ -0,0 +1,30 @@ +package org.gluu.model; + +public class LocaleSupported { + + public LocaleSupported() { + super(); + } + private String locale; + private String displayName; + + public LocaleSupported(String locale, String displayName) { + super(); + this.locale = locale; + this.displayName = displayName; + } + + public String getLocale() { + return locale; + } + public void setLocale(String locale) { + this.locale = locale; + } + public String getDisplayName() { + return displayName; + } + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + +} From 2770f1c2741e60a0734654e22e0f667ecb567ef7 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Thu, 1 Sep 2022 20:43:40 +0530 Subject: [PATCH 302/362] feat: added few corrections oxtrust 2226 --- .../src/main/java/org/gluu/model/LocaleSupported.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/oxService/src/main/java/org/gluu/model/LocaleSupported.java b/oxService/src/main/java/org/gluu/model/LocaleSupported.java index 41bc9e29..c3a009f5 100644 --- a/oxService/src/main/java/org/gluu/model/LocaleSupported.java +++ b/oxService/src/main/java/org/gluu/model/LocaleSupported.java @@ -1,15 +1,14 @@ package org.gluu.model; -public class LocaleSupported { +public class LocaleSupported { - public LocaleSupported() { - super(); - } private String locale; private String displayName; + public LocaleSupported() { + } + public LocaleSupported(String locale, String displayName) { - super(); this.locale = locale; this.displayName = displayName; } From 1ed3753ba12ee8bac97ccd4c833556770232a4d8 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Thu, 29 Sep 2022 01:37:37 +0530 Subject: [PATCH 303/362] feat : added module as multivalue #244 --- .../store/provider/DBDocumentStoreProvider.java | 12 ++++++------ .../document/store/provider/DocumentStore.java | 5 +++-- .../store/provider/JcaDocumentStoreProvider.java | 5 +++-- .../store/provider/LocalDocumentStoreProvider.java | 5 +++-- .../store/provider/WebDavDocumentStoreProvider.java | 5 +++-- .../store/service/BaseDocumentStoreService.java | 9 +++++---- .../service/document/store/service/OxDocument.java | 8 +++++--- .../store/manual/JcaDocumentStoreManualTest.java | 5 +++-- .../store/manual/WebDavDocumentStoreManualTest.java | 5 +++-- 9 files changed, 34 insertions(+), 25 deletions(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index b81fa456..363fec04 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -4,7 +4,9 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.util.ArrayList; import java.util.Base64; +import java.util.List; import javax.annotation.PostConstruct; import javax.enterprise.context.ApplicationScoped; @@ -82,7 +84,7 @@ public boolean hasDocument(String DisplayName) { } @Override - public boolean saveDocument(String name, String documentContent, Charset charset) { + public boolean saveDocument(String name, String documentContent, Charset charset, List moduleList) { log.debug("Save document: '{}'", name); OxDocument oxDocument = new OxDocument(); oxDocument.setDocument(documentContent); @@ -94,9 +96,8 @@ public boolean saveDocument(String name, String documentContent, Charset charset oxDocument.setDn(dn); oxDocument.setDescription(name); oxDocument.setOxEnabled("true"); - oxDocument.setOxModuleProperty("oxtrusr server"); + oxDocument.setOxModuleProperty(moduleList); documentService.addOxDocument(oxDocument); - //persistenceEntryManager.persist(oxDocument); return true; } finally { } @@ -108,7 +109,7 @@ public boolean saveDocument(String name, String documentContent, Charset charset } @Override - public boolean saveDocumentStream(String name, InputStream documentStream) { + public boolean saveDocumentStream(String name, InputStream documentStream, List moduleList) { //log.debug("Save document from stream: '{}'", name); OxDocument oxDocument = new OxDocument(); @@ -123,9 +124,8 @@ public boolean saveDocumentStream(String name, InputStream documentStream) { oxDocument.setDn(dn); oxDocument.setDescription(name); oxDocument.setOxEnabled("true"); - oxDocument.setOxModuleProperty("oxtrusr server"); + oxDocument.setOxModuleProperty(moduleList); documentService.addOxDocument(oxDocument); - //persistenceEntryManager.persist(oxDocument); return true; } catch (IOException e) { log.error("Failed to write document from stream to file '{}'", name, e); diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStore.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStore.java index 259146e1..72cc51dd 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStore.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DocumentStore.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.util.List; import org.gluu.service.document.store.conf.DocumentStoreType; @@ -19,12 +20,12 @@ public interface DocumentStore { /** * Save document into store */ - boolean saveDocument(String path, String documentContent, Charset charset); + boolean saveDocument(String path, String documentContent, Charset charset, List moduleList); /** * Save document stream into store */ - boolean saveDocumentStream(String path, InputStream documentStream); + boolean saveDocumentStream(String path, InputStream documentStream, List moduleList); /** * Load document from store diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java index c9ad1345..30af4248 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/JcaDocumentStoreProvider.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -139,7 +140,7 @@ public boolean hasDocument(String path) { } @Override - public boolean saveDocument(String path, String documentContent, Charset charset) { + public boolean saveDocument(String path, String documentContent, Charset charset, List moduleList) { log.debug("Save document: '{}'", path); String normalizedPath = getNormalizedPath(path); @@ -163,7 +164,7 @@ public boolean saveDocument(String path, String documentContent, Charset charset } @Override - public boolean saveDocumentStream(String path, InputStream documentStream) { + public boolean saveDocumentStream(String path, InputStream documentStream, List moduleList) { log.debug("Save document from stream: '{}'", path); String normalizedPath = getNormalizedPath(path); diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java index c51f1e0b..0ee4e4b4 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/LocalDocumentStoreProvider.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.util.List; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -93,7 +94,7 @@ public boolean hasDocument(String path) { } @Override - public boolean saveDocument(String path, String documentContent, Charset charset) { + public boolean saveDocument(String path, String documentContent, Charset charset, List moduleList) { log.debug("Save document: '{}'", path); File file = buildFilePath(path); @@ -114,7 +115,7 @@ public boolean saveDocument(String path, String documentContent, Charset charset } @Override - public boolean saveDocumentStream(String path, InputStream documentStream) { + public boolean saveDocumentStream(String path, InputStream documentStream, List moduleList) { log.debug("Save document from stream: '{}'", path); File file = buildFilePath(path); diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java index a0e6a993..c09c079a 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/WebDavDocumentStoreProvider.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.util.List; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -139,7 +140,7 @@ public boolean hasDocument(String path) { } @Override - public boolean saveDocument(String path, String documentContent, Charset charset) { + public boolean saveDocument(String path, String documentContent, Charset charset, List moduleList) { if (true) { log.debug("Save document: '{}'", path); @@ -178,7 +179,7 @@ public boolean saveDocument(String path, String documentContent, Charset charset } @Override - public boolean saveDocumentStream(String path, InputStream documentStream) { + public boolean saveDocumentStream(String path, InputStream documentStream, List moduleList) { log.debug("Save document from stream: '{}'", path); String normalizedPath = getNormalizedPath(path); try { diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/service/BaseDocumentStoreService.java b/core-document-store/src/main/java/org/gluu/service/document/store/service/BaseDocumentStoreService.java index 3a36ee5d..def1d0b5 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/service/BaseDocumentStoreService.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/service/BaseDocumentStoreService.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.util.List; import javax.inject.Inject; @@ -32,17 +33,17 @@ public boolean hasDocument(String path) { } @Override - public boolean saveDocument(String path, String documentContent, Charset charset) { + public boolean saveDocument(String path, String documentContent, Charset charset, List moduleList) { DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); - return documentStoreProvider.saveDocument(path, documentContent, charset); + return documentStoreProvider.saveDocument(path, documentContent, charset, moduleList); } @Override - public boolean saveDocumentStream(String path, InputStream documentStream) { + public boolean saveDocumentStream(String path, InputStream documentStream, List moduleList) { DocumentStoreProvider documentStoreProvider = getDocumentStoreProvider(); - return documentStoreProvider.saveDocumentStream(path, documentStream); + return documentStoreProvider.saveDocumentStream(path, documentStream, moduleList); } @Override diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java b/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java index bee87445..0f8ba187 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java @@ -8,6 +8,8 @@ import java.io.Serializable; import java.util.Date; +import java.util.List; + import org.gluu.persist.model.base.Entry; import org.gluu.persist.annotation.AttributeName; import org.gluu.persist.annotation.DataEntry; @@ -47,7 +49,7 @@ public class OxDocument extends Entry implements Serializable { private Date creationDate; @AttributeName - private String oxModuleProperty; + private List oxModuleProperty; @AttributeName private String oxLevel; @@ -101,11 +103,11 @@ public void setDocument(String document) { this.document = document; } - public String getOxModuleProperty() { + public List getOxModuleProperty() { return oxModuleProperty; } - public void setOxModuleProperty(String oxModuleProperty) { + public void setOxModuleProperty(List oxModuleProperty) { this.oxModuleProperty = oxModuleProperty; } diff --git a/core-document-store/src/test/java/org/gluu/service/document/store/manual/JcaDocumentStoreManualTest.java b/core-document-store/src/test/java/org/gluu/service/document/store/manual/JcaDocumentStoreManualTest.java index 6758d81d..61d1a84a 100644 --- a/core-document-store/src/test/java/org/gluu/service/document/store/manual/JcaDocumentStoreManualTest.java +++ b/core-document-store/src/test/java/org/gluu/service/document/store/manual/JcaDocumentStoreManualTest.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.List; import javax.jcr.RepositoryException; @@ -60,13 +61,13 @@ public static void main(String[] args) throws RepositoryException, IOException, System.out.println(dsp.hasDocument("/test2/test3/test3.jmx")); System.out.print("Write document: " + "/test2/test3/test4/test5.jmx: "); - System.out.println(dsp.saveDocumentStream("/test2/test3/test4/test5.jmx", new ByteArrayInputStream(doc2))); + System.out.println(dsp.saveDocumentStream("/test2/test3/test4/test5.jmx", new ByteArrayInputStream(doc2), List.of("oxtrust-server","Shibboleth"))); System.out.print("Has document: " + "/test2/test3/test4/test5.jmx: "); System.out.println(dsp.hasDocument("/test2/test3/test4/test5.jmx")); System.out.print("Write document: " + "/test2/test3/test4/test5.jmx: "); - System.out.println(dsp.saveDocument("/test2/test3/test4/test5.jmx", doc1, StandardCharsets.UTF_8)); + System.out.println(dsp.saveDocument("/test2/test3/test4/test5.jmx", doc1, StandardCharsets.UTF_8, List.of("oxtrust-server","Shibboleth"))); System.out.print("Has document: " + "/test2/test3/test4/test5.jmx: "); System.out.println(dsp.hasDocument("/test2/test3/test4/test5.jmx")); diff --git a/core-document-store/src/test/java/org/gluu/service/document/store/manual/WebDavDocumentStoreManualTest.java b/core-document-store/src/test/java/org/gluu/service/document/store/manual/WebDavDocumentStoreManualTest.java index eaf09b59..7692c60b 100644 --- a/core-document-store/src/test/java/org/gluu/service/document/store/manual/WebDavDocumentStoreManualTest.java +++ b/core-document-store/src/test/java/org/gluu/service/document/store/manual/WebDavDocumentStoreManualTest.java @@ -4,6 +4,7 @@ import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.List; import javax.jcr.RepositoryException; @@ -60,13 +61,13 @@ public static void main(String[] args) throws RepositoryException, IOException, System.out.println(dsp.hasDocument("/test2/test3/test3.jmx")); System.out.print("Write document: " + "/test2/test3/test4/test5.jmx: "); - System.out.println(dsp.saveDocumentStream("/test-1.jmx", new ByteArrayInputStream(doc2))); + System.out.println(dsp.saveDocumentStream("/test-1.jmx", new ByteArrayInputStream(doc2), List.of("oxtrust-server","Shibboleth"))); /* System.out.print("Has document: " + "/test2/test3/test4/test5.jmx: "); System.out.println(dsp.hasDocument("/test2/test3/test4/test5.jmx")); */ System.out.print("Write document: " + "/test2/test3/test4/test5.jmx: "); - System.out.println(dsp.saveDocument("/test7.jmx", doc1, StandardCharsets.UTF_8)); + System.out.println(dsp.saveDocument("/test7.jmx", doc1, StandardCharsets.UTF_8, List.of("oxtrust-server","Shibboleth"))); /* System.out.print("Has document: " + "/test2/test3/test4/test5.jmx: "); System.out.println(dsp.hasDocument("/test2/test3/test4/test5.jmx")); From 36f933831a40313d3e8279bfb8d57abdbc11b13c Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Mon, 3 Oct 2022 11:10:37 +0300 Subject: [PATCH 304/362] chore: dump jython location --- .../java/org/gluu/service/PythonService.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/core-script/src/main/java/org/gluu/service/PythonService.java b/core-script/src/main/java/org/gluu/service/PythonService.java index e452455b..340d8558 100644 --- a/core-script/src/main/java/org/gluu/service/PythonService.java +++ b/core-script/src/main/java/org/gluu/service/PythonService.java @@ -67,9 +67,12 @@ public void configure() { public boolean initPythonInterpreter(String pythonModulesDir) { boolean result = false; - if (isInitInterpreter()) { + String pythonHome = getPythonHome(); + log.info("Initializing PythonService with Jython: '{}'", pythonHome); + if (StringHelper.isNotEmpty(pythonHome)) { try { - PythonInterpreter.initialize(getPreProperties(), getPostProperties(pythonModulesDir), null); + + PythonInterpreter.initialize(getPreProperties(), getPostProperties(pythonModulesDir, pythonHome), null); this.pythonInterpreter = new PythonInterpreter(); initPythonInterpreter(this.pythonInterpreter); @@ -80,6 +83,8 @@ public boolean initPythonInterpreter(String pythonModulesDir) { } catch (Exception ex) { log.error("Failed to initialize PythonInterpreter correctly", ex); } + } else { + log.error("Failed to initialize PythonService. Jython location is not defined!"); } this.interpereterReady = result; @@ -120,16 +125,13 @@ private Properties getPreProperties() { return clonedProps; } - private Properties getPostProperties(String pythonModulesDir) { + private Properties getPostProperties(String pythonModulesDir, String pythonHome) { Properties props = getPreProperties(); String catalinaTmpFolder = System.getProperty("java.io.tmpdir") + File.separator + "python" + File.separator + "cachedir"; props.setProperty("python.cachedir", catalinaTmpFolder); - String pythonHome = System.getenv("PYTHON_HOME"); - if (StringHelper.isNotEmpty(pythonHome)) { - props.setProperty("python.home", pythonHome); - } + props.setProperty("python.home", pythonHome); // Register custom python modules if (StringHelper.isNotEmpty(pythonModulesDir)) { @@ -142,15 +144,14 @@ private Properties getPostProperties(String pythonModulesDir) { return props; } - private boolean isInitInterpreter() { - String pythonHome = System.getenv("PYTHON_HOME"); + private String getPythonHome() { + String pythonHome = System.getenv("PYTHON_HOME"); if (StringHelper.isNotEmpty(pythonHome)) { - System.setProperty("python.home", pythonHome); + return pythonHome; } - String pythonHomeProperty = System.getProperty("python.home"); - return StringHelper.isNotEmpty(pythonHomeProperty); - } + return System.getProperty("python.home"); + } public T loadPythonScript(String scriptName, String scriptPythonType, Class scriptJavaType, PyObject[] constructorArgs) throws PythonException { From 6ea7456ce013fb2c0d521f02b0556f944e33aef5 Mon Sep 17 00:00:00 2001 From: SMan Date: Fri, 24 Jun 2022 08:05:23 -0500 Subject: [PATCH 305/362] feat: sending signed emails has been added; feat: updating smtp configuring has been added; --- .../java/org/gluu/service/MailService.java | 24 ++++++- .../org/gluu/model/SmtpConfiguration.java | 49 +++++++++++++-- .../gluu/model/SmtpConnectProtectionType.java | 62 +++++++++++++++++++ 3 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index 2a393072..e2026f40 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -8,6 +8,10 @@ import java.util.Date; import java.util.Properties; +import javax.activation.CommandMap; +import javax.activation.MailcapCommandMap; +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.inject.Named; @@ -22,6 +26,7 @@ import javax.mail.internet.MimeMultipart; import org.gluu.model.SmtpConfiguration; +import org.gluu.model.SmtpConnectProtectionType; import org.gluu.util.StringHelper; import org.slf4j.Logger; @@ -66,6 +71,13 @@ public boolean sendMail(SmtpConfiguration mailSmtpConfiguration, String from, St log.debug("Host name: " + mailSmtpConfiguration.getHost() + ", port: " + mailSmtpConfiguration.getPort() + ", connection time out: " + this.connectionTimeout); + MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap(); + mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html"); + mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml"); + mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain"); + mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed"); + mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822"); + String mailFrom = from; if (StringHelper.isEmpty(mailFrom)) { mailFrom = mailSmtpConfiguration.getFromEmailAddress(); @@ -83,12 +95,20 @@ public boolean sendMail(SmtpConfiguration mailSmtpConfiguration, String from, St props.put("mail.smtp.connectiontimeout", this.connectionTimeout); props.put("mail.smtp.timeout", this.connectionTimeout); props.put("mail.transport.protocol", "smtp"); - props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); - if (mailSmtpConfiguration.isRequiresSsl()) { + SmtpConnectProtectionType smtpConnectProtect = mailSmtpConfiguration.getConnectProtection(); + + if (smtpConnectProtect == SmtpConnectProtectionType.StartTls) { + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); props.put("mail.smtp.starttls.enable", true); + } + else if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + props.put("mail.smtp.ssl.enable", true); } Session session = null; diff --git a/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java b/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java index 0c3ea30c..582b1907 100644 --- a/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java +++ b/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java @@ -27,8 +27,8 @@ public class SmtpConfiguration implements java.io.Serializable { @JsonProperty("port") private int port; - @JsonProperty("requires-ssl") - private boolean requiresSsl; + @JsonProperty("connect-protection") + private SmtpConnectProtectionType connectProtection; @JsonProperty("trust-host") private boolean serverTrust; @@ -52,6 +52,15 @@ public class SmtpConfiguration implements java.io.Serializable { @JsonIgnore private String passwordDecrypted; + @JsonProperty("key-store") + private String keyStore; + + @JsonProperty("key-store-password") + private String keyStorePassword; + + @JsonProperty("key-store-alias") + private String keyStoreAlias; + public String getHost() { return host; } @@ -68,12 +77,12 @@ public void setPort(int port) { this.port = port; } - public boolean isRequiresSsl() { - return requiresSsl; + public SmtpConnectProtectionType getConnectProtection() { + return connectProtection; } - public void setRequiresSsl(boolean requiresSsl) { - this.requiresSsl = requiresSsl; + public void setConnectProtection(SmtpConnectProtectionType connectProtection) { + this.connectProtection = connectProtection; } public boolean isServerTrust() { @@ -137,5 +146,33 @@ public String getPasswordDecrypted() { public void setPasswordDecrypted(String passwordDecrypted) { this.passwordDecrypted = passwordDecrypted; } + + public SmtpConnectProtectionType[] getConnectProtectionList() { + return SmtpConnectProtectionType.values(); + } + + public String getKeyStore() { + return keyStore; + } + + public void setKeyStore(String keyStore) { + this.keyStore = keyStore; + } + + public String getKeyStorePassword() { + return keyStorePassword; + } + + public void setKeyStorePassword(String keyStorePassword) { + this.keyStorePassword = keyStorePassword; + } + + public String getKeyStoreAlias() { + return keyStoreAlias; + } + + public void setKeyStoreAlias(String keyStoreAlias) { + this.keyStoreAlias = keyStoreAlias; + } } diff --git a/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java b/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java new file mode 100644 index 00000000..9ae88bbb --- /dev/null +++ b/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java @@ -0,0 +1,62 @@ +/** + * + */ +package org.gluu.model; + +import java.util.HashMap; +import java.util.Map; + +import org.gluu.persist.annotation.AttributeEnum; + +/** + * @author Sergey Manoylo + * @version + */ +public enum SmtpConnectProtectionType implements AttributeEnum { + + None("None", "NONE"), StartTls("StartTls", "STARTTLS"), SslTls("SslTls", "SSL/TLS"); + + private String value; + private String displayName; + + private static final Map mapByValues = new HashMap(); + + static { + for (SmtpConnectProtectionType enumType : values()) { + mapByValues.put(enumType.getValue(), enumType); + } + } + + /** + * + * @param value + * @param displayName + */ + private SmtpConnectProtectionType(String value, String displayName) { + this.value = value; + this.displayName = displayName; + } + + @Override + public String getValue() { + return value; + } + + public String getDisplayName() { + return displayName; + } + + public static SmtpConnectProtectionType getByValue(String value) { + return mapByValues.get(value); + } + + @Override + public Enum resolveByValue(String value) { + return getByValue(value); + } + + @Override + public String toString() { + return value; + } +} From a1a48b207ad92702d831ec4c0aa864e7247678a0 Mon Sep 17 00:00:00 2001 From: SMan Date: Mon, 4 Jul 2022 03:04:31 -0500 Subject: [PATCH 306/362] feat: definition of signing algorithm has been added; fix: unnecessary downloading of the oxauth-server has been removed; --- oxService/pom.xml | 15 ++ .../java/org/gluu/service/MailService.java | 230 +++++++++++++++++- .../org/gluu/model/SmtpConfiguration.java | 10 + 3 files changed, 248 insertions(+), 7 deletions(-) diff --git a/oxService/pom.xml b/oxService/pom.xml index 3080fc1f..b2d05bd8 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -160,6 +160,21 @@ aalto-xml 1.2.1 + + + + org.bouncycastle + bcprov-jdk15on + + + org.bouncycastle + bcpkix-jdk15on + + + org.bouncycastle + bcmail-jdk15on + provided + \ No newline at end of file diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index e2026f40..0a6fd22f 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -5,13 +5,22 @@ */ package org.gluu.service; +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.Properties; import javax.activation.CommandMap; import javax.activation.MailcapCommandMap; import javax.annotation.PostConstruct; -import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.inject.Named; @@ -25,9 +34,23 @@ import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.cms.AttributeTable; +import org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute; +import org.bouncycastle.asn1.smime.SMIMECapability; +import org.bouncycastle.asn1.smime.SMIMECapabilityVector; +import org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute; +import org.bouncycastle.cert.jcajce.JcaCertStore; +import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder; +import org.bouncycastle.mail.smime.SMIMEException; +import org.bouncycastle.mail.smime.SMIMESignedGenerator; +import org.bouncycastle.mail.smime.SMIMEUtil; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.util.Store; import org.gluu.model.SmtpConfiguration; import org.gluu.model.SmtpConnectProtectionType; import org.gluu.util.StringHelper; +import org.gluu.util.security.SecurityProviderUtility; import org.slf4j.Logger; /** @@ -45,8 +68,30 @@ public class MailService { @Inject private SmtpConfiguration smtpConfiguration; + private KeyStore keyStore; + private long connectionTimeout = 5000; + @PostConstruct + public void init() { + MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap(); + mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html"); + mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml"); + mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain"); + mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed"); + mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822"); + + String keystoreFile = smtpConfiguration.getKeyStore(); + String keystoreSecret = smtpConfiguration.getKeyStorePassword(); + + try(InputStream is = new FileInputStream(keystoreFile)) { + keyStore = KeyStore.getInstance("PKCS12", SecurityProviderUtility.getBCProvider()); + keyStore.load(is, keystoreSecret.toCharArray()); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + public boolean sendMail(String to, String subject, String message) { return sendMail(smtpConfiguration, null, null, to, null, subject, message, null); } @@ -71,12 +116,132 @@ public boolean sendMail(SmtpConfiguration mailSmtpConfiguration, String from, St log.debug("Host name: " + mailSmtpConfiguration.getHost() + ", port: " + mailSmtpConfiguration.getPort() + ", connection time out: " + this.connectionTimeout); - MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap(); - mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html"); - mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml"); - mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain"); - mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed"); - mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822"); + String mailFrom = from; + if (StringHelper.isEmpty(mailFrom)) { + mailFrom = mailSmtpConfiguration.getFromEmailAddress(); + } + + String mailFromName = fromDisplayName; + if (StringHelper.isEmpty(mailFromName)) { + mailFromName = mailSmtpConfiguration.getFromName(); + } + + Properties props = new Properties(); + props.put("mail.smtp.host", mailSmtpConfiguration.getHost()); + props.put("mail.smtp.port", mailSmtpConfiguration.getPort()); + props.put("mail.from", mailFrom); + props.put("mail.smtp.connectiontimeout", this.connectionTimeout); + props.put("mail.smtp.timeout", this.connectionTimeout); + props.put("mail.transport.protocol", "smtp"); + + SmtpConnectProtectionType smtpConnectProtect = mailSmtpConfiguration.getConnectProtection(); + + if (smtpConnectProtect == SmtpConnectProtectionType.StartTls) { + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + props.put("mail.smtp.starttls.enable", true); + } + else if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + props.put("mail.smtp.ssl.enable", true); + } + + Session session = null; + if (mailSmtpConfiguration.isRequiresAuthentication()) { + props.put("mail.smtp.auth", "true"); + + final String userName = mailSmtpConfiguration.getUserName(); + final String password = mailSmtpConfiguration.getPasswordDecrypted(); + + session = Session.getInstance(props, new javax.mail.Authenticator() { + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(userName, password); + } + }); + } else { + session = Session.getInstance(props, null); + } + + MimeMessage msg = new MimeMessage(session); + try { + msg.setFrom(new InternetAddress(mailFrom, mailFromName)); + if (StringHelper.isEmpty(toDisplayName)) { + msg.setRecipients(Message.RecipientType.TO, to); + } else { + msg.addRecipient(Message.RecipientType.TO, new InternetAddress(to, toDisplayName)); + } + msg.setSubject(subject, "UTF-8"); + msg.setSentDate(new Date()); + + if (StringHelper.isEmpty(htmlMessage)) { + msg.setText(message + "\n", "UTF-8", "plain"); + } else { + // Unformatted text version + final MimeBodyPart textPart = new MimeBodyPart(); + textPart.setText(message, "UTF-8", "plain"); + // HTML version + final MimeBodyPart htmlPart = new MimeBodyPart(); + htmlPart.setText(htmlMessage, "UTF-8", "html"); + + // Create the Multipart. Add BodyParts to it. + final Multipart mp = new MimeMultipart("alternative"); + mp.addBodyPart(textPart); + mp.addBodyPart(htmlPart); + + // Set Multipart as the message's content + msg.setContent(mp); + } + + Transport.send(msg); + } catch (Exception ex) { + log.error("Failed to send message", ex); + return false; + } + + return true; + } + + public boolean sendMailSigned(String to, String subject, String message) { + return sendMailSigned(smtpConfiguration, null, null, to, null, subject, message, null); + } + + public boolean sendMailSigned(String to, String toDisplayName, String subject, String message, String htmlMessage) { + return sendMailSigned(smtpConfiguration, null, null, to, null, subject, message, htmlMessage); + } + + public boolean sendMailSigned(String from, String fromDisplayName, String to, String toDisplayName, String subject, + String message, String htmlMessage) { + return sendMailSigned(smtpConfiguration, from, fromDisplayName, to, null, subject, message, htmlMessage); + } + + public boolean sendMailSigned(SmtpConfiguration mailSmtpConfiguration, String from, String fromDisplayName, String to, + String toDisplayName, + String subject, String message, String htmlMessage) { + if (mailSmtpConfiguration == null) { + log.error("Failed to send message from '{}' to '{}' because the SMTP configuration isn't valid!", from, to); + return false; + } + + log.debug("Host name: " + mailSmtpConfiguration.getHost() + ", port: " + mailSmtpConfiguration.getPort() + ", connection time out: " + + this.connectionTimeout); + + PrivateKey privateKey = null; + + Certificate certificate = null; + X509Certificate x509Certificate = null; + + try { + privateKey = (PrivateKey)keyStore.getKey(mailSmtpConfiguration.getKeyStoreAlias(), + smtpConfiguration.getKeyStorePassword().toCharArray()); + + certificate = keyStore.getCertificate(smtpConfiguration.getKeyStoreAlias()); + x509Certificate = (X509Certificate)certificate; + } catch (Exception e) { + log.error(e.getMessage()); + } String mailFrom = from; if (StringHelper.isEmpty(mailFrom)) { @@ -155,6 +320,10 @@ protected PasswordAuthentication getPasswordAuthentication() { // Set Multipart as the message's content msg.setContent(mp); + + MimeMultipart multiPart = createMultipartWithSignature(privateKey, x509Certificate, smtpConfiguration.getSigningAlgorithm(), msg); + + msg.setContent(multiPart); } Transport.send(msg); @@ -174,4 +343,51 @@ public void setConnectionTimeout(long connectionTimeout) { this.connectionTimeout = connectionTimeout; } + /** + * @param cert + * @return + * @throws CertificateParsingException + */ + private static ASN1EncodableVector generateSignedAttributes(X509Certificate cert) throws CertificateParsingException { + ASN1EncodableVector signedAttrs = new ASN1EncodableVector(); + SMIMECapabilityVector caps = new SMIMECapabilityVector(); + caps.addCapability(SMIMECapability.aES256_CBC); + caps.addCapability(SMIMECapability.dES_EDE3_CBC); + caps.addCapability(SMIMECapability.rC2_CBC, 128); + signedAttrs.add(new SMIMECapabilitiesAttribute(caps)); + signedAttrs.add(new SMIMEEncryptionKeyPreferenceAttribute(SMIMEUtil.createIssuerAndSerialNumberFor(cert))); + return signedAttrs; + } + + /** + * + * @param key + * @param cert + * @param signingAlgorithm + * @param dataPart + * @return + * @throws CertificateEncodingException + * @throws CertificateParsingException + * @throws OperatorCreationException + * @throws SMIMEException + */ + public static MimeMultipart createMultipartWithSignature(PrivateKey key, X509Certificate cert, String signingAlgorithm, MimeMessage mm) throws CertificateEncodingException, CertificateParsingException, OperatorCreationException, SMIMEException { + List certList = new ArrayList(); + certList.add(cert); + Store certs = new JcaCertStore(certList); + ASN1EncodableVector signedAttrs = generateSignedAttributes(cert); + + SMIMESignedGenerator gen = new SMIMESignedGenerator(); + + if (signingAlgorithm == null || signingAlgorithm.isEmpty()) { + signingAlgorithm = cert.getSigAlgName(); + } + + gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider(SecurityProviderUtility.getBCProvider()).setSignedAttributeGenerator(new AttributeTable(signedAttrs)).build(signingAlgorithm, key, cert)); + + gen.addCertificates(certs); + + return gen.generate(mm); + } + } diff --git a/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java b/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java index 582b1907..e0ed1678 100644 --- a/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java +++ b/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java @@ -61,6 +61,9 @@ public class SmtpConfiguration implements java.io.Serializable { @JsonProperty("key-store-alias") private String keyStoreAlias; + @JsonProperty("signing-algorithm") + private String signingAlgorithm; + public String getHost() { return host; } @@ -175,4 +178,11 @@ public void setKeyStoreAlias(String keyStoreAlias) { this.keyStoreAlias = keyStoreAlias; } + public String getSigningAlgorithm() { + return signingAlgorithm; + } + + public void setSigningAlgorithm(String signingAlgorithm) { + this.signingAlgorithm = signingAlgorithm; + } } From 1f82312b35c35f09f4e496c00e4bc67d3848c7cf Mon Sep 17 00:00:00 2001 From: SMan Date: Mon, 11 Jul 2022 04:30:34 -0500 Subject: [PATCH 307/362] feat: sending of emails has been updated (for bcprov and bc-fips); --- oxService/pom.xml | 1 - .../java/org/gluu/service/MailService.java | 95 +++++++++++++++++-- 2 files changed, 86 insertions(+), 10 deletions(-) diff --git a/oxService/pom.xml b/oxService/pom.xml index b2d05bd8..4ec8b414 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -173,7 +173,6 @@ org.bouncycastle bcmail-jdk15on - provided diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index 0a6fd22f..0abc544a 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -7,6 +7,7 @@ import java.io.FileInputStream; import java.io.InputStream; +import java.security.InvalidParameterException; import java.security.KeyStore; import java.security.PrivateKey; import java.security.cert.Certificate; @@ -34,6 +35,7 @@ import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; +import org.apache.commons.io.FilenameUtils; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.cms.AttributeTable; import org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute; @@ -47,10 +49,12 @@ import org.bouncycastle.mail.smime.SMIMEUtil; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.util.Store; + import org.gluu.model.SmtpConfiguration; import org.gluu.model.SmtpConnectProtectionType; import org.gluu.util.StringHelper; import org.gluu.util.security.SecurityProviderUtility; + import org.slf4j.Logger; /** @@ -84,8 +88,23 @@ public void init() { String keystoreFile = smtpConfiguration.getKeyStore(); String keystoreSecret = smtpConfiguration.getKeyStorePassword(); + SecurityProviderUtility.KeyStorageType keystoreType = solveKeyStorageType(keystoreFile); + try(InputStream is = new FileInputStream(keystoreFile)) { - keyStore = KeyStore.getInstance("PKCS12", SecurityProviderUtility.getBCProvider()); + switch (keystoreType) { + case JKS_KS: { + keyStore = KeyStore.getInstance("JKS"); + break; + } + case PKCS12_KS: { + keyStore = KeyStore.getInstance("PKCS12", SecurityProviderUtility.getBCProvider()); + break; + } + case BCFKS_KS: { + keyStore = KeyStore.getInstance("BCFKS", SecurityProviderUtility.getBCProvider()); + break; + } + } keyStore.load(is, keystoreSecret.toCharArray()); } catch (Exception e) { log.error(e.getMessage(), e); @@ -254,31 +273,56 @@ public boolean sendMailSigned(SmtpConfiguration mailSmtpConfiguration, String fr } Properties props = new Properties(); - props.put("mail.smtp.host", mailSmtpConfiguration.getHost()); - props.put("mail.smtp.port", mailSmtpConfiguration.getPort()); + props.put("mail.from", mailFrom); - props.put("mail.smtp.connectiontimeout", this.connectionTimeout); - props.put("mail.smtp.timeout", this.connectionTimeout); - props.put("mail.transport.protocol", "smtp"); SmtpConnectProtectionType smtpConnectProtect = mailSmtpConfiguration.getConnectProtection(); if (smtpConnectProtect == SmtpConnectProtectionType.StartTls) { - props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.transport.protocol", "smtp"); + + props.put("mail.smtp.host", mailSmtpConfiguration.getHost()); + props.put("mail.smtp.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtp.connectiontimeout", this.connectionTimeout); + props.put("mail.smtp.timeout", this.connectionTimeout); + + props.put("mail.smtp.socketFactory.class", "com.sun.mail.util.MailSSLSocketFactory"); props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); props.put("mail.smtp.starttls.enable", true); + props.put("mail.smtp.starttls.required", true); } else if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { - props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.transport.protocol.rfc822", "smtps"); + + props.put("mail.smtps.host", mailSmtpConfiguration.getHost()); + props.put("mail.smtps.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtps.connectiontimeout", this.connectionTimeout); + props.put("mail.smtps.timeout", this.connectionTimeout); + + props.put("mail.smtp.socketFactory.class", "com.sun.mail.util.MailSSLSocketFactory"); props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); props.put("mail.smtp.ssl.enable", true); + } + else { + props.put("mail.transport.protocol", "smtp"); + + props.put("mail.smtp.host", mailSmtpConfiguration.getHost()); + props.put("mail.smtp.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtp.connectiontimeout", this.connectionTimeout); + props.put("mail.smtp.timeout", this.connectionTimeout); } Session session = null; if (mailSmtpConfiguration.isRequiresAuthentication()) { - props.put("mail.smtp.auth", "true"); + + if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { + props.put("mail.smtps.auth", "true"); + } + else { + props.put("mail.smtp.auth", "true"); + } final String userName = mailSmtpConfiguration.getUserName(); final String password = mailSmtpConfiguration.getPasswordDecrypted(); @@ -390,4 +434,37 @@ public static MimeMultipart createMultipartWithSignature(PrivateKey key, X509Cer return gen.generate(mm); } + /** + * + * @return + */ + private SecurityProviderUtility.KeyStorageType solveKeyStorageType(final String keyStoreFile) { + SecurityProviderUtility.SecurityModeType securityMode = SecurityProviderUtility.getSecurityMode(); + if (securityMode == null) { + throw new InvalidParameterException("Security Mode wasn't initialized. Call installBCProvider() before"); + } + String keyStoreExt = FilenameUtils.getExtension(keyStoreFile); + SecurityProviderUtility.KeyStorageType keyStorageType = SecurityProviderUtility.KeyStorageType.fromExtension(keyStoreExt); + boolean ksTypeFound = false; + for (SecurityProviderUtility.KeyStorageType ksType : securityMode.getKeystorageTypes()) { + if (keyStorageType == ksType) { + ksTypeFound = true; + break; + } + } + if (!ksTypeFound) { + switch (securityMode) { + case BCFIPS_SECURITY_MODE: { + keyStorageType = SecurityProviderUtility.KeyStorageType.BCFKS_KS; + break; + } + case BCPROV_SECURITY_MODE: { + keyStorageType = SecurityProviderUtility.KeyStorageType.PKCS12_KS; + break; + } + } + } + return keyStorageType; + } + } From 8aab7071126ab901d2280771d9b165bcfca86148 Mon Sep 17 00:00:00 2001 From: SMan Date: Tue, 12 Jul 2022 09:31:01 -0500 Subject: [PATCH 308/362] fix: checking of trust server has been added; --- .../src/main/java/org/gluu/service/MailService.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index 0abc544a..496f56c4 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -288,9 +288,11 @@ public boolean sendMailSigned(SmtpConfiguration mailSmtpConfiguration, String fr props.put("mail.smtp.socketFactory.class", "com.sun.mail.util.MailSSLSocketFactory"); props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); - props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + if (mailSmtpConfiguration.isServerTrust()) { + props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + } props.put("mail.smtp.starttls.enable", true); - props.put("mail.smtp.starttls.required", true); + props.put("mail.smtp.starttls.required", true); } else if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { props.put("mail.transport.protocol.rfc822", "smtps"); @@ -302,7 +304,9 @@ else if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { props.put("mail.smtp.socketFactory.class", "com.sun.mail.util.MailSSLSocketFactory"); props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); - props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + if (mailSmtpConfiguration.isServerTrust()) { + props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + } props.put("mail.smtp.ssl.enable", true); } else { From 4e7c1c28ef1b772f54e8c5696c47d98e2ecf23f3 Mon Sep 17 00:00:00 2001 From: SMan Date: Tue, 26 Jul 2022 07:57:03 -0500 Subject: [PATCH 309/362] feat: improvement of sending emails has been added; --- .../java/org/gluu/service/MailService.java | 49 ++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index 496f56c4..96054cf9 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -10,11 +10,11 @@ import java.security.InvalidParameterException; import java.security.KeyStore; import java.security.PrivateKey; -import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Properties; @@ -48,7 +48,6 @@ import org.bouncycastle.mail.smime.SMIMESignedGenerator; import org.bouncycastle.mail.smime.SMIMEUtil; import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.util.Store; import org.gluu.model.SmtpConfiguration; import org.gluu.model.SmtpConnectProtectionType; @@ -246,18 +245,15 @@ public boolean sendMailSigned(SmtpConfiguration mailSmtpConfiguration, String fr log.debug("Host name: " + mailSmtpConfiguration.getHost() + ", port: " + mailSmtpConfiguration.getPort() + ", connection time out: " + this.connectionTimeout); - + PrivateKey privateKey = null; - Certificate certificate = null; - X509Certificate x509Certificate = null; + X509Certificate[] certificates = null; try { privateKey = (PrivateKey)keyStore.getKey(mailSmtpConfiguration.getKeyStoreAlias(), smtpConfiguration.getKeyStorePassword().toCharArray()); - - certificate = keyStore.getCertificate(smtpConfiguration.getKeyStoreAlias()); - x509Certificate = (X509Certificate)certificate; + certificates = (X509Certificate[])keyStore.getCertificateChain(mailSmtpConfiguration.getKeyStoreAlias()); } catch (Exception e) { log.error(e.getMessage()); } @@ -369,7 +365,7 @@ protected PasswordAuthentication getPasswordAuthentication() { // Set Multipart as the message's content msg.setContent(mp); - MimeMultipart multiPart = createMultipartWithSignature(privateKey, x509Certificate, smtpConfiguration.getSigningAlgorithm(), msg); + MimeMultipart multiPart = createMultipartWithSignature(privateKey, certificates, smtpConfiguration.getSigningAlgorithm(), msg); msg.setContent(multiPart); } @@ -422,11 +418,12 @@ private static ASN1EncodableVector generateSignedAttributes(X509Certificate cert public static MimeMultipart createMultipartWithSignature(PrivateKey key, X509Certificate cert, String signingAlgorithm, MimeMessage mm) throws CertificateEncodingException, CertificateParsingException, OperatorCreationException, SMIMEException { List certList = new ArrayList(); certList.add(cert); - Store certs = new JcaCertStore(certList); + + JcaCertStore certs = new JcaCertStore(certList); ASN1EncodableVector signedAttrs = generateSignedAttributes(cert); SMIMESignedGenerator gen = new SMIMESignedGenerator(); - + if (signingAlgorithm == null || signingAlgorithm.isEmpty()) { signingAlgorithm = cert.getSigAlgName(); } @@ -438,6 +435,36 @@ public static MimeMultipart createMultipartWithSignature(PrivateKey key, X509Cer return gen.generate(mm); } + /** + * + * @param key + * @param inCerts + * @param signingAlgorithm + * @param mm + * @return + * @throws CertificateEncodingException + * @throws CertificateParsingException + * @throws OperatorCreationException + * @throws SMIMEException + */ + public static MimeMultipart createMultipartWithSignature(PrivateKey key, X509Certificate[] inCerts, String signingAlgorithm, MimeMessage mm) throws CertificateEncodingException, CertificateParsingException, OperatorCreationException, SMIMEException { + + JcaCertStore certs = new JcaCertStore(Arrays.asList(inCerts)); + ASN1EncodableVector signedAttrs = generateSignedAttributes((X509Certificate)inCerts[0]); + + SMIMESignedGenerator gen = new SMIMESignedGenerator(); + + if (signingAlgorithm == null || signingAlgorithm.isEmpty()) { + signingAlgorithm = ((X509Certificate)inCerts[0]).getSigAlgName(); + } + + gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider(SecurityProviderUtility.getBCProvider()).setSignedAttributeGenerator(new AttributeTable(signedAttrs)).build(signingAlgorithm, key, (X509Certificate)inCerts[0])); + + gen.addCertificates(certs); + + return gen.generate(mm); + } + /** * * @return From 2f60a6e4456b5b3ffa370d4868f40cf19d81f610 Mon Sep 17 00:00:00 2001 From: SMan Date: Tue, 2 Aug 2022 05:52:33 -0500 Subject: [PATCH 310/362] feat: encrypting keystore password has been added; --- .../java/org/gluu/service/MailService.java | 18 +++++++++++++----- .../java/org/gluu/model/SmtpConfiguration.java | 12 ++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index 96054cf9..bfbaa19a 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -10,6 +10,7 @@ import java.security.InvalidParameterException; import java.security.KeyStore; import java.security.PrivateKey; +import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; @@ -85,7 +86,7 @@ public void init() { mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822"); String keystoreFile = smtpConfiguration.getKeyStore(); - String keystoreSecret = smtpConfiguration.getKeyStorePassword(); + String keystoreSecret = smtpConfiguration.getKeyStorePasswordDecrypted(); SecurityProviderUtility.KeyStorageType keystoreType = solveKeyStorageType(keystoreFile); @@ -248,12 +249,19 @@ public boolean sendMailSigned(SmtpConfiguration mailSmtpConfiguration, String fr PrivateKey privateKey = null; - X509Certificate[] certificates = null; + Certificate[] certificates = null; + X509Certificate[] x509Certificates = null; try { privateKey = (PrivateKey)keyStore.getKey(mailSmtpConfiguration.getKeyStoreAlias(), - smtpConfiguration.getKeyStorePassword().toCharArray()); - certificates = (X509Certificate[])keyStore.getCertificateChain(mailSmtpConfiguration.getKeyStoreAlias()); + smtpConfiguration.getKeyStorePasswordDecrypted().toCharArray()); + certificates = keyStore.getCertificateChain(mailSmtpConfiguration.getKeyStoreAlias()); + if (certificates != null) { + x509Certificates = new X509Certificate[certificates.length]; + for (int i = 0; i < certificates.length; i++) { + x509Certificates[i] = (X509Certificate)certificates[i]; + } + } } catch (Exception e) { log.error(e.getMessage()); } @@ -365,7 +373,7 @@ protected PasswordAuthentication getPasswordAuthentication() { // Set Multipart as the message's content msg.setContent(mp); - MimeMultipart multiPart = createMultipartWithSignature(privateKey, certificates, smtpConfiguration.getSigningAlgorithm(), msg); + MimeMultipart multiPart = createMultipartWithSignature(privateKey, x509Certificates, smtpConfiguration.getSigningAlgorithm(), msg); msg.setContent(multiPart); } diff --git a/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java b/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java index e0ed1678..f5baf736 100644 --- a/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java +++ b/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java @@ -58,6 +58,10 @@ public class SmtpConfiguration implements java.io.Serializable { @JsonProperty("key-store-password") private String keyStorePassword; + @Transient + @JsonIgnore + private String keyStorePasswordDecrypted; + @JsonProperty("key-store-alias") private String keyStoreAlias; @@ -170,6 +174,14 @@ public void setKeyStorePassword(String keyStorePassword) { this.keyStorePassword = keyStorePassword; } + public String getKeyStorePasswordDecrypted() { + return keyStorePasswordDecrypted; + } + + public void setKeyStorePasswordDecrypted(String keyStorePasswordDecrypted) { + this.keyStorePasswordDecrypted = keyStorePasswordDecrypted; + } + public String getKeyStoreAlias() { return keyStoreAlias; } From 5eef07d797f01ce32f234ed8812c59d092176808 Mon Sep 17 00:00:00 2001 From: SMan Date: Fri, 24 Jun 2022 08:05:23 -0500 Subject: [PATCH 311/362] feat: sending signed emails has been added; feat: updating smtp configuring has been added; --- .../java/org/gluu/service/MailService.java | 24 ++++++- .../org/gluu/model/SmtpConfiguration.java | 49 +++++++++++++-- .../gluu/model/SmtpConnectProtectionType.java | 62 +++++++++++++++++++ 3 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index 2a393072..e2026f40 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -8,6 +8,10 @@ import java.util.Date; import java.util.Properties; +import javax.activation.CommandMap; +import javax.activation.MailcapCommandMap; +import javax.annotation.PostConstruct; +import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.inject.Named; @@ -22,6 +26,7 @@ import javax.mail.internet.MimeMultipart; import org.gluu.model.SmtpConfiguration; +import org.gluu.model.SmtpConnectProtectionType; import org.gluu.util.StringHelper; import org.slf4j.Logger; @@ -66,6 +71,13 @@ public boolean sendMail(SmtpConfiguration mailSmtpConfiguration, String from, St log.debug("Host name: " + mailSmtpConfiguration.getHost() + ", port: " + mailSmtpConfiguration.getPort() + ", connection time out: " + this.connectionTimeout); + MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap(); + mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html"); + mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml"); + mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain"); + mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed"); + mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822"); + String mailFrom = from; if (StringHelper.isEmpty(mailFrom)) { mailFrom = mailSmtpConfiguration.getFromEmailAddress(); @@ -83,12 +95,20 @@ public boolean sendMail(SmtpConfiguration mailSmtpConfiguration, String from, St props.put("mail.smtp.connectiontimeout", this.connectionTimeout); props.put("mail.smtp.timeout", this.connectionTimeout); props.put("mail.transport.protocol", "smtp"); - props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); - if (mailSmtpConfiguration.isRequiresSsl()) { + SmtpConnectProtectionType smtpConnectProtect = mailSmtpConfiguration.getConnectProtection(); + + if (smtpConnectProtect == SmtpConnectProtectionType.StartTls) { + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); props.put("mail.smtp.starttls.enable", true); + } + else if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + props.put("mail.smtp.ssl.enable", true); } Session session = null; diff --git a/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java b/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java index 0c3ea30c..582b1907 100644 --- a/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java +++ b/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java @@ -27,8 +27,8 @@ public class SmtpConfiguration implements java.io.Serializable { @JsonProperty("port") private int port; - @JsonProperty("requires-ssl") - private boolean requiresSsl; + @JsonProperty("connect-protection") + private SmtpConnectProtectionType connectProtection; @JsonProperty("trust-host") private boolean serverTrust; @@ -52,6 +52,15 @@ public class SmtpConfiguration implements java.io.Serializable { @JsonIgnore private String passwordDecrypted; + @JsonProperty("key-store") + private String keyStore; + + @JsonProperty("key-store-password") + private String keyStorePassword; + + @JsonProperty("key-store-alias") + private String keyStoreAlias; + public String getHost() { return host; } @@ -68,12 +77,12 @@ public void setPort(int port) { this.port = port; } - public boolean isRequiresSsl() { - return requiresSsl; + public SmtpConnectProtectionType getConnectProtection() { + return connectProtection; } - public void setRequiresSsl(boolean requiresSsl) { - this.requiresSsl = requiresSsl; + public void setConnectProtection(SmtpConnectProtectionType connectProtection) { + this.connectProtection = connectProtection; } public boolean isServerTrust() { @@ -137,5 +146,33 @@ public String getPasswordDecrypted() { public void setPasswordDecrypted(String passwordDecrypted) { this.passwordDecrypted = passwordDecrypted; } + + public SmtpConnectProtectionType[] getConnectProtectionList() { + return SmtpConnectProtectionType.values(); + } + + public String getKeyStore() { + return keyStore; + } + + public void setKeyStore(String keyStore) { + this.keyStore = keyStore; + } + + public String getKeyStorePassword() { + return keyStorePassword; + } + + public void setKeyStorePassword(String keyStorePassword) { + this.keyStorePassword = keyStorePassword; + } + + public String getKeyStoreAlias() { + return keyStoreAlias; + } + + public void setKeyStoreAlias(String keyStoreAlias) { + this.keyStoreAlias = keyStoreAlias; + } } diff --git a/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java b/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java new file mode 100644 index 00000000..9ae88bbb --- /dev/null +++ b/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java @@ -0,0 +1,62 @@ +/** + * + */ +package org.gluu.model; + +import java.util.HashMap; +import java.util.Map; + +import org.gluu.persist.annotation.AttributeEnum; + +/** + * @author Sergey Manoylo + * @version + */ +public enum SmtpConnectProtectionType implements AttributeEnum { + + None("None", "NONE"), StartTls("StartTls", "STARTTLS"), SslTls("SslTls", "SSL/TLS"); + + private String value; + private String displayName; + + private static final Map mapByValues = new HashMap(); + + static { + for (SmtpConnectProtectionType enumType : values()) { + mapByValues.put(enumType.getValue(), enumType); + } + } + + /** + * + * @param value + * @param displayName + */ + private SmtpConnectProtectionType(String value, String displayName) { + this.value = value; + this.displayName = displayName; + } + + @Override + public String getValue() { + return value; + } + + public String getDisplayName() { + return displayName; + } + + public static SmtpConnectProtectionType getByValue(String value) { + return mapByValues.get(value); + } + + @Override + public Enum resolveByValue(String value) { + return getByValue(value); + } + + @Override + public String toString() { + return value; + } +} From 153da81e791a7136d4fd95ebce4bc02bd76b3c1f Mon Sep 17 00:00:00 2001 From: SMan Date: Mon, 4 Jul 2022 03:04:31 -0500 Subject: [PATCH 312/362] feat: definition of signing algorithm has been added; fix: unnecessary downloading of the oxauth-server has been removed; --- oxService/pom.xml | 15 ++ .../java/org/gluu/service/MailService.java | 230 +++++++++++++++++- .../org/gluu/model/SmtpConfiguration.java | 10 + 3 files changed, 248 insertions(+), 7 deletions(-) diff --git a/oxService/pom.xml b/oxService/pom.xml index 3080fc1f..b2d05bd8 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -160,6 +160,21 @@ aalto-xml 1.2.1 + + + + org.bouncycastle + bcprov-jdk15on + + + org.bouncycastle + bcpkix-jdk15on + + + org.bouncycastle + bcmail-jdk15on + provided + \ No newline at end of file diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index e2026f40..0a6fd22f 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -5,13 +5,22 @@ */ package org.gluu.service; +import java.io.FileInputStream; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.Properties; import javax.activation.CommandMap; import javax.activation.MailcapCommandMap; import javax.annotation.PostConstruct; -import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.inject.Named; @@ -25,9 +34,23 @@ import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.cms.AttributeTable; +import org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute; +import org.bouncycastle.asn1.smime.SMIMECapability; +import org.bouncycastle.asn1.smime.SMIMECapabilityVector; +import org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute; +import org.bouncycastle.cert.jcajce.JcaCertStore; +import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder; +import org.bouncycastle.mail.smime.SMIMEException; +import org.bouncycastle.mail.smime.SMIMESignedGenerator; +import org.bouncycastle.mail.smime.SMIMEUtil; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.util.Store; import org.gluu.model.SmtpConfiguration; import org.gluu.model.SmtpConnectProtectionType; import org.gluu.util.StringHelper; +import org.gluu.util.security.SecurityProviderUtility; import org.slf4j.Logger; /** @@ -45,8 +68,30 @@ public class MailService { @Inject private SmtpConfiguration smtpConfiguration; + private KeyStore keyStore; + private long connectionTimeout = 5000; + @PostConstruct + public void init() { + MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap(); + mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html"); + mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml"); + mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain"); + mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed"); + mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822"); + + String keystoreFile = smtpConfiguration.getKeyStore(); + String keystoreSecret = smtpConfiguration.getKeyStorePassword(); + + try(InputStream is = new FileInputStream(keystoreFile)) { + keyStore = KeyStore.getInstance("PKCS12", SecurityProviderUtility.getBCProvider()); + keyStore.load(is, keystoreSecret.toCharArray()); + } catch (Exception e) { + log.error(e.getMessage(), e); + } + } + public boolean sendMail(String to, String subject, String message) { return sendMail(smtpConfiguration, null, null, to, null, subject, message, null); } @@ -71,12 +116,132 @@ public boolean sendMail(SmtpConfiguration mailSmtpConfiguration, String from, St log.debug("Host name: " + mailSmtpConfiguration.getHost() + ", port: " + mailSmtpConfiguration.getPort() + ", connection time out: " + this.connectionTimeout); - MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap(); - mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html"); - mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml"); - mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain"); - mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed"); - mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822"); + String mailFrom = from; + if (StringHelper.isEmpty(mailFrom)) { + mailFrom = mailSmtpConfiguration.getFromEmailAddress(); + } + + String mailFromName = fromDisplayName; + if (StringHelper.isEmpty(mailFromName)) { + mailFromName = mailSmtpConfiguration.getFromName(); + } + + Properties props = new Properties(); + props.put("mail.smtp.host", mailSmtpConfiguration.getHost()); + props.put("mail.smtp.port", mailSmtpConfiguration.getPort()); + props.put("mail.from", mailFrom); + props.put("mail.smtp.connectiontimeout", this.connectionTimeout); + props.put("mail.smtp.timeout", this.connectionTimeout); + props.put("mail.transport.protocol", "smtp"); + + SmtpConnectProtectionType smtpConnectProtect = mailSmtpConfiguration.getConnectProtection(); + + if (smtpConnectProtect == SmtpConnectProtectionType.StartTls) { + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + props.put("mail.smtp.starttls.enable", true); + } + else if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { + props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + props.put("mail.smtp.ssl.enable", true); + } + + Session session = null; + if (mailSmtpConfiguration.isRequiresAuthentication()) { + props.put("mail.smtp.auth", "true"); + + final String userName = mailSmtpConfiguration.getUserName(); + final String password = mailSmtpConfiguration.getPasswordDecrypted(); + + session = Session.getInstance(props, new javax.mail.Authenticator() { + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(userName, password); + } + }); + } else { + session = Session.getInstance(props, null); + } + + MimeMessage msg = new MimeMessage(session); + try { + msg.setFrom(new InternetAddress(mailFrom, mailFromName)); + if (StringHelper.isEmpty(toDisplayName)) { + msg.setRecipients(Message.RecipientType.TO, to); + } else { + msg.addRecipient(Message.RecipientType.TO, new InternetAddress(to, toDisplayName)); + } + msg.setSubject(subject, "UTF-8"); + msg.setSentDate(new Date()); + + if (StringHelper.isEmpty(htmlMessage)) { + msg.setText(message + "\n", "UTF-8", "plain"); + } else { + // Unformatted text version + final MimeBodyPart textPart = new MimeBodyPart(); + textPart.setText(message, "UTF-8", "plain"); + // HTML version + final MimeBodyPart htmlPart = new MimeBodyPart(); + htmlPart.setText(htmlMessage, "UTF-8", "html"); + + // Create the Multipart. Add BodyParts to it. + final Multipart mp = new MimeMultipart("alternative"); + mp.addBodyPart(textPart); + mp.addBodyPart(htmlPart); + + // Set Multipart as the message's content + msg.setContent(mp); + } + + Transport.send(msg); + } catch (Exception ex) { + log.error("Failed to send message", ex); + return false; + } + + return true; + } + + public boolean sendMailSigned(String to, String subject, String message) { + return sendMailSigned(smtpConfiguration, null, null, to, null, subject, message, null); + } + + public boolean sendMailSigned(String to, String toDisplayName, String subject, String message, String htmlMessage) { + return sendMailSigned(smtpConfiguration, null, null, to, null, subject, message, htmlMessage); + } + + public boolean sendMailSigned(String from, String fromDisplayName, String to, String toDisplayName, String subject, + String message, String htmlMessage) { + return sendMailSigned(smtpConfiguration, from, fromDisplayName, to, null, subject, message, htmlMessage); + } + + public boolean sendMailSigned(SmtpConfiguration mailSmtpConfiguration, String from, String fromDisplayName, String to, + String toDisplayName, + String subject, String message, String htmlMessage) { + if (mailSmtpConfiguration == null) { + log.error("Failed to send message from '{}' to '{}' because the SMTP configuration isn't valid!", from, to); + return false; + } + + log.debug("Host name: " + mailSmtpConfiguration.getHost() + ", port: " + mailSmtpConfiguration.getPort() + ", connection time out: " + + this.connectionTimeout); + + PrivateKey privateKey = null; + + Certificate certificate = null; + X509Certificate x509Certificate = null; + + try { + privateKey = (PrivateKey)keyStore.getKey(mailSmtpConfiguration.getKeyStoreAlias(), + smtpConfiguration.getKeyStorePassword().toCharArray()); + + certificate = keyStore.getCertificate(smtpConfiguration.getKeyStoreAlias()); + x509Certificate = (X509Certificate)certificate; + } catch (Exception e) { + log.error(e.getMessage()); + } String mailFrom = from; if (StringHelper.isEmpty(mailFrom)) { @@ -155,6 +320,10 @@ protected PasswordAuthentication getPasswordAuthentication() { // Set Multipart as the message's content msg.setContent(mp); + + MimeMultipart multiPart = createMultipartWithSignature(privateKey, x509Certificate, smtpConfiguration.getSigningAlgorithm(), msg); + + msg.setContent(multiPart); } Transport.send(msg); @@ -174,4 +343,51 @@ public void setConnectionTimeout(long connectionTimeout) { this.connectionTimeout = connectionTimeout; } + /** + * @param cert + * @return + * @throws CertificateParsingException + */ + private static ASN1EncodableVector generateSignedAttributes(X509Certificate cert) throws CertificateParsingException { + ASN1EncodableVector signedAttrs = new ASN1EncodableVector(); + SMIMECapabilityVector caps = new SMIMECapabilityVector(); + caps.addCapability(SMIMECapability.aES256_CBC); + caps.addCapability(SMIMECapability.dES_EDE3_CBC); + caps.addCapability(SMIMECapability.rC2_CBC, 128); + signedAttrs.add(new SMIMECapabilitiesAttribute(caps)); + signedAttrs.add(new SMIMEEncryptionKeyPreferenceAttribute(SMIMEUtil.createIssuerAndSerialNumberFor(cert))); + return signedAttrs; + } + + /** + * + * @param key + * @param cert + * @param signingAlgorithm + * @param dataPart + * @return + * @throws CertificateEncodingException + * @throws CertificateParsingException + * @throws OperatorCreationException + * @throws SMIMEException + */ + public static MimeMultipart createMultipartWithSignature(PrivateKey key, X509Certificate cert, String signingAlgorithm, MimeMessage mm) throws CertificateEncodingException, CertificateParsingException, OperatorCreationException, SMIMEException { + List certList = new ArrayList(); + certList.add(cert); + Store certs = new JcaCertStore(certList); + ASN1EncodableVector signedAttrs = generateSignedAttributes(cert); + + SMIMESignedGenerator gen = new SMIMESignedGenerator(); + + if (signingAlgorithm == null || signingAlgorithm.isEmpty()) { + signingAlgorithm = cert.getSigAlgName(); + } + + gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider(SecurityProviderUtility.getBCProvider()).setSignedAttributeGenerator(new AttributeTable(signedAttrs)).build(signingAlgorithm, key, cert)); + + gen.addCertificates(certs); + + return gen.generate(mm); + } + } diff --git a/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java b/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java index 582b1907..e0ed1678 100644 --- a/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java +++ b/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java @@ -61,6 +61,9 @@ public class SmtpConfiguration implements java.io.Serializable { @JsonProperty("key-store-alias") private String keyStoreAlias; + @JsonProperty("signing-algorithm") + private String signingAlgorithm; + public String getHost() { return host; } @@ -175,4 +178,11 @@ public void setKeyStoreAlias(String keyStoreAlias) { this.keyStoreAlias = keyStoreAlias; } + public String getSigningAlgorithm() { + return signingAlgorithm; + } + + public void setSigningAlgorithm(String signingAlgorithm) { + this.signingAlgorithm = signingAlgorithm; + } } From a016b7731e750243cd47c9c8fe25f84dab73f2a7 Mon Sep 17 00:00:00 2001 From: SMan Date: Mon, 11 Jul 2022 04:30:34 -0500 Subject: [PATCH 313/362] feat: sending of emails has been updated (for bcprov and bc-fips); --- oxService/pom.xml | 1 - .../java/org/gluu/service/MailService.java | 95 +++++++++++++++++-- 2 files changed, 86 insertions(+), 10 deletions(-) diff --git a/oxService/pom.xml b/oxService/pom.xml index b2d05bd8..4ec8b414 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -173,7 +173,6 @@ org.bouncycastle bcmail-jdk15on - provided diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index 0a6fd22f..0abc544a 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -7,6 +7,7 @@ import java.io.FileInputStream; import java.io.InputStream; +import java.security.InvalidParameterException; import java.security.KeyStore; import java.security.PrivateKey; import java.security.cert.Certificate; @@ -34,6 +35,7 @@ import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; +import org.apache.commons.io.FilenameUtils; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.cms.AttributeTable; import org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute; @@ -47,10 +49,12 @@ import org.bouncycastle.mail.smime.SMIMEUtil; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.util.Store; + import org.gluu.model.SmtpConfiguration; import org.gluu.model.SmtpConnectProtectionType; import org.gluu.util.StringHelper; import org.gluu.util.security.SecurityProviderUtility; + import org.slf4j.Logger; /** @@ -84,8 +88,23 @@ public void init() { String keystoreFile = smtpConfiguration.getKeyStore(); String keystoreSecret = smtpConfiguration.getKeyStorePassword(); + SecurityProviderUtility.KeyStorageType keystoreType = solveKeyStorageType(keystoreFile); + try(InputStream is = new FileInputStream(keystoreFile)) { - keyStore = KeyStore.getInstance("PKCS12", SecurityProviderUtility.getBCProvider()); + switch (keystoreType) { + case JKS_KS: { + keyStore = KeyStore.getInstance("JKS"); + break; + } + case PKCS12_KS: { + keyStore = KeyStore.getInstance("PKCS12", SecurityProviderUtility.getBCProvider()); + break; + } + case BCFKS_KS: { + keyStore = KeyStore.getInstance("BCFKS", SecurityProviderUtility.getBCProvider()); + break; + } + } keyStore.load(is, keystoreSecret.toCharArray()); } catch (Exception e) { log.error(e.getMessage(), e); @@ -254,31 +273,56 @@ public boolean sendMailSigned(SmtpConfiguration mailSmtpConfiguration, String fr } Properties props = new Properties(); - props.put("mail.smtp.host", mailSmtpConfiguration.getHost()); - props.put("mail.smtp.port", mailSmtpConfiguration.getPort()); + props.put("mail.from", mailFrom); - props.put("mail.smtp.connectiontimeout", this.connectionTimeout); - props.put("mail.smtp.timeout", this.connectionTimeout); - props.put("mail.transport.protocol", "smtp"); SmtpConnectProtectionType smtpConnectProtect = mailSmtpConfiguration.getConnectProtection(); if (smtpConnectProtect == SmtpConnectProtectionType.StartTls) { - props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.transport.protocol", "smtp"); + + props.put("mail.smtp.host", mailSmtpConfiguration.getHost()); + props.put("mail.smtp.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtp.connectiontimeout", this.connectionTimeout); + props.put("mail.smtp.timeout", this.connectionTimeout); + + props.put("mail.smtp.socketFactory.class", "com.sun.mail.util.MailSSLSocketFactory"); props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); props.put("mail.smtp.starttls.enable", true); + props.put("mail.smtp.starttls.required", true); } else if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { - props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.put("mail.transport.protocol.rfc822", "smtps"); + + props.put("mail.smtps.host", mailSmtpConfiguration.getHost()); + props.put("mail.smtps.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtps.connectiontimeout", this.connectionTimeout); + props.put("mail.smtps.timeout", this.connectionTimeout); + + props.put("mail.smtp.socketFactory.class", "com.sun.mail.util.MailSSLSocketFactory"); props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); props.put("mail.smtp.ssl.enable", true); + } + else { + props.put("mail.transport.protocol", "smtp"); + + props.put("mail.smtp.host", mailSmtpConfiguration.getHost()); + props.put("mail.smtp.port", mailSmtpConfiguration.getPort()); + props.put("mail.smtp.connectiontimeout", this.connectionTimeout); + props.put("mail.smtp.timeout", this.connectionTimeout); } Session session = null; if (mailSmtpConfiguration.isRequiresAuthentication()) { - props.put("mail.smtp.auth", "true"); + + if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { + props.put("mail.smtps.auth", "true"); + } + else { + props.put("mail.smtp.auth", "true"); + } final String userName = mailSmtpConfiguration.getUserName(); final String password = mailSmtpConfiguration.getPasswordDecrypted(); @@ -390,4 +434,37 @@ public static MimeMultipart createMultipartWithSignature(PrivateKey key, X509Cer return gen.generate(mm); } + /** + * + * @return + */ + private SecurityProviderUtility.KeyStorageType solveKeyStorageType(final String keyStoreFile) { + SecurityProviderUtility.SecurityModeType securityMode = SecurityProviderUtility.getSecurityMode(); + if (securityMode == null) { + throw new InvalidParameterException("Security Mode wasn't initialized. Call installBCProvider() before"); + } + String keyStoreExt = FilenameUtils.getExtension(keyStoreFile); + SecurityProviderUtility.KeyStorageType keyStorageType = SecurityProviderUtility.KeyStorageType.fromExtension(keyStoreExt); + boolean ksTypeFound = false; + for (SecurityProviderUtility.KeyStorageType ksType : securityMode.getKeystorageTypes()) { + if (keyStorageType == ksType) { + ksTypeFound = true; + break; + } + } + if (!ksTypeFound) { + switch (securityMode) { + case BCFIPS_SECURITY_MODE: { + keyStorageType = SecurityProviderUtility.KeyStorageType.BCFKS_KS; + break; + } + case BCPROV_SECURITY_MODE: { + keyStorageType = SecurityProviderUtility.KeyStorageType.PKCS12_KS; + break; + } + } + } + return keyStorageType; + } + } From 9751a6702c667f4beafdae986a49fdb9da52e8ac Mon Sep 17 00:00:00 2001 From: SMan Date: Tue, 12 Jul 2022 09:31:01 -0500 Subject: [PATCH 314/362] fix: checking of trust server has been added; --- .../src/main/java/org/gluu/service/MailService.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index 0abc544a..496f56c4 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -288,9 +288,11 @@ public boolean sendMailSigned(SmtpConfiguration mailSmtpConfiguration, String fr props.put("mail.smtp.socketFactory.class", "com.sun.mail.util.MailSSLSocketFactory"); props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); - props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + if (mailSmtpConfiguration.isServerTrust()) { + props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + } props.put("mail.smtp.starttls.enable", true); - props.put("mail.smtp.starttls.required", true); + props.put("mail.smtp.starttls.required", true); } else if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { props.put("mail.transport.protocol.rfc822", "smtps"); @@ -302,7 +304,9 @@ else if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { props.put("mail.smtp.socketFactory.class", "com.sun.mail.util.MailSSLSocketFactory"); props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); - props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + if (mailSmtpConfiguration.isServerTrust()) { + props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); + } props.put("mail.smtp.ssl.enable", true); } else { From c2c45406eb4abee1abce519ee091ef337cbc1418 Mon Sep 17 00:00:00 2001 From: SMan Date: Tue, 26 Jul 2022 07:57:03 -0500 Subject: [PATCH 315/362] feat: improvement of sending emails has been added; --- .../java/org/gluu/service/MailService.java | 49 ++++++++++++++----- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index 496f56c4..96054cf9 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -10,11 +10,11 @@ import java.security.InvalidParameterException; import java.security.KeyStore; import java.security.PrivateKey; -import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Properties; @@ -48,7 +48,6 @@ import org.bouncycastle.mail.smime.SMIMESignedGenerator; import org.bouncycastle.mail.smime.SMIMEUtil; import org.bouncycastle.operator.OperatorCreationException; -import org.bouncycastle.util.Store; import org.gluu.model.SmtpConfiguration; import org.gluu.model.SmtpConnectProtectionType; @@ -246,18 +245,15 @@ public boolean sendMailSigned(SmtpConfiguration mailSmtpConfiguration, String fr log.debug("Host name: " + mailSmtpConfiguration.getHost() + ", port: " + mailSmtpConfiguration.getPort() + ", connection time out: " + this.connectionTimeout); - + PrivateKey privateKey = null; - Certificate certificate = null; - X509Certificate x509Certificate = null; + X509Certificate[] certificates = null; try { privateKey = (PrivateKey)keyStore.getKey(mailSmtpConfiguration.getKeyStoreAlias(), smtpConfiguration.getKeyStorePassword().toCharArray()); - - certificate = keyStore.getCertificate(smtpConfiguration.getKeyStoreAlias()); - x509Certificate = (X509Certificate)certificate; + certificates = (X509Certificate[])keyStore.getCertificateChain(mailSmtpConfiguration.getKeyStoreAlias()); } catch (Exception e) { log.error(e.getMessage()); } @@ -369,7 +365,7 @@ protected PasswordAuthentication getPasswordAuthentication() { // Set Multipart as the message's content msg.setContent(mp); - MimeMultipart multiPart = createMultipartWithSignature(privateKey, x509Certificate, smtpConfiguration.getSigningAlgorithm(), msg); + MimeMultipart multiPart = createMultipartWithSignature(privateKey, certificates, smtpConfiguration.getSigningAlgorithm(), msg); msg.setContent(multiPart); } @@ -422,11 +418,12 @@ private static ASN1EncodableVector generateSignedAttributes(X509Certificate cert public static MimeMultipart createMultipartWithSignature(PrivateKey key, X509Certificate cert, String signingAlgorithm, MimeMessage mm) throws CertificateEncodingException, CertificateParsingException, OperatorCreationException, SMIMEException { List certList = new ArrayList(); certList.add(cert); - Store certs = new JcaCertStore(certList); + + JcaCertStore certs = new JcaCertStore(certList); ASN1EncodableVector signedAttrs = generateSignedAttributes(cert); SMIMESignedGenerator gen = new SMIMESignedGenerator(); - + if (signingAlgorithm == null || signingAlgorithm.isEmpty()) { signingAlgorithm = cert.getSigAlgName(); } @@ -438,6 +435,36 @@ public static MimeMultipart createMultipartWithSignature(PrivateKey key, X509Cer return gen.generate(mm); } + /** + * + * @param key + * @param inCerts + * @param signingAlgorithm + * @param mm + * @return + * @throws CertificateEncodingException + * @throws CertificateParsingException + * @throws OperatorCreationException + * @throws SMIMEException + */ + public static MimeMultipart createMultipartWithSignature(PrivateKey key, X509Certificate[] inCerts, String signingAlgorithm, MimeMessage mm) throws CertificateEncodingException, CertificateParsingException, OperatorCreationException, SMIMEException { + + JcaCertStore certs = new JcaCertStore(Arrays.asList(inCerts)); + ASN1EncodableVector signedAttrs = generateSignedAttributes((X509Certificate)inCerts[0]); + + SMIMESignedGenerator gen = new SMIMESignedGenerator(); + + if (signingAlgorithm == null || signingAlgorithm.isEmpty()) { + signingAlgorithm = ((X509Certificate)inCerts[0]).getSigAlgName(); + } + + gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider(SecurityProviderUtility.getBCProvider()).setSignedAttributeGenerator(new AttributeTable(signedAttrs)).build(signingAlgorithm, key, (X509Certificate)inCerts[0])); + + gen.addCertificates(certs); + + return gen.generate(mm); + } + /** * * @return From 9a65149a60584aab572493393ffbf3ec84766cc2 Mon Sep 17 00:00:00 2001 From: SMan Date: Tue, 2 Aug 2022 05:52:33 -0500 Subject: [PATCH 316/362] feat: encrypting keystore password has been added; --- .../java/org/gluu/service/MailService.java | 18 +++++++++++++----- .../java/org/gluu/model/SmtpConfiguration.java | 12 ++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index 96054cf9..bfbaa19a 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -10,6 +10,7 @@ import java.security.InvalidParameterException; import java.security.KeyStore; import java.security.PrivateKey; +import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateParsingException; import java.security.cert.X509Certificate; @@ -85,7 +86,7 @@ public void init() { mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822"); String keystoreFile = smtpConfiguration.getKeyStore(); - String keystoreSecret = smtpConfiguration.getKeyStorePassword(); + String keystoreSecret = smtpConfiguration.getKeyStorePasswordDecrypted(); SecurityProviderUtility.KeyStorageType keystoreType = solveKeyStorageType(keystoreFile); @@ -248,12 +249,19 @@ public boolean sendMailSigned(SmtpConfiguration mailSmtpConfiguration, String fr PrivateKey privateKey = null; - X509Certificate[] certificates = null; + Certificate[] certificates = null; + X509Certificate[] x509Certificates = null; try { privateKey = (PrivateKey)keyStore.getKey(mailSmtpConfiguration.getKeyStoreAlias(), - smtpConfiguration.getKeyStorePassword().toCharArray()); - certificates = (X509Certificate[])keyStore.getCertificateChain(mailSmtpConfiguration.getKeyStoreAlias()); + smtpConfiguration.getKeyStorePasswordDecrypted().toCharArray()); + certificates = keyStore.getCertificateChain(mailSmtpConfiguration.getKeyStoreAlias()); + if (certificates != null) { + x509Certificates = new X509Certificate[certificates.length]; + for (int i = 0; i < certificates.length; i++) { + x509Certificates[i] = (X509Certificate)certificates[i]; + } + } } catch (Exception e) { log.error(e.getMessage()); } @@ -365,7 +373,7 @@ protected PasswordAuthentication getPasswordAuthentication() { // Set Multipart as the message's content msg.setContent(mp); - MimeMultipart multiPart = createMultipartWithSignature(privateKey, certificates, smtpConfiguration.getSigningAlgorithm(), msg); + MimeMultipart multiPart = createMultipartWithSignature(privateKey, x509Certificates, smtpConfiguration.getSigningAlgorithm(), msg); msg.setContent(multiPart); } diff --git a/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java b/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java index e0ed1678..f5baf736 100644 --- a/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java +++ b/oxUtil/src/main/java/org/gluu/model/SmtpConfiguration.java @@ -58,6 +58,10 @@ public class SmtpConfiguration implements java.io.Serializable { @JsonProperty("key-store-password") private String keyStorePassword; + @Transient + @JsonIgnore + private String keyStorePasswordDecrypted; + @JsonProperty("key-store-alias") private String keyStoreAlias; @@ -170,6 +174,14 @@ public void setKeyStorePassword(String keyStorePassword) { this.keyStorePassword = keyStorePassword; } + public String getKeyStorePasswordDecrypted() { + return keyStorePasswordDecrypted; + } + + public void setKeyStorePasswordDecrypted(String keyStorePasswordDecrypted) { + this.keyStorePasswordDecrypted = keyStorePasswordDecrypted; + } + public String getKeyStoreAlias() { return keyStoreAlias; } From a6b41e875a94ef3dc6baf6448551731d4d96a1be Mon Sep 17 00:00:00 2001 From: SMan Date: Mon, 17 Oct 2022 19:07:40 -0500 Subject: [PATCH 317/362] fix: formatting has been updated; --- .../main/java/org/gluu/model/SmtpConnectProtectionType.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java b/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java index 9ae88bbb..245a70f8 100644 --- a/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java +++ b/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java @@ -10,7 +10,7 @@ /** * @author Sergey Manoylo - * @version + * @version 06/24/2022 */ public enum SmtpConnectProtectionType implements AttributeEnum { @@ -37,7 +37,7 @@ private SmtpConnectProtectionType(String value, String displayName) { this.displayName = displayName; } - @Override + @Override public String getValue() { return value; } @@ -50,7 +50,7 @@ public static SmtpConnectProtectionType getByValue(String value) { return mapByValues.get(value); } - @Override + @Override public Enum resolveByValue(String value) { return getByValue(value); } From 2fdecbcee4bd389d7fbd250164e5915fc7668014 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Sun, 23 Oct 2022 11:47:44 +0530 Subject: [PATCH 318/362] feat(oxtrust-server): remove files from ldifStore #2225 --- .../java/org/gluu/config/oxtrust/AppConfiguration.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index 96e7a4bb..ead578b5 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -46,6 +46,8 @@ public class AppConfiguration implements Configuration, Serializable { private String[] contactObjectClassDisplayNames; private String ldifStore; + + private int keepLdifStoreHistoryDays; private boolean updateStatus; @@ -955,4 +957,12 @@ public List getAdminUiLocaleSupported() { public void setAdminUiLocaleSupported(List adminUiLocaleSupported) { this.adminUiLocaleSupported = adminUiLocaleSupported; } + + public int getKeepLdifStoreHistoryDays() { + return keepLdifStoreHistoryDays; + } + + public void setKeepLdifStoreHistoryDays(int keepLdifStoreHistoryDays) { + this.keepLdifStoreHistoryDays = keepLdifStoreHistoryDays; + } } From f5895bd2d5980b663725790092a539c32a81d242 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Tue, 25 Oct 2022 00:04:55 +0530 Subject: [PATCH 319/362] fix(oxtrust-server): duplicated saml config files after restarts --- .../provider/DBDocumentStoreProvider.java | 70 ++++++++++++------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index 363fec04..fcd34c47 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -86,21 +86,29 @@ public boolean hasDocument(String DisplayName) { @Override public boolean saveDocument(String name, String documentContent, Charset charset, List moduleList) { log.debug("Save document: '{}'", name); - OxDocument oxDocument = new OxDocument(); - oxDocument.setDocument(documentContent); - oxDocument.setDisplayName(name); try { - try { - oxDocument.setInum(documentService.generateInumForNewOxDocument()); - String dn = "inum="+ oxDocument.getInum() +",ou=document,o=gluu"; + boolean update = true; + OxDocument oxDocument = documentService.getOxDocumentByDisplayName(name); + if (oxDocument == null) { + update = false; + oxDocument = new OxDocument(); + oxDocument.setDisplayName(name); + oxDocument.setInum(documentService.generateInumForNewOxDocument()); + String dn = "inum=" + oxDocument.getInum() + ",ou=document,o=gluu"; oxDocument.setDn(dn); - oxDocument.setDescription(name); - oxDocument.setOxEnabled("true"); - oxDocument.setOxModuleProperty(moduleList); - documentService.addOxDocument(oxDocument); - return true; - } finally { } + + oxDocument.setDocument(documentContent); + oxDocument.setDescription(name); + oxDocument.setOxEnabled("true"); + oxDocument.setOxModuleProperty(moduleList); + + if (update) + documentService.updateOxDocument(oxDocument); + else + documentService.addOxDocument(oxDocument); + return true; + } catch (Exception ex) { log.error("Failed to write document to file '{}'", name, ex); } @@ -109,29 +117,39 @@ public boolean saveDocument(String name, String documentContent, Charset charset } @Override - public boolean saveDocumentStream(String name, InputStream documentStream, List moduleList) { - - //log.debug("Save document from stream: '{}'", name); - OxDocument oxDocument = new OxDocument(); - oxDocument.setDisplayName(name); - - try { + public boolean saveDocumentStream(String name, InputStream documentStream, List moduleList) { + try { + // log.debug("Save document from stream: '{}'", name); + boolean update = true; + OxDocument oxDocument = documentService.getOxDocumentByDisplayName(name); + if (oxDocument == null) { + update = false; + oxDocument = new OxDocument(); + oxDocument.setDisplayName(name); + + String inum = documentService.generateInumForNewOxDocument(); + oxDocument.setInum(inum); + + String dn = "inum=" + oxDocument.getInum() + ",ou=document,o=gluu"; + oxDocument.setDn(dn); + } String documentContent = Base64.getEncoder().encodeToString(IOUtils.toByteArray(documentStream)); oxDocument.setDocument(documentContent); - String inum = documentService.generateInumForNewOxDocument(); - oxDocument.setInum(inum); - String dn = "inum="+ oxDocument.getInum() +",ou=document,o=gluu"; - oxDocument.setDn(dn); oxDocument.setDescription(name); oxDocument.setOxEnabled("true"); oxDocument.setOxModuleProperty(moduleList); - documentService.addOxDocument(oxDocument); + + if(update) + documentService.updateOxDocument(oxDocument); + else + documentService.addOxDocument(oxDocument); + return true; } catch (IOException e) { log.error("Failed to write document from stream to file '{}'", name, e); - }catch (Exception e) { + } catch (Exception e) { log.error("Failed to write document from stream to file '{}'", name, e); - } + } return false; } From b880ab17d43c1c38aaaf7389c1d18820b0022f4a Mon Sep 17 00:00:00 2001 From: SMan Date: Mon, 24 Oct 2022 23:54:07 -0500 Subject: [PATCH 320/362] refactor: class smtp_connect_protection_type has been updated (according to sonar requirements); --- .../src/main/java/org/gluu/service/MailService.java | 10 +++++----- .../java/org/gluu/model/SmtpConnectProtectionType.java | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/MailService.java b/oxService/src/main/java/org/gluu/service/MailService.java index bfbaa19a..93c1892c 100644 --- a/oxService/src/main/java/org/gluu/service/MailService.java +++ b/oxService/src/main/java/org/gluu/service/MailService.java @@ -155,13 +155,13 @@ public boolean sendMail(SmtpConfiguration mailSmtpConfiguration, String from, St SmtpConnectProtectionType smtpConnectProtect = mailSmtpConfiguration.getConnectProtection(); - if (smtpConnectProtect == SmtpConnectProtectionType.StartTls) { + if (smtpConnectProtect == SmtpConnectProtectionType.START_TLS) { props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); props.put("mail.smtp.starttls.enable", true); } - else if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { + else if (smtpConnectProtect == SmtpConnectProtectionType.SSL_TLS) { props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); props.put("mail.smtp.socketFactory.port", mailSmtpConfiguration.getPort()); props.put("mail.smtp.ssl.trust", mailSmtpConfiguration.getHost()); @@ -282,7 +282,7 @@ public boolean sendMailSigned(SmtpConfiguration mailSmtpConfiguration, String fr SmtpConnectProtectionType smtpConnectProtect = mailSmtpConfiguration.getConnectProtection(); - if (smtpConnectProtect == SmtpConnectProtectionType.StartTls) { + if (smtpConnectProtect == SmtpConnectProtectionType.START_TLS) { props.put("mail.transport.protocol", "smtp"); props.put("mail.smtp.host", mailSmtpConfiguration.getHost()); @@ -298,7 +298,7 @@ public boolean sendMailSigned(SmtpConfiguration mailSmtpConfiguration, String fr props.put("mail.smtp.starttls.enable", true); props.put("mail.smtp.starttls.required", true); } - else if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { + else if (smtpConnectProtect == SmtpConnectProtectionType.SSL_TLS) { props.put("mail.transport.protocol.rfc822", "smtps"); props.put("mail.smtps.host", mailSmtpConfiguration.getHost()); @@ -325,7 +325,7 @@ else if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { Session session = null; if (mailSmtpConfiguration.isRequiresAuthentication()) { - if (smtpConnectProtect == SmtpConnectProtectionType.SslTls) { + if (smtpConnectProtect == SmtpConnectProtectionType.SSL_TLS) { props.put("mail.smtps.auth", "true"); } else { diff --git a/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java b/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java index 245a70f8..67dbad0d 100644 --- a/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java +++ b/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java @@ -14,12 +14,12 @@ */ public enum SmtpConnectProtectionType implements AttributeEnum { - None("None", "NONE"), StartTls("StartTls", "STARTTLS"), SslTls("SslTls", "SSL/TLS"); + NONE("None", "NONE"), START_TLS("StartTls", "STARTTLS"), SSL_TLS("SslTls", "SSL/TLS"); private String value; private String displayName; - - private static final Map mapByValues = new HashMap(); + + private static final Map mapByValues = new HashMap<>(); static { for (SmtpConnectProtectionType enumType : values()) { @@ -58,5 +58,5 @@ public Enum resolveByValue(String value) { @Override public String toString() { return value; - } + } } From 7fabe5bf43df6f8aa4fb13a06060b2b2da86c318 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Thu, 27 Oct 2022 20:45:25 +0530 Subject: [PATCH 321/362] fix(oxtrust-server): fix for oxEnable field oxtrust issue 2256 --- .../document/store/provider/DBDocumentStoreProvider.java | 4 ++-- .../org/gluu/service/document/store/service/OxDocument.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index fcd34c47..35ef3cc4 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -100,7 +100,7 @@ public boolean saveDocument(String name, String documentContent, Charset charset oxDocument.setDocument(documentContent); oxDocument.setDescription(name); - oxDocument.setOxEnabled("true"); + oxDocument.setOxEnabled(true); oxDocument.setOxModuleProperty(moduleList); if (update) @@ -136,7 +136,7 @@ public boolean saveDocumentStream(String name, InputStream documentStream, List< String documentContent = Base64.getEncoder().encodeToString(IOUtils.toByteArray(documentStream)); oxDocument.setDocument(documentContent); oxDocument.setDescription(name); - oxDocument.setOxEnabled("true"); + oxDocument.setOxEnabled(true); oxDocument.setOxModuleProperty(moduleList); if(update) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java b/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java index 0f8ba187..a2b74be7 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java @@ -58,7 +58,7 @@ public class OxDocument extends Entry implements Serializable { private String oxRevision; @AttributeName - private String oxEnabled; + private boolean oxEnabled; @AttributeName private String oxAlias; @@ -127,11 +127,11 @@ public void setOxRevision(String oxRevision) { this.oxRevision = oxRevision; } - public String getOxEnabled() { + public boolean getOxEnabled() { return oxEnabled; } - public void setOxEnabled(String oxEnabled) { + public void setOxEnabled(boolean oxEnabled) { this.oxEnabled = oxEnabled; } From d4fe38f2d9976850feec77c589c9d9dc90f73b24 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Mon, 7 Nov 2022 11:48:56 +0300 Subject: [PATCH 322/362] feat: for file based scripts check both script revision and file modification time jans: #2877 --- .../org/gluu/service/custom/script/CustomScriptManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java index 409aec07..67f4bb50 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java @@ -233,7 +233,7 @@ private ReloadResult reloadCustomScriptConfigurations( // reload script automatically after changing location_type long fileModifiactionTime = getFileModificationTime(newCustomScript.getLocationPath()); - newCustomScript.setRevision(fileModifiactionTime); + newCustomScript.setRevision(newCustomScript.getRevision() + fileModifiactionTime); } String newSupportedCustomScriptInum = StringHelper.toLowerCase(newCustomScript.getInum()); From bf6275bbff939d9bd7efce02a33cc42be8f0a53c Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Mon, 28 Nov 2022 22:10:30 +0530 Subject: [PATCH 323/362] feat : added oauth protection on oxtrust apis --- .../java/org/gluu/config/oxtrust/AppConfiguration.java | 9 +++++++++ .../java/org/gluu/config/oxtrust/OxTrustApiMode.java | 3 +++ 2 files changed, 12 insertions(+) create mode 100644 oxService/src/main/java/org/gluu/config/oxtrust/OxTrustApiMode.java diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index ead578b5..11210313 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -168,6 +168,7 @@ public class AppConfiguration implements Configuration, Serializable { private Boolean useLocalCache = false; private boolean passIdTokenHintToLogoutRedirectUri = false; + private OxTrustApiMode oxTrustProtectionMode; public ScimProperties getScimProperties() { return scimProperties; @@ -965,4 +966,12 @@ public int getKeepLdifStoreHistoryDays() { public void setKeepLdifStoreHistoryDays(int keepLdifStoreHistoryDays) { this.keepLdifStoreHistoryDays = keepLdifStoreHistoryDays; } + + public OxTrustApiMode getOxTrustProtectionMode() { + return oxTrustProtectionMode; + } + + public void setOxTrustProtectionMode(OxTrustApiMode oxTrustProtectionMode) { + this.oxTrustProtectionMode = oxTrustProtectionMode; + } } diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/OxTrustApiMode.java b/oxService/src/main/java/org/gluu/config/oxtrust/OxTrustApiMode.java new file mode 100644 index 00000000..81de7310 --- /dev/null +++ b/oxService/src/main/java/org/gluu/config/oxtrust/OxTrustApiMode.java @@ -0,0 +1,3 @@ +package org.gluu.config.oxtrust; + +public enum OxTrustApiMode { OAUTH, TEST, UMA }; From ad0bd07646710a446da794d02dd0a94251bcdedf Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Tue, 6 Dec 2022 00:22:09 +0200 Subject: [PATCH 324/362] feat: added aes util (#256) https://github.com/GluuFederation/oxCore/issues/255 --- .../java/org/gluu/util/security/AESUtil.java | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 oxUtil/src/main/java/org/gluu/util/security/AESUtil.java diff --git a/oxUtil/src/main/java/org/gluu/util/security/AESUtil.java b/oxUtil/src/main/java/org/gluu/util/security/AESUtil.java new file mode 100644 index 00000000..7cdd8d44 --- /dev/null +++ b/oxUtil/src/main/java/org/gluu/util/security/AESUtil.java @@ -0,0 +1,89 @@ +package org.gluu.util.security; + +import javax.crypto.*; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.util.Base64; + +public class AESUtil { + + public static final int IV_LENGTH = 16; + public static final int GCM_TAG_LENGTH = 16; + + public static SecretKey generateKey(int n) throws NoSuchAlgorithmException { + KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); + keyGenerator.init(n); + return keyGenerator.generateKey(); + } + + public static SecretKey getKeyFromPassword(String password, String salt) + throws NoSuchAlgorithmException, InvalidKeySpecException { + SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); + KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), 65536, 256); + return new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES"); + } + + public static IvParameterSpec generateIv() { + return generateIv(IV_LENGTH); + } + + public static IvParameterSpec generateIv(int size) { + byte[] iv = new byte[size]; + new SecureRandom().nextBytes(iv); + return new IvParameterSpec(iv); + } + + public static GCMParameterSpec generateGcmSpec() { + return new GCMParameterSpec(GCM_TAG_LENGTH * 8, generateIv().getIV()); + } + + + public static String encrypt(String algorithm, String input, SecretKey key, AlgorithmParameterSpec spec) throws NoSuchPaddingException, NoSuchAlgorithmException, + InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + + Cipher cipher = Cipher.getInstance(algorithm); + cipher.init(Cipher.ENCRYPT_MODE, key, spec); + byte[] cipherText = cipher.doFinal(input.getBytes()); + return Base64.getEncoder().encodeToString(cipherText); + } + + public static String decrypt(String algorithm, String cipherText, SecretKey key, AlgorithmParameterSpec spec) throws NoSuchPaddingException, NoSuchAlgorithmException, + InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + Cipher cipher = Cipher.getInstance(algorithm); + cipher.init(Cipher.DECRYPT_MODE, key, spec); + byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(cipherText)); + return new String(plainText); + } + + /* + public static void main(String[] args) throws NoSuchPaddingException, InvalidKeyException, NoSuchAlgorithmException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException { + String input = "textToEncrypt"; + SecretKey key = AESUtil.generateKey(128); + IvParameterSpec ivParameterSpec = AESUtil.generateIv(); + + // CBC + String algorithm = "AES/CBC/PKCS5Padding"; + String cipherText = AESUtil.encrypt(algorithm, input, key, ivParameterSpec); + String plainText = AESUtil.decrypt(algorithm, cipherText, key, ivParameterSpec); + boolean equals = input.equals(plainText); + System.out.println(equals); + + // GCM + algorithm = "AES/GCM/NoPadding"; + final GCMParameterSpec gcmSpec = generateGcmSpec(); + cipherText = AESUtil.encrypt(algorithm, input, key, gcmSpec); + plainText = AESUtil.decrypt(algorithm, cipherText, key, gcmSpec); + equals = input.equals(plainText); + System.out.println(equals); + } + */ +} From a51d0efba2a69495cd9fef63669e3f1391cbcf83 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Tue, 6 Dec 2022 22:44:15 +0530 Subject: [PATCH 325/362] fix(oxtrust): duplicated SAML config files after restarts #2258 --- .../org/gluu/service/document/store/service/OxDocument.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java b/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java index a2b74be7..f78c9662 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/service/OxDocument.java @@ -58,7 +58,7 @@ public class OxDocument extends Entry implements Serializable { private String oxRevision; @AttributeName - private boolean oxEnabled; + private Boolean oxEnabled; @AttributeName private String oxAlias; @@ -127,11 +127,11 @@ public void setOxRevision(String oxRevision) { this.oxRevision = oxRevision; } - public boolean getOxEnabled() { + public Boolean getOxEnabled() { return oxEnabled; } - public void setOxEnabled(boolean oxEnabled) { + public void setOxEnabled(Boolean oxEnabled) { this.oxEnabled = oxEnabled; } From 03091dcca449ff04708cee3443fd5117baaa3a2d Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Mon, 26 Dec 2022 20:50:22 +0300 Subject: [PATCH 326/362] Branch for version 4.6.0 --- core-cache/pom.xml | 2 +- core-cdi/pom.xml | 2 +- core-document-store/pom.xml | 2 +- core-java-ext/pom.xml | 2 +- core-script/pom.xml | 2 +- core-standalone/pom.xml | 2 +- core-timer-weld/pom.xml | 2 +- demo-cdi/pom.xml | 2 +- exception-extension-cdi/pom.xml | 2 +- oxJsfUtil/pom.xml | 2 +- oxModel/pom.xml | 2 +- oxRadius/pom.xml | 2 +- oxSaml/pom.xml | 2 +- oxService/pom.xml | 2 +- oxUtil/pom.xml | 2 +- pom.xml | 4 ++-- security-extension-cdi/pom.xml | 2 +- server/pom.xml | 2 +- 18 files changed, 19 insertions(+), 19 deletions(-) diff --git a/core-cache/pom.xml b/core-cache/pom.xml index 4f859785..6743bbe2 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/core-cdi/pom.xml b/core-cdi/pom.xml index ffb04be8..3c08d1af 100644 --- a/core-cdi/pom.xml +++ b/core-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index 2c1e9c11..2c73fc07 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/core-java-ext/pom.xml b/core-java-ext/pom.xml index 04eac55d..88b0daca 100644 --- a/core-java-ext/pom.xml +++ b/core-java-ext/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/core-script/pom.xml b/core-script/pom.xml index 79980813..592d8d1c 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/core-standalone/pom.xml b/core-standalone/pom.xml index 242c6928..3ce4a8df 100644 --- a/core-standalone/pom.xml +++ b/core-standalone/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/core-timer-weld/pom.xml b/core-timer-weld/pom.xml index d91bf860..94233100 100644 --- a/core-timer-weld/pom.xml +++ b/core-timer-weld/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index 1e6dd0fd..b79652b5 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/exception-extension-cdi/pom.xml b/exception-extension-cdi/pom.xml index 58d92692..544a4d14 100644 --- a/exception-extension-cdi/pom.xml +++ b/exception-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index c09fe435..17b799a7 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/oxModel/pom.xml b/oxModel/pom.xml index 60dbf61d..9c0b41f9 100644 --- a/oxModel/pom.xml +++ b/oxModel/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/oxRadius/pom.xml b/oxRadius/pom.xml index b8269a68..ad0d1686 100644 --- a/oxRadius/pom.xml +++ b/oxRadius/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index bc302c14..80b46046 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/oxService/pom.xml b/oxService/pom.xml index 4ec8b414..5793d59c 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index baf7d4e5..b887244a 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/pom.xml b/pom.xml index cf8eb286..9972b04d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.gluu oxcore pom - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT oxCore https://www.gluu.org @@ -50,7 +50,7 @@ org.gluu gluu-core-bom - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT import pom diff --git a/security-extension-cdi/pom.xml b/security-extension-cdi/pom.xml index d32d6dd2..e3504c8b 100644 --- a/security-extension-cdi/pom.xml +++ b/security-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT diff --git a/server/pom.xml b/server/pom.xml index e5b2b315..f4dbf0f0 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.0-SNAPSHOT + 4.6.0-SNAPSHOT From d358637aca4ab07900125df8cc9b399ea0832e8d Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Thu, 5 Jan 2023 20:19:49 +0300 Subject: [PATCH 327/362] fix: login page doesn't display the correct localized characters #1660 --- .../java/org/gluu/jsf2/message/FacesMessages.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/oxJsfUtil/src/main/java/org/gluu/jsf2/message/FacesMessages.java b/oxJsfUtil/src/main/java/org/gluu/jsf2/message/FacesMessages.java index 2d910a32..51151f96 100644 --- a/oxJsfUtil/src/main/java/org/gluu/jsf2/message/FacesMessages.java +++ b/oxJsfUtil/src/main/java/org/gluu/jsf2/message/FacesMessages.java @@ -17,6 +17,7 @@ import javax.inject.Inject; import org.apache.commons.text.StringEscapeUtils; +import org.gluu.orm.util.StringHelper; import org.gluu.service.el.ExpressionEvaluator; /** @@ -49,12 +50,20 @@ public void add(Severity severity, String message) { } public void add(String clientId, Severity severity, String message) { + boolean escape = StringHelper.isNotEmpty(clientId); + add(clientId, severity, message, escape); + } + + public void add(String clientId, Severity severity, String message, boolean escape) { if (facesContext == null) { return; } String evaluatedMessage = evalAsString(message); - String encodedMessage = StringEscapeUtils.escapeHtml4(evaluatedMessage); + String encodedMessage = evaluatedMessage; + if (escape) { + encodedMessage = StringEscapeUtils.escapeHtml4(evaluatedMessage); + } FacesMessage facesMessage = new FacesMessage(severity, encodedMessage, encodedMessage); facesContext.addMessage(clientId, facesMessage); From ef68d625ef93f456eb3e6ace2b679d54c070a215 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Thu, 5 Jan 2023 22:57:45 +0530 Subject: [PATCH 328/362] fix(oxtrust-server): format of generated Shibboleth files --- .../document/store/provider/DBDocumentStoreProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index 35ef3cc4..2b2d6a13 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Base64; import java.util.List; @@ -133,7 +134,7 @@ public boolean saveDocumentStream(String name, InputStream documentStream, List< String dn = "inum=" + oxDocument.getInum() + ",ou=document,o=gluu"; oxDocument.setDn(dn); } - String documentContent = Base64.getEncoder().encodeToString(IOUtils.toByteArray(documentStream)); + String documentContent = new String(documentStream.readAllBytes(), StandardCharsets.UTF_8); oxDocument.setDocument(documentContent); oxDocument.setDescription(name); oxDocument.setOxEnabled(true); From 2d4d72bf5de8335912c01c22653885762930a51f Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Fri, 6 Jan 2023 00:09:58 +0300 Subject: [PATCH 329/362] chore: use utility from core lib --- .../src/main/java/org/gluu/jsf2/message/FacesMessages.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxJsfUtil/src/main/java/org/gluu/jsf2/message/FacesMessages.java b/oxJsfUtil/src/main/java/org/gluu/jsf2/message/FacesMessages.java index 51151f96..9d2879da 100644 --- a/oxJsfUtil/src/main/java/org/gluu/jsf2/message/FacesMessages.java +++ b/oxJsfUtil/src/main/java/org/gluu/jsf2/message/FacesMessages.java @@ -17,8 +17,8 @@ import javax.inject.Inject; import org.apache.commons.text.StringEscapeUtils; -import org.gluu.orm.util.StringHelper; import org.gluu.service.el.ExpressionEvaluator; +import org.gluu.util.StringHelper; /** * @author Yuriy Movchan From 24e3841d5a8b460c880c3c8c1a29f6908b2f27ce Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Mon, 23 Jan 2023 02:03:43 +0530 Subject: [PATCH 330/362] feat(oxtrust-server): added audit log location property --- .../gluu/config/oxtrust/AppConfiguration.java | 9 +++++++ .../java/org/gluu/model/LocaleSupported.java | 25 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index 11210313..b16c87bd 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -169,6 +169,7 @@ public class AppConfiguration implements Configuration, Serializable { private boolean passIdTokenHintToLogoutRedirectUri = false; private OxTrustApiMode oxTrustProtectionMode; + private String auditLogsLocation; public ScimProperties getScimProperties() { return scimProperties; @@ -974,4 +975,12 @@ public OxTrustApiMode getOxTrustProtectionMode() { public void setOxTrustProtectionMode(OxTrustApiMode oxTrustProtectionMode) { this.oxTrustProtectionMode = oxTrustProtectionMode; } + + public String getAuditLogsLocation() { + return auditLogsLocation; + } + + public void setAuditLogsLocation(String auditLogsLocation) { + this.auditLogsLocation = auditLogsLocation; + } } diff --git a/oxService/src/main/java/org/gluu/model/LocaleSupported.java b/oxService/src/main/java/org/gluu/model/LocaleSupported.java index c3a009f5..c3229ef3 100644 --- a/oxService/src/main/java/org/gluu/model/LocaleSupported.java +++ b/oxService/src/main/java/org/gluu/model/LocaleSupported.java @@ -1,5 +1,7 @@ package org.gluu.model; +import java.util.Objects; + public class LocaleSupported { private String locale; @@ -19,11 +21,34 @@ public String getLocale() { public void setLocale(String locale) { this.locale = locale; } + public String getDisplayName() { return displayName; } public void setDisplayName(String displayName) { this.displayName = displayName; } + + @Override + public int hashCode() { + return Objects.hash(displayName, locale); + } + + @Override + public String toString() { + return "LocaleSupported [locale=" + locale + ", displayName=" + displayName + "]"; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + LocaleSupported other = (LocaleSupported) obj; + return Objects.equals(displayName, other.displayName) && Objects.equals(locale, other.locale); + } } From bbfc404aafbc7da22373743232371da97df2d20a Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Tue, 24 Jan 2023 00:10:12 +0530 Subject: [PATCH 331/362] feat(oxtrust-server): changed the variable name --- .../java/org/gluu/config/oxtrust/AppConfiguration.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index b16c87bd..9d348ff9 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -169,7 +169,7 @@ public class AppConfiguration implements Configuration, Serializable { private boolean passIdTokenHintToLogoutRedirectUri = false; private OxTrustApiMode oxTrustProtectionMode; - private String auditLogsLocation; + private String auditConfigLogsLocation; public ScimProperties getScimProperties() { return scimProperties; @@ -976,11 +976,11 @@ public void setOxTrustProtectionMode(OxTrustApiMode oxTrustProtectionMode) { this.oxTrustProtectionMode = oxTrustProtectionMode; } - public String getAuditLogsLocation() { - return auditLogsLocation; + public String getAuditConfigLogsLocation() { + return auditConfigLogsLocation; } - public void setAuditLogsLocation(String auditLogsLocation) { - this.auditLogsLocation = auditLogsLocation; + public void setAuditConfigLogsLocation(String auditConfigLogsLocation) { + this.auditConfigLogsLocation = auditConfigLogsLocation; } } From 638ecd4a965dfab2efec5acd69d07db728678cf2 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Thu, 26 Jan 2023 21:57:37 +0300 Subject: [PATCH 332/362] fix: set correct revision of script reloaded from file system --- .../org/gluu/service/custom/script/CustomScriptManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java index 67f4bb50..cc40f50d 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java @@ -270,7 +270,7 @@ private ReloadResult reloadCustomScriptConfigurations( // Replace script revision with file modification time. This should allow to // reload script automatically after changing location_type long fileModifiactionTime = getFileModificationTime(loadedCustomScript.getLocationPath()); - loadedCustomScript.setRevision(fileModifiactionTime); + loadedCustomScript.setRevision(loadedCustomScript.getRevision() + fileModifiactionTime); if (fileModifiactionTime != 0) { String scriptFromFile = loadFromFile(loadedCustomScript.getLocationPath()); From 393e32ab3efb1ec447e4edb4775a43c70dba036d Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Thu, 6 Apr 2023 19:36:42 +0300 Subject: [PATCH 333/362] feat: CR should support person loads from AD servers with different primary key attribute names #2333 --- .../model/custom/script/type/user/CacheRefreshType.java | 2 ++ .../custom/script/type/user/DummyCacheRefreshType.java | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java index 878ee8cc..6ff5108f 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/user/CacheRefreshType.java @@ -24,4 +24,6 @@ public interface CacheRefreshType extends BaseExternalType { public boolean updateUser(Object person, Map configurationAttributes); + public boolean updateSourceUser(Object person, Map configurationAttributes); + } diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java index bb8c70da..a89966b2 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/user/DummyCacheRefreshType.java @@ -32,7 +32,7 @@ public boolean destroy(Map configurationAttributes @Override public int getApiVersion() { - return 2; + return 3; } @Override @@ -40,6 +40,11 @@ public boolean updateUser(Object person, Map confi return false; } + @Override + public boolean updateSourceUser(Object person, Map configurationAttributes) { + return false; + } + @Override public BindCredentials getBindCredentials(String configId, Map configurationAttributes) { return null; From d4d411d8ef1a78f55077e74a5324e407a873e299 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Fri, 7 Apr 2023 21:20:58 +0300 Subject: [PATCH 334/362] chore: fix default config API settings --- .../java/org/gluu/config/oxtrust/AppConfiguration.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java index 9d348ff9..92352ceb 100644 --- a/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java +++ b/oxService/src/main/java/org/gluu/config/oxtrust/AppConfiguration.java @@ -117,7 +117,7 @@ public class AppConfiguration implements Configuration, Serializable { private String apiUmaClientId; private String apiUmaClientKeyId; private String apiUmaResourceId; - private String[] apiUmaScopes; + private String apiUmaScope; private String apiUmaClientKeyStoreFile; private String apiUmaClientKeyStorePassword; @@ -834,12 +834,12 @@ public void setApiUmaResourceId(String apiUmaResourceId) { this.apiUmaResourceId = apiUmaResourceId; } - public String[] getApiUmaScopes() { - return apiUmaScopes; + public String getApiUmaScope() { + return apiUmaScope; } - public void setApiUmaScopes(String[] apiUmaScopes) { - this.apiUmaScopes = apiUmaScopes; + public void setApiUmaScope(String apiUmaScope) { + this.apiUmaScope = apiUmaScope; } /** From 4bca75804fe683d13ac2fbb6107d732a7ed96d54 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Wed, 19 Apr 2023 13:40:07 +0300 Subject: [PATCH 335/362] fix: cors filter should not store in local variable allowed origins oxAuth #1773 --- .../server/filters/AbstractCorsFilter.java | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java b/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java index a7374a75..71d881f8 100644 --- a/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java +++ b/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java @@ -178,7 +178,7 @@ protected void handleSimpleCORS(final HttpServletRequest request, final String method = request.getMethod(); // Section 6.1.2 - if (!isOriginAllowed(origin)) { + if (!isOriginAllowed(request, origin)) { handleInvalidCORS(request, response, filterChain); return; } @@ -190,7 +190,7 @@ protected void handleSimpleCORS(final HttpServletRequest request, // Section 6.1.3 // Add a single Access-Control-Allow-Origin header. - if (isAnyOriginAllowed() && !supportsCredentials) { + if (isAnyOriginAllowed(request) && !supportsCredentials) { // If resource doesn't support credentials and if any origin is // allowed // to make CORS request, return header with '*'. @@ -256,7 +256,7 @@ protected void handlePreflightCORS(final HttpServletRequest request, .getHeader(AbstractCorsFilter.REQUEST_HEADER_ORIGIN); // Section 6.2.2 - if (!isOriginAllowed(origin)) { + if (!isOriginAllowed(request, origin)) { handleInvalidCORS(request, response, filterChain); return; } @@ -310,7 +310,7 @@ protected void handlePreflightCORS(final HttpServletRequest request, AbstractCorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); } else { - if (isAnyOriginAllowed()) { + if (isAnyOriginAllowed(request)) { response.addHeader( AbstractCorsFilter.RESPONSE_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, "*"); @@ -583,17 +583,23 @@ protected CORSRequestType checkRequestType(final HttpServletRequest request) { * Checks if the Origin is allowed to make a CORS request. * * @param origin The Origin. + * @param request * @return true if origin is allowed; false * otherwise. */ - private boolean isOriginAllowed(final String origin) { - if (isAnyOriginAllowed()) { + private boolean isOriginAllowed(ServletRequest servletRequest, final String origin) { + if (isAnyOriginAllowed(servletRequest)) { return true; } // If 'Origin' header is a case-sensitive match of any of allowed // origins, then return true, else return false. - return allowedOrigins.contains(origin); + if ((allowedOrigins != null) && allowedOrigins.contains(origin)) { + return true; + } + + Collection clientAllowedOrigins = getContextClientAllowedOrigins(servletRequest); + return (clientAllowedOrigins != null) && clientAllowedOrigins.contains(origin); } @@ -735,14 +741,25 @@ protected static boolean isValidOrigin(String origin) { * * @return true if it's enabled; false otherwise. */ - public boolean isAnyOriginAllowed() { - if (allowedOrigins != null && allowedOrigins.size() == 0) { + public boolean isAnyOriginAllowed(ServletRequest servletRequest) { + Collection clientAllowedOrigins = getContextClientAllowedOrigins(servletRequest); + + if ((allowedOrigins != null && allowedOrigins.size() == 0) && + (clientAllowedOrigins != null && clientAllowedOrigins.size() == 0)) { return true; } return false; } + protected void setContextClientAllowedOrigins(ServletRequest servletRequest, Collection clientAllowedOrigins) { + servletRequest.setAttribute(PARTAM_CLIENT_ALLOWED_ORIGINS, clientAllowedOrigins); + } + + @SuppressWarnings("unchecked") + protected Collection getContextClientAllowedOrigins(ServletRequest servletRequest) { + return (Collection) servletRequest.getAttribute(PARTAM_CLIENT_ALLOWED_ORIGINS); + } /** * Returns a {@link Set} of headers that should be exposed by browser. @@ -1086,6 +1103,8 @@ protected enum CORSRequestType { public static final String PARAM_CORS_REQUEST_DECORATE = "cors.request.decorate"; + public static final String PARTAM_CLIENT_ALLOWED_ORIGINS = "CLIENT_ALLOWED_ORIGINS"; + } final class StringManager { @@ -1286,6 +1305,7 @@ public static StringManager getManager(String packageName, // Return the default return getManager(packageName); } + } final class Constants { From 387a7558a2a074d051b82140ffd07da276837c23 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Wed, 19 Apr 2023 14:14:22 +0300 Subject: [PATCH 336/362] fix: cors filter should not store in local variable allowed origins oxAuth #1773 --- .../server/filters/AbstractCorsFilter.java | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java b/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java index 71d881f8..decfa155 100644 --- a/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java +++ b/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java @@ -15,6 +15,7 @@ import java.util.Enumeration; import java.util.HashSet; import java.util.Hashtable; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; @@ -741,24 +742,40 @@ protected static boolean isValidOrigin(String origin) { * * @return true if it's enabled; false otherwise. */ - public boolean isAnyOriginAllowed(ServletRequest servletRequest) { - Collection clientAllowedOrigins = getContextClientAllowedOrigins(servletRequest); + public boolean isAnyOriginAllowed(ServletRequest servletRequest) { + if (allowedOrigins != null && allowedOrigins.size() == 0) { + if (!hasContextClientAllowedOrigins(servletRequest)) { + return true; + } - if ((allowedOrigins != null && allowedOrigins.size() == 0) && - (clientAllowedOrigins != null && clientAllowedOrigins.size() == 0)) { - return true; - } + Collection clientAllowedOrigins = getContextClientAllowedOrigins(servletRequest); + if (clientAllowedOrigins != null && clientAllowedOrigins.size() == 0) { + return true; + } + } - return false; - } + return false; + } protected void setContextClientAllowedOrigins(ServletRequest servletRequest, Collection clientAllowedOrigins) { - servletRequest.setAttribute(PARTAM_CLIENT_ALLOWED_ORIGINS, clientAllowedOrigins); + servletRequest.setAttribute(PARAM_CLIENT_ALLOWED_ORIGINS, clientAllowedOrigins); } @SuppressWarnings("unchecked") protected Collection getContextClientAllowedOrigins(ServletRequest servletRequest) { - return (Collection) servletRequest.getAttribute(PARTAM_CLIENT_ALLOWED_ORIGINS); + return (Collection) servletRequest.getAttribute(PARAM_CLIENT_ALLOWED_ORIGINS); + } + + protected boolean hasContextClientAllowedOrigins(ServletRequest servletRequest) { + Enumeration attributeNames = servletRequest.getAttributeNames(); + while (attributeNames.hasMoreElements()) { + String attributeName = attributeNames.nextElement(); + if (PARAM_CLIENT_ALLOWED_ORIGINS.equals(attributeName)) { + return true; + } + } + + return false; } /** @@ -1103,7 +1120,7 @@ protected enum CORSRequestType { public static final String PARAM_CORS_REQUEST_DECORATE = "cors.request.decorate"; - public static final String PARTAM_CLIENT_ALLOWED_ORIGINS = "CLIENT_ALLOWED_ORIGINS"; + public static final String PARAM_CLIENT_ALLOWED_ORIGINS = "CLIENT_ALLOWED_ORIGINS"; } From cbe04e5a73eb34d004a58c8d3ee930a00cb4bb9f Mon Sep 17 00:00:00 2001 From: SMan Date: Thu, 20 Apr 2023 19:59:42 -0500 Subject: [PATCH 337/362] fix: SmtpConnectProtectionType has been updated; fix: serialization/deserialization annotations have been added; --- .../java/org/gluu/model/SmtpConnectProtectionType.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java b/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java index 67dbad0d..ba68af7c 100644 --- a/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java +++ b/oxUtil/src/main/java/org/gluu/model/SmtpConnectProtectionType.java @@ -8,6 +8,9 @@ import org.gluu.persist.annotation.AttributeEnum; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + /** * @author Sergey Manoylo * @version 06/24/2022 @@ -37,6 +40,11 @@ private SmtpConnectProtectionType(String value, String displayName) { this.displayName = displayName; } + @JsonCreator + public static SmtpConnectProtectionType forValues(String value) { + return getByValue(value); + } + @Override public String getValue() { return value; @@ -55,6 +63,7 @@ public Enum resolveByValue(String value) { return getByValue(value); } + @JsonValue @Override public String toString() { return value; From f636dde045bab1e454e173b7c016155307b0ca05 Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Fri, 28 Apr 2023 12:16:16 +0300 Subject: [PATCH 338/362] feat(oxcore): introduce new UpdateToken methods #1728 (#263) https://github.com/GluuFederation/oxAuth/issues/1728 --- .../type/token/DummyUpdateTokenType.java | 29 +++++++++++++++++-- .../script/type/token/UpdateTokenType.java | 10 +++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/token/DummyUpdateTokenType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/token/DummyUpdateTokenType.java index a17864ca..a165317c 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/token/DummyUpdateTokenType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/token/DummyUpdateTokenType.java @@ -6,11 +6,11 @@ package org.gluu.model.custom.script.type.token; -import java.util.Map; - import org.gluu.model.SimpleCustomProperty; import org.gluu.model.custom.script.model.CustomScript; +import java.util.Map; + /** * @author Yuriy Movchan */ @@ -41,4 +41,29 @@ public boolean modifyIdToken(Object jwr, Object tokenContext) { return false; } + @Override + public boolean modifyRefreshToken(Object refreshToken, Object tokenContext) { + return false; + } + + @Override + public boolean modifyAccessToken(Object accessToken, Object tokenContext) { + return false; + } + + @Override + public int getRefreshTokenLifetimeInSeconds(Object tokenContext) { + return 0; + } + + @Override + public int getIdTokenLifetimeInSeconds(Object context) { + return 0; + } + + @Override + public int getAccessTokenLifetimeInSeconds(Object context) { + return 0; + } + } diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/token/UpdateTokenType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/token/UpdateTokenType.java index 907d1812..dafae084 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/type/token/UpdateTokenType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/token/UpdateTokenType.java @@ -14,4 +14,14 @@ public interface UpdateTokenType extends BaseExternalType { boolean modifyIdToken(Object jsonWebResponse, Object tokenContext); + + boolean modifyRefreshToken(Object refreshToken, Object tokenContext); + + boolean modifyAccessToken(Object accessToken, Object tokenContext); + + int getRefreshTokenLifetimeInSeconds(Object tokenContext); + + int getIdTokenLifetimeInSeconds(Object context); + + int getAccessTokenLifetimeInSeconds(Object context); } From 1ba6e192a2d4706ba68e3b41680ad580726ce6f8 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Tue, 2 May 2023 22:13:58 +0530 Subject: [PATCH 339/362] fix(oxauth-server): on error pages currentdatetime is null --- oxService/src/main/java/org/gluu/service/util/PageService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/oxService/src/main/java/org/gluu/service/util/PageService.java b/oxService/src/main/java/org/gluu/service/util/PageService.java index 873ac64e..1e77bd8a 100644 --- a/oxService/src/main/java/org/gluu/service/util/PageService.java +++ b/oxService/src/main/java/org/gluu/service/util/PageService.java @@ -5,6 +5,7 @@ import java.util.Date; import javax.enterprise.context.ApplicationScoped; +import javax.inject.Named; import javax.servlet.http.HttpServletRequest; /** @@ -13,6 +14,7 @@ * @author Yuriy Movchan */ @ApplicationScoped +@Named public class PageService { private final String CURRENT_DATE_TIME_FORMATTER = "yyyy-MM-dd hh:mm:ss a"; From 44e95c587ab17fa27b22202c960adef8d8e0bc1e Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Tue, 2 May 2023 19:50:36 +0300 Subject: [PATCH 340/362] fix: remove commons-httpclient and classes which uses it --- oxUtil/pom.xml | 4 - .../util/EasySSLProtocolSocketFactory.java | 213 ------------------ .../org/gluu/util/io/HTTPFileDownloader.java | 89 -------- 3 files changed, 306 deletions(-) delete mode 100644 oxUtil/src/main/java/org/gluu/util/EasySSLProtocolSocketFactory.java delete mode 100644 oxUtil/src/main/java/org/gluu/util/io/HTTPFileDownloader.java diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index b887244a..81031959 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -62,10 +62,6 @@ commons-io commons-io - - commons-httpclient - commons-httpclient - org.apache.commons commons-exec diff --git a/oxUtil/src/main/java/org/gluu/util/EasySSLProtocolSocketFactory.java b/oxUtil/src/main/java/org/gluu/util/EasySSLProtocolSocketFactory.java deleted file mode 100644 index 9a5be686..00000000 --- a/oxUtil/src/main/java/org/gluu/util/EasySSLProtocolSocketFactory.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.util; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.net.UnknownHostException; - -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; - -import org.apache.commons.httpclient.ConnectTimeoutException; -import org.apache.commons.httpclient.HttpClientError; -import org.apache.commons.httpclient.params.HttpConnectionParams; -import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - *

- * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s that - * accept self-signed certificates. - *

- *

- * This socket factory SHOULD NOT be used for productive systems due to security - * reasons, unless it is a concious decision and you are perfectly aware of - * security implications of accepting self-signed certificates - *

- * - *

- * Example of using custom protocol socket factory for a specific host: - * - *

- * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
- *
- * URI uri = new URI("https://localhost/", true);
- * // use relative url only
- * GetMethod httpget = new GetMethod(uri.getPathQuery());
- * HostConfiguration hc = new HostConfiguration();
- * hc.setHost(uri.getHost(), uri.getPort(), easyhttps);
- * HttpClient client = new HttpClient();
- * client.executeMethod(hc, httpget);
- * 
- * - *

- *

- * Example of using custom protocol socket factory per default instead of the - * standard one: - * - *

- * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
- * Protocol.registerProtocol("https", easyhttps);
- *
- * HttpClient client = new HttpClient();
- * GetMethod httpget = new GetMethod("https://localhost/");
- * client.executeMethod(httpget);
- * 
- * - *

- * - * @author Oleg Kalnichevski - * - *

- * DISCLAIMER: HttpClient developers DO NOT actively support this - * component. The component is provided as a reference material, which - * may be inappropriate for use without additional customization. - *

- */ - -public class EasySSLProtocolSocketFactory implements ProtocolSocketFactory { - - /** Log object for this class. */ - private static final Log LOG = LogFactory.getLog(EasySSLProtocolSocketFactory.class); - - private SSLContext sslcontext = null; - - /** - * Constructor for EasySSLProtocolSocketFactory. - */ - public EasySSLProtocolSocketFactory() { - super(); - } - - protected SSLContext createEasySSLContext() { - try { - SSLContext context = SSLContext.getInstance("SSL"); - context.init(null, new TrustManager[] {new EasyX509TrustManager(null)}, null); - return context; - } catch (Exception e) { - LOG.error(e.getMessage(), e); - throw new HttpClientError(e.toString()); - } - } - - private SSLContext getSSLContext() { - if (this.sslcontext == null) { - this.sslcontext = createEasySSLContext(); - } - return this.sslcontext; - } - - /** - * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int) - */ - public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) - throws IOException, UnknownHostException { - - return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort); - } - - /** - * Attempts to get a new socket connection to the given host within the given - * time limit. - *

- * To circumvent the limitations of older JREs that do not support connect - * timeout a controller thread is executed. The controller thread attempts to - * create a new socket within the given limit of time. If socket constructor - * does not return until the timeout expires, the controller terminates and - * throws an {@link ConnectTimeoutException} - *

- * - * @param host - * the host name/IP - * @param port - * the port on the host - * @param localAddress - * the local host name/IP to bind the socket to - * @param localPort - * the port on the local machine - * @param params - * {@link HttpConnectionParams Http connection parameters} - * - * @return Socket a new socket - * - * @throws IOException - * if an I/O error occurs while creating the socket - * @throws UnknownHostException - * if the IP address of the host cannot be determined - */ - public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort, - final HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException { - if (params == null) { - throw new IllegalArgumentException("Parameters may not be null"); - } - int timeout = params.getConnectionTimeout(); - SocketFactory socketfactory = getSSLContext().getSocketFactory(); - if (timeout == 0) { - return socketfactory.createSocket(host, port, localAddress, localPort); - } else { - Socket socket = socketfactory.createSocket(); - SocketAddress localaddr = new InetSocketAddress(localAddress, localPort); - SocketAddress remoteaddr = new InetSocketAddress(host, port); - socket.bind(localaddr); - socket.connect(remoteaddr, timeout); - return socket; - } - } - - /** - * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int) - */ - public Socket createSocket(String host, int port) throws IOException, UnknownHostException { - return getSSLContext().getSocketFactory().createSocket(host, port); - } - - /** - * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean) - */ - public Socket createSocket(Socket socket, String host, int port, boolean autoClose) - throws IOException, UnknownHostException { - return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose); - } - - // public boolean equals(Object obj) { - // return ((obj != null) && - // obj.getClass().equals(EasySSLProtocolSocketFactory.class)); - // } - - // public int hashCode() { - // return EasySSLProtocolSocketFactory.class.hashCode(); - // } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - EasySSLProtocolSocketFactory that = (EasySSLProtocolSocketFactory) o; - - if (sslcontext != null ? !sslcontext.equals(that.sslcontext) : that.sslcontext != null) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - return sslcontext != null ? sslcontext.hashCode() : 0; - } -} diff --git a/oxUtil/src/main/java/org/gluu/util/io/HTTPFileDownloader.java b/oxUtil/src/main/java/org/gluu/util/io/HTTPFileDownloader.java deleted file mode 100644 index 0fa4d51c..00000000 --- a/oxUtil/src/main/java/org/gluu/util/io/HTTPFileDownloader.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. - * - * Copyright (c) 2014, Gluu - */ - -package org.gluu.util.io; - -import java.io.IOException; - -import org.apache.commons.httpclient.Credentials; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpStatus; -import org.apache.commons.httpclient.UsernamePasswordCredentials; -import org.apache.commons.httpclient.auth.AuthScope; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.protocol.Protocol; -import org.gluu.util.EasySSLProtocolSocketFactory; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author: Yuriy Movchan Date: 11.21.2010 - */ -public final class HTTPFileDownloader { - - private HTTPFileDownloader() { } - - private static final Logger LOG = LoggerFactory.getLogger(HTTPFileDownloader.class); - private static Protocol EASY_HTTPS; - - public static String getResource(String path, String contentType, String user, String password) { - boolean isUseAuthentication = (user != null) && (password != null); - - if (!path.contains("://")) { - path = "http://" + path; - } - String result = null; - - GetMethod method = new GetMethod(path); - try { - method.setRequestHeader("Accept", contentType); - - if (getEasyhttps() == null) { - setEasyhttps(new Protocol("https", new EasySSLProtocolSocketFactory(), 443)); - } - Protocol.registerProtocol("https", getEasyhttps()); - - final HttpClient httpClient; - if (isUseAuthentication) { - httpClient = createHttpClientWithBasicAuth(user, password); - } else { - httpClient = new HttpClient(); - } - - httpClient.executeMethod(method); - if (method.getStatusCode() == HttpStatus.SC_OK) { - result = method.getResponseBodyAsString(); - } - } catch (IOException ex) { - result = null; - LOG.error(String.format("Failed to get resource %s", path), ex); - } catch (Exception ex) { - result = null; - LOG.error(String.format("Failed to get resource %s", path), ex); - } finally { - method.releaseConnection(); - } - - return result; - } - - private static HttpClient createHttpClientWithBasicAuth(String userid, String password) { - Credentials credentials = new UsernamePasswordCredentials(userid, password); - HttpClient httpClient = new HttpClient(); - httpClient.getState().setCredentials(AuthScope.ANY, credentials); - httpClient.getParams().setAuthenticationPreemptive(true); - return httpClient; - } - - public static void setEasyhttps(Protocol easyhttps) { - HTTPFileDownloader.EASY_HTTPS = easyhttps; - } - - public static Protocol getEasyhttps() { - return EASY_HTTPS; - } - -} From bf60c2c7452bef02122ebd0fdecece7eb11e2874 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Tue, 2 May 2023 20:10:02 +0300 Subject: [PATCH 341/362] fix: update to use new http client libs --- core-cache/pom.xml | 4 -- .../saml/metadata/SAMLMetadataParser.java | 47 +++++++++++++++++-- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/core-cache/pom.xml b/core-cache/pom.xml index 6743bbe2..c0270533 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -82,10 +82,6 @@ commons-io commons-io
- - commons-httpclient - commons-httpclient - org.apache.httpcomponents httpcore diff --git a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java index 6b05fc6a..614ea3b2 100644 --- a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java +++ b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java @@ -5,11 +5,11 @@ */ package org.gluu.saml.metadata; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.io.StringBufferInputStream; import java.net.URL; import java.util.List; @@ -21,8 +21,17 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.config.CookieSpecs; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; import org.gluu.service.document.store.service.DocumentStoreService; -import org.gluu.util.io.HTTPFileDownloader; import org.slf4j.Logger; import org.xml.sax.SAXException; @@ -150,17 +159,45 @@ public EntityIDHandler parseMetadata(InputStream is) { return handler; } - public EntityIDHandler parseMetadata(URL metadataURL) { - String metadataFileContent = HTTPFileDownloader.getResource(metadataURL.toExternalForm(), "application/xml, text/xml", null, null); + public EntityIDHandler parseMetadata(URL metadataURL) throws ClientProtocolException, IOException { + HttpGet httpGet = new HttpGet(metadataURL.toExternalForm()); + httpGet.setHeader("Accept", "application/xml, text/xml"); + + byte[] metadataFileContent = null; + try ( CloseableHttpClient httpClient = HttpClients.custom() + .setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build()) + .build() ) { + HttpResponse httpResponse = httpClient.execute(httpGet); + metadataFileContent = getResponseContent(httpResponse); + } if (metadataFileContent == null) { return null; } - InputStream is = new StringBufferInputStream(metadataFileContent); + InputStream is = new ByteArrayInputStream(metadataFileContent); return parseMetadata(is); } + public byte[] getResponseContent(HttpResponse httpResponse) throws IOException { + if ((httpResponse == null) || (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK)) { + return null; + } + + HttpEntity entity = httpResponse.getEntity(); + byte[] responseBytes = new byte[0]; + if (entity != null) { + responseBytes = EntityUtils.toByteArray(entity); + } + + // Consume response content + if (entity != null) { + EntityUtils.consume(entity); + } + + return responseBytes; + } + } From 3cbebbb1e9b90fc195d261ae8e01a824ad3ad0d2 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Tue, 2 May 2023 21:07:46 +0300 Subject: [PATCH 342/362] feat: allow to reuse metadata download method --- .../gluu/saml/metadata/SAMLMetadataParser.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java index 614ea3b2..553c7ba6 100644 --- a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java +++ b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java @@ -160,7 +160,15 @@ public EntityIDHandler parseMetadata(InputStream is) { } public EntityIDHandler parseMetadata(URL metadataURL) throws ClientProtocolException, IOException { - HttpGet httpGet = new HttpGet(metadataURL.toExternalForm()); + byte[] metadataFileContent = downloadMetadata(metadataURL.toExternalForm()); + + InputStream is = new ByteArrayInputStream(metadataFileContent); + + return parseMetadata(is); + } + + public byte[] downloadMetadata(String metadataURL) throws IOException, ClientProtocolException { + HttpGet httpGet = new HttpGet(); httpGet.setHeader("Accept", "application/xml, text/xml"); byte[] metadataFileContent = null; @@ -175,10 +183,8 @@ public EntityIDHandler parseMetadata(URL metadataURL) throws ClientProtocolExcep return null; } - InputStream is = new ByteArrayInputStream(metadataFileContent); - - return parseMetadata(is); - } + return metadataFileContent; + } public byte[] getResponseContent(HttpResponse httpResponse) throws IOException { if ((httpResponse == null) || (httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK)) { From 4b1b6c5f7442c64da892afd4b150d3a1ed9594df Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Fri, 26 May 2023 19:50:45 +0300 Subject: [PATCH 343/362] fix: failed to initialize resteasy proxy from script at server startup #5116 #1838 --- .../java/org/gluu/service/PythonService.java | 1 - .../custom/script/CustomScriptManager.java | 19 ++++++++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/core-script/src/main/java/org/gluu/service/PythonService.java b/core-script/src/main/java/org/gluu/service/PythonService.java index 340d8558..ce13fd20 100644 --- a/core-script/src/main/java/org/gluu/service/PythonService.java +++ b/core-script/src/main/java/org/gluu/service/PythonService.java @@ -71,7 +71,6 @@ public boolean initPythonInterpreter(String pythonModulesDir) { log.info("Initializing PythonService with Jython: '{}'", pythonHome); if (StringHelper.isNotEmpty(pythonHome)) { try { - PythonInterpreter.initialize(getPreProperties(), getPostProperties(pythonModulesDir, pythonHome), null); this.pythonInterpreter = new PythonInterpreter(); diff --git a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java index cc40f50d..593d025f 100644 --- a/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java +++ b/core-script/src/main/java/org/gluu/service/custom/script/CustomScriptManager.java @@ -428,11 +428,20 @@ public BaseExternalType createExternalTypeFromStringWithPythonException(CustomSc boolean initialized = false; try { - if (externalType.getApiVersion() > 10) { - initialized = externalType.init(customScript, configurationAttributes); - } else { - initialized = externalType.init(configurationAttributes); - log.warn(" Update the script's init method to init(self, customScript, configurationAttributes)", customScript.getName()); + // Workaround to allow load all required class in init method needed for proper script work + // At the end we restore ContextClassLoader + // More details: https://github.com/JanssenProject/jans/issues/5116 + ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); + try { + if (externalType.getApiVersion() > 10) { + initialized = externalType.init(customScript, configurationAttributes); + } else { + initialized = externalType.init(configurationAttributes); + log.warn(" Update the script's init method to init(self, customScript, configurationAttributes)", customScript.getName()); + } + } finally { + Thread.currentThread().setContextClassLoader(oldClassLoader); } } catch (Exception ex) { log.error("Failed to initialize custom script: '{}'", ex, customScript.getName()); From c3a865a90db16a6ddec356abc237a8679c27c3da Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Mon, 29 May 2023 14:27:47 +0300 Subject: [PATCH 344/362] feat: dump stack trace on invalid CORS request if debug enabled --- .../main/java/org/gluu/server/filters/AbstractCorsFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java b/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java index decfa155..989863f6 100644 --- a/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java +++ b/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java @@ -393,7 +393,7 @@ private void handleInvalidCORS(final HttpServletRequest request, message.append(";Access-Control-Request-Headers="); message.append(accessControlRequestHeaders); } - log.debug(message.toString()); + log.debug(message.toString(), new Throwable()); } } From bbd88542d65de5848a61c78eea74ebba19ceb11e Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Mon, 10 Jul 2023 22:37:44 +0300 Subject: [PATCH 345/362] chore: add trace logging to gather details about token CORS filter issue --- .../server/filters/AbstractCorsFilter.java | 54 +++++++++++++++++-- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java b/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java index 989863f6..1821b78f 100644 --- a/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java +++ b/server/src/main/java/org/gluu/server/filters/AbstractCorsFilter.java @@ -118,9 +118,11 @@ public void doFilter(final ServletRequest servletRequest, // Determines the CORS request type. AbstractCorsFilter.CORSRequestType requestType = checkRequestType(request); + dumpRequestDetails("before doFilter", request, requestType); + // Adds CORS specific attributes to request. if (decorateRequest) { - AbstractCorsFilter.decorateCORSProperties(request, requestType); + decorateCORSProperties(request, requestType); } switch (requestType) { case SIMPLE: @@ -144,6 +146,8 @@ public void doFilter(final ServletRequest servletRequest, this.handleInvalidCORS(request, response, filterChain); break; } + + dumpRequestDetails("after doFilter", request, requestType); } @Override @@ -173,6 +177,7 @@ protected void handleSimpleCORS(final HttpServletRequest request, AbstractCorsFilter.CORSRequestType.SIMPLE, AbstractCorsFilter.CORSRequestType.ACTUAL)); } + dumpRequestDetails("before handleSimpleCORS", request, requestType); final String origin = request .getHeader(AbstractCorsFilter.REQUEST_HEADER_ORIGIN); @@ -180,11 +185,13 @@ protected void handleSimpleCORS(final HttpServletRequest request, // Section 6.1.2 if (!isOriginAllowed(request, origin)) { + log.trace("handleSimpleCORS: handleInvalidCORS"); handleInvalidCORS(request, response, filterChain); return; } if (!allowedHttpMethods.contains(method)) { + log.trace("handleSimpleCORS: handleInvalidCORS"); handleInvalidCORS(request, response, filterChain); return; } @@ -228,6 +235,8 @@ protected void handleSimpleCORS(final HttpServletRequest request, exposedHeadersString); } + dumpRequestDetails("after handleSimpleCORS", request, requestType); + // Forward the request down the filter chain. filterChain.doFilter(request, response); } @@ -253,6 +262,8 @@ protected void handlePreflightCORS(final HttpServletRequest request, CORSRequestType.PRE_FLIGHT.name().toLowerCase())); } + dumpRequestDetails("before handlePreflightCORS", request, requestType); + final String origin = request .getHeader(AbstractCorsFilter.REQUEST_HEADER_ORIGIN); @@ -341,6 +352,8 @@ protected void handlePreflightCORS(final HttpServletRequest request, join(allowedHttpHeaders, ",")); } + dumpRequestDetails("after handlePreflightCORS", request, requestType); + // Do not forward the request down the filter chain. } @@ -382,7 +395,7 @@ private void handleInvalidCORS(final HttpServletRequest request, response.setStatus(HttpServletResponse.SC_FORBIDDEN); response.resetBuffer(); - if (log.isDebugEnabled()) { + if (log.isDebugEnabled() || log.isTraceEnabled()) { // Debug so no need for i18n StringBuilder message = new StringBuilder("Invalid CORS request; Origin="); @@ -421,7 +434,7 @@ public void destroy() { * @param request The {@link HttpServletRequest} object. * @param corsRequestType The {@link CORSRequestType} object. */ - protected static void decorateCORSProperties( + protected void decorateCORSProperties( final HttpServletRequest request, final CORSRequestType corsRequestType) { if (request == null) { @@ -434,6 +447,8 @@ protected static void decorateCORSProperties( SM.getString("corsFilter.nullRequestType")); } + dumpRequestDetails("before decorateCORSProperties", request, corsRequestType); + switch (corsRequestType) { case SIMPLE: request.setAttribute( @@ -481,8 +496,9 @@ protected static void decorateCORSProperties( // Don't set any attributes break; } - } + dumpRequestDetails("after decorateCORSProperties", request, corsRequestType); + } /** * Joins elements of {@link Set} into a string, where each element is @@ -758,6 +774,9 @@ public boolean isAnyOriginAllowed(ServletRequest servletRequest) { } protected void setContextClientAllowedOrigins(ServletRequest servletRequest, Collection clientAllowedOrigins) { + if (log.isTraceEnabled()) { + log.trace("setContextClientAllowedOrigins: {}", clientAllowedOrigins); + } servletRequest.setAttribute(PARAM_CLIENT_ALLOWED_ORIGINS, clientAllowedOrigins); } @@ -778,6 +797,33 @@ protected boolean hasContextClientAllowedOrigins(ServletRequest servletRequest) return false; } + private void dumpRequestDetails(final String prefix, final HttpServletRequest request, final CORSRequestType corsRequestType) { + if (!log.isTraceEnabled()) { + return; + } + StringBuilder allAttributes = new StringBuilder("["); + for (Iterator it = request.getAttributeNames().asIterator(); it.hasNext();) { + if (allAttributes.length() > 1) { + allAttributes.append(","); + } + String attributeName = (String) it.next(); + allAttributes.append(attributeName).append(" = ").append(request.getAttribute(attributeName)); + } + allAttributes.append("]"); + + StringBuilder allHeaders = new StringBuilder("["); + for (Iterator it = request.getHeaderNames().asIterator(); it.hasNext();) { + if (allHeaders.length() > 1) { + allHeaders.append(","); + } + String HeaderName = (String) it.next(); + allHeaders.append(HeaderName).append(" = ").append(request.getHeader(HeaderName)); + } + allHeaders.append("]"); + + log.trace("{}: request method {} to URI {}, corsType {}, attributes {}, headers {}", prefix, request.getMethod(), request.getRequestURI(), corsRequestType, allAttributes, allHeaders); + } + /** * Returns a {@link Set} of headers that should be exposed by browser. */ From 77601d451ba4405960f22fc0ba58ab6850264d08 Mon Sep 17 00:00:00 2001 From: shekhar16 Date: Tue, 18 Jul 2023 00:49:00 +0530 Subject: [PATCH 346/362] fix(oxtrust-server): 2351 validate TR metadata --- .../document/store/provider/DBDocumentStoreProvider.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java index 2b2d6a13..ed1b8209 100644 --- a/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java +++ b/core-document-store/src/main/java/org/gluu/service/document/store/provider/DBDocumentStoreProvider.java @@ -77,6 +77,9 @@ public boolean hasDocument(String DisplayName) { OxDocument oxDocument = null; try { oxDocument = documentService.getOxDocumentByDisplayName(DisplayName); + if(oxDocument != null) { + return true; + } } catch (Exception e) { log.error("Failed to check if path '" + DisplayName + "' exists in repository", e); } @@ -180,7 +183,7 @@ public InputStream readDocumentAsStream(String name) { return null; } - InputStream InputStream = new ByteArrayInputStream(Base64.getDecoder().decode(filecontecnt)); + InputStream InputStream = new ByteArrayInputStream(filecontecnt.getBytes()); return InputStream; } From bcec1d01215a6852500c31988612d4694034e309 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Wed, 7 Feb 2024 18:38:53 +0300 Subject: [PATCH 347/362] chore: merge fvrom 4.5.3 Signed-off-by: Yuriy Movchan --- jetty-session-store-jdbc-extended/pom.xml | 225 +++++++++ .../src/main/assembly/site-component.xml | 15 + .../etc/sessions/jdbc-extended/datasource.xml | 11 + .../etc/sessions/jdbc-extended/driver.xml | 16 + .../jdbc-extended/session-store-extended.xml | 76 +++ .../modules/session-store-jdbc-extended.mod | 75 +++ .../sessions/jdbc-extended/datasource.mod | 10 + .../modules/sessions/jdbc-extended/driver.mod | 10 + .../src/main/java/module-info.java | 24 + .../session/extended/DatabaseAdaptor.java | 13 + .../extended/ExtendedObjectOutputStream.java | 28 ++ .../JDBCExtendedSessionDataStore.java | 476 ++++++++++++++++++ .../JDBCExtendedSessionDataStoreFactory.java | 95 ++++ 13 files changed, 1074 insertions(+) create mode 100644 jetty-session-store-jdbc-extended/pom.xml create mode 100644 jetty-session-store-jdbc-extended/src/main/assembly/site-component.xml create mode 100644 jetty-session-store-jdbc-extended/src/main/config/etc/sessions/jdbc-extended/datasource.xml create mode 100644 jetty-session-store-jdbc-extended/src/main/config/etc/sessions/jdbc-extended/driver.xml create mode 100644 jetty-session-store-jdbc-extended/src/main/config/etc/sessions/jdbc-extended/session-store-extended.xml create mode 100644 jetty-session-store-jdbc-extended/src/main/config/modules/session-store-jdbc-extended.mod create mode 100644 jetty-session-store-jdbc-extended/src/main/config/modules/sessions/jdbc-extended/datasource.mod create mode 100644 jetty-session-store-jdbc-extended/src/main/config/modules/sessions/jdbc-extended/driver.mod create mode 100644 jetty-session-store-jdbc-extended/src/main/java/module-info.java create mode 100644 jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/DatabaseAdaptor.java create mode 100644 jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/ExtendedObjectOutputStream.java create mode 100644 jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/JDBCExtendedSessionDataStore.java create mode 100644 jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/JDBCExtendedSessionDataStoreFactory.java diff --git a/jetty-session-store-jdbc-extended/pom.xml b/jetty-session-store-jdbc-extended/pom.xml new file mode 100644 index 00000000..d3e163d9 --- /dev/null +++ b/jetty-session-store-jdbc-extended/pom.xml @@ -0,0 +1,225 @@ + + + 4.0.0 + org.gluu.jetty + session-store-jdbc-extended + ${jetty-server.version} + Jetty :: Session store jdbc extended + Session store jdbc extended artifact. + + + org.gluu + oxcore + 4.6.0-SNAPSHOT + + + + 10.0.15 + https://www.eclipse.org/jetty/ + + + 11 + 11 + 11 + + false + 3.5.0 + 1.1 + 3.2.0 + 3.2.1 + 3.11.0 + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + ${maven.assembly.plugin.version} + + + org.eclipse.jetty.toolchain + jetty-assembly-descriptors + ${maven.jetty-assembly-descriptors.version} + + + + + org.apache.maven.plugins + maven-clean-plugin + ${maven.clean.plugin.version} + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven.compiler.plugin.version} + + ${compiler.source} + ${compiler.target} + ${compiler.release} + true + + -Xlint:exports + + -nowarn + + + + + + + + + + org.eclipse.jetty + jetty-bom + ${jetty-server.version} + import + pom + + + + org.eclipse.jetty + jetty-project + ${jetty-server.version} + import + pom + + + + + + + config + + + src/main/config + + + + + + org.apache.maven.plugins + maven-resources-plugin + + + copy-resources + process-resources + + copy-resources + + + UTF-8 + false + + @ + + + ${project.build.directory}/jetty-config-files + + + src/main/config + true + + **/*.p12 + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + config-assembly + package + + single + + + + config + + + + + + + + + + config-template + + + src/main/config-template + + + + + + org.apache.maven.plugins + maven-resources-plugin + + + copy-resources + process-resources + + copy-resources + + + UTF-8 + false + + @ + + + ${project.build.directory}/jetty-config-files + + + src/main/config-template + true + + **/*.p12 + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + package + + single + + + + src/main/assembly/config.xml + + + + + + + + + + + + + org.eclipse.jetty + jetty-server + + + + diff --git a/jetty-session-store-jdbc-extended/src/main/assembly/site-component.xml b/jetty-session-store-jdbc-extended/src/main/assembly/site-component.xml new file mode 100644 index 00000000..575269c1 --- /dev/null +++ b/jetty-session-store-jdbc-extended/src/main/assembly/site-component.xml @@ -0,0 +1,15 @@ + + site-component + + jar + + + + ${basedir} + jetty + + src/main/resources/org/eclipse/** + + + + diff --git a/jetty-session-store-jdbc-extended/src/main/config/etc/sessions/jdbc-extended/datasource.xml b/jetty-session-store-jdbc-extended/src/main/config/etc/sessions/jdbc-extended/datasource.xml new file mode 100644 index 00000000..be79e957 --- /dev/null +++ b/jetty-session-store-jdbc-extended/src/main/config/etc/sessions/jdbc-extended/datasource.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/jetty-session-store-jdbc-extended/src/main/config/etc/sessions/jdbc-extended/driver.xml b/jetty-session-store-jdbc-extended/src/main/config/etc/sessions/jdbc-extended/driver.xml new file mode 100644 index 00000000..2f4c5ecc --- /dev/null +++ b/jetty-session-store-jdbc-extended/src/main/config/etc/sessions/jdbc-extended/driver.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/jetty-session-store-jdbc-extended/src/main/config/etc/sessions/jdbc-extended/session-store-extended.xml b/jetty-session-store-jdbc-extended/src/main/config/etc/sessions/jdbc-extended/session-store-extended.xml new file mode 100644 index 00000000..2a39cb4a --- /dev/null +++ b/jetty-session-store-jdbc-extended/src/main/config/etc/sessions/jdbc-extended/session-store-extended.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jetty-session-store-jdbc-extended/src/main/config/modules/session-store-jdbc-extended.mod b/jetty-session-store-jdbc-extended/src/main/config/modules/session-store-jdbc-extended.mod new file mode 100644 index 00000000..c345f5e7 --- /dev/null +++ b/jetty-session-store-jdbc-extended/src/main/config/modules/session-store-jdbc-extended.mod @@ -0,0 +1,75 @@ +# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[description] +Enables extended JDBC persistent/distributed session storage. + +[tags] +session + +[provides] +session-store-jdbc-extended + +[depend] +jdbc +sessions +sessions/jdbc-extended/${db-connection-type} + +[lib] +lib/session-store-jdbc-extended-${jetty.version}.jar + +[xml] +etc/sessions/jdbc-extended/session-store-extended.xml + +[ini] +db-connection-type?=datasource + +[ini-template] +## +##Extended JDBC Session properties +## + +#jetty.session.gracePeriod.seconds=3600 +#jetty.session.savePeriod.seconds=0 +#jetty.session.lockTime.millis=0 +#jetty.session.delayTime.millis=0 +#jetty.session.serialization.compress.data=false + +jetty.session.jdbc.blobType=mediumblob +#jetty.session.jdbc.longType= +#jetty.session.jdbc.stringType= + +## Connection type:Datasource +#db-connection-type=datasource +#jetty.session.jdbc.datasourceName=/jdbc/sessions + +## Connection type:driver +db-connection-type=driver +#jetty.session.jdbc.driverClass= +#jetty.session.jdbc.driverUrl= + +## Session table schema +#jetty.session.jdbc.schema.accessTimeColumn=accessTime +#jetty.session.jdbc.schema.contextPathColumn=contextPath +#jetty.session.jdbc.schema.cookieTimeColumn=cookieTime +#jetty.session.jdbc.schema.createTimeColumn=createTime +#jetty.session.jdbc.schema.expiryTimeColumn=expiryTime +#jetty.session.jdbc.schema.lastAccessTimeColumn=lastAccessTime +#jetty.session.jdbc.schema.lastSavedTimeColumn=lastSavedTime +#jetty.session.jdbc.schema.lockTimeColumn=lockTime +#jetty.session.jdbc.schema.idColumn=sessionId +#jetty.session.jdbc.schema.lastNodeColumn=lastNode +#jetty.session.jdbc.schema.virtualHostColumn=virtualHost +#jetty.session.jdbc.schema.maxIntervalColumn=maxInterval +#jetty.session.jdbc.schema.mapColumn=map +#jetty.session.jdbc.schema.table=JettySessions +# Optional name of the schema used to identify where the session table is defined in the database: +# "" - empty string, no schema name +# "INFERRED" - special string meaning infer from the current db connection +# name - a string defined by the user +#jetty.session.jdbc.schema.schemaName +# Optional name of the catalog used to identify where the session table is defined in the database: +# "" - empty string, no catalog name +# "INFERRED" - special string meaning infer from the current db connection +# name - a string defined by the user +#jetty.session.jdbc.schema.catalogName + diff --git a/jetty-session-store-jdbc-extended/src/main/config/modules/sessions/jdbc-extended/datasource.mod b/jetty-session-store-jdbc-extended/src/main/config/modules/sessions/jdbc-extended/datasource.mod new file mode 100644 index 00000000..50348add --- /dev/null +++ b/jetty-session-store-jdbc-extended/src/main/config/modules/sessions/jdbc-extended/datasource.mod @@ -0,0 +1,10 @@ +# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[description] +JDBC Datasource connections for session storage. + +[depends] +jdbc + +[xml] +etc/sessions/jdbc-extended/datasource.xml diff --git a/jetty-session-store-jdbc-extended/src/main/config/modules/sessions/jdbc-extended/driver.mod b/jetty-session-store-jdbc-extended/src/main/config/modules/sessions/jdbc-extended/driver.mod new file mode 100644 index 00000000..2e2ee9fa --- /dev/null +++ b/jetty-session-store-jdbc-extended/src/main/config/modules/sessions/jdbc-extended/driver.mod @@ -0,0 +1,10 @@ +# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html + +[description] +JDBC Driver connections for session storage. + +[depend] +jdbc + +[xml] +etc/sessions/jdbc-extended/driver.xml diff --git a/jetty-session-store-jdbc-extended/src/main/java/module-info.java b/jetty-session-store-jdbc-extended/src/main/java/module-info.java new file mode 100644 index 00000000..41748e35 --- /dev/null +++ b/jetty-session-store-jdbc-extended/src/main/java/module-info.java @@ -0,0 +1,24 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +module org.eclipse.jetty.server.session.extended +{ + requires transitive jetty.servlet.api; + requires transitive org.eclipse.jetty.server; + requires transitive org.slf4j; + + // Only required if using DatabaseAdaptor/JDBCSessionDataStore. + requires static java.sql; + + exports org.eclipse.jetty.server.session.extended; +} diff --git a/jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/DatabaseAdaptor.java b/jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/DatabaseAdaptor.java new file mode 100644 index 00000000..682b0a24 --- /dev/null +++ b/jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/DatabaseAdaptor.java @@ -0,0 +1,13 @@ +package org.eclipse.jetty.server.session.extended; + +import java.sql.Connection; +import java.sql.SQLException; + +public class DatabaseAdaptor extends org.eclipse.jetty.server.session.DatabaseAdaptor { + + @Override + protected Connection getConnection() throws SQLException { + return super.getConnection(); + } + +} diff --git a/jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/ExtendedObjectOutputStream.java b/jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/ExtendedObjectOutputStream.java new file mode 100644 index 00000000..04b40c08 --- /dev/null +++ b/jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/ExtendedObjectOutputStream.java @@ -0,0 +1,28 @@ +package org.eclipse.jetty.server.session.extended; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Serializable; + +public class ExtendedObjectOutputStream extends java.io.ObjectOutputStream { + + public ExtendedObjectOutputStream(OutputStream out) throws IOException { + super(out); + enableReplaceObject(true); + } + + @Override + protected Object replaceObject(Object obj) throws IOException { + if (obj instanceof Serializable) { + return obj; + } + + return null; + } + + public class NullOutputStream extends OutputStream { + @Override + public void write(int b) throws IOException {} + } + +} diff --git a/jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/JDBCExtendedSessionDataStore.java b/jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/JDBCExtendedSessionDataStore.java new file mode 100644 index 00000000..f33f3d25 --- /dev/null +++ b/jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/JDBCExtendedSessionDataStore.java @@ -0,0 +1,476 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.server.session.extended; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectOutputStream; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.Base64; +import java.util.HashMap; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import org.eclipse.jetty.server.session.JDBCSessionDataStore; +import org.eclipse.jetty.server.session.SessionContext; +import org.eclipse.jetty.server.session.SessionData; +import org.eclipse.jetty.server.session.UnreadableSessionDataException; +import org.eclipse.jetty.util.ClassLoadingObjectInputStream; +import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.annotation.ManagedAttribute; +import org.eclipse.jetty.util.annotation.ManagedObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * JDBCExtendedSessionDataStore + * + * Session data stored in database + */ +@ManagedObject +public class JDBCExtendedSessionDataStore extends JDBCSessionDataStore +{ + private static final Logger LOG = LoggerFactory.getLogger(JDBCExtendedSessionDataStore.class); + + private int _lockPeriodMillis; + private int _delayPeriodMillis; + private boolean _compressSerializedData = false; + + /** + * SessionTableSchema + */ + public static class SessionTableSchema extends org.eclipse.jetty.server.session.JDBCSessionDataStore.SessionTableSchema + { + protected String _lockTimeColumn = "lockTime"; + + protected void setDatabaseAdaptor(DatabaseAdaptor dbadaptor) + { + _dbAdaptor = dbadaptor; + } + + public void setLockTimeColumn(String lockTimeColumn) + { + checkNotNull(lockTimeColumn); + _lockTimeColumn = lockTimeColumn; + } + + public String getLockTimeColumn() + { + return _lockTimeColumn; + } + + private void checkNotNull(String s) + { + if (s == null) + throw new IllegalArgumentException(s); + } + + private String getSchemaTableName() + { + return (getSchemaName() != null ? getSchemaName() + "." : "") + getTableName(); + } + + /* + * Added lockTableColumn creation + */ + public String getCreateStatementAsString() + { + if (_dbAdaptor == null) + throw new IllegalStateException("No DBAdaptor"); + + String blobType = _dbAdaptor.getBlobType(); + String longType = _dbAdaptor.getLongType(); + String stringType = _dbAdaptor.getStringType(); + + return "create table " + getSchemaTableName() + " (" + _idColumn + " " + stringType + "(120), " + + _contextPathColumn + " " + stringType + "(60), " + _virtualHostColumn + " " + stringType + "(60), " + _lastNodeColumn + " " + stringType + "(60), " + _accessTimeColumn + " " + longType + ", " + + _lastAccessTimeColumn + " " + longType + ", " + _createTimeColumn + " " + longType + ", " + _cookieTimeColumn + " " + longType + ", " + + _lastSavedTimeColumn + " " + longType + ", " + _expiryTimeColumn + " " + longType + ", " + _maxIntervalColumn + " " + longType + ", " + _lockTimeColumn + " " + longType + ", " + + _mapColumn + " " + blobType + ", primary key(" + _idColumn + ", " + _contextPathColumn + "," + _virtualHostColumn + "))"; + } + + /* + * Added lockTableColumn value set + */ + @Override + public String getInsertSessionStatementAsString() + { + return "insert into " + getSchemaTableName() + + " (" + getIdColumn() + ", " + getContextPathColumn() + ", " + getVirtualHostColumn() + ", " + getLastNodeColumn() + + ", " + getAccessTimeColumn() + ", " + getLastAccessTimeColumn() + ", " + getCreateTimeColumn() + ", " + getCookieTimeColumn() + + ", " + getLastSavedTimeColumn() + ", " + getExpiryTimeColumn() + ", " + getMaxIntervalColumn() + ", " + getLockTimeColumn() + ", " + getMapColumn() + ") " + + " values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + } + + /* + * Added lockTableColumn value clear + */ + @Override + public PreparedStatement getUpdateSessionStatement(Connection connection, String id, SessionContext context) + throws SQLException + { + String s = "update " + getSchemaTableName() + + " set " + getLastNodeColumn() + " = ?, " + getAccessTimeColumn() + " = ?, " + + getLastAccessTimeColumn() + " = ?, " + getLastSavedTimeColumn() + " = ?, " + getExpiryTimeColumn() + " = ?, " + + getMaxIntervalColumn() + " = ?, " + getLockTimeColumn() + " = ?, " + getMapColumn() + " = ? where " + getIdColumn() + " = ? and " + getContextPathColumn() + + " = ? and " + getVirtualHostColumn() + " = ?"; + + String cp = context.getCanonicalContextPath(); + if (_dbAdaptor.isEmptyStringNull() && StringUtil.isBlank(cp)) + cp = NULL_CONTEXT_PATH; + + PreparedStatement statement = connection.prepareStatement(s); + statement.setString(9, id); + statement.setString(10, cp); + statement.setString(11, context.getVhost()); + return statement; + } + + @Override + public String toString() + { + return String.format("%s[%s]", super.toString(), _lockTimeColumn); + } + } + + /* + * Quickly insert with lockTime. After that do update with session data + */ + @Override + protected void doInsert(String id, SessionData data) + throws Exception + { + if (LOG.isDebugEnabled()) { + LOG.debug(">>>>>>>>>> INSERT START: {}", id); + } + boolean useLock = _lockPeriodMillis > 0; + String s = _sessionTableSchema.getInsertSessionStatementAsString(); + + try (Connection connection = ((org.eclipse.jetty.server.session.extended.DatabaseAdaptor) _dbAdaptor).getConnection()) + { + connection.setAutoCommit(true); + try (PreparedStatement statement = connection.prepareStatement(s)) + { + statement.setString(1, id); //session id + + String cp = _context.getCanonicalContextPath(); + if (_dbAdaptor.isEmptyStringNull() && StringUtil.isBlank(cp)) + cp = NULL_CONTEXT_PATH; + + statement.setString(2, cp); //context path + + statement.setString(3, _context.getVhost()); //first vhost + statement.setString(4, data.getLastNode()); //my node id + statement.setLong(5, data.getAccessed()); //accessTime + statement.setLong(6, data.getLastAccessed()); //lastAccessTime + statement.setLong(7, data.getCreated()); //time created + statement.setLong(8, data.getCookieSet()); //time cookie was set + statement.setLong(9, data.getLastSaved()); //last saved time + statement.setLong(10, data.getExpiry()); + statement.setLong(11, data.getMaxInactiveMs()); + statement.setLong(12, System.currentTimeMillis()); // lockTime + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ExtendedObjectOutputStream(baos)) + { + if (useLock) { + // Write empty legacy object to speed up initial record insert + oos.writeObject(new HashMap()); + } else { + SessionData.serializeAttributes(data, oos); + } + byte[] bytes = baos.toByteArray(); + if (LOG.isDebugEnabled()) { + LOG.debug("SessionData dump in INSERT for Vhost {} in base64: {}", _context.getVhost(), Base64.getEncoder().encodeToString(bytes)); + } + + if (_compressSerializedData) { + try (ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); + GZIPOutputStream gos = new GZIPOutputStream(baos2)) { + gos.write(bytes); + gos.finish(); + bytes = baos2.toByteArray(); + } + } + try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) + { + statement.setBinaryStream(13, bais, bytes.length); //attribute map as blob + } + } + + statement.executeUpdate(); + if (LOG.isDebugEnabled()) + LOG.debug("Inserted session {}", data); + } + } + if (LOG.isDebugEnabled()) { + LOG.debug("<<<<<<<<<< INSERT END: {}", id); + } + + if (useLock) { + // Save with serialized data + doUpdate(id, data); + } + } + + @Override + protected void doUpdate(String id, SessionData data) + throws Exception + { + if (LOG.isDebugEnabled()) { + LOG.debug(">>>>>>>>>> UPDATE START: {}", id); + } + try (Connection connection = ((org.eclipse.jetty.server.session.extended.DatabaseAdaptor) _dbAdaptor).getConnection()) + { + connection.setAutoCommit(true); + try (PreparedStatement statement = _sessionTableSchema.getUpdateSessionStatement(connection, data.getId(), _context)) + { + statement.setString(1, data.getLastNode()); //should be my node id + statement.setLong(2, data.getAccessed()); //accessTime + statement.setLong(3, data.getLastAccessed()); //lastAccessTime + statement.setLong(4, data.getLastSaved()); //last saved time + statement.setLong(5, data.getExpiry()); + statement.setLong(6, data.getMaxInactiveMs()); + statement.setNull(7, Types.BIGINT); + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ExtendedObjectOutputStream(baos)) + { + SessionData.serializeAttributes(data, oos); + byte[] bytes = baos.toByteArray(); + if (LOG.isDebugEnabled()) { + LOG.debug("SessionData dump in UPDATE for Vhost {} in base64: {}", _context.getVhost(), Base64.getEncoder().encodeToString(bytes)); + } + + if (_compressSerializedData) { + try (ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); + GZIPOutputStream gos = new GZIPOutputStream(baos2)) { + gos.write(bytes); + gos.finish(); + bytes = baos2.toByteArray(); + } + } + try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) + { + statement.setBinaryStream(8, bais, bytes.length); //attribute map as blob + } + } + + statement.executeUpdate(); + + if (LOG.isDebugEnabled()) + LOG.debug("Updated session {}", data); + } + } + if (LOG.isDebugEnabled()) { + LOG.debug("<<<<<<<<<< UPDATE END: {}", id); + } + } + + @Override + public SessionData doLoad(String id) throws Exception + { + if (LOG.isDebugEnabled()) { + LOG.debug(">>>>>>>>>> LOAD START: {}", id); + } + ExtendedSessionData extendedSessionData = doLoadImpl(id, true); + if (extendedSessionData.getLockTime() == null) { + return extendedSessionData.getSessionData(); + } + + // Wait specified milliseconds and try to load again + long unlockTime = extendedSessionData.getLockTime() + _lockPeriodMillis; + long currTime = System.currentTimeMillis(); + long sleepTime = unlockTime - currTime; + if (sleepTime > 0) { + if (LOG.isDebugEnabled()) { + LOG.debug("<<<<<<<<<< LOAD START DELAY FOR LOCK: {}", id); + } + Thread.sleep(sleepTime); + if (LOG.isDebugEnabled()) { + LOG.debug(">>>>>>>>>> LOAD END DELAY FOR LOCK: {}", id); + } + } + + // Load after lock expiration + extendedSessionData = doLoadImpl(id, false); + + if (LOG.isDebugEnabled()) { + LOG.debug("<<<<<<<<<< LOAD END: {}", id); + } + return extendedSessionData.getSessionData(); + } + + protected ExtendedSessionData doLoadImpl(String id, boolean checkLock) throws Exception + { + if (LOG.isDebugEnabled()) { + LOG.debug("---------- LOAD IMPL: {} : {}", id, checkLock); + } + try (Connection connection = ((org.eclipse.jetty.server.session.extended.DatabaseAdaptor) _dbAdaptor).getConnection(); + PreparedStatement statement = _sessionTableSchema.getLoadStatement(connection, id, _context); + ResultSet result = statement.executeQuery()) + { + SessionData data = null; + Long lockTime = null; + if (result.next()) + { + data = newSessionData(id, + result.getLong(_sessionTableSchema.getCreateTimeColumn()), + result.getLong(_sessionTableSchema.getAccessTimeColumn()), + result.getLong(_sessionTableSchema.getLastAccessTimeColumn()), + result.getLong(_sessionTableSchema.getMaxIntervalColumn())); + data.setCookieSet(result.getLong(_sessionTableSchema.getCookieTimeColumn())); + data.setLastNode(result.getString(_sessionTableSchema.getLastNodeColumn())); + data.setLastSaved(result.getLong(_sessionTableSchema.getLastSavedTimeColumn())); + data.setExpiry(result.getLong(_sessionTableSchema.getExpiryTimeColumn())); + data.setContextPath(_context.getCanonicalContextPath()); + data.setVhost(_context.getVhost()); + + lockTime = result.getLong(((org.eclipse.jetty.server.session.extended.JDBCExtendedSessionDataStore.SessionTableSchema) _sessionTableSchema).getLockTimeColumn()); + + // Check lock if needed + if (checkLock && !isLockExpired(lockTime)) { + return new ExtendedSessionData(data, lockTime); + } + + InputStream is2 = _dbAdaptor.getBlobInputStream(result, _sessionTableSchema.getMapColumn()); + + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int nRead; + byte[] buf = new byte[16384]; + + while ((nRead = is2.read(buf, 0, buf.length)) != -1) { + buffer.write(buf, 0, nRead); + } + + if (LOG.isDebugEnabled()) { + LOG.debug("Data for deserialization in base64: {}", Base64.getEncoder().encodeToString(buffer.toByteArray())); + } + + try (InputStream is = getBlobInputStream(result); + ClassLoadingObjectInputStream ois = new ClassLoadingObjectInputStream(is)) + { + if (LOG.isDebugEnabled()) { + LOG.debug(">>>>>>>>>> DESERIALIZATION START: {}", id); + } + if (_delayPeriodMillis > 0) { + if (LOG.isDebugEnabled()) { + LOG.debug(">>>>>>>>>> DESERIALIZATION DELAY: {}", id); + } + Thread.sleep(_delayPeriodMillis); + if (LOG.isDebugEnabled()) { + LOG.debug("<<<<<<<<<< DESERIALIZATION RESUME: {}", id); + } + } + SessionData.deserializeAttributes(data, ois); + if (LOG.isDebugEnabled()) { + LOG.debug("<<<<<<<<<< DESERIALIZATION END: {}", id); + } + } + catch (Exception e) + { + throw new UnreadableSessionDataException(id, _context, e); + } + + if (LOG.isDebugEnabled()) + LOG.debug("LOADED session {}", data); + } + else if (LOG.isDebugEnabled()) { + LOG.debug("No session {}", id); + } + + return new ExtendedSessionData(data, null); + } + } + + private InputStream getBlobInputStream(ResultSet resultSet) throws SQLException, IOException { + InputStream resultStream =_dbAdaptor.getBlobInputStream(resultSet, _sessionTableSchema.getMapColumn()); + if (_compressSerializedData) { + LOG.info("USING COMPRESSION"); + try (InputStream gis = new GZIPInputStream(resultStream)) { + resultStream = new ByteArrayInputStream(gis.readAllBytes()); + } + } + + return resultStream; + } + + private boolean isLockExpired(Long lockTime) { + if (lockTime == null) { + return true; + } + + long unlockTime = lockTime + _lockPeriodMillis; + long currTime = System.currentTimeMillis(); + + return unlockTime < currTime; + } + + public static class ExtendedSessionData { + private final SessionData sessionData; + private final Long lockTime; + + public ExtendedSessionData(SessionData sessionData, Long lockTime) { + this.sessionData = sessionData; + this.lockTime = lockTime; + } + + public SessionData getSessionData() { + return sessionData; + } + + public Long getLockTime() { + return lockTime; + } + + } + + @ManagedAttribute(value = "interval in millis to wait for session record lock", readonly = true) + public int getLockPeriodMillis() + { + return _lockPeriodMillis; + } + + public void setLockPeriodMillis(int millis) + { + _lockPeriodMillis = millis; + } + + @ManagedAttribute(value = "interval in millis to wait before session deserialization", readonly = true) + public int getDelayPeriodMillis() + { + return _delayPeriodMillis; + } + + public void setDelayPeriodMillis(int millis) + { + _delayPeriodMillis = millis; + } + + @ManagedAttribute(value = "specify if serialized data should be compressed", readonly = true) + public boolean getCompressSerializedData() { + return _compressSerializedData; + } + + public void setCompressSerializedData(boolean compressSerializedData) { + _compressSerializedData = compressSerializedData; + } + +} diff --git a/jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/JDBCExtendedSessionDataStoreFactory.java b/jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/JDBCExtendedSessionDataStoreFactory.java new file mode 100644 index 00000000..e73f7d40 --- /dev/null +++ b/jetty-session-store-jdbc-extended/src/main/java/org/eclipse/jetty/server/session/extended/JDBCExtendedSessionDataStoreFactory.java @@ -0,0 +1,95 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.server.session.extended; + +import org.eclipse.jetty.server.session.DatabaseAdaptor; +import org.eclipse.jetty.server.session.JDBCSessionDataStore; +import org.eclipse.jetty.server.session.JDBCSessionDataStoreFactory; +import org.eclipse.jetty.server.session.SessionDataStore; +import org.eclipse.jetty.server.session.SessionHandler; + +/** + * JDBCExtendedSessionDataStoreFactory + */ +public class JDBCExtendedSessionDataStoreFactory extends JDBCSessionDataStoreFactory +{ + + public static final int DEFAULT_LOCK_PERIOD_MILLIS = 0; //default of 0 millis + public static final int DEFAULT_DELAY_PERIOD_MILLIS = 0; //default of 0 millis + + DatabaseAdaptor _adaptor; + + JDBCSessionDataStore.SessionTableSchema _schema; + + private int _lockPeriodMillis = DEFAULT_LOCK_PERIOD_MILLIS; + private int _delayPeriodMillis = DEFAULT_DELAY_PERIOD_MILLIS; + private boolean _compressSerializedData = false; + + @Override + public SessionDataStore getSessionDataStore(SessionHandler handler) + { + JDBCExtendedSessionDataStore ds = new JDBCExtendedSessionDataStore(); + ds.setDatabaseAdaptor(_adaptor); + ds.setSessionTableSchema(_schema); + ds.setGracePeriodSec(getGracePeriodSec()); + ds.setSavePeriodSec(getSavePeriodSec()); + + ds.setLockPeriodMillis(_lockPeriodMillis); + ds.setDelayPeriodMillis(_delayPeriodMillis); + ds.setCompressSerializedData(_compressSerializedData); + return ds; + } + + /** + * @param adaptor the {@link DatabaseAdaptor} to set + */ + public void setDatabaseAdaptor(DatabaseAdaptor adaptor) + { + _adaptor = adaptor; + } + + /** + * @param schema the {@link JDBCSessionDataStoreFactory} to set + */ + public void setSessionTableSchema(JDBCSessionDataStore.SessionTableSchema schema) + { + _schema = schema; + } + + public int getLockPeriodMillis() + { + return _lockPeriodMillis; + } + + public void setLockPeriodMillis(int millis) + { + _lockPeriodMillis = millis; + } + + public int getDelayPeriodMillis() { + return _delayPeriodMillis; + } + + public void setDelayPeriodMillis(int millis) { + this._delayPeriodMillis = millis; + } + + public boolean getCompressSerializedData() { + return _compressSerializedData; + } + + public void setCompressSerializedData(boolean compressSerializedData) { + _compressSerializedData = compressSerializedData; + } +} From 6f25a0f6f8b3a719937bf6d2fd57f029a7ddf671 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Mon, 13 Nov 2023 22:12:24 +0300 Subject: [PATCH 348/362] chore: update libs --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 9972b04d..f08b5c38 100644 --- a/pom.xml +++ b/pom.xml @@ -202,5 +202,10 @@ Gluu project repository https://maven.gluu.org/maven + + shib-release + shib release + https://build.shibboleth.net/nexus/content/groups/public + \ No newline at end of file From 192c30e93e145ee8e620e0a3b7fc0f28d9cc6906 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Tue, 14 Nov 2023 18:21:51 +0300 Subject: [PATCH 349/362] chore: update BC libs --- oxService/pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/oxService/pom.xml b/oxService/pom.xml index 5793d59c..c621f83e 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -164,15 +164,15 @@ org.bouncycastle - bcprov-jdk15on + bcprov-jdk18on org.bouncycastle - bcpkix-jdk15on + bcpkix-jdk18on org.bouncycastle - bcmail-jdk15on + bcmail-jdk18on
From ca3267644583a672cf16fcefd8d5f18fe83be3a7 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Thu, 23 Nov 2023 14:06:33 +0000 Subject: [PATCH 350/362] feat: move HttpService to HttpServiceUtility oxcore-util #272 --- .../gluu/model/net/HttpServiceResponse.java | 43 +++ .../java/org/gluu/net/HttpServiceUtility.java | 282 ++++++++++++++++++ .../util/{ilocale => locale}/LocaleUtil.java | 2 +- 3 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 oxUtil/src/main/java/org/gluu/model/net/HttpServiceResponse.java create mode 100644 oxUtil/src/main/java/org/gluu/net/HttpServiceUtility.java rename oxUtil/src/main/java/org/gluu/util/{ilocale => locale}/LocaleUtil.java (98%) diff --git a/oxUtil/src/main/java/org/gluu/model/net/HttpServiceResponse.java b/oxUtil/src/main/java/org/gluu/model/net/HttpServiceResponse.java new file mode 100644 index 00000000..0d3803ec --- /dev/null +++ b/oxUtil/src/main/java/org/gluu/model/net/HttpServiceResponse.java @@ -0,0 +1,43 @@ +/** + * + */ +package org.gluu.model.net; + +import java.io.Serializable; + +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpRequestBase; + +/** + * @author Yuriy Movchan Date: 07/14/2015 + * + */ +public class HttpServiceResponse implements Serializable { + + private static final long serialVersionUID = 2218884738060554709L; + + private HttpRequestBase httpRequest; + private HttpResponse httpResponse; + + public HttpServiceResponse(HttpRequestBase httpRequest, HttpResponse httpResponse) { + this.httpRequest = httpRequest; + this.httpResponse = httpResponse; + } + + public HttpRequestBase getHttpRequest() { + return httpRequest; + } + + public HttpResponse getHttpResponse() { + return httpResponse; + } + + public void closeConnection() { + if (httpRequest == null) { + return; + } + + httpRequest.releaseConnection(); + } + +} diff --git a/oxUtil/src/main/java/org/gluu/net/HttpServiceUtility.java b/oxUtil/src/main/java/org/gluu/net/HttpServiceUtility.java new file mode 100644 index 00000000..dfa85d98 --- /dev/null +++ b/oxUtil/src/main/java/org/gluu/net/HttpServiceUtility.java @@ -0,0 +1,282 @@ +/* + * oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.net; + +import java.io.IOException; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Map; +import java.util.Map.Entry; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.commons.codec.binary.Base64; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.PlainSocketFactory; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.AllowAllHostnameVerifier; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.conn.ssl.TrustStrategy; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.PoolingClientConnectionManager; +import org.apache.http.util.EntityUtils; +import org.gluu.model.net.HttpServiceResponse; +import org.gluu.util.StringHelper; +import org.gluu.util.Util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +/** + * Provides operations with http requests + * + * @author Yuriy Movchan Date: 02/05/2013 + */ +public class HttpServiceUtility implements Serializable { + + private static final long serialVersionUID = -2398422090669045605L; + + private static int SC_OK = 200; + + private static final Logger LOG = LoggerFactory.getLogger(HttpServiceUtility.class); + + private Base64 base64; + + public void init() { + this.base64 = new Base64(); + } + + public HttpClient getHttpsClientTrustAll() { + try { + SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){ + @Override + public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { + return true; + } + }, new AllowAllHostnameVerifier()); + + PlainSocketFactory psf = PlainSocketFactory.getSocketFactory(); + + SchemeRegistry registry = new SchemeRegistry(); + registry.register(new Scheme("http", 80, psf)); + registry.register(new Scheme("https", 443, sf)); + ClientConnectionManager ccm = new PoolingClientConnectionManager(registry); + return new DefaultHttpClient(ccm); + } catch (Exception ex) { + getLogger().error("Failed to create TrustAll https client", ex); + return new DefaultHttpClient(); + } + } + + public HttpClient getHttpsClient() { + HttpClient httpClient = new SslDefaultHttpClient(); + + return httpClient; + } + + public HttpClient getHttpsClient(String trustStoreType, String trustStorePath, String trustStorePassword) { + HttpClient httpClient = new SslDefaultHttpClient(trustStoreType, trustStorePath, trustStorePassword); + + return httpClient; + } + + public HttpClient getHttpsClient(String trustStoreType, String trustStorePath, String trustStorePassword, + String keyStoreType, String keyStorePath, String keyStorePassword) { + HttpClient httpClient = new SslDefaultHttpClient(trustStoreType, trustStorePath, trustStorePassword, + keyStoreType, keyStorePath, keyStorePassword); + + return httpClient; + } + + public HttpServiceResponse executePost(HttpClient httpClient, String uri, String authData, Map headers, String postData, ContentType contentType) { + HttpPost httpPost = new HttpPost(uri); + if (StringHelper.isNotEmpty(authData)) { + httpPost.setHeader("Authorization", "Basic " + authData); + } + + if (headers != null) { + for (Entry headerEntry : headers.entrySet()) { + httpPost.setHeader(headerEntry.getKey(), headerEntry.getValue()); + } + } + + StringEntity stringEntity = new StringEntity(postData, contentType); + httpPost.setEntity(stringEntity); + + try { + HttpResponse httpResponse = httpClient.execute(httpPost); + + return new HttpServiceResponse(httpPost, httpResponse); + } catch (IOException ex) { + getLogger().error("Failed to execute post request", ex); + } + + return null; + } + + public HttpServiceResponse executePost(HttpClient httpClient, String uri, String authData, Map headers, String postData) { + return executePost(httpClient, uri, authData, headers, postData, null); + } + + public HttpServiceResponse executePost(HttpClient httpClient, String uri, String authData, String postData, ContentType contentType) { + return executePost(httpClient, uri, authData, null, postData, contentType); + } + + public String encodeBase64(String value) { + try { + return new String(base64.encode((value).getBytes(Util.UTF8)), Util.UTF8); + } catch (UnsupportedEncodingException ex) { + getLogger().error("Failed to convert '{}' to base64", value, ex); + } + + return null; + } + + public String encodeUrl(String value) { + try { + return URLEncoder.encode(value, Util.UTF8); + } catch (UnsupportedEncodingException ex) { + getLogger().error("Failed to encode url '{}'", value, ex); + } + + return null; + } + + public HttpServiceResponse executeGet(HttpClient httpClient, String requestUri, Map headers) { + HttpGet httpGet = new HttpGet(requestUri); + + if (headers != null) { + for (Entry headerEntry : headers.entrySet()) { + httpGet.setHeader(headerEntry.getKey(), headerEntry.getValue()); + } + } + + try { + HttpResponse httpResponse = httpClient.execute(httpGet); + + return new HttpServiceResponse(httpGet, httpResponse); + } catch (IOException ex) { + getLogger().error("Failed to execute get request", ex); + } + + return null; + } + + public HttpServiceResponse executeGet(HttpClient httpClient, String requestUri) throws ClientProtocolException, IOException { + return executeGet(httpClient, requestUri, null); + } + + public byte[] getResponseContent(HttpResponse httpResponse) throws IOException { + if ((httpResponse == null) || (httpResponse.getStatusLine().getStatusCode() != SC_OK)) { + return null; + } + + HttpEntity entity = httpResponse.getEntity(); + byte[] responseBytes = new byte[0]; + if (entity != null) { + responseBytes = EntityUtils.toByteArray(entity); + } + + // Consume response content + if (entity != null) { + EntityUtils.consume(entity); + } + + return responseBytes; + } + + public void consume(HttpResponse httpResponse) throws IOException { + if ((httpResponse == null) || (httpResponse.getStatusLine().getStatusCode() != SC_OK)) { + return; + } + + // Consume response content + HttpEntity entity = httpResponse.getEntity(); + if (entity != null) { + EntityUtils.consume(entity); + } + } + + public String convertEntityToString(byte[] responseBytes) { + if (responseBytes == null) { + return null; + } + + return new String(responseBytes); + } + + public String convertEntityToString(byte[] responseBytes, Charset charset) { + if (responseBytes == null) { + return null; + } + + return new String(responseBytes, charset); + } + + public String convertEntityToString(byte[] responseBytes, String charsetName) throws UnsupportedEncodingException { + if (responseBytes == null) { + return null; + } + + return new String(responseBytes, charsetName); + } + + public boolean isResponseStastusCodeOk(HttpResponse httpResponse) { + int responseStastusCode = httpResponse.getStatusLine().getStatusCode(); + if (responseStastusCode == HttpStatus.SC_OK) { + return true; + } + + return false; + } + + + public boolean isContentTypeXml(HttpResponse httpResponse) { + Header contentType = httpResponse.getEntity().getContentType(); + if (contentType == null) { + return false; + } + + String contentTypeValue = contentType.getValue(); + if (StringHelper.equals(contentTypeValue, ContentType.APPLICATION_XML.getMimeType()) || StringHelper.equals(contentTypeValue, ContentType.TEXT_XML.getMimeType())) { + return true; + } + + return false; + } + + public String constructServerUrl(final HttpServletRequest request) { + int serverPort = request.getServerPort(); + + String redirectUrl; + if ((serverPort == 80) || (serverPort == 443)) { + redirectUrl = String.format("%s://%s%s", request.getScheme(), request.getServerName(), request.getContextPath()); + } else { + redirectUrl = String.format("%s://%s:%s%s", request.getScheme(), request.getServerName(), request.getServerPort(), request.getContextPath()); + } + + return redirectUrl.toLowerCase(); + } + + public Logger getLogger() { + return LOG; + } + +} diff --git a/oxUtil/src/main/java/org/gluu/util/ilocale/LocaleUtil.java b/oxUtil/src/main/java/org/gluu/util/locale/LocaleUtil.java similarity index 98% rename from oxUtil/src/main/java/org/gluu/util/ilocale/LocaleUtil.java rename to oxUtil/src/main/java/org/gluu/util/locale/LocaleUtil.java index 9bdcef2b..baec7e39 100644 --- a/oxUtil/src/main/java/org/gluu/util/ilocale/LocaleUtil.java +++ b/oxUtil/src/main/java/org/gluu/util/locale/LocaleUtil.java @@ -4,7 +4,7 @@ * Copyright (c) 2014, Gluu */ -package org.gluu.util.ilocale; +package org.gluu.util.locale; import java.util.List; import java.util.Locale; From be94a931fa6355da1f7b09550bda5a66245b901a Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Thu, 23 Nov 2023 14:20:45 +0000 Subject: [PATCH 351/362] feat: move HttpService to HttpServiceUtility oxcore-util #272 --- .../java/org/gluu/net/HttpServiceUtility.java | 136 +++++++++++------- 1 file changed, 84 insertions(+), 52 deletions(-) diff --git a/oxUtil/src/main/java/org/gluu/net/HttpServiceUtility.java b/oxUtil/src/main/java/org/gluu/net/HttpServiceUtility.java index dfa85d98..3c74d61a 100644 --- a/oxUtil/src/main/java/org/gluu/net/HttpServiceUtility.java +++ b/oxUtil/src/main/java/org/gluu/net/HttpServiceUtility.java @@ -6,38 +6,46 @@ package org.gluu.net; +import java.io.File; import java.io.IOException; import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.Charset; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; import java.util.Map; import java.util.Map.Entry; +import javax.net.ssl.SSLContext; import javax.servlet.http.HttpServletRequest; import org.apache.commons.codec.binary.Base64; import org.apache.http.Header; import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; +import org.apache.http.client.config.CookieSpecs; +import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.PlainSocketFactory; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.conn.ssl.AllowAllHostnameVerifier; -import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.conn.routing.HttpRoutePlanner; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.conn.PoolingClientConnectionManager; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.conn.DefaultProxyRoutePlanner; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; import org.gluu.model.net.HttpServiceResponse; import org.gluu.util.StringHelper; @@ -52,65 +60,81 @@ public class HttpServiceUtility implements Serializable { private static final long serialVersionUID = -2398422090669045605L; - - private static int SC_OK = 200; private static final Logger LOG = LoggerFactory.getLogger(HttpServiceUtility.class); private Base64 base64; - + + private PoolingHttpClientConnectionManager connectionManager; + public void init() { - this.base64 = new Base64(); + connectionManager = new PoolingHttpClientConnectionManager(); + connectionManager.setMaxTotal(200); // Increase max total connection to 200 + connectionManager.setDefaultMaxPerRoute(50); // Increase default max connection per route to 50 + + this.base64 = new Base64(); } - public HttpClient getHttpsClientTrustAll() { - try { - SSLSocketFactory sf = new SSLSocketFactory(new TrustStrategy(){ - @Override - public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException { - return true; - } - }, new AllowAllHostnameVerifier()); - - PlainSocketFactory psf = PlainSocketFactory.getSocketFactory(); - - SchemeRegistry registry = new SchemeRegistry(); - registry.register(new Scheme("http", 80, psf)); - registry.register(new Scheme("https", 443, sf)); - ClientConnectionManager ccm = new PoolingClientConnectionManager(registry); - return new DefaultHttpClient(ccm); - } catch (Exception ex) { - getLogger().error("Failed to create TrustAll https client", ex); - return new DefaultHttpClient(); - } + public CloseableHttpClient getHttpsClientTrustAll() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException { + getLogger().trace("Connection manager stats: {}", connectionManager.getTotalStats()); + + TrustStrategy acceptingTrustStrategy = (cert, authType) -> true; + SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build(); + SSLConnectionSocketFactory sslConSocFactory = new SSLConnectionSocketFactory(sslContext, + NoopHostnameVerifier.INSTANCE); + + return HttpClients.custom().setSSLSocketFactory(sslConSocFactory) + .setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build()) + .setConnectionManager(connectionManager).build(); } - public HttpClient getHttpsClient() { - HttpClient httpClient = new SslDefaultHttpClient(); + public CloseableHttpClient getHttpsClient() { + getLogger().trace("Connection manager stats: {}", connectionManager.getTotalStats()); - return httpClient; + return HttpClients.custom() + .setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build()) + .setConnectionManager(connectionManager).build(); } - public HttpClient getHttpsClient(String trustStoreType, String trustStorePath, String trustStorePassword) { - HttpClient httpClient = new SslDefaultHttpClient(trustStoreType, trustStorePath, trustStorePassword); + public CloseableHttpClient getHttpsClient(HttpRoutePlanner routerPlanner) { + getLogger().trace("Connection manager stats: {}", connectionManager.getTotalStats()); - return httpClient; + return HttpClients.custom() + .setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build()) + .setConnectionManager(connectionManager).setRoutePlanner(routerPlanner).build(); + } - public HttpClient getHttpsClient(String trustStoreType, String trustStorePath, String trustStorePassword, - String keyStoreType, String keyStorePath, String keyStorePassword) { - HttpClient httpClient = new SslDefaultHttpClient(trustStoreType, trustStorePath, trustStorePassword, - keyStoreType, keyStorePath, keyStorePassword); + public CloseableHttpClient getHttpsClient(String trustStoreType, String trustStorePath, String trustStorePassword) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException { + getLogger().trace("Connection manager stats: {}", connectionManager.getTotalStats()); + + SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(new File(trustStorePath), trustStorePassword.toCharArray()).build(); + SSLConnectionSocketFactory sslConSocFactory = new SSLConnectionSocketFactory(sslContext); - return httpClient; + return HttpClients.custom().setSSLSocketFactory(sslConSocFactory) + .setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build()) + .setConnectionManager(connectionManager).build(); } - + + public CloseableHttpClient getHttpsClient(String trustStoreType, String trustStorePath, String trustStorePassword, + String keyStoreType, String keyStorePath, String keyStorePassword) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException, UnrecoverableKeyException { + getLogger().trace("Connection manager stats: {}", connectionManager.getTotalStats()); + + SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(new File(trustStorePath), trustStorePassword.toCharArray()) + .loadKeyMaterial(new File(keyStorePath), keyStorePassword.toCharArray(), keyStorePassword.toCharArray()).build(); + SSLConnectionSocketFactory sslConSocFactory = new SSLConnectionSocketFactory(sslContext); + + return HttpClients.custom().setSSLSocketFactory(sslConSocFactory) + .setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build()) + .setConnectionManager(connectionManager).build(); + } + public HttpServiceResponse executePost(HttpClient httpClient, String uri, String authData, Map headers, String postData, ContentType contentType) { HttpPost httpPost = new HttpPost(uri); if (StringHelper.isNotEmpty(authData)) { httpPost.setHeader("Authorization", "Basic " + authData); } - + if (headers != null) { for (Entry headerEntry : headers.entrySet()) { httpPost.setHeader(headerEntry.getKey(), headerEntry.getValue()); @@ -119,7 +143,7 @@ public HttpServiceResponse executePost(HttpClient httpClient, String uri, String StringEntity stringEntity = new StringEntity(postData, contentType); httpPost.setEntity(stringEntity); - + try { HttpResponse httpResponse = httpClient.execute(httpPost); @@ -127,7 +151,7 @@ public HttpServiceResponse executePost(HttpClient httpClient, String uri, String } catch (IOException ex) { getLogger().error("Failed to execute post request", ex); } - + return null; } @@ -184,7 +208,7 @@ public HttpServiceResponse executeGet(HttpClient httpClient, String requestUri) } public byte[] getResponseContent(HttpResponse httpResponse) throws IOException { - if ((httpResponse == null) || (httpResponse.getStatusLine().getStatusCode() != SC_OK)) { + if ((httpResponse == null) || !isResponseStastusCodeOk(httpResponse)) { return null; } @@ -203,7 +227,7 @@ public byte[] getResponseContent(HttpResponse httpResponse) throws IOException { } public void consume(HttpResponse httpResponse) throws IOException { - if ((httpResponse == null) || (httpResponse.getStatusLine().getStatusCode() != SC_OK)) { + if ((httpResponse == null) || !isResponseStastusCodeOk(httpResponse)) { return; } @@ -240,13 +264,14 @@ public String convertEntityToString(byte[] responseBytes, String charsetName) th public boolean isResponseStastusCodeOk(HttpResponse httpResponse) { int responseStastusCode = httpResponse.getStatusLine().getStatusCode(); - if (responseStastusCode == HttpStatus.SC_OK) { + if ((responseStastusCode == HttpStatus.SC_OK) || (responseStastusCode == HttpStatus.SC_CREATED) || (responseStastusCode == HttpStatus.SC_ACCEPTED) + || (responseStastusCode == HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION) || (responseStastusCode == HttpStatus.SC_NO_CONTENT) || (responseStastusCode == HttpStatus.SC_RESET_CONTENT) + || (responseStastusCode == HttpStatus.SC_PARTIAL_CONTENT) || (responseStastusCode == HttpStatus.SC_MULTI_STATUS)) { return true; } return false; } - public boolean isContentTypeXml(HttpResponse httpResponse) { Header contentType = httpResponse.getEntity().getContentType(); @@ -274,6 +299,13 @@ public String constructServerUrl(final HttpServletRequest request) { return redirectUrl.toLowerCase(); } + + public HttpRoutePlanner buildDefaultRoutePlanner(final String proxy) { + //Creating an HttpHost object for proxy + HttpHost proxyHost = new HttpHost(proxy); + + return new DefaultProxyRoutePlanner(proxyHost); + } public Logger getLogger() { return LOG; From 8e4c0d42556658ba0dc89519569cf1777d5567c9 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Thu, 23 Nov 2023 15:12:34 +0000 Subject: [PATCH 352/362] feat: move HttpService to HttpServiceUtility oxcore-util #272 --- oxUtil/src/main/java/org/gluu/net/HttpServiceUtility.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/oxUtil/src/main/java/org/gluu/net/HttpServiceUtility.java b/oxUtil/src/main/java/org/gluu/net/HttpServiceUtility.java index 3c74d61a..e82607f8 100644 --- a/oxUtil/src/main/java/org/gluu/net/HttpServiceUtility.java +++ b/oxUtil/src/main/java/org/gluu/net/HttpServiceUtility.java @@ -75,6 +75,12 @@ public void init() { this.base64 = new Base64(); } + public void destroy() { + if (connectionManager != null) { + connectionManager.shutdown(); + } + } + public CloseableHttpClient getHttpsClientTrustAll() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException { getLogger().trace("Connection manager stats: {}", connectionManager.getTotalStats()); From 69f052baa0c65e63ebb3e7b1d44c89a5179a1707 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Tue, 10 Oct 2023 15:23:15 +0300 Subject: [PATCH 353/362] feat: add private script properties --- .../model/custom/script/model/CustomScript.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/core-script/src/main/java/org/gluu/model/custom/script/model/CustomScript.java b/core-script/src/main/java/org/gluu/model/custom/script/model/CustomScript.java index 3060404e..8e698cb2 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/model/CustomScript.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/model/CustomScript.java @@ -33,6 +33,8 @@ @ObjectClass("oxCustomScript") public class CustomScript extends BaseEntry { + private static final long serialVersionUID = -7507701887397812523L; + public static final String LOCATION_TYPE_MODEL_PROPERTY = "location_type"; public static final String LOCATION_PATH_MODEL_PROPERTY = "location_path"; @@ -61,12 +63,16 @@ public class CustomScript extends BaseEntry { @JsonObject @AttributeName(name = "oxModuleProperty") - private List moduleProperties =new ArrayList<>(); + private List moduleProperties = new ArrayList<>(); @JsonObject @AttributeName(name = "oxConfigurationProperty") private List configurationProperties; + @JsonObject + @AttributeName(name = "gluuPrivateProperty") + private List privateProperties; + @AttributeName(name = "oxLevel") private int level; @@ -105,6 +111,7 @@ public CustomScript(CustomScript customScript) { this.programmingLanguage = customScript.programmingLanguage; this.moduleProperties = customScript.moduleProperties; this.configurationProperties = customScript.configurationProperties; + this.privateProperties = customScript.privateProperties; this.level = customScript.level; this.revision = customScript.revision; this.enabled = customScript.enabled; @@ -195,6 +202,14 @@ public void setConfigurationProperties(List proper this.configurationProperties = properties; } + public List getPrivateProperties() { + return privateProperties; + } + + public void setPrivateProperties(List properties) { + this.privateProperties = properties; + } + public int getLevel() { return level; } From b2cd537d983cb789747370479932c7e12e46e11f Mon Sep 17 00:00:00 2001 From: Rolain Djeumen Date: Thu, 18 May 2023 10:30:51 +0100 Subject: [PATCH 354/362] fix: bug in downloadMetadata function caused NullPtrException --- .../main/java/org/gluu/saml/metadata/SAMLMetadataParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java index 553c7ba6..9ff3aa1a 100644 --- a/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java +++ b/oxSaml/src/main/java/org/gluu/saml/metadata/SAMLMetadataParser.java @@ -168,7 +168,7 @@ public EntityIDHandler parseMetadata(URL metadataURL) throws ClientProtocolExcep } public byte[] downloadMetadata(String metadataURL) throws IOException, ClientProtocolException { - HttpGet httpGet = new HttpGet(); + HttpGet httpGet = new HttpGet(metadataURL); httpGet.setHeader("Accept", "application/xml, text/xml"); byte[] metadataFileContent = null; From 22506283615d519de3ed436fa6c14a8e10d4179b Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Wed, 7 Feb 2024 19:22:33 +0300 Subject: [PATCH 355/362] chore: version 4.5.4-SNAPSHOT Signed-off-by: Yuriy Movchan --- core-cache/pom.xml | 2 +- core-cdi/pom.xml | 2 +- core-document-store/pom.xml | 2 +- core-java-ext/pom.xml | 2 +- core-script/pom.xml | 2 +- core-standalone/pom.xml | 2 +- core-timer-weld/pom.xml | 2 +- demo-cdi/pom.xml | 2 +- exception-extension-cdi/pom.xml | 2 +- jetty-session-store-jdbc-extended/pom.xml | 2 +- oxJsfUtil/pom.xml | 2 +- oxModel/pom.xml | 2 +- oxRadius/pom.xml | 2 +- oxSaml/pom.xml | 2 +- oxService/pom.xml | 2 +- oxUtil/pom.xml | 2 +- pom.xml | 4 ++-- security-extension-cdi/pom.xml | 2 +- server/pom.xml | 2 +- 19 files changed, 20 insertions(+), 20 deletions(-) diff --git a/core-cache/pom.xml b/core-cache/pom.xml index c0270533..6c53ad26 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/core-cdi/pom.xml b/core-cdi/pom.xml index 3c08d1af..e9f4dc70 100644 --- a/core-cdi/pom.xml +++ b/core-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index 2c73fc07..8fdaa41e 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/core-java-ext/pom.xml b/core-java-ext/pom.xml index 88b0daca..83501c73 100644 --- a/core-java-ext/pom.xml +++ b/core-java-ext/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/core-script/pom.xml b/core-script/pom.xml index 592d8d1c..31ba8911 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/core-standalone/pom.xml b/core-standalone/pom.xml index 3ce4a8df..efe9b484 100644 --- a/core-standalone/pom.xml +++ b/core-standalone/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/core-timer-weld/pom.xml b/core-timer-weld/pom.xml index 94233100..23038359 100644 --- a/core-timer-weld/pom.xml +++ b/core-timer-weld/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index b79652b5..162b1ca7 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/exception-extension-cdi/pom.xml b/exception-extension-cdi/pom.xml index 544a4d14..fd3076e4 100644 --- a/exception-extension-cdi/pom.xml +++ b/exception-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/jetty-session-store-jdbc-extended/pom.xml b/jetty-session-store-jdbc-extended/pom.xml index d3e163d9..0b4a814b 100644 --- a/jetty-session-store-jdbc-extended/pom.xml +++ b/jetty-session-store-jdbc-extended/pom.xml @@ -12,7 +12,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index 17b799a7..e0158064 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/oxModel/pom.xml b/oxModel/pom.xml index 9c0b41f9..d15305bf 100644 --- a/oxModel/pom.xml +++ b/oxModel/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/oxRadius/pom.xml b/oxRadius/pom.xml index ad0d1686..2a13c61c 100644 --- a/oxRadius/pom.xml +++ b/oxRadius/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index 80b46046..4f9e82bf 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/oxService/pom.xml b/oxService/pom.xml index c621f83e..da1cf0b1 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index 81031959..76e22709 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/pom.xml b/pom.xml index f08b5c38..035c2948 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.gluu oxcore pom - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT oxCore https://www.gluu.org @@ -50,7 +50,7 @@ org.gluu gluu-core-bom - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT import pom diff --git a/security-extension-cdi/pom.xml b/security-extension-cdi/pom.xml index e3504c8b..2416615b 100644 --- a/security-extension-cdi/pom.xml +++ b/security-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT diff --git a/server/pom.xml b/server/pom.xml index f4dbf0f0..84d91f17 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.6.0-SNAPSHOT + 4.5.4-SNAPSHOT From 90e048f427168ad305fee4374e14cbba4f8a72f3 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Mon, 22 Apr 2024 15:33:31 +0300 Subject: [PATCH 356/362] Version 4.5.5-SNAPSHOT --- core-cache/pom.xml | 2 +- core-cdi/pom.xml | 2 +- core-document-store/pom.xml | 2 +- core-java-ext/pom.xml | 2 +- core-script/pom.xml | 2 +- core-standalone/pom.xml | 2 +- core-timer-weld/pom.xml | 2 +- demo-cdi/pom.xml | 2 +- exception-extension-cdi/pom.xml | 2 +- jetty-session-store-jdbc-extended/pom.xml | 2 +- oxJsfUtil/pom.xml | 2 +- oxModel/pom.xml | 2 +- oxRadius/pom.xml | 2 +- oxSaml/pom.xml | 2 +- oxService/pom.xml | 2 +- oxUtil/pom.xml | 2 +- pom.xml | 4 ++-- security-extension-cdi/pom.xml | 2 +- server/pom.xml | 2 +- 19 files changed, 20 insertions(+), 20 deletions(-) diff --git a/core-cache/pom.xml b/core-cache/pom.xml index 6c53ad26..cc2be9bf 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/core-cdi/pom.xml b/core-cdi/pom.xml index e9f4dc70..7aac93b6 100644 --- a/core-cdi/pom.xml +++ b/core-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index 8fdaa41e..e3c949b8 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/core-java-ext/pom.xml b/core-java-ext/pom.xml index 83501c73..71377aad 100644 --- a/core-java-ext/pom.xml +++ b/core-java-ext/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/core-script/pom.xml b/core-script/pom.xml index 31ba8911..53765c81 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/core-standalone/pom.xml b/core-standalone/pom.xml index efe9b484..b16963d8 100644 --- a/core-standalone/pom.xml +++ b/core-standalone/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/core-timer-weld/pom.xml b/core-timer-weld/pom.xml index 23038359..2b9dad01 100644 --- a/core-timer-weld/pom.xml +++ b/core-timer-weld/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index 162b1ca7..52cbe88e 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/exception-extension-cdi/pom.xml b/exception-extension-cdi/pom.xml index fd3076e4..cdb62e35 100644 --- a/exception-extension-cdi/pom.xml +++ b/exception-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/jetty-session-store-jdbc-extended/pom.xml b/jetty-session-store-jdbc-extended/pom.xml index 0b4a814b..74d78a22 100644 --- a/jetty-session-store-jdbc-extended/pom.xml +++ b/jetty-session-store-jdbc-extended/pom.xml @@ -12,7 +12,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index e0158064..d95a7940 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/oxModel/pom.xml b/oxModel/pom.xml index d15305bf..f1fc9476 100644 --- a/oxModel/pom.xml +++ b/oxModel/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/oxRadius/pom.xml b/oxRadius/pom.xml index 2a13c61c..4f3b6567 100644 --- a/oxRadius/pom.xml +++ b/oxRadius/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index 4f9e82bf..f349ceac 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/oxService/pom.xml b/oxService/pom.xml index da1cf0b1..71631063 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index 76e22709..831db589 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/pom.xml b/pom.xml index 035c2948..35a4972c 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.gluu oxcore pom - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT oxCore https://www.gluu.org @@ -50,7 +50,7 @@ org.gluu gluu-core-bom - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT import pom diff --git a/security-extension-cdi/pom.xml b/security-extension-cdi/pom.xml index 2416615b..433875c2 100644 --- a/security-extension-cdi/pom.xml +++ b/security-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT diff --git a/server/pom.xml b/server/pom.xml index 84d91f17..907ca335 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.4-SNAPSHOT + 4.5.5-SNAPSHOT From e0211f4f27e694f9d6f984e026ae438890b3d513 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Fri, 28 Jun 2024 21:41:41 +0300 Subject: [PATCH 357/362] chore(fido2): merge from jans Signed-off-by: Yuriy Movchan --- .../model/custom/script/CustomScriptType.java | 5 +- .../type/fido2/DummyFido2ExtensionType.java | 76 +++++++++++ .../script/type/fido2/Fido2ExtensionType.java | 24 ++++ doc/pom.xml | 15 +++ .../gluu/doc/annotation/DocFeatureFlag.java | 16 +++ .../annotation/DocFeatureFlagProcessor.java | 112 ++++++++++++++++ .../org/gluu/doc/annotation/DocProperty.java | 16 +++ .../doc/annotation/DocPropertyProcessor.java | 120 ++++++++++++++++++ .../org/gluu/model/error/ErrorMessage.java | 76 +++++++++++ pom.xml | 1 + 10 files changed, 460 insertions(+), 1 deletion(-) create mode 100644 core-script/src/main/java/org/gluu/model/custom/script/type/fido2/DummyFido2ExtensionType.java create mode 100644 core-script/src/main/java/org/gluu/model/custom/script/type/fido2/Fido2ExtensionType.java create mode 100644 doc/pom.xml create mode 100644 doc/src/main/java/org/gluu/doc/annotation/DocFeatureFlag.java create mode 100644 doc/src/main/java/org/gluu/doc/annotation/DocFeatureFlagProcessor.java create mode 100644 doc/src/main/java/org/gluu/doc/annotation/DocProperty.java create mode 100644 doc/src/main/java/org/gluu/doc/annotation/DocPropertyProcessor.java create mode 100644 oxModel/src/main/java/org/gluu/model/error/ErrorMessage.java diff --git a/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java b/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java index d2b32ae7..2d25f2ef 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java @@ -17,6 +17,8 @@ import org.gluu.model.custom.script.type.ciba.EndUserNotificationType; import org.gluu.model.custom.script.type.client.ClientRegistrationType; import org.gluu.model.custom.script.type.client.DummyClientRegistrationType; +import org.gluu.model.custom.script.type.fido2.DummyFido2ExtensionType; +import org.gluu.model.custom.script.type.fido2.Fido2ExtensionType; import org.gluu.model.custom.script.type.id.DummyIdGeneratorType; import org.gluu.model.custom.script.type.id.IdGeneratorType; import org.gluu.model.custom.script.type.idp.DummyIdpType; @@ -89,7 +91,8 @@ public enum CustomScriptType implements AttributeEnum { REVOKE_TOKEN("revoke_token", "Revoke Token", RevokeTokenType.class, CustomScript.class, "RevokeToken", new DummyRevokeTokenType()), PERSISTENCE_EXTENSION("persistence_extension", "Persistence Extension", PersistenceType.class, CustomScript.class, "PersistenceExtension", new DummyPeristenceType()), IDP("idp", "Idp Extension", IdpType.class, CustomScript.class, "IdpExtension", new DummyIdpType()), - UPDATE_TOKEN("update_token", "Update Token", UpdateTokenType.class, CustomScript.class, "UpdateToken", new DummyUpdateTokenType()); + UPDATE_TOKEN("update_token", "Update Token", UpdateTokenType.class, CustomScript.class, "UpdateToken", new DummyUpdateTokenType()), + FIDO2_EXTENSION("fido2_extension", "Fido2 Extension", Fido2ExtensionType.class, CustomScript.class, "Fido2Extension", new DummyFido2ExtensionType()); private String value; private String displayName; diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/fido2/DummyFido2ExtensionType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/fido2/DummyFido2ExtensionType.java new file mode 100644 index 00000000..e3377918 --- /dev/null +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/fido2/DummyFido2ExtensionType.java @@ -0,0 +1,76 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2020, Gluu + */ + +package org.gluu.model.custom.script.type.fido2; + +import java.util.Map; + +import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.model.CustomScript; + +public class DummyFido2ExtensionType implements Fido2ExtensionType { + + @Override + public boolean init(Map configurationAttributes) { + return true; + } + + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return true; + } + + @Override + public boolean destroy(Map configurationAttributes) { + return true; + } + + @Override + public int getApiVersion() { + return 1; + } + + @Override + public boolean registerAttestationStart(Object paramAsJsonNode, Object context) { + return false; + } + + @Override + public boolean registerAttestationFinish(Object paramAsJsonNode, Object context) { + return false; + } + + @Override + public boolean verifyAttestationStart(Object paramAsJsonNode, Object context) { + return false; + } + + @Override + public boolean verifyAttestationFinish(Object paramAsJsonNode, Object context) { + return false; + } + + @Override + public boolean authenticateAssertionStart(Object paramAsJsonNode, Object context) { + return false; + } + + @Override + public boolean authenticateAssertionFinish(Object paramAsJsonNode, Object context) { + return false; + } + + @Override + public boolean verifyAssertionStart(Object paramAsJsonNode, Object context) { + return false; + } + + @Override + public boolean verifyAssertionFinish(Object paramAsJsonNode, Object context) { + return false; + } + +} diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/fido2/Fido2ExtensionType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/fido2/Fido2ExtensionType.java new file mode 100644 index 00000000..d9c9eedd --- /dev/null +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/fido2/Fido2ExtensionType.java @@ -0,0 +1,24 @@ +/* + * oxCore is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2020, Gluu + */ + +package org.gluu.model.custom.script.type.fido2; + +import org.gluu.model.custom.script.type.BaseExternalType; + +public interface Fido2ExtensionType extends BaseExternalType { + + boolean registerAttestationStart(Object paramAsJsonNode, Object context); + boolean registerAttestationFinish(Object paramAsJsonNode, Object context); + + boolean verifyAttestationStart(Object paramAsJsonNode, Object context); + boolean verifyAttestationFinish(Object paramAsJsonNode, Object context); + + boolean authenticateAssertionStart(Object paramAsJsonNode, Object context); + boolean authenticateAssertionFinish(Object paramAsJsonNode, Object context); + + boolean verifyAssertionStart(Object paramAsJsonNode, Object context); + boolean verifyAssertionFinish(Object paramAsJsonNode, Object context); +} diff --git a/doc/pom.xml b/doc/pom.xml new file mode 100644 index 00000000..c9fb1a5d --- /dev/null +++ b/doc/pom.xml @@ -0,0 +1,15 @@ + + + org.gluu + oxcore + 4.5.5-SNAPSHOT + + + 4.0.0 + gluu-doc + jar + gluu-doc + + + diff --git a/doc/src/main/java/org/gluu/doc/annotation/DocFeatureFlag.java b/doc/src/main/java/org/gluu/doc/annotation/DocFeatureFlag.java new file mode 100644 index 00000000..613fde79 --- /dev/null +++ b/doc/src/main/java/org/gluu/doc/annotation/DocFeatureFlag.java @@ -0,0 +1,16 @@ +package org.gluu.doc.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.SOURCE) +public @interface DocFeatureFlag { + String description(); + + boolean isRequired() default false; + + String defaultValue(); +} diff --git a/doc/src/main/java/org/gluu/doc/annotation/DocFeatureFlagProcessor.java b/doc/src/main/java/org/gluu/doc/annotation/DocFeatureFlagProcessor.java new file mode 100644 index 00000000..f9c40196 --- /dev/null +++ b/doc/src/main/java/org/gluu/doc/annotation/DocFeatureFlagProcessor.java @@ -0,0 +1,112 @@ +package org.gluu.doc.annotation; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedOptions; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; +import javax.tools.FileObject; +import javax.tools.StandardLocation; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@SupportedAnnotationTypes("org.gluu.doc.annotation.DocFeatureFlag") +@SupportedOptions({"module"}) +public class DocFeatureFlagProcessor extends AbstractProcessor { + + String moduleName; + @Override + public boolean process(Set annotations, RoundEnvironment env) { + + moduleName = processingEnv.getOptions().get("module"); + + for (TypeElement annotation : annotations) { + Set annotatedElements = env.getElementsAnnotatedWith(annotation); + + // sort alphabetically + List sortedElements = annotatedElements.stream() + .sorted((prop1, prop2)->prop1.getSimpleName().toString().toLowerCase().compareTo(prop2.getSimpleName().toString().toLowerCase())) + .collect(Collectors.toList()); + + StringBuilder docContents = new StringBuilder(); + StringBuilder tableContents = new StringBuilder(); + StringBuilder detailsContent = new StringBuilder(); + + // prepare document header + prepareDocTagsAndTableHeader(docContents, tableContents); + + // for each feature flag add a row in table and add content for the details section + for (Element element : sortedElements) + { + DocFeatureFlag elementAnnotation = element.getAnnotation(DocFeatureFlag.class); + addToTable(tableContents, element, elementAnnotation); + addToDetails(detailsContent, element, elementAnnotation); + } + tableContents.append("\n\n"); + createAndWriteDoc(docContents.append((tableContents.append(detailsContent.toString())))); + + } + return false; + } + + private void prepareDocTagsAndTableHeader(StringBuilder docContents, StringBuilder tableContents) { + // add tags + docContents.append("---\n") + .append("tags:\n") + .append("- administration\n") + .append("- reference\n") + .append("- json\n") + .append("- feature-flags\n") + .append("---\n") + .append("\n") + .append("# "+moduleName+" Feature Flags") // add doc header + .append("\n") + .append("\n"); + + tableContents.append("| Feature Flag Name ") // prepare table header + .append("| Description ") + .append("| | ") + .append("\n") + .append("|-----|-----|-----|") + .append("\n"); + } + + private void createAndWriteDoc(StringBuilder docContent) { + + FileObject docFile = null; + try{ + docFile = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", moduleName.toLowerCase().replaceAll("\\s", "")+"-feature-flags.md"); + } + catch (IOException ioe){ + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, this.getClass().getName()+": Error occurred while creating annotation documentation file"); + } + if(docFile!=null){ + try(PrintWriter docWriter = new PrintWriter(docFile.openWriter());) { + docWriter.write(docContent.toString()); + docWriter.flush(); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, this.getClass().getName()+": Error occurred while writing annotation documentation file"); + } + } + } + + private static void addToDetails(StringBuilder propDetails, Element jansElement, DocFeatureFlag featureFlagAnnotation) { + propDetails.append("### "+ jansElement.getSimpleName()+"\n\n"); + propDetails.append("- Description: "+ featureFlagAnnotation.description()+"\n\n"); + propDetails.append("- Required: "+ (featureFlagAnnotation.isRequired()?"Yes":"No")+"\n\n"); + propDetails.append("- Default value: "+ featureFlagAnnotation.defaultValue()+"\n\n"); + propDetails.append("\n"); + } + + private static void addToTable(StringBuilder propTable, Element jansElement, DocFeatureFlag featureFlagAnnotation) { + propTable.append("| "+ jansElement.getSimpleName()+" "); + propTable.append("| "+ featureFlagAnnotation.description()+" "); + propTable.append("| [Details](#"+jansElement.getSimpleName().toString().toLowerCase()+") |"); + propTable.append("\n"); + } +} diff --git a/doc/src/main/java/org/gluu/doc/annotation/DocProperty.java b/doc/src/main/java/org/gluu/doc/annotation/DocProperty.java new file mode 100644 index 00000000..e2126c86 --- /dev/null +++ b/doc/src/main/java/org/gluu/doc/annotation/DocProperty.java @@ -0,0 +1,16 @@ +package org.gluu.doc.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.SOURCE) +public @interface DocProperty { + String description() default "None"; + + boolean isRequired() default false; + + String defaultValue() default "None"; +} diff --git a/doc/src/main/java/org/gluu/doc/annotation/DocPropertyProcessor.java b/doc/src/main/java/org/gluu/doc/annotation/DocPropertyProcessor.java new file mode 100644 index 00000000..614703b2 --- /dev/null +++ b/doc/src/main/java/org/gluu/doc/annotation/DocPropertyProcessor.java @@ -0,0 +1,120 @@ +package org.gluu.doc.annotation; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedOptions; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; +import javax.tools.FileObject; +import javax.tools.StandardLocation; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@SupportedAnnotationTypes("org.gluu.doc.annotation.DocProperty") +@SupportedOptions({"module"}) +public class DocPropertyProcessor extends AbstractProcessor { + + String moduleName; + + // This method would be called once per class containing annotated elements + @Override + public boolean process(Set annotations, RoundEnvironment env) { + + moduleName = processingEnv.getOptions().get("module"); + + // Loop iterates once per supported annotation type by this processor + for (TypeElement annotation : annotations) { + + // Get all the elements that are annotated by a particular annotation located across classes in this module + Set annotatedProperties = env.getElementsAnnotatedWith(annotation); + + // sort alphabetically + List sortedProperties = annotatedProperties.stream() + .sorted((prop1, prop2)->prop1.getSimpleName().toString().toLowerCase().compareTo(prop2.getSimpleName().toString().toLowerCase())) + .collect(Collectors.toList()); + + StringBuilder docContents = new StringBuilder(); + StringBuilder tableContents = new StringBuilder(); + StringBuilder detailsContent = new StringBuilder(); + + // prepare document header + prepareDocTagsAndTableHeader(docContents, tableContents); + + // for each property add a row in table and add content for the details section + for (Element jansProperty : sortedProperties) + { + DocProperty propertyAnnotation = jansProperty.getAnnotation(DocProperty.class); + addToTable(tableContents, jansProperty, propertyAnnotation); + addToDetails(detailsContent, jansProperty, propertyAnnotation); + } + tableContents.append("\n\n"); + docContents.append((tableContents.append(detailsContent.toString()))); + createAndWriteDoc(docContents); + + } + return false; + } + + private void prepareDocTagsAndTableHeader(StringBuilder docContents, StringBuilder tableContents) { + + // add tags + docContents.append("---\n") + .append("tags:\n") + .append("- administration\n") + .append("- reference\n") + .append("- json\n") + .append("- properties\n") + .append("---\n") + .append("\n") + .append("# "+moduleName+" Configuration Properties") // add doc headers + .append("\n") + .append("\n"); + + tableContents.append("| Property Name ") // prepare table header + .append("| Description ") + .append("| | ") + .append("\n") + .append("|-----|-----|-----|") + .append("\n"); + } + + private void createAndWriteDoc(StringBuilder docContent) { + + FileObject docFile = null; + try{ + docFile = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", moduleName.toLowerCase().replaceAll("\\s", "")+"-properties.md"); + } + catch (IOException ioe){ + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, this.getClass().getName()+": Error occurred while creating annotation documentation file"); + } + if(docFile!=null){ + try(PrintWriter docWriter = new PrintWriter(docFile.openWriter());) { + docWriter.write(docContent.toString()); + docWriter.flush(); + } catch (IOException e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, this.getClass().getName()+": Error occurred while writing annotation documentation file"); + } + } + + } + + private static void addToDetails(StringBuilder propDetails, Element jansProperty, DocProperty propertyAnnotation) { + propDetails.append("### "+ jansProperty.getSimpleName()+"\n\n"); + propDetails.append("- Description: "+ propertyAnnotation.description()+"\n\n"); + propDetails.append("- Required: "+ (propertyAnnotation.isRequired()?"Yes":"No")+"\n\n"); + propDetails.append("- Default value: "+ propertyAnnotation.defaultValue()+"\n\n"); + propDetails.append("\n"); + } + + private static void addToTable(StringBuilder propTable, Element jansProperty, DocProperty propertyAnnotation) { + propTable.append("| "+ jansProperty.getSimpleName()+" "); + propTable.append("| "+ propertyAnnotation.description()+" "); + propTable.append("| [Details](#"+jansProperty.getSimpleName().toString().toLowerCase()+") |"); + propTable.append("\n"); + } +} diff --git a/oxModel/src/main/java/org/gluu/model/error/ErrorMessage.java b/oxModel/src/main/java/org/gluu/model/error/ErrorMessage.java new file mode 100644 index 00000000..580f6a35 --- /dev/null +++ b/oxModel/src/main/java/org/gluu/model/error/ErrorMessage.java @@ -0,0 +1,76 @@ +/* + * oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text. + * + * Copyright (c) 2014, Gluu + */ + +package org.gluu.model.error; + +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + *

+ * Represents an error message in a configuration XML file. + *

+ *

+ * The attribute id is REQUIRED. A single error code. + *

+ *

+ * The element description is OPTIONAL. A human-readable UTF-8 encoded text + * providing additional information, used to assist the client developer in + * understanding the error that occurred. + *

+ *

+ * The element URI is OPTIONAL. A URI identifying a human-readable web page with + * information about the error, used to provide the client developer with + * additional information about the error. + *

+ * + * @author Javier Rojas Date: 09.23.2011 + * + */ +@XmlRootElement(name = "error") +public class ErrorMessage { + + private String id; + private String description; + private String uri; + + public ErrorMessage() { + } + + public ErrorMessage(String id, String description, String uri) { + this.id = id; + this.description = description; + this.uri = uri; + } + + @XmlAttribute(name = "id") + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + @XmlElement(name = "error-description") + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + @XmlElement(name = "error-uri") + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } +} diff --git a/pom.xml b/pom.xml index 35a4972c..3f982e83 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,7 @@ server oxRadius demo-cdi + doc
From f6ec0a6e380c8e7e59dc941d38145256508c9aeb Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Fri, 28 Jun 2024 22:32:07 +0300 Subject: [PATCH 358/362] feat(core): merge loggin changes Signed-off-by: Yuriy Movchan --- .../gluu/service/logger/LoggerService.java | 79 ++++++++++++------- 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/oxService/src/main/java/org/gluu/service/logger/LoggerService.java b/oxService/src/main/java/org/gluu/service/logger/LoggerService.java index cb94ae7a..b02d04be 100644 --- a/oxService/src/main/java/org/gluu/service/logger/LoggerService.java +++ b/oxService/src/main/java/org/gluu/service/logger/LoggerService.java @@ -1,18 +1,17 @@ package org.gluu.service.logger; +import java.io.File; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.LogManager; + +import javax.annotation.PostConstruct; +import javax.enterprise.event.Event; +import javax.enterprise.event.Observes; +import javax.inject.Inject; + import org.apache.commons.lang.StringUtils; import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.appender.AbstractAppender; -import org.apache.logging.log4j.core.appender.ConsoleAppender; -import org.apache.logging.log4j.core.appender.RollingFileAppender; -import org.apache.logging.log4j.core.config.AbstractConfiguration; -import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.config.LoggerConfig; -import org.apache.logging.log4j.core.layout.JsonLayout; -import org.apache.logging.log4j.core.layout.PatternLayout; import org.gluu.model.types.LoggingLayoutType; import org.gluu.service.cdi.async.Asynchronous; import org.gluu.service.cdi.event.ConfigurationUpdate; @@ -23,16 +22,6 @@ import org.gluu.util.StringHelper; import org.slf4j.Logger; -import javax.annotation.PostConstruct; -import javax.enterprise.event.Event; -import javax.enterprise.event.Observes; -import javax.inject.Inject; -import java.io.File; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.logging.LogManager; - /** * Logger service * @@ -48,6 +37,8 @@ public abstract class LoggerService { @Inject private Event timerEvent; + private Level prevLogLevel; + private AtomicBoolean isActive; @PostConstruct @@ -56,15 +47,26 @@ public void create() { } public void initTimer() { + initTimer(false); + } + + public void initTimer(boolean updateNow) { log.info("Initializing Logger Update Timer"); final int delay = 15; final int interval = DEFAULT_INTERVAL; + + this.prevLogLevel = getCurrentLogLevel(); timerEvent.fire(new TimerEvent(new TimerSchedule(delay, interval), new LoggerUpdateEvent(), Scheduled.Literal.INSTANCE)); + + if (updateNow) { + updateLoggerTimerEvent(null); + } } + @Asynchronous public void updateLoggerTimerEvent(@Observes @Scheduled LoggerUpdateEvent loggerUpdateEvent) { if (this.isActive.get()) { @@ -77,6 +79,7 @@ public void updateLoggerTimerEvent(@Observes @Scheduled LoggerUpdateEvent logger try { updateLoggerConfiguration(); + this.prevLogLevel = getCurrentLogLevel(); } catch (Throwable ex) { log.error("Exception happened while updating newly added logger configuration", ex); } finally { @@ -95,7 +98,7 @@ private void updateLoggerConfiguration() { Level level = Level.toLevel(loggingLevel, Level.INFO); LoggingLayoutType loggingLayout = LoggingLayoutType.getByValue(this.getLoggingLayout().toUpperCase()); - updateAppendersAndLogLevel(loggingLayout, level); + updateAppendersAndLogLevel(loggingLayout, prevLogLevel, level); } public void updateLoggerSeverity(@Observes @ConfigurationUpdate Object appConfiguration) { @@ -141,7 +144,7 @@ private void updateLoggerSeverityImpl() { log.info("Setting layout and loggers level to '{}`, `{}' after configuration update", loggingLayout, loggingLevel); - updateAppendersAndLogLevel(loggingLayout, level); + updateAppendersAndLogLevel(loggingLayout, prevLogLevel, level); } private void setDisableJdkLogger() { @@ -184,25 +187,29 @@ public void resetLoggerConfigLocation() { loggerContext.reconfigure(); } - private void updateAppendersAndLogLevel(LoggingLayoutType loggingLayout, Level level) { + private void updateAppendersAndLogLevel(LoggingLayoutType loggingLayout, Level prevLevel, Level newLevel) { if (loggingLayout == LoggingLayoutType.TEXT) { - final LoggerContext ctx = LoggerContext.getContext(false); - ctx.reconfigure(); - LoggerContext loggerContext = LoggerContext.getContext(false); + if (newLevel != prevLevel) { + final LoggerContext ctx = LoggerContext.getContext(false); + ctx.getConfiguration().getRootLogger().setLevel(newLevel); + ctx.reconfigure(); + } + + LoggerContext loggerContext = LoggerContext.getContext(false); int count = 0; for (org.apache.logging.log4j.core.Logger logger : loggerContext.getLoggers()) { String loggerName = logger.getName(); if (loggerName.startsWith("org.gluu")) { - if (logger.getLevel() != level) { + if (logger.getLevel() != newLevel) { count++; - logger.setLevel(level); + logger.setLevel(newLevel); } } } if (count > 0) { - log.info("Updated log level of '{}' loggers to {}", count, level.toString()); + log.info("Updated log level of '{}' loggers to {}", count, newLevel.toString()); } } // boolean runLoggersUpdate = false; @@ -280,7 +287,19 @@ private void updateAppendersAndLogLevel(LoggingLayoutType loggingLayout, Level l // ctx.updateLoggers(); // } } - + + private Level getCurrentLogLevel() { + String loggingLevel = getLoggingLevel(); + if (StringHelper.isEmpty(loggingLevel) || StringUtils.isEmpty(this.getLoggingLayout()) + || StringHelper.equalsIgnoreCase("DEFAULT", loggingLevel)) { + return Level.INFO; + } + + Level level = Level.toLevel(loggingLevel, Level.INFO); + + return level; + } + public abstract boolean isDisableJdkLogger(); public abstract String getLoggingLevel(); From fcb1f4bb2b6cf98ce345e5fee63ebae6bef574b1 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Sat, 29 Jun 2024 09:48:16 +0300 Subject: [PATCH 359/362] feat(core): merge from jans Signed-off-by: Yuriy Movchan --- core-cache/src/main/java/org/gluu/service/BaseCacheService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-cache/src/main/java/org/gluu/service/BaseCacheService.java b/core-cache/src/main/java/org/gluu/service/BaseCacheService.java index e4ad7760..b3ed5ae5 100644 --- a/core-cache/src/main/java/org/gluu/service/BaseCacheService.java +++ b/core-cache/src/main/java/org/gluu/service/BaseCacheService.java @@ -22,7 +22,7 @@ */ public abstract class BaseCacheService implements CacheInterface { - private static int DEFAULT_EXPIRATION = 60; + public static int DEFAULT_EXPIRATION = 60; @Inject private Logger log; From fd7dc24cdac22c266239244db6b8c92fed18a903 Mon Sep 17 00:00:00 2001 From: Yuriy Movchan Date: Wed, 31 Jul 2024 14:38:07 +0300 Subject: [PATCH 360/362] Version 4.5.6-SNAPSHOT --- core-cache/pom.xml | 2 +- core-cdi/pom.xml | 2 +- core-document-store/pom.xml | 2 +- core-java-ext/pom.xml | 2 +- core-script/pom.xml | 2 +- core-standalone/pom.xml | 2 +- core-timer-weld/pom.xml | 2 +- demo-cdi/pom.xml | 2 +- doc/pom.xml | 2 +- exception-extension-cdi/pom.xml | 2 +- jetty-session-store-jdbc-extended/pom.xml | 2 +- oxJsfUtil/pom.xml | 2 +- oxModel/pom.xml | 2 +- oxRadius/pom.xml | 2 +- oxSaml/pom.xml | 2 +- oxService/pom.xml | 2 +- oxUtil/pom.xml | 2 +- pom.xml | 4 ++-- security-extension-cdi/pom.xml | 2 +- server/pom.xml | 2 +- 20 files changed, 21 insertions(+), 21 deletions(-) diff --git a/core-cache/pom.xml b/core-cache/pom.xml index cc2be9bf..68f02ee4 100644 --- a/core-cache/pom.xml +++ b/core-cache/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/core-cdi/pom.xml b/core-cdi/pom.xml index 7aac93b6..91dbff93 100644 --- a/core-cdi/pom.xml +++ b/core-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/core-document-store/pom.xml b/core-document-store/pom.xml index e3c949b8..65fe0401 100644 --- a/core-document-store/pom.xml +++ b/core-document-store/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/core-java-ext/pom.xml b/core-java-ext/pom.xml index 71377aad..064f83e3 100644 --- a/core-java-ext/pom.xml +++ b/core-java-ext/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/core-script/pom.xml b/core-script/pom.xml index 53765c81..f7d11cb2 100644 --- a/core-script/pom.xml +++ b/core-script/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/core-standalone/pom.xml b/core-standalone/pom.xml index b16963d8..c9b0a9a1 100644 --- a/core-standalone/pom.xml +++ b/core-standalone/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/core-timer-weld/pom.xml b/core-timer-weld/pom.xml index 2b9dad01..e5ab6878 100644 --- a/core-timer-weld/pom.xml +++ b/core-timer-weld/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/demo-cdi/pom.xml b/demo-cdi/pom.xml index 52cbe88e..d868e766 100644 --- a/demo-cdi/pom.xml +++ b/demo-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/doc/pom.xml b/doc/pom.xml index c9fb1a5d..c88fa3e9 100644 --- a/doc/pom.xml +++ b/doc/pom.xml @@ -3,7 +3,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT 4.0.0 diff --git a/exception-extension-cdi/pom.xml b/exception-extension-cdi/pom.xml index cdb62e35..f0168b1c 100644 --- a/exception-extension-cdi/pom.xml +++ b/exception-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/jetty-session-store-jdbc-extended/pom.xml b/jetty-session-store-jdbc-extended/pom.xml index 74d78a22..5338d49f 100644 --- a/jetty-session-store-jdbc-extended/pom.xml +++ b/jetty-session-store-jdbc-extended/pom.xml @@ -12,7 +12,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/oxJsfUtil/pom.xml b/oxJsfUtil/pom.xml index d95a7940..3f7a1ce9 100644 --- a/oxJsfUtil/pom.xml +++ b/oxJsfUtil/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/oxModel/pom.xml b/oxModel/pom.xml index f1fc9476..4b48f7ca 100644 --- a/oxModel/pom.xml +++ b/oxModel/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/oxRadius/pom.xml b/oxRadius/pom.xml index 4f3b6567..66c3fd2e 100644 --- a/oxRadius/pom.xml +++ b/oxRadius/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/oxSaml/pom.xml b/oxSaml/pom.xml index f349ceac..a5c0e31e 100644 --- a/oxSaml/pom.xml +++ b/oxSaml/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/oxService/pom.xml b/oxService/pom.xml index 71631063..cfb66e9e 100644 --- a/oxService/pom.xml +++ b/oxService/pom.xml @@ -10,7 +10,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/oxUtil/pom.xml b/oxUtil/pom.xml index 831db589..b6cf2bba 100644 --- a/oxUtil/pom.xml +++ b/oxUtil/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/pom.xml b/pom.xml index 3f982e83..9f119a30 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ org.gluu oxcore pom - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT oxCore https://www.gluu.org @@ -51,7 +51,7 @@ org.gluu gluu-core-bom - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT import pom diff --git a/security-extension-cdi/pom.xml b/security-extension-cdi/pom.xml index 433875c2..b78634ac 100644 --- a/security-extension-cdi/pom.xml +++ b/security-extension-cdi/pom.xml @@ -8,7 +8,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT diff --git a/server/pom.xml b/server/pom.xml index 907ca335..129b2318 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -9,7 +9,7 @@ org.gluu oxcore - 4.5.5-SNAPSHOT + 4.5.6-SNAPSHOT From c82410db6386118d9a03021456c670ee9ba8f2c2 Mon Sep 17 00:00:00 2001 From: YuriyZ Date: Mon, 7 Oct 2024 14:24:02 +0300 Subject: [PATCH 361/362] feat(oxauth): added new authorization challenge custom script definition #1925 (#276) https://github.com/GluuFederation/oxAuth/issues/1925 --- .../model/custom/script/CustomScriptType.java | 6 ++- .../AuthorizationChallengeType.java | 11 ++++++ .../DummyAuthorizationChallengeType.java | 37 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 core-script/src/main/java/org/gluu/model/custom/script/type/authzchallenge/AuthorizationChallengeType.java create mode 100644 core-script/src/main/java/org/gluu/model/custom/script/type/authzchallenge/DummyAuthorizationChallengeType.java diff --git a/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java b/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java index 2d25f2ef..9f29d516 100644 --- a/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java +++ b/core-script/src/main/java/org/gluu/model/custom/script/CustomScriptType.java @@ -13,6 +13,8 @@ import org.gluu.model.custom.script.type.auth.PersonAuthenticationType; import org.gluu.model.custom.script.type.authz.ConsentGatheringType; import org.gluu.model.custom.script.type.authz.DummyConsentGatheringType; +import org.gluu.model.custom.script.type.authzchallenge.AuthorizationChallengeType; +import org.gluu.model.custom.script.type.authzchallenge.DummyAuthorizationChallengeType; import org.gluu.model.custom.script.type.ciba.DummyEndUserNotificationType; import org.gluu.model.custom.script.type.ciba.EndUserNotificationType; import org.gluu.model.custom.script.type.client.ClientRegistrationType; @@ -43,9 +45,10 @@ import org.gluu.model.custom.script.type.session.DummyApplicationSessionType; import org.gluu.model.custom.script.type.spontaneous.DummySpontaneousScopeType; import org.gluu.model.custom.script.type.spontaneous.SpontaneousScopeType; +import org.gluu.model.custom.script.type.token.DummyUpdateTokenType; +import org.gluu.model.custom.script.type.token.UpdateTokenType; import org.gluu.model.custom.script.type.uma.*; import org.gluu.model.custom.script.type.user.*; -import org.gluu.model.custom.script.type.token.*; import org.gluu.persist.annotation.AttributeEnum; import java.util.HashMap; @@ -60,6 +63,7 @@ public enum CustomScriptType implements AttributeEnum { PERSON_AUTHENTICATION("person_authentication", "Person Authentication", PersonAuthenticationType.class, AuthenticationCustomScript.class, "PersonAuthentication", new DummyPersonAuthenticationType()), + AUTHORIZATION_CHALLENGE("authorization_challenge", "Authorization Challenge", AuthorizationChallengeType.class, CustomScript.class, "AuthorizationChallenge", new DummyAuthorizationChallengeType()), INTROSPECTION("introspection", "Introspection", IntrospectionType.class, CustomScript.class, "Introspection", new DummyIntrospectionType()), RESOURCE_OWNER_PASSWORD_CREDENTIALS("resource_owner_password_credentials", "Resource Owner Password Credentials", ResourceOwnerPasswordCredentialsType.class, CustomScript.class, "ResourceOwnerPasswordCredentials", new DummyResourceOwnerPasswordCredentialsType()), APPLICATION_SESSION("application_session", "Application Session", ApplicationSessionType.class, CustomScript.class, "ApplicationSession", diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/authzchallenge/AuthorizationChallengeType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/authzchallenge/AuthorizationChallengeType.java new file mode 100644 index 00000000..f9f3f0be --- /dev/null +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/authzchallenge/AuthorizationChallengeType.java @@ -0,0 +1,11 @@ +package org.gluu.model.custom.script.type.authzchallenge; + +import org.gluu.model.custom.script.type.BaseExternalType; + +/** + * @author Yuriy Z + */ +public interface AuthorizationChallengeType extends BaseExternalType { + + boolean authorize(Object context); +} diff --git a/core-script/src/main/java/org/gluu/model/custom/script/type/authzchallenge/DummyAuthorizationChallengeType.java b/core-script/src/main/java/org/gluu/model/custom/script/type/authzchallenge/DummyAuthorizationChallengeType.java new file mode 100644 index 00000000..e33d5213 --- /dev/null +++ b/core-script/src/main/java/org/gluu/model/custom/script/type/authzchallenge/DummyAuthorizationChallengeType.java @@ -0,0 +1,37 @@ +package org.gluu.model.custom.script.type.authzchallenge; + +import org.gluu.model.SimpleCustomProperty; +import org.gluu.model.custom.script.model.CustomScript; + +import java.util.Map; + +/** + * @author Yuriy Z + */ +public class DummyAuthorizationChallengeType implements AuthorizationChallengeType { + + @Override + public boolean authorize(Object context) { + return false; + } + + @Override + public boolean init(Map configurationAttributes) { + return false; + } + + @Override + public boolean init(CustomScript customScript, Map configurationAttributes) { + return false; + } + + @Override + public boolean destroy(Map configurationAttributes) { + return false; + } + + @Override + public int getApiVersion() { + return 1; + } +} From 077a4b76e1f18433b63ce9c47901addba0fb267d Mon Sep 17 00:00:00 2001 From: Mohammad Abudayyeh <47318409+moabu@users.noreply.github.com> Date: Mon, 14 Oct 2024 12:26:19 +0300 Subject: [PATCH 362/362] docs: move to monorepo Signed-off-by: Mohammad Abudayyeh <47318409+moabu@users.noreply.github.com> --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3ef3dac2..5ed54751 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ +# Moved to [Gluu4 monorepo](https://github.com/GluuFederation/gluu4/tree/main/oxCore) oxCore ======