diff --git a/.asf.yaml b/.asf.yaml index 3b0662d64b8..632495fb372 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -22,17 +22,18 @@ github: - request-routing - service-mesh - microservices + dependabot_alerts: false + dependabot_updates: true enabled_merge_buttons: - # enable squash button: - squash: true - # enable merge button: - merge: false - # disable rebase button: - rebase: true + squash: true + squash_commit_message: PR_TITLE + merge: false + rebase: true - notifications: - commits: commits@syncope.apache.org - issues: dev@syncope.apache.org - pullrequests_status: dev@syncope.apache.org - pullrequests_comment: dev@syncope.apache.org - jira_options: link label worklog +notifications: + commits: commits@syncope.apache.org + issues: dev@syncope.apache.org + pullrequests_status: dev@syncope.apache.org + pullrequests_comment: dev@syncope.apache.org + pullrequests_bot_dependabot: dev@syncope.apache.org + jira_options: link label worklog diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 779056e11be..00000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,22 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d9e36d2eb21..d9d8950afc7 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -18,10 +18,10 @@ name: "CodeQL" on: push: - branches: [master,2_1_X,pr-*] + branches: [3_0_X,pr-*] pull_request: # The branches below must be a subset of the branches above - branches: [master,2_1_X] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -29,6 +29,10 @@ jobs: analyze: name: Analyze runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write strategy: fail-fast: false @@ -41,21 +45,26 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -80,4 +89,4 @@ jobs: mvn -T 1C -PskipTests,all - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/crosschecks.yml b/.github/workflows/crosschecks.yml index 0c821532693..e0a562802da 100644 --- a/.github/workflows/crosschecks.yml +++ b/.github/workflows/crosschecks.yml @@ -18,10 +18,10 @@ name: "Cross Checks" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -38,17 +38,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: ${{ matrix.java }} - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: Validate diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml new file mode 100644 index 00000000000..37d071f7f10 --- /dev/null +++ b/.github/workflows/dockerhub.yml @@ -0,0 +1,75 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License +name: "Push to DockerHub" + +on: + push: + branches: + - 3_0_X + +jobs: + push2DockerHub: + runs-on: ubuntu-latest + + steps: + - name: Disk space before + run: df . -h + - name: Free disk space + run: | + sudo docker rmi $(docker image ls -aq) >/dev/null 2>&1 || true + sudo rm -rf /usr/share/dotnet/ /usr/local/graalvm/ /usr/local/.ghcup/ \ + /usr/local/share/powershell /usr/local/share/chromium /usr/local/share/boost \ + /usr/local/lib/android /usr/local/lib/node_modules /opt/hostedtoolcache/CodeQL \ + /opt/ghc /usr/local/.ghcup || true + echo "some directories deleted" + sudo apt-get remove --purge -y google-chrome-stable >/dev/null 2>&1 || true + sudo apt-get remove --purge -y microsoft-edge-stable >/dev/null 2>&1 || true + sudo apt-get remove --purge -y firefox >/dev/null 2>&1 || true + sudo apt-get remove --purge -y '^dotnet-.*' >/dev/null 2>&1 || true + sudo apt-get remove --purge -y '^llvm-.*' >/dev/null 2>&1 || true + sudo apt-get remove --purge -y 'php.*' >/dev/null 2>&1 || true + sudo apt-get remove --purge -y '^mongodb-.*' >/dev/null 2>&1 || true + sudo apt-get remove --purge -y '^mysql-.*' >/dev/null 2>&1 || true + sudo apt-get remove --purge -y '^postgresql-.*' >/dev/null 2>&1 || true + sudo apt-get remove --purge -y temurin-* >/dev/null 2>&1 || true + sudo apt-get remove --purge -y azure-cli google-cloud-cli* powershell >/dev/null 2>&1 || true + sudo apt-get autoremove -y + sudo apt-get autoclean -y + echo "some packages purged" + - name: Disk space after + run: df . -h + - name: Checkout repository + uses: actions/checkout@v6 + - name: Setup Java JDK + uses: actions/setup-java@v5 + with: + distribution: 'zulu' + java-version: 11 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 + with: + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Build + run: mvn -U -T 1C -P 'skipTests,all,docker' + - name: 'Push to DockerHub' + run: mvn -f docker/pom.xml docker:push -Ddocker.username=${{secrets.DOCKERHUB_USER}} -Ddocker.password=${{secrets.DOCKERHUB_TOKEN}} diff --git a/.github/workflows/fit_Elasticsearch.yml b/.github/workflows/fit_Elasticsearch.yml index 6ff57c89b94..67fd89e399b 100644 --- a/.github/workflows/fit_Elasticsearch.yml +++ b/.github/workflows/fit_Elasticsearch.yml @@ -18,10 +18,10 @@ name: "FIT Elasticsearch" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Elasticsearch / H2 / JSON' diff --git a/.github/workflows/fit_OpenSearch.yml b/.github/workflows/fit_OpenSearch.yml new file mode 100644 index 00000000000..7a51f565312 --- /dev/null +++ b/.github/workflows/fit_OpenSearch.yml @@ -0,0 +1,53 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License +name: "FIT OpenSearch" + +on: + push: + branches: ['3_0_X', 'pr-*'] + pull_request: + # The branches below must be a subset of the branches above + branches: [3_0_X] + schedule: + - cron: '0 13 * * 4' + +jobs: + fit_OpenSearch: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + - name: Setup Java JDK + uses: actions/setup-java@v5 + with: + distribution: 'zulu' + java-version: 11 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 + with: + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Build + run: mvn -U -T 1C -P 'skipTests,all' + - name: 'OpenSearch / H2 / JSON' + run: mvn -f fit/core-reference/pom.xml -P opensearch-it -Dinvoker.streamLogs=true -Dmodernizer.skip=true -Drat.skip=true -Dcheckstyle.skip=true -Djacoco.skip=true diff --git a/.github/workflows/fit_Payara.yml b/.github/workflows/fit_Payara.yml index 903ad3e6355..843a19cfbd1 100644 --- a/.github/workflows/fit_Payara.yml +++ b/.github/workflows/fit_Payara.yml @@ -18,10 +18,10 @@ name: "FIT Payara" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Payara / H2 / JSON' diff --git a/.github/workflows/fit_Tomcat_H2_JSON.yml b/.github/workflows/fit_Tomcat_H2_JSON.yml index 546f00d0709..35205ed479e 100644 --- a/.github/workflows/fit_Tomcat_H2_JSON.yml +++ b/.github/workflows/fit_Tomcat_H2_JSON.yml @@ -18,10 +18,10 @@ name: "FIT Tomcat H2 JSON" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Tomcat / H2 / JSON' diff --git a/.github/workflows/fit_Tomcat_H2_XML.yml b/.github/workflows/fit_Tomcat_H2_XML.yml index 4482ce97d06..5eeadd14d97 100644 --- a/.github/workflows/fit_Tomcat_H2_XML.yml +++ b/.github/workflows/fit_Tomcat_H2_XML.yml @@ -18,10 +18,10 @@ name: "FIT Tomcat H2 XML" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Tomcat / H2 / XML' diff --git a/.github/workflows/fit_Tomcat_H2_YAML.yml b/.github/workflows/fit_Tomcat_H2_YAML.yml index 141b74c91ab..5334f9d4b8b 100644 --- a/.github/workflows/fit_Tomcat_H2_YAML.yml +++ b/.github/workflows/fit_Tomcat_H2_YAML.yml @@ -18,10 +18,10 @@ name: "FIT Tomcat H2 YAML" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Tomcat / H2 / YAML' diff --git a/.github/workflows/fit_WA_SAML2PS4UI_OIDCC4UI.yml b/.github/workflows/fit_WA_SAML2PS4UI_OIDCC4UI.yml index 76d97855c5f..6d5e96e2523 100644 --- a/.github/workflows/fit_WA_SAML2PS4UI_OIDCC4UI.yml +++ b/.github/workflows/fit_WA_SAML2PS4UI_OIDCC4UI.yml @@ -18,10 +18,10 @@ name: "FIT WA SAML2SP4UI OIDCC4UI" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'WA / SAML2SP4UI, OIDCC4UI' diff --git a/.github/workflows/fit_WA_SRA_CASClient.yml b/.github/workflows/fit_WA_SRA_CASClient.yml index 3ba99446c0e..51e398012eb 100644 --- a/.github/workflows/fit_WA_SRA_CASClient.yml +++ b/.github/workflows/fit_WA_SRA_CASClient.yml @@ -18,10 +18,10 @@ name: "FIT WA SRA CASClient" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,20 +31,23 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' -# - name: Setup tmate session -# uses: mxschmitt/action-tmate@v3 - name: 'WA / SRA / CAS Client' run: mvn -f fit/wa-reference/pom.xml verify -Dinvoker.streamLogs=true -Dmodernizer.skip=true -Drat.skip=true -Dcheckstyle.skip=true -Djacoco.skip=true -Dit.test=org.apache.syncope.fit.sra.CASSRAITCase diff --git a/.github/workflows/fit_WA_SRA_OAuth2.yml b/.github/workflows/fit_WA_SRA_OAuth2.yml index de0ec2f0f87..67a1a745e75 100644 --- a/.github/workflows/fit_WA_SRA_OAuth2.yml +++ b/.github/workflows/fit_WA_SRA_OAuth2.yml @@ -18,10 +18,10 @@ name: "FIT WA SRA OAuth2" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'WA / SRA / OAuth 2.0' diff --git a/.github/workflows/fit_WA_SRA_OIDC.yml b/.github/workflows/fit_WA_SRA_OIDC.yml index 11a2e4941a5..ab74d103e31 100644 --- a/.github/workflows/fit_WA_SRA_OIDC.yml +++ b/.github/workflows/fit_WA_SRA_OIDC.yml @@ -18,10 +18,10 @@ name: "FIT WA SRA OIDC" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'WA / SRA / OpenID Connect 1.0' diff --git a/.github/workflows/fit_WA_SRA_SAML2.yml b/.github/workflows/fit_WA_SRA_SAML2.yml index b2a013fe99f..838c36dae2f 100644 --- a/.github/workflows/fit_WA_SRA_SAML2.yml +++ b/.github/workflows/fit_WA_SRA_SAML2.yml @@ -18,10 +18,10 @@ name: "FIT WA SRA SAML2" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'WA / SRA / SAML 2.0' diff --git a/.github/workflows/fit_Wildfly.yml b/.github/workflows/fit_Wildfly.yml index 3e8fb0d0270..c5227aa839e 100644 --- a/.github/workflows/fit_Wildfly.yml +++ b/.github/workflows/fit_Wildfly.yml @@ -18,10 +18,10 @@ name: "FIT Wildfly" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Wildfly / H2 / JSON' diff --git a/.github/workflows/fit_Zookeeper.yml b/.github/workflows/fit_Zookeeper.yml index 27c7139b13c..f70bbcc5d4d 100644 --- a/.github/workflows/fit_Zookeeper.yml +++ b/.github/workflows/fit_Zookeeper.yml @@ -18,10 +18,10 @@ name: "FIT Zookeeper" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Zookeeper / H2 / JSON' diff --git a/.github/workflows/mariadb.yml b/.github/workflows/mariadb.yml index 62f514b8b8d..d02a6dcf21a 100644 --- a/.github/workflows/mariadb.yml +++ b/.github/workflows/mariadb.yml @@ -18,10 +18,10 @@ name: "MariaDB" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,18 +31,51 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Integration Tests: MariaDB' run: mvn -f fit/core-reference/pom.xml -P mariadb-it -Dinvoker.streamLogs=true -Dmodernizer.skip=true -Drat.skip=true -Dcheckstyle.skip=true -Djacoco.skip=true + + majson: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + - name: Setup Java JDK + uses: actions/setup-java@v5 + with: + distribution: 'zulu' + java-version: 11 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 + with: + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + - name: Build + run: mvn -U -T 1C -P 'skipTests,all' + - name: 'Unit Tests: MariaDB JPA JSON' + run: mvn -f core/persistence-jpa-json/pom.xml -P majson -Dinvoker.streamLogs=true -Dmodernizer.skip=true -Dianal.phase=none -Drat.skip=true -Dcheckstyle.skip=true -Djacoco.skip=true + - name: 'Integration Tests: MariaDB JPA JSON' + run: mvn -f fit/core-reference/pom.xml -P majson-it -Dinvoker.streamLogs=true -Dmodernizer.skip=true -Drat.skip=true -Dcheckstyle.skip=true -Djacoco.skip=true diff --git a/.github/workflows/mysql.yml b/.github/workflows/mysql.yml index 4e31b234edf..12f3ba9ee62 100644 --- a/.github/workflows/mysql.yml +++ b/.github/workflows/mysql.yml @@ -18,10 +18,10 @@ name: "MySQL" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Integration Tests: MySQL' @@ -52,17 +57,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: - distribution: 'zulu' + distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 + with: + maven-version: 3.9.6 + - uses: actions/cache@v4 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Unit Tests: MySQL JPA JSON' diff --git a/.github/workflows/oracle.yml b/.github/workflows/oracle.yml index 3b4cd1f3f35..af08ebec242 100644 --- a/.github/workflows/oracle.yml +++ b/.github/workflows/oracle.yml @@ -18,10 +18,10 @@ name: "Oracle" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Integration Tests: Oracle' @@ -52,17 +57,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 + with: + maven-version: 3.9.6 + - uses: actions/cache@v4 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Unit Tests: Oracle JPA JSON' diff --git a/.github/workflows/postgresql.yml b/.github/workflows/postgresql.yml index b1b575b3913..3efab625d64 100644 --- a/.github/workflows/postgresql.yml +++ b/.github/workflows/postgresql.yml @@ -18,10 +18,10 @@ name: "PostgreSQL" on: push: - branches: ['master', 'pr-*'] + branches: ['3_0_X', 'pr-*'] pull_request: # The branches below must be a subset of the branches above - branches: [master] + branches: [3_0_X] schedule: - cron: '0 13 * * 4' @@ -31,17 +31,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + maven-version: 3.9.6 + - uses: actions/cache@v4 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Integration Tests: PostgreSQL' @@ -52,17 +57,22 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Setup Java JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'zulu' java-version: 11 - - uses: actions/cache@v3 + - name: Setup Maven + uses: stCarolas/setup-maven@v5 + with: + maven-version: 3.9.6 + - uses: actions/cache@v4 with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- - name: Build run: mvn -U -T 1C -P 'skipTests,all' - name: 'Unit Tests: PostgreSQL JPA JSON' diff --git a/.gitignore b/.gitignore index 1d105b47ba9..984b61bfb8c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ target maven-eclipse.xml .externalToolBuilders -archetype/src/main/resources/archetype-resources/pom.xml *nb-configuration.xml node_modules **/checkstyle.cache diff --git a/SECURITY.md b/.mvn/extensions.xml similarity index 65% rename from SECURITY.md rename to .mvn/extensions.xml index 72c8f7851db..0fa026d33a7 100644 --- a/SECURITY.md +++ b/.mvn/extensions.xml @@ -1,3 +1,4 @@ + -# Security Policy - -## Supported Versions - -| Version | Supported | -| ------- | ------------------ | -| 3.0.x | :white_check_mark: | -| 2.1.x | :white_check_mark: | -| 2.0.x | :x: | -| 1.2.x | :x: | -| 1.1.x | :x: | - -## Reporting a Vulnerability - -The general guidelines are set by the Apache Security Team and described at https://apache.org/security/ + + + org.apache.maven.extensions + maven-build-cache-extension + 1.2.2 + + diff --git a/.mvn/maven-build-cache-config.xml b/.mvn/maven-build-cache-config.xml new file mode 100644 index 00000000000..0f0daea7fa0 --- /dev/null +++ b/.mvn/maven-build-cache-config.xml @@ -0,0 +1,53 @@ + + + + + true + XX + + + + {*.java,*.xml,*.properties} + + + + + + + + + + + unpack-autoupdate + + + + + + + install + + + + + + diff --git a/CHANGES b/CHANGES index ccd13febe80..7a9ca6e5c84 100644 --- a/CHANGES +++ b/CHANGES @@ -2,6 +2,304 @@ Apache Syncope - CHANGES Licensed under Apache License 2.0 - http://www.apache.org/licenses/LICENSE-2.0 -------------------------------------------------------------------------------- +Release Notes - Syncope - Version 3.0.16 +================================================================================ + +** Bug + * [SYNCOPE-1933] - Console: only first dynamic group is shown + * [SYNCOPE-1936] - WA: only SIGNATURE and CURRENT keys generated for OIDC + * [SYNCOPE-1937] - User password history length is not correctly trimmed + * [SYNCOPE-1943] - French Canadian GUI failed with Groups contextual menu + +Release Notes - Syncope - Version 3.0.15 +================================================================================ + +** Bug + * [SYNCOPE-1922] - Disallow searches by encrypted attribute + * [SYNCOPE-1924] - Bug in retainAll, removeAll, and removeIf methods of PropagationByResource + * [SYNCOPE-1925] - Contextual menu stays open after modal window is closed + +** Improvement + * [SYNCOPE-1926] - Reduce number of update on Syncope after a SCIM PATCH + * [SYNCOPE-1932] - Improve AES management + +Release Notes - Syncope - Version 3.0.14 +================================================================================ + +** Bug + * [SYNCOPE-1906] - Wrong result order if sorting by plain attribute + * [SYNCOPE-1912] - Linked account password is not propagated on update + * [SYNCOPE-1920] - Error in search panel while trying to add a condition after an attribute of type Long + +** Improvement + * [SYNCOPE-1907] - Run Groovy code in a sandbox + * [SYNCOPE-1908] - Improve Relationship management + * [SYNCOPE-1909] - Docker containers as unprivileged user + * [SYNCOPE-1918] - Push task with assign unmatching rule remove dynamic memberships + +Release Notes - Syncope - Version 3.0.13 +================================================================================ + +** Bug + * [SYNCOPE-1888] - Console: change required property for specific inputs in policy configuration + * [SYNCOPE-1891] - Missing mapped attribute setting for SAML2IdPAuthModuleConf + * [SYNCOPE-1894] - Mapping parsing error while schema contains a dot + * [SYNCOPE-1895] - Console CSV export does not consider search filter + * [SYNCOPE-1896] - Audit: not serializable exception for ConnectorObject and Any instances + * [SYNCOPE-1902] - Can't set Unauthorized Redirect URL in access policy via Console + * [SYNCOPE-1904] - Console: cannot edit authentication.attributes under Keymaster > Parameters + +** Improvement + * [SYNCOPE-1886] - Elasticsearch and Opensearch query performance improvements + * [SYNCOPE-1887] - Enduser: require re-authentication for sensitive features + * [SYNCOPE-1889] - Improve group search using SCIM extension + * [SYNCOPE-1893] - SCIM extension improvement + * [SYNCOPE-1897] - WA: mapping Google MFA crypto settings + * [SYNCOPE-1900] - Implement OIDC Back-Channel Logout for Console and Enduser + +Release Notes - Syncope - Version 3.0.12 +================================================================================ + +** Bug + * [SYNCOPE-1868] - NPE when performing provision without changing password + * [SYNCOPE-1871] - Realm selection shows only one of allowed sub-trees + * [SYNCOPE-1873] - LocalDateTime fields not properly handled in BeanPanel + * [SYNCOPE-1875] - SAML delegated authentication: metadata keeps getting re-generated + * [SYNCOPE-1878] - Priority propagation failing with NOT_ATTEMPTED + * [SYNCOPE-1883] - Google MFA authentication does not validate scratch codes + * [SYNCOPE-1884] - Errors with Encrypted plain values + +** Improvement + * [SYNCOPE-1841] - Read-only multi value schema must not show new and delete button + * [SYNCOPE-1869] - Support evaluation order for client apps + * [SYNCOPE-1872] - Allow setting of force execution for MFA authentication + * [SYNCOPE-1880] - SCIM endpoints ignore the Prefer header + * [SYNCOPE-1885] - Self password reset does not trigger notification tasks without Flowable extension + +** Task + * [SYNCOPE-1866] - Implement AuthProfile management in Enduser + +Release Notes - Syncope - Version 3.0.11 +================================================================================ + +** Bug + * [SYNCOPE-1849] - NullPointerException when logging into Console + * [SYNCOPE-1851] - NullPointerExeption for Date fields in Macro execution forms + * [SYNCOPE-1853] - Deprovision is wrongly fired on group delete + * [SYNCOPE-1856] - Administrator can update and delete realms outside of the granted subtree + * [SYNCOPE-1858] - Macro operation with dropdown form property without default value generates stacktrace + * [SYNCOPE-1860] - Standalone WAR artifacts duplicates JAR dependencies + * [SYNCOPE-1864] - Unwanted password propagation after update on pull + * [SYNCOPE-1867] - Prevent NPE when fetching realm entitlements to enforce authorization + +** Improvement + * [SYNCOPE-1854] - propagation not triggered after user updated while in status "updateApproved" + * [SYNCOPE-1855] - Refactor database search to use less nested queries + * [SYNCOPE-1859] - SearchPanel displays the schema keys and doesn't consider translations + * [SYNCOPE-1865] - Allow to specify signing and encryption algorithms for OIDC client application + +Release Notes - Syncope - Version 3.0.10 +================================================================================ + +** Bug + * [SYNCOPE-1686] - relationship refering to object itself + * [SYNCOPE-1833] - Non-compliant SCIM payload returned when user extension is defined + * [SYNCOPE-1837] - Resources, Relationships and AuxClasses are deleted after SCIM PUT method invocation + * [SYNCOPE-1838] - Group owners cannot log into Console + * [SYNCOPE-1839] - In Console Commands cannot be removed from Macro Tasks + * [SYNCOPE-1840] - Cannot define the same form property for different Macro tasks + * [SYNCOPE-1846] - Cannot create more than one relationship at a time from the console + * [SYNCOPE-1847] - Propagation task audit throws exception during serialzation + * [SYNCOPE-1848] - Can't read user memberships with SCIM search endpoint + +** Improvement + * [SYNCOPE-1835] - Support Credential Criteria for LDAP authentication + * [SYNCOPE-1836] - Password propagation on resource doesn't happen from the SCIM extension + * [SYNCOPE-1842] - Support Credential Criteria for JAAS, JDBC and Syncope authentication + * [SYNCOPE-1843] - Support Azure AD authentication and attribute resolution + * [SYNCOPE-1844] - Support Okta authentication and attribute repository + * [SYNCOPE-1845] - Support doubleclik on data tables rows + +Release Notes - Syncope - Version 3.0.9 +================================================================================ + +** Bug + * [SYNCOPE-1824] - Password policies are not always enforced on linked account password while updating account + * [SYNCOPE-1825] - Database schema not set on OpenJPA even if configured by properties + * [SYNCOPE-1826] - Search fails if search condition contains four digits at the end of the value + * [SYNCOPE-1828] - Can't open the profiles tab in WA page if one of the fields is null + * [SYNCOPE-1831] - SCIM general configuration can not be updated + +** New Feature + * [SYNCOPE-1662] - Leverage MariaDB JSON type + +** Improvement + * [SYNCOPE-1830] - Add support for membership attributes on elasticsearch and opensearch searches + * [SYNCOPE-1832] - Replace number input method for UI + +Release Notes - Syncope - Version 3.0.8 +================================================================================ + +** Improvement + * [SYNCOPE-1822] - SCIM: support user extension + * [SYNCOPE-1823] - SCIM: support search by extension attributes + +Release Notes - Syncope - Version 3.0.7 +================================================================================ + +** Bug + * [SYNCOPE-1798] - Incorrect descendant Realms found by Elasticsearch / OpenSearch + * [SYNCOPE-1800] - FIQL comparison espressions with single quote cause JSONB search to fail + * [SYNCOPE-1803] - Can't remove multivalue membership plain schema value from console + * [SYNCOPE-1806] - Overlapping dynamic realms don't get updated + * [SYNCOPE-1808] - Wrong location for group in ResourceTypes SCIM service + * [SYNCOPE-1812] - Can't perform case-sensitive search using MariaDB + * [SYNCOPE-1813] - Wrong provisioning result shown after batch operation + * [SYNCOPE-1817] - Standalone: components not available + * [SYNCOPE-1818] - Wrong status value propagated to external resources if changed while pulling + * [SYNCOPE-1820] - Console label not working with multivalue schema + +** Improvement + * [SYNCOPE-1802] - Missing delegated SAML2 IdP configuration parameters + * [SYNCOPE-1807] - Status propagation on resource doesn't happen from the SCIM extension + * [SYNCOPE-1809] - Cleanup of uid-on-create attribute on resource unassignment + * [SYNCOPE-1811] - Missing Bypass MFA properties + * [SYNCOPE-1815] - Macro improvements + * [SYNCOPE-1816] - Provide the possibility to add a JcifsSpnegoAuthenticationHandler + +** Task + * [SYNCOPE-1805] - Upgrade Spring Framework and Security versions + +Release Notes - Syncope - Version 3.0.6 +================================================================================ + +** Bug + * [SYNCOPE-1778] - Reset password requires double click in order to provide username + * [SYNCOPE-1779] - Missing support for underscore in queries + * [SYNCOPE-1785] - Display rows changes not effective until reload + * [SYNCOPE-1790] - Swagger filtered GET returns multiple Users/AnyObjects instead of one + * [SYNCOPE-1791] - Unable to save audit config for CUSTOM event in the console + * [SYNCOPE-1792] - Error in console while editing conf parameter with values containing numbers + * [SYNCOPE-1793] - A logged in user cannot associate/deassociate a resource to himself + * [SYNCOPE-1794] - SAML: Authentication issue instant is too old or in the future + +** New Feature + * [SYNCOPE-1783] - Provide OpenSearch extension + * [SYNCOPE-1789] - Add support for X509 authentication + * [SYNCOPE-1796] - Verify access token issued by Microsoft Entra (formerly Azure) + +** Improvement + * [SYNCOPE-1780] - Password policy allows a minimum length less than the number of characters needed + * [SYNCOPE-1784] - Allow you to use other OIDCScopes in addition to those currently defined + * [SYNCOPE-1786] - Self Keymaster improvements + * [SYNCOPE-1787] - Support deployments with large number of Realms + * [SYNCOPE-1788] - Allow to insert JWKS value in OIDC Client Applications + * [SYNCOPE-1795] - JWT_SSO_PROVIDER and AUDIT_APPENDER should not be Implementations + * [SYNCOPE-1797] - Compatibility of SCIM 2.0 requests from Microsoft Entra + +Release Notes - Syncope - Version 3.0.5 +================================================================================ + +** Bug + * [SYNCOPE-1764] - Connector capabilities and/or configuration are not updated in cluster environments + * [SYNCOPE-1770] - Errors upon Core restart after adding domain + * [SYNCOPE-1774] - Admin console does not recognize parameter type + * [SYNCOPE-1777] - DelegatedAdministrationException is occasionally thrown during Pull Task execution + +** New Feature + * [SYNCOPE-1772] - WA: support MFA trusted device storage + +** Improvement + * [SYNCOPE-1771] - WA: support delegated authentication for Google, Keycloak and Apple ID + * [SYNCOPE-1773] - Support configuration for multi-nodes Elasticsearch clusters + * [SYNCOPE-1775] - It should be possible to set logoutType to WA services + * [SYNCOPE-1776] - Let Elasticsearch re-index use bulk requests + +Release Notes - Syncope - Version 3.0.4 +================================================================================ + +** Bug + * [SYNCOPE-1755] - NullPointer exception during PULL delete operation in case of NO_MATCH + * [SYNCOPE-1757] - Misalignment between SyncTokenSerializer and SyncTokenDeserializer in case of token given as a clear string + * [SYNCOPE-1761] - As admin, searching Users, Groups or Any Objects performs full Realm tree traversal + * [SYNCOPE-1763] - Constant increase of open files after upgrade to CXF 3.6.0 + * [SYNCOPE-1767] - When searching Groups with GROUP_MEMBER condition only Users are considered + +** Improvement + * [SYNCOPE-1759] - REST endpoint to evaluate account and password compliance with policies + * [SYNCOPE-1760] - Align Core Spring Boot actuator endpoint security with other components + * [SYNCOPE-1762] - Enrich actuator info with JPA provider information + * [SYNCOPE-1765] - allow WA to decrypt properties during the configuration bootstrap phase + * [SYNCOPE-1768] - Improve internal storage export feature + * [SYNCOPE-1769] - Allow the same name to be used across different Any Object types + +Release Notes - Syncope - Version 3.0.3 +================================================================================ + +** Bug + * [SYNCOPE-1731] - Performance issue with multiple any type classes + * [SYNCOPE-1734] - Elasticsearch not updated for uidOnCreate + * [SYNCOPE-1735] - Can't retrieve all policies during Realm create and update + * [SYNCOPE-1736] - Templates do not set the latest additions to Users and Groups + * [SYNCOPE-1737] - Cannot specifiy attribute mapping for AttributeRelease policies + * [SYNCOPE-1739] - Wrong volume mapping for source code in fit docker profile + * [SYNCOPE-1742] - Exception in console when defining a date for delegation + * [SYNCOPE-1749] - Incorrect Dynamic Group Membership Condition save from Console + * [SYNCOPE-1750] - Password policy not enforced if password is not stored in Syncope + +** New Feature + * [SYNCOPE-1741] - Add support form Azure Active Directory delegated authentication + * [SYNCOPE-1746] - Provide Software Bill Of Materials (SBOM) + +** Improvement + * [SYNCOPE-1732] - Console does not support custom Access Policy Configuration + * [SYNCOPE-1733] - Support OAUTH20 authentication module in WA + * [SYNCOPE-1738] - Refactor Report management + * [SYNCOPE-1740] - Allow to specify UsernameAttributeProvider for Client Applications + * [SYNCOPE-1743] - Add support for Ticket Expiration Policies into ClientApp + * [SYNCOPE-1745] - Allow to manage ConnId bundles with more Connectors + * [SYNCOPE-1747] - Provide controls to refresh WA client applications from Console + * [SYNCOPE-1748] - SCIM 2.0 Implement PATCH operations + * [SYNCOPE-1751] - Improve password auto generation on propagation + * [SYNCOPE-1752] - Support large number of Realms + * [SYNCOPE-1753] - Extend changes' history management to most relevant WA configuration objects + +Release Notes - Syncope - Version 3.0.2 +================================================================================ + +** Bug + * [SYNCOPE-1725] - Error when searching with high number of OR or AND conditions with Elasticsearch + * [SYNCOPE-1726] - WA does not always get configuration from Core on startup + * [SYNCOPE-1727] - Elasticsearch cannot find anything under given Realm in case of parent update + * [SYNCOPE-1728] - Unable to create LDAP authentication module from console + * [SYNCOPE-1730] - Standalone on Windows: Console Topology page does not show any Connector or Resource + +** Improvement + * [SYNCOPE-1722] - Allow password fields to reveal their value to the end-user + * [SYNCOPE-1723] - remove some non-reproducible bits + * [SYNCOPE-1724] - Provide health status for Elasticsearch + * [SYNCOPE-1729] - Configure Maven Build Cache Extension + +Release Notes - Syncope - Version 3.0.1 +================================================================================ + +** Bug + * [SYNCOPE-1711] - WA Docker image not working properly + * [SYNCOPE-1712] - Invalid HTTP method: PATCH with JDK 17 + * [SYNCOPE-1715] - Cannot update Audit settings via Console + +** New Feature + * [SYNCOPE-1105] - Provide unique key for operations + +** Improvement + * [SYNCOPE-1709] - Persist Jobs' current status in the database to support multi-node deployments + * [SYNCOPE-1713] - Support time-based conditions for Audit, Exec and Remediation queries + * [SYNCOPE-1714] - Support Docker deployments from archetype + * [SYNCOPE-1716] - Concurrent handling for pull and push tasks + * [SYNCOPE-1719] - Remove limitations for memberships and relationships + * [SYNCOPE-1720] - Switch persistence identifiers to UUID version 7 + * [SYNCOPE-1721] - Allow for more Access Policy types + Release Notes - Syncope - Version 3.0.0 ================================================================================ diff --git a/NOTICE b/NOTICE index 20545c539f1..d7aa1399613 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ Apache Syncope -Copyright 2012-2022 The Apache Software Foundation +Copyright 2012-2023 The Apache Software Foundation This product includes software developed by: The Apache Software Foundation (http://www.apache.org/). diff --git a/README.md b/README.md deleted file mode 100644 index da05e9a8784..00000000000 --- a/README.md +++ /dev/null @@ -1,35 +0,0 @@ - -**Apache Syncope** is an Open Source system for managing digital identities in enterprise environments, -implemented in Java EE technology and released under Apache 2.0 license. - -More information at https://syncope.apache.org - - - - - - - - - - - - - diff --git a/archetype/pom.xml b/archetype/pom.xml index d75dd77f555..3e9fae9a9e5 100644 --- a/archetype/pom.xml +++ b/archetype/pom.xml @@ -24,7 +24,7 @@ under the License. org.apache.syncope syncope - 3.0.1-SNAPSHOT + 3.0.17-SNAPSHOT Apache Syncope Archetype @@ -34,6 +34,8 @@ under the License. maven-archetype + 3.4.1 + ${basedir}/.. @@ -42,7 +44,7 @@ under the License. org.apache.maven.archetype archetype-packaging - 3.2.0 + ${maven.archetype.version} @@ -51,56 +53,38 @@ under the License. org.apache.maven.plugins maven-archetype-plugin - 3.2.1 + ${maven.archetype.version} true - - org.codehaus.mojo - xml-maven-plugin - true + org.apache.maven.plugins + maven-antrun-plugin - generate-resources + adjust-MasterContent - transform + run + prepare-package + + + + + + + - - - - ${basedir}/src/main/resources - - meta-pom.xml - - ${basedir}/src/main/resources/archetype-resources - ${basedir}/src/main/resources/properties2pom.xsl - - - syncopeVersion - ${project.version} - - - - - indent - yes - - - - - ^meta-(.*)\.xml$ - $1.xml - - - - - @@ -131,18 +115,18 @@ under the License. core.properties - ${project.build.outputDirectory}/archetype-resources/core/src/main/resources + archetype-resources/core/src/main/resources ../core/provisioning-java/src/main/resources - ${project.build.outputDirectory}/archetype-resources/core/src/main/resources + archetype-resources/core/src/main/resources ../core/persistence-jpa/src/main/resources META-INF/spring-persistence.xml - ${project.build.outputDirectory}/archetype-resources/core/src/main/resources + archetype-resources/core/src/main/resources ../core/persistence-jpa-json/src/main/resources/ @@ -150,41 +134,41 @@ under the License. META-INF/* audit/* - ${project.build.outputDirectory}/archetype-resources/core/src/main/resources + archetype-resources/core/src/main/resources ../core/persistence-jpa/src/test/resources/domains - ${project.build.outputDirectory}/archetype-resources/core/src/test/resources/domains + archetype-resources/core/src/test/resources/domains ../fit/core-reference/src/main/resources - ${project.build.outputDirectory}/archetype-resources/core/src/main/resources + archetype-resources/core/src/main/resources log4j2.xml ../fit/core-reference/src/test/resources - ${project.build.outputDirectory}/archetype-resources/core/src/test/resources + archetype-resources/core/src/test/resources keystore ../fit/core-reference/src/test/resources/scriptedsql - ${project.build.outputDirectory}/archetype-resources/core/src/test/resources/scriptedsql + archetype-resources/core/src/test/resources/scriptedsql ../fit/core-reference/src/test/resources/rest - ${project.build.outputDirectory}/archetype-resources/core/src/test/resources/rest + archetype-resources/core/src/test/resources/rest ../fit/core-reference/src/main/webapp/WEB-INF - ${project.build.outputDirectory}/archetype-resources/core/src/main/webapp/WEB-INF + archetype-resources/core/src/main/webapp/WEB-INF ../fit/core-reference/src/main/resources - ${project.build.outputDirectory}/archetype-resources/core/src/test/resources + archetype-resources/core/src/test/resources core-embedded.properties core-all.properties @@ -195,25 +179,25 @@ under the License. ../client/idrepo/console/src/main/resources - ${project.build.outputDirectory}/archetype-resources/console/src/main/resources + archetype-resources/console/src/main/resources console.properties ../fit/console-reference/src/main/resources - ${project.build.outputDirectory}/archetype-resources/console/src/main/resources + archetype-resources/console/src/main/resources log4j2.xml ../fit/console-reference/src/main/webapp/WEB-INF - ${project.build.outputDirectory}/archetype-resources/console/src/main/webapp/WEB-INF + archetype-resources/console/src/main/webapp/WEB-INF ../fit/console-reference/src/main/resources - ${project.build.outputDirectory}/archetype-resources/console/src/test/resources + archetype-resources/console/src/test/resources console-embedded.properties console-https.properties @@ -222,7 +206,7 @@ under the License. ../client/idrepo/enduser/src/main/resources - ${project.build.outputDirectory}/archetype-resources/enduser/src/main/resources + archetype-resources/enduser/src/main/resources enduser.properties customFormLayout.json @@ -230,18 +214,18 @@ under the License. ../fit/enduser-reference/src/main/resources - ${project.build.outputDirectory}/archetype-resources/enduser/src/main/resources + archetype-resources/enduser/src/main/resources log4j2.xml ../fit/enduser-reference/src/main/webapp/WEB-INF - ${project.build.outputDirectory}/archetype-resources/enduser/src/main/webapp/WEB-INF + archetype-resources/enduser/src/main/webapp/WEB-INF ../fit/enduser-reference/src/main/resources - ${project.build.outputDirectory}/archetype-resources/enduser/src/test/resources + archetype-resources/enduser/src/test/resources enduser-embedded.properties enduser-https.properties @@ -250,11 +234,11 @@ under the License. ../sra/src/main/resources - ${project.build.outputDirectory}/archetype-resources/sra/src/main/resources + archetype-resources/sra/src/main/resources ../fit/wa-reference/src/test/resources - ${project.build.outputDirectory}/archetype-resources/sra/src/test/resources + archetype-resources/sra/src/test/resources sra-*.properties @@ -266,22 +250,22 @@ under the License. cas-theme-default.properties wa.properties - ${project.build.outputDirectory}/archetype-resources/wa/src/main/resources + archetype-resources/wa/src/main/resources ../fit/wa-reference/src/main/webapp/WEB-INF - ${project.build.outputDirectory}/archetype-resources/wa/src/main/webapp/WEB-INF + archetype-resources/wa/src/main/webapp/WEB-INF ../fit/wa-reference/src/main/resources - ${project.build.outputDirectory}/archetype-resources/wa/src/main/resources + archetype-resources/wa/src/main/resources log4j2.xml ../fit/wa-reference/src/main/resources - ${project.build.outputDirectory}/archetype-resources/wa/src/test/resources + archetype-resources/wa/src/test/resources wa-embedded.properties @@ -289,7 +273,7 @@ under the License. ../fit/wa-reference/src/test/resources - ${project.build.outputDirectory}/archetype-resources/fit/src/test/resources + archetype-resources/fit/src/test/resources keystore.jks diff --git a/archetype/src/main/resources/archetype-resources/common/pom.xml b/archetype/src/main/resources/archetype-resources/common/pom.xml index b7e87968a9c..16e1d9e0e14 100644 --- a/archetype/src/main/resources/archetype-resources/common/pom.xml +++ b/archetype/src/main/resources/archetype-resources/common/pom.xml @@ -38,6 +38,10 @@ under the License. org.apache.syncope.common.idm syncope-common-idm-lib + + org.apache.syncope.common.am + syncope-common-am-lib + diff --git a/archetype/src/main/resources/archetype-resources/console/pom.xml b/archetype/src/main/resources/archetype-resources/console/pom.xml index b1bca655473..5292c723a57 100644 --- a/archetype/src/main/resources/archetype-resources/console/pom.xml +++ b/archetype/src/main/resources/archetype-resources/console/pom.xml @@ -30,7 +30,11 @@ under the License. Apache Syncope sample project - Console ${groupId} ${artifactId} - war + ${packaging} + + + war + @@ -121,8 +125,12 @@ under the License. - executable - + standalone + + + jar + + org.springframework.boot diff --git a/archetype/src/main/resources/archetype-resources/core/pom.xml b/archetype/src/main/resources/archetype-resources/core/pom.xml index 602e5280b2e..93a046ac73b 100644 --- a/archetype/src/main/resources/archetype-resources/core/pom.xml +++ b/archetype/src/main/resources/archetype-resources/core/pom.xml @@ -30,7 +30,11 @@ under the License. Apache Syncope sample project - Core ${groupId} ${artifactId} - war + ${packaging} + + + war + @@ -158,10 +162,6 @@ under the License. src/main/resources true - - workflow.properties - provisioning.properties - src/main/resources/all @@ -172,17 +172,12 @@ under the License. - - executable - + standalone + + + jar + + org.springframework.boot diff --git a/archetype/src/main/resources/archetype-resources/enduser/pom.xml b/archetype/src/main/resources/archetype-resources/enduser/pom.xml index 04dbfa86d3d..3f4da4cf70d 100644 --- a/archetype/src/main/resources/archetype-resources/enduser/pom.xml +++ b/archetype/src/main/resources/archetype-resources/enduser/pom.xml @@ -30,7 +30,11 @@ under the License. Apache Syncope sample project - Enduser ${groupId} ${artifactId} - war + ${packaging} + + + war + @@ -40,8 +44,8 @@ under the License. - org.apache.syncope.client.idrepo - syncope-client-idrepo-enduser + org.apache.syncope.client.am + syncope-client-am-enduser @@ -148,8 +152,12 @@ under the License. - executable - + standalone + + + jar + + org.springframework.boot diff --git a/archetype/src/main/resources/archetype-resources/fit/pom.xml b/archetype/src/main/resources/archetype-resources/fit/pom.xml index 6999730f1de..e55d33bc8e8 100644 --- a/archetype/src/main/resources/archetype-resources/fit/pom.xml +++ b/archetype/src/main/resources/archetype-resources/fit/pom.xml @@ -194,9 +194,10 @@ under the License. -Djavax.net.ssl.trustStore=${basedir}/src/test/resources/keystore.jks -Djavax.net.ssl.trustStorePassword=password + -Dreactor.netty.http.server.accessLogEnabled=true + -Dsyncope.log.dir=${project.build.directory}/log -jar ${basedir}/../sra/target/syncope-sra-exec.jar - -Dreactor.netty.http.server.accessLogEnabled=true ${basedir}/../sra/target/test-classes @@ -222,8 +223,6 @@ under the License. ${project.build.directory}/cargo/extract 600000 - ${cargo.log} - ${cargo.output} @@ -240,6 +239,9 @@ under the License. ${basedir}/src/test/resources/keystore.jks password + + ${basedir}/../core/target/test-classes + file:${basedir}/../core/target/bundles/ @@ -298,6 +300,25 @@ under the License. + + org.codehaus.mojo + build-helper-maven-plugin + + + regex-property + + regex-property + + + groupIdDocker + ${groupId} + \. + / + true + + + + @@ -409,6 +430,11 @@ under the License. postgres + -Dfile.encoding=UTF-8 -Dwicket.ioc.useByteBuddy=true -server -Xms1536m -Xmx1536m + -XX:NewSize=256m -XX:MaxNewSize=256m -XX:+DisableExplicitGC + -Djava.security.egd=file:/dev/./urandom + -Djavax.net.ssl.trustStore=/opt/syncope/conf/keystore.p12 + -Djavax.net.ssl.trustStorePassword=password docker,postgresql,all jdbc:postgresql://postgres:5432/syncope?stringtype=unspecified syncope @@ -426,7 +452,9 @@ under the License. ${basedir}/../core/target/classes/domains/MasterContent.xml:/opt/syncope/conf/domains/MasterContent.xml:ro - ${settings.localRepository}/${groupId}/syncope-core/${project.version}/syncope-core-${project.version}-classes.jar:/opt/syncope/lib/${groupId}-syncope-core-classes.jar:ro + ${settings.localRepository}/${groupIdDocker}/syncope-core/${project.version}/syncope-core-${project.version}-classes.jar:/opt/syncope/lib/syncope-core-classes.jar:ro + ${settings.localRepository}/${groupIdDocker}/syncope-common/${project.version}/syncope-common-${project.version}.jar:/opt/syncope/lib/syncope-common.jar:ro + ${basedir}/src/test/resources/keystore.p12:/opt/syncope/conf/keystore.p12:ro @@ -445,11 +473,6 @@ under the License. syncope - -Dfile.encoding=UTF-8 -Dwicket.ioc.useByteBuddy=true -server -Xms1536m -Xmx1536m - -XX:NewSize=256m -XX:MaxNewSize=256m -XX:+DisableExplicitGC - -Djava.security.egd=file:/dev/./urandom - -Djavax.net.ssl.trustStore=/opt/syncope/conf/keystore.p12 - -Djavax.net.ssl.trustStorePassword=password docker,all http://syncope-console:8080/syncope-console/ http://syncope:8080/syncope/rest/keymaster @@ -460,8 +483,8 @@ under the License. - ${basedir}/src/test/resources/keystore.p12:/opt/syncope/conf/keystore.p12:ro - ${settings.localRepository}/${groupId}/syncope-console/${project.version}/syncope-console-${project.version}-classes.jar:/opt/syncope/lib/${groupId}-syncope-console-classes.jar:ro + ${settings.localRepository}/${groupIdDocker}/syncope-console/${project.version}/syncope-console-${project.version}-classes.jar:/opt/syncope/lib/syncope-console-classes.jar:ro + ${settings.localRepository}/${groupIdDocker}/syncope-common/${project.version}/syncope-common-${project.version}.jar:/opt/syncope/lib/syncope-common.jar:ro @@ -491,7 +514,8 @@ under the License. - ${settings.localRepository}/${groupId}/syncope-enduser/${project.version}/syncope-enduser-${project.version}-classes.jar:/opt/syncope/lib/${groupId}-syncope-enduser-classes.jar:ro + ${settings.localRepository}/${groupIdDocker}/syncope-enduser/${project.version}/syncope-enduser-${project.version}-classes.jar:/opt/syncope/lib/syncope-enduser-classes.jar:ro + ${settings.localRepository}/${groupIdDocker}/syncope-common/${project.version}/syncope-common-${project.version}.jar:/opt/syncope/lib/syncope-common.jar:ro @@ -524,7 +548,8 @@ under the License. ${basedir}/../wa/src/test/resources/wa-docker-https.properties:/opt/syncope/conf/wa-docker-https.properties:ro ${basedir}/src/test/resources/keystore.p12:/opt/syncope/conf/keystore.p12:ro - ${settings.localRepository}/${groupId}/syncope-wa/${project.version}/syncope-wa-${project.version}-classes.jar:/opt/syncope/lib/${groupId}-syncope-wa-classes.jar:ro + ${settings.localRepository}/${groupIdDocker}/syncope-wa/${project.version}/syncope-wa-${project.version}-classes.jar:/opt/syncope/lib/syncope-wa-classes.jar:ro + ${settings.localRepository}/${groupIdDocker}/syncope-common/${project.version}/syncope-common-${project.version}.jar:/opt/syncope/lib/syncope-common.jar:ro @@ -557,7 +582,8 @@ under the License. - ${settings.localRepository}/${groupId}/syncope-sra/${project.version}/syncope-sra-${project.version}.jar:/opt/syncope/lib/${groupId}-syncope-sra.jar:ro + ${settings.localRepository}/${groupIdDocker}/syncope-sra/${project.version}/syncope-sra-${project.version}.jar:/opt/syncope/lib/syncope-sra.jar:ro + ${settings.localRepository}/${groupIdDocker}/syncope-common/${project.version}/syncope-common-${project.version}.jar:/opt/syncope/lib/syncope-common.jar:ro diff --git a/archetype/src/main/resources/meta-pom.xml b/archetype/src/main/resources/archetype-resources/pom.xml similarity index 90% rename from archetype/src/main/resources/meta-pom.xml rename to archetype/src/main/resources/archetype-resources/pom.xml index 0a453ee8103..25a71bc0e92 100644 --- a/archetype/src/main/resources/meta-pom.xml +++ b/archetype/src/main/resources/archetype-resources/pom.xml @@ -26,11 +26,11 @@ under the License. org.apache.syncope syncope - + syncopeVersion - + syncopeVersion ${secretKey} ${anonymousKey} ${jwsKey} @@ -39,6 +39,8 @@ under the License. none true true + + 9443 Apache Syncope sample project @@ -54,7 +56,12 @@ under the License. syncope-common-idm-lib ${syncope.version} - + + org.apache.syncope.common.am + syncope-common-am-lib + ${syncope.version} + + org.apache.syncope.core syncope-core-starter @@ -83,8 +90,8 @@ under the License. - org.apache.syncope.client.idrepo - syncope-client-idrepo-enduser + org.apache.syncope.client.am + syncope-client-am-enduser ${syncope.version} diff --git a/archetype/src/main/resources/archetype-resources/wa/pom.xml b/archetype/src/main/resources/archetype-resources/wa/pom.xml index cab9c2420c1..6e9082af022 100644 --- a/archetype/src/main/resources/archetype-resources/wa/pom.xml +++ b/archetype/src/main/resources/archetype-resources/wa/pom.xml @@ -30,10 +30,35 @@ under the License. Apache Syncope sample project - WA ${groupId} ${artifactId} - war + ${packaging} + + + war + + + org.springframework + spring-framework-bom + ${spring-framework.version} + pom + import + + + org.springframework.security + spring-security-bom + ${spring-security.version} + pom + import + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + org.apereo.cas cas-server-support-bom @@ -41,6 +66,19 @@ under the License. pom import + + + + nz.net.ultraq.thymeleaf + thymeleaf-layout-dialect + ${thymeleaf-layout-dialect.version} + + + + org.apache.cxf + cxf-rt-transports-http + ${cxf.version} + @@ -106,8 +144,12 @@ under the License. - executable - + standalone + + + jar + + org.springframework.boot diff --git a/archetype/src/main/resources/properties2pom.xsl b/archetype/src/main/resources/properties2pom.xsl deleted file mode 100644 index 41e76b47451..00000000000 --- a/archetype/src/main/resources/properties2pom.xsl +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/am/console/pom.xml b/client/am/console/pom.xml index ded3392d8a5..d39c5aed80d 100644 --- a/client/am/console/pom.xml +++ b/client/am/console/pom.xml @@ -24,7 +24,7 @@ under the License. org.apache.syncope.client syncope-client-am - 3.0.1-SNAPSHOT + 3.0.17-SNAPSHOT Apache Syncope Client AM Console diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/AMConsoleContext.java b/client/am/console/src/main/java/org/apache/syncope/client/console/AMConsoleContext.java new file mode 100644 index 00000000000..46b94e1603e --- /dev/null +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/AMConsoleContext.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.console; + +import org.apache.syncope.client.console.commons.AMAccessPolicyConfProvider; +import org.apache.syncope.client.console.commons.AMPolicyTabProvider; +import org.apache.syncope.client.console.commons.AMRealmPolicyProvider; +import org.apache.syncope.client.console.commons.AccessPolicyConfProvider; +import org.apache.syncope.client.console.commons.PolicyTabProvider; +import org.apache.syncope.client.console.commons.RealmPolicyProvider; +import org.apache.syncope.client.console.init.AMClassPathScanImplementationContributor; +import org.apache.syncope.client.console.init.ClassPathScanImplementationContributor; +import org.apache.syncope.client.console.rest.AttrRepoRestClient; +import org.apache.syncope.client.console.rest.AuthModuleRestClient; +import org.apache.syncope.client.console.rest.AuthProfileRestClient; +import org.apache.syncope.client.console.rest.ClientAppRestClient; +import org.apache.syncope.client.console.rest.OIDCJWKSRestClient; +import org.apache.syncope.client.console.rest.PolicyRestClient; +import org.apache.syncope.client.console.rest.SAML2IdPEntityRestClient; +import org.apache.syncope.client.console.rest.SAML2SPEntityRestClient; +import org.apache.syncope.client.console.rest.SRARouteRestClient; +import org.apache.syncope.client.console.rest.SRAStatisticsRestClient; +import org.apache.syncope.client.console.rest.WAConfigRestClient; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +public class AMConsoleContext { + + @Bean + public ClassPathScanImplementationContributor amClassPathScanImplementationContributor() { + return new AMClassPathScanImplementationContributor(); + } + + @Bean + public RealmPolicyProvider realmPolicyProvider(final PolicyRestClient policyRestClient) { + return new AMRealmPolicyProvider(policyRestClient); + } + + @Bean + public PolicyTabProvider amPolicyTabProvider(final PolicyRestClient policyRestClient) { + return new AMPolicyTabProvider(policyRestClient); + } + + @Bean + public AccessPolicyConfProvider accessPolicyConfProvider() { + return new AMAccessPolicyConfProvider(); + } + + @ConditionalOnMissingBean + @Bean + public AttrRepoRestClient attrRepoRestClient() { + return new AttrRepoRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public AuthModuleRestClient authModuleRestClient() { + return new AuthModuleRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public AuthProfileRestClient authProfileRestClient() { + return new AuthProfileRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public ClientAppRestClient clientAppRestClient() { + return new ClientAppRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public OIDCJWKSRestClient oidcJWKSRestClient() { + return new OIDCJWKSRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public SAML2IdPEntityRestClient saml2IdPEntityRestClient() { + return new SAML2IdPEntityRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public SAML2SPEntityRestClient saml2SPEntityRestClient() { + return new SAML2SPEntityRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public SRARouteRestClient sraRouteRestClient() { + return new SRARouteRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public SRAStatisticsRestClient sRAStatisticsRestClient() { + return new SRAStatisticsRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public WAConfigRestClient waConfigRestClient() { + return new WAConfigRestClient(); + } +} diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/SyncopeAMConsoleContext.java b/client/am/console/src/main/java/org/apache/syncope/client/console/SyncopeAMConsoleContext.java deleted file mode 100644 index b5b35524d8e..00000000000 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/SyncopeAMConsoleContext.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.syncope.client.console; - -import org.apache.syncope.client.console.commons.AMPolicyTabProvider; -import org.apache.syncope.client.console.commons.AMRealmPolicyProvider; -import org.apache.syncope.client.console.commons.PolicyTabProvider; -import org.apache.syncope.client.console.commons.RealmPolicyProvider; -import org.apache.syncope.client.console.init.AMClassPathScanImplementationContributor; -import org.apache.syncope.client.console.init.ClassPathScanImplementationContributor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration(proxyBeanMethods = false) -public class SyncopeAMConsoleContext { - - @Bean - public ClassPathScanImplementationContributor amClassPathScanImplementationContributor() { - return new AMClassPathScanImplementationContributor(); - } - - @Bean - public RealmPolicyProvider realmPolicyProvider() { - return new AMRealmPolicyProvider(); - } - - @Bean - public PolicyTabProvider amPolicyTabProvider() { - return new AMPolicyTabProvider(); - } -} diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel.java index 1066f1268c7..da73e8b0021 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel.java @@ -19,14 +19,15 @@ package org.apache.syncope.client.console.authprofiles; import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal; -import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; +import org.apache.commons.collections4.CollectionUtils; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.authprofiles.AuthProfileDirectoryPanel.AuthProfileProvider; import org.apache.syncope.client.console.commons.AMConstants; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.panels.DirectoryPanel; import org.apache.syncope.client.console.panels.ModalDirectoryPanel; import org.apache.syncope.client.console.rest.AuthProfileRestClient; @@ -37,27 +38,23 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; -import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.common.lib.to.AuthProfileTO; import org.apache.syncope.common.lib.types.AMEntitlement; import org.apache.syncope.common.lib.wa.GoogleMfaAuthAccount; import org.apache.syncope.common.lib.wa.GoogleMfaAuthToken; import org.apache.syncope.common.lib.wa.ImpersonationAccount; +import org.apache.syncope.common.lib.wa.MfaTrustedDevice; import org.apache.syncope.common.lib.wa.U2FDevice; import org.apache.syncope.common.lib.wa.WebAuthnDeviceCredential; import org.apache.wicket.PageReference; import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; -import org.apache.wicket.extensions.wizard.WizardModel; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; -import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.StringResourceModel; @@ -68,8 +65,10 @@ public class AuthProfileDirectoryPanel private final BaseModal authProfileModal; - public AuthProfileDirectoryPanel(final String id, final PageReference pageRef) { - super(id, pageRef); + public AuthProfileDirectoryPanel( + final String id, final AuthProfileRestClient restClient, final PageReference pageRef) { + + super(id, restClient, pageRef); authProfileModal = new BaseModal<>(Constants.OUTER) { @@ -82,15 +81,9 @@ protected void onConfigure() { } }; authProfileModal.size(Modal.Size.Large); - authProfileModal.setWindowClosedCallback(target -> { - updateResultTable(target); - authProfileModal.show(false); - }); + setWindowClosedReloadCallback(authProfileModal, true); addOuterObject(authProfileModal); - addNewItemPanelBuilder(new CreateAuthProfileWizardBuilder(pageRef), true); - MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, AMEntitlement.AUTH_PROFILE_CREATE); - disableCheckBoxes(); initResultTable(); } @@ -125,7 +118,7 @@ protected List> getColumns() { @Override protected boolean isCondition(final IModel rowModel) { - return !rowModel.getObject().getImpersonationAccounts().isEmpty(); + return CollectionUtils.isNotEmpty(rowModel.getObject().getImpersonationAccounts()); } }); columns.add(new BooleanConditionColumn<>(new StringResourceModel("googleMfaAuthTokens")) { @@ -134,7 +127,7 @@ protected boolean isCondition(final IModel rowModel) { @Override protected boolean isCondition(final IModel rowModel) { - return !rowModel.getObject().getGoogleMfaAuthTokens().isEmpty(); + return CollectionUtils.isNotEmpty(rowModel.getObject().getGoogleMfaAuthTokens()); } }); columns.add(new BooleanConditionColumn<>(new StringResourceModel("googleMfaAuthAccounts")) { @@ -143,7 +136,7 @@ protected boolean isCondition(final IModel rowModel) { @Override protected boolean isCondition(final IModel rowModel) { - return !rowModel.getObject().getGoogleMfaAuthAccounts().isEmpty(); + return CollectionUtils.isNotEmpty(rowModel.getObject().getGoogleMfaAuthAccounts()); } }); columns.add(new BooleanConditionColumn<>(new StringResourceModel("u2fRegisteredDevices")) { @@ -152,7 +145,16 @@ protected boolean isCondition(final IModel rowModel) { @Override protected boolean isCondition(final IModel rowModel) { - return !rowModel.getObject().getU2FRegisteredDevices().isEmpty(); + return CollectionUtils.isNotEmpty(rowModel.getObject().getU2FRegisteredDevices()); + } + }); + columns.add(new BooleanConditionColumn<>(new StringResourceModel("mfaTrustedDevices")) { + + private static final long serialVersionUID = -8236820422411536323L; + + @Override + protected boolean isCondition(final IModel rowModel) { + return CollectionUtils.isNotEmpty(rowModel.getObject().getMfaTrustedDevices()); } }); columns.add(new BooleanConditionColumn<>(new StringResourceModel("webAuthnAccount")) { @@ -161,7 +163,7 @@ protected boolean isCondition(final IModel rowModel) { @Override protected boolean isCondition(final IModel rowModel) { - return !rowModel.getObject().getWebAuthnDeviceCredentials().isEmpty(); + return CollectionUtils.isNotEmpty(rowModel.getObject().getWebAuthnDeviceCredentials()); } }); @@ -178,11 +180,11 @@ public ActionsPanel getActions(final IModel model) @Override public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) { - model.setObject(AuthProfileRestClient.read(model.getObject().getKey())); + model.setObject(restClient.read(model.getObject().getKey())); target.add(authProfileModal.setContent(new ModalDirectoryPanel<>( authProfileModal, new AuthProfileItemDirectoryPanel( - "panel", authProfileModal, model.getObject(), pageRef) { + "panel", restClient, authProfileModal, model.getObject(), pageRef) { private static final long serialVersionUID = -5380664539000792237L; @@ -225,11 +227,11 @@ protected List> getColumns() { @Override public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) { - model.setObject(AuthProfileRestClient.read(model.getObject().getKey())); + model.setObject(restClient.read(model.getObject().getKey())); target.add(authProfileModal.setContent(new ModalDirectoryPanel<>( authProfileModal, new AuthProfileItemDirectoryPanel( - "panel", authProfileModal, model.getObject(), pageRef) { + "panel", restClient, authProfileModal, model.getObject(), pageRef) { private static final long serialVersionUID = 7332357430197837993L; @@ -274,11 +276,11 @@ protected List> getColumns() { @Override public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) { - model.setObject(AuthProfileRestClient.read(model.getObject().getKey())); + model.setObject(restClient.read(model.getObject().getKey())); target.add(authProfileModal.setContent(new ModalDirectoryPanel<>( authProfileModal, new AuthProfileItemDirectoryPanel( - "panel", authProfileModal, model.getObject(), pageRef) { + "panel", restClient, authProfileModal, model.getObject(), pageRef) { private static final long serialVersionUID = -670769282358547044L; @@ -323,11 +325,11 @@ protected List> getColumns() { @Override public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) { - model.setObject(AuthProfileRestClient.read(model.getObject().getKey())); + model.setObject(restClient.read(model.getObject().getKey())); target.add(authProfileModal.setContent(new ModalDirectoryPanel<>( authProfileModal, new AuthProfileItemDirectoryPanel( - "panel", authProfileModal, model.getObject(), pageRef) { + "panel", restClient, authProfileModal, model.getObject(), pageRef) { private static final long serialVersionUID = 5788448799796630011L; @@ -364,7 +366,58 @@ protected List> getColumns() { authProfileModal.header(new Model<>(getString("u2fRegisteredDevices", model))); authProfileModal.show(true); } - }, ActionLink.ActionType.FO_EDIT, AMEntitlement.AUTH_PROFILE_UPDATE); + }, ActionLink.ActionType.DEPROVISION, AMEntitlement.AUTH_PROFILE_UPDATE); + + panel.add(new ActionLink<>() { + + private static final long serialVersionUID = -3722207913631435501L; + + @Override + public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) { + model.setObject(restClient.read(model.getObject().getKey())); + target.add(authProfileModal.setContent(new ModalDirectoryPanel<>( + authProfileModal, + new AuthProfileItemDirectoryPanel( + "panel", restClient, authProfileModal, model.getObject(), pageRef) { + + private static final long serialVersionUID = 5788448799796630011L; + + @Override + protected List getItems() { + return model.getObject().getMfaTrustedDevices(); + } + + @Override + protected MfaTrustedDevice defaultItem() { + return new MfaTrustedDevice(); + } + + @Override + protected String sortProperty() { + return "id"; + } + + @Override + protected String paginatorRowsKey() { + return AMConstants.PREF_AUTHPROFILE_MFA_TRUSTED_FDEVICES_PAGINATOR_ROWS; + } + + @Override + protected List> getColumns() { + List> columns = new ArrayList<>(); + columns.add(new PropertyColumn<>(new ResourceModel("id"), "id", "id")); + columns.add(new PropertyColumn<>(new ResourceModel("name"), "name", "name")); + columns.add(new DatePropertyColumn<>( + new ResourceModel("recordDate"), "recordDate", "recordDate")); + columns.add(new DatePropertyColumn<>( + new ResourceModel("expirationDate"), "expirationDate", "expirationDate")); + return columns; + } + }, pageRef))); + authProfileModal.header(new Model<>(getString("mfaTrustedDevices", model))); + authProfileModal.show(true); + } + }, ActionLink.ActionType.DOWN, AMEntitlement.AUTH_PROFILE_UPDATE); panel.add(new ActionLink<>() { @@ -372,11 +425,11 @@ protected List> getColumns() { @Override public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) { - model.setObject(AuthProfileRestClient.read(model.getObject().getKey())); + model.setObject(restClient.read(model.getObject().getKey())); target.add(authProfileModal.setContent(new ModalDirectoryPanel<>( authProfileModal, new AuthProfileItemDirectoryPanel( - "panel", authProfileModal, model.getObject(), pageRef) { + "panel", restClient, authProfileModal, model.getObject(), pageRef) { private static final long serialVersionUID = 6820212423488933184L; @@ -422,7 +475,7 @@ protected List> getColumns() { @Override public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) { try { - AuthProfileRestClient.delete(model.getObject().getKey()); + restClient.delete(model.getObject().getKey()); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); target.add(container); @@ -437,7 +490,7 @@ public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) return panel; } - protected static final class AuthProfileProvider extends DirectoryDataProvider { + protected final class AuthProfileProvider extends DirectoryDataProvider { private static final long serialVersionUID = -185944053385660794L; @@ -449,12 +502,12 @@ private AuthProfileProvider(final int paginatorRows) { @Override public Iterator iterator(final long first, final long count) { int page = ((int) first / paginatorRows); - return AuthProfileRestClient.list((page < 0 ? 0 : page) + 1, paginatorRows).iterator(); + return restClient.list((page < 0 ? 0 : page) + 1, paginatorRows).iterator(); } @Override public long size() { - return AuthProfileRestClient.count(); + return restClient.count(); } @Override @@ -462,39 +515,4 @@ public IModel model(final AuthProfileTO object) { return new CompoundPropertyModel<>(object); } } - - private class CreateAuthProfileWizardBuilder extends AuthProfileWizardBuilder { - - private static final long serialVersionUID = 1L; - - private class NewAuthProfileStep extends AuthProfileWizardBuilder.Step { - - private static final long serialVersionUID = 1L; - - NewAuthProfileStep(final AuthProfileTO modelObject) { - super(modelObject); - - AjaxTextFieldPanel owner = new AjaxTextFieldPanel( - "bean", "owner", new PropertyModel<>(modelObject, "owner")); - owner.addRequiredLabel(); - addOrReplace(owner); - } - } - - CreateAuthProfileWizardBuilder(final PageReference pageRef) { - super(new AuthProfileTO(), new StepModel<>(), pageRef); - } - - @Override - protected WizardModel buildModelSteps(final AuthProfileTO modelObject, final WizardModel wizardModel) { - wizardModel.add(new NewAuthProfileStep(modelObject)); - return wizardModel; - } - - @Override - protected Serializable onApplyInternal(final AuthProfileTO modelObject) { - AuthProfileRestClient.create(modelObject); - return modelObject; - } - } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileItemDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileItemDirectoryPanel.java index a125278ef7b..c1e46041630 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileItemDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileItemDirectoryPanel.java @@ -25,6 +25,7 @@ import java.util.Objects; import java.util.stream.Collectors; import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.SortableDataProviderComparator; import org.apache.syncope.client.console.panels.DirectoryPanel; import org.apache.syncope.client.console.rest.AuthProfileRestClient; @@ -32,7 +33,6 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; import org.apache.syncope.common.lib.BaseBean; @@ -52,19 +52,20 @@ public abstract class AuthProfileItemDirectoryPanel extends DirectoryPanel.AuthProfileItemProvider, AuthProfileRestClient> { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 7640851594812655896L; - private final BaseModal authProfileModal; + protected final BaseModal authProfileModal; - private final AuthProfileTO authProfile; + protected final AuthProfileTO authProfile; public AuthProfileItemDirectoryPanel( final String id, + final AuthProfileRestClient restClient, final BaseModal authProfileModal, final AuthProfileTO authProfile, final PageReference pageRef) { - super(id, pageRef, false); + super(id, restClient, pageRef, false); this.authProfileModal = authProfileModal; this.authProfile = authProfile; @@ -74,8 +75,6 @@ public AuthProfileItemDirectoryPanel( enableUtilityButton(); setFooterVisibility(false); - addNewItemPanelBuilder(new AuthProfileItemWizardBuilder(pageRef), true); - disableCheckBoxes(); initResultTable(); } @@ -132,7 +131,7 @@ public void onClick(final AjaxRequestTarget target, final I ignore) { public void onClick(final AjaxRequestTarget target, final I ignore) { try { getItems().remove(model.getObject()); - AuthProfileRestClient.update(authProfile); + restClient.update(authProfile); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); target.add(container); @@ -212,7 +211,7 @@ protected Serializable onApplyInternal(final I modelObject) { getItems().remove(model.getInitialModelObject()); getItems().add(modelObject); - AuthProfileRestClient.update(authProfile); + restClient.update(authProfile); return modelObject; } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileWizardBuilder.java index 08475c41109..41a5ff99586 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileWizardBuilder.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileWizardBuilder.java @@ -29,7 +29,7 @@ public abstract class AuthProfileWizardBuilder extends BaseAjaxWizardBuilder { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = -723891643398238220L; protected final StepModel model; @@ -46,7 +46,7 @@ protected WizardModel buildModelSteps(final T modelObject, final WizardModel wiz protected static class StepModel extends Model { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = -3300650579312254364L; private T initialModelObject; diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/CASSPDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/CASSPDirectoryPanel.java index da990b68976..64d4900d19f 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/CASSPDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/CASSPDirectoryPanel.java @@ -19,6 +19,7 @@ package org.apache.syncope.client.console.clientapps; import java.util.List; +import org.apache.syncope.client.console.rest.ClientAppRestClient; import org.apache.syncope.common.lib.to.CASSPClientAppTO; import org.apache.syncope.common.lib.types.AMEntitlement; import org.apache.syncope.common.lib.types.ClientAppType; @@ -32,13 +33,20 @@ public class CASSPDirectoryPanel extends ClientAppDirectoryPanel(ClientAppType.CASSP, defaultItem, modal, pageRef), true); + addNewItemPanelBuilder(new ClientAppModalPanelBuilder<>( + ClientAppType.CASSP, + defaultItem, + modal, + policyRestClient, + clientAppRestClient, + realmRestClient, + pageRef), + true); MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, AMEntitlement.CLIENTAPP_CREATE); initResultTable(); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.java index 68ea7862192..208f4ce2c64 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.java @@ -19,30 +19,38 @@ package org.apache.syncope.client.console.clientapps; import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.apache.commons.lang3.SerializationUtils; import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.audit.AuditHistoryModal; import org.apache.syncope.client.console.commons.AMConstants; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.SortableDataProviderComparator; +import org.apache.syncope.client.console.pages.BasePage; import org.apache.syncope.client.console.panels.DirectoryPanel; import org.apache.syncope.client.console.panels.ModalDirectoryPanel; +import org.apache.syncope.client.console.rest.AuditRestClient; import org.apache.syncope.client.console.rest.ClientAppRestClient; +import org.apache.syncope.client.console.rest.PolicyRestClient; +import org.apache.syncope.client.console.rest.RealmRestClient; import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.KeyPropertyColumn; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; import org.apache.syncope.common.lib.SyncopeClientException; import org.apache.syncope.common.lib.to.ClientAppTO; import org.apache.syncope.common.lib.types.AMEntitlement; +import org.apache.syncope.common.lib.types.AuditElements; import org.apache.syncope.common.lib.types.ClientAppType; +import org.apache.syncope.common.lib.types.IdRepoEntitlement; import org.apache.wicket.PageReference; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.event.Broadcast; @@ -53,26 +61,43 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public abstract class ClientAppDirectoryPanel extends DirectoryPanel, ClientAppRestClient> { private static final long serialVersionUID = 4100100988730985059L; - private final ClientAppType type; + @SpringBean + protected PolicyRestClient policyRestClient; + + @SpringBean + protected ClientAppRestClient clientAppRestClient; + + @SpringBean + protected RealmRestClient realmRestClient; + + @SpringBean + protected AuditRestClient auditRestClient; + + protected final ClientAppType type; protected final BaseModal propertiesModal; - public ClientAppDirectoryPanel(final String id, final ClientAppType type, final PageReference pageRef) { - super(id, pageRef, true); + protected final BaseModal historyModal; + + public ClientAppDirectoryPanel( + final String id, + final ClientAppRestClient restClient, + final ClientAppType type, + final PageReference pageRef) { + + super(id, restClient, pageRef, true); this.type = type; modal.addSubmitButton(); modal.size(Modal.Size.Large); - modal.setWindowClosedCallback(target -> { - updateResultTable(target); - modal.show(false); - }); + setWindowClosedReloadCallback(modal, true); setFooterVisibility(true); propertiesModal = new BaseModal<>(Constants.OUTER) { @@ -86,10 +111,14 @@ protected void onConfigure() { } }; propertiesModal.size(Modal.Size.Large); - propertiesModal.setWindowClosedCallback(target -> propertiesModal.show(false)); + setWindowClosedReloadCallback(propertiesModal); addOuterObject(propertiesModal); disableCheckBoxes(); + + historyModal = new BaseModal<>(Constants.OUTER); + historyModal.size(Modal.Size.Large); + addOuterObject(historyModal); } @Override @@ -103,6 +132,8 @@ protected List> getColumns() { Constants.NAME_FIELD_NAME, Constants.NAME_FIELD_NAME)); columns.add(new PropertyColumn<>( new StringResourceModel("clientAppId", this), "clientAppId", "clientAppId")); + columns.add(new PropertyColumn<>( + new StringResourceModel("evaluationOrder", this), "evaluationOrder", "evaluationOrder")); addCustomColumnFields(columns); @@ -124,7 +155,7 @@ public ActionsPanel getActions(final IModel model) { public void onClick(final AjaxRequestTarget target, final ClientAppTO ignore) { send(ClientAppDirectoryPanel.this, Broadcast.EXACT, new AjaxWizard.EditItemActionEvent<>( - ClientAppRestClient.read(type, model.getObject().getKey()), target)); + restClient.read(type, model.getObject().getKey()), target)); } }, ActionLink.ActionType.EDIT, AMEntitlement.CLIENTAPP_UPDATE); @@ -134,16 +165,72 @@ public void onClick(final AjaxRequestTarget target, final ClientAppTO ignore) { @Override public void onClick(final AjaxRequestTarget target, final ClientAppTO ignore) { - model.setObject(ClientAppRestClient.read(type, model.getObject().getKey())); + model.setObject(restClient.read(type, model.getObject().getKey())); + modal.setContent(new UsernameAttributeProviderModalPanelBuilder<>( + type, model.getObject(), modal, clientAppRestClient, pageRef). + build(actualId, 1, AjaxWizard.Mode.EDIT)); + modal.header(new Model<>(getString("usernameAttributeProviderConf.title", model))); + modal.show(true); + target.add(modal); + } + }, ActionLink.ActionType.COMPOSE, AMEntitlement.CLIENTAPP_UPDATE); + + panel.add(new ActionLink<>() { + + private static final long serialVersionUID = -3722207913631435501L; + + @Override + public void onClick(final AjaxRequestTarget target, final ClientAppTO ignore) { + model.setObject(restClient.read(type, model.getObject().getKey())); target.add(propertiesModal.setContent(new ModalDirectoryPanel<>( propertiesModal, - new ClientAppPropertiesDirectoryPanel<>("panel", propertiesModal, type, model, pageRef), + new ClientAppPropertiesDirectoryPanel<>( + "panel", restClient, propertiesModal, type, model, pageRef), pageRef))); propertiesModal.header(new Model<>(getString("properties.title", model))); propertiesModal.show(true); } }, ActionLink.ActionType.TYPE_EXTENSIONS, AMEntitlement.CLIENTAPP_UPDATE); + panel.add(new ActionLink<>() { + + private static final long serialVersionUID = -5432034353017728756L; + + @Override + public void onClick(final AjaxRequestTarget target, final ClientAppTO ignore) { + model.setObject(restClient.read(type, model.getObject().getKey())); + + target.add(historyModal.setContent(new AuditHistoryModal<>( + AuditElements.EventCategoryType.LOGIC, + "ClientAppLogic", + model.getObject(), + AMEntitlement.CLIENTAPP_UPDATE, + auditRestClient) { + + private static final long serialVersionUID = -3712506022627033811L; + + @Override + protected void restore(final String json, final AjaxRequestTarget target) { + try { + ClientAppTO updated = MAPPER.readValue(json, ClientAppTO.class); + restClient.update(type, updated); + + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); + } catch (Exception e) { + LOG.error("While restoring ClientApp {}", ((ClientAppTO) model.getObject()).getKey(), e); + SyncopeConsoleSession.get().onException(e); + } + ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target); + } + })); + + historyModal.header(new Model<>(getString("auditHistory.title", new Model<>(model.getObject())))); + + historyModal.show(true); + } + }, ActionLink.ActionType.VIEW_AUDIT_HISTORY, String.format("%s,%s", AMEntitlement.CLIENTAPP_READ, + IdRepoEntitlement.AUDIT_LIST)); + panel.add(new ActionLink<>() { private static final long serialVersionUID = -3722207913631435501L; @@ -166,7 +253,8 @@ public void onClick(final AjaxRequestTarget target, final ClientAppTO ignore) { public void onClick(final AjaxRequestTarget target, final ClientAppTO ignore) { T clientAppTO = model.getObject(); try { - ClientAppRestClient.delete(type, clientAppTO.getKey()); + restClient.delete(type, clientAppTO.getKey()); + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); target.add(container); } catch (SyncopeClientException e) { @@ -210,14 +298,14 @@ protected class ClientAppDataProvider extends DirectoryDataProvider { @Override public Iterator iterator(final long first, final long count) { - List list = ClientAppRestClient.list(type); + List list = restClient.list(type); list.sort(comparator); return list.subList((int) first, (int) first + (int) count).iterator(); } @Override public long size() { - return ClientAppRestClient.list(type).size(); + return restClient.list(type).size(); } @Override diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java index bcc20e79cf5..5276ae85b62 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java @@ -18,16 +18,21 @@ */ package org.apache.syncope.client.console.clientapps; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Base64; import java.util.Comparator; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.ws.rs.core.MediaType; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.SyncopeWebApplication; import org.apache.syncope.client.console.commons.RealmsUtils; import org.apache.syncope.client.console.panels.AbstractModalPanel; import org.apache.syncope.client.console.rest.ClientAppRestClient; @@ -35,27 +40,35 @@ import org.apache.syncope.client.console.rest.RealmRestClient; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSearchFieldPanel; +import org.apache.syncope.client.console.wicket.markup.html.form.BinaryFieldPanel; import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel; import org.apache.syncope.client.console.wicket.markup.html.form.PolicyRenderer; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxNumberFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel; -import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.client.ui.commons.panels.WizardModalPanel; import org.apache.syncope.client.ui.commons.wizards.AbstractModalPanelBuilder; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; -import org.apache.syncope.common.lib.SyncopeConstants; +import org.apache.syncope.common.lib.OIDCScopeConstants; import org.apache.syncope.common.lib.policy.PolicyTO; import org.apache.syncope.common.lib.to.ClientAppTO; +import org.apache.syncope.common.lib.to.OIDCRPClientAppTO; import org.apache.syncope.common.lib.to.RealmTO; import org.apache.syncope.common.lib.types.ClientAppType; +import org.apache.syncope.common.lib.types.LogoutType; +import org.apache.syncope.common.lib.types.OIDCApplicationType; +import org.apache.syncope.common.lib.types.OIDCClientAuthenticationMethod; import org.apache.syncope.common.lib.types.OIDCGrantType; import org.apache.syncope.common.lib.types.OIDCResponseType; import org.apache.syncope.common.lib.types.OIDCSubjectType; +import org.apache.syncope.common.lib.types.OIDCTokenEncryptionAlg; +import org.apache.syncope.common.lib.types.OIDCTokenEncryptionEncoding; +import org.apache.syncope.common.lib.types.OIDCTokenSigningAlg; import org.apache.syncope.common.lib.types.PolicyType; import org.apache.syncope.common.lib.types.SAML2SPNameId; import org.apache.syncope.common.lib.types.XmlSecAlgorithm; @@ -77,49 +90,75 @@ public class ClientAppModalPanelBuilder extends AbstractM private static final long serialVersionUID = 5945391813567245081L; - private final IModel> accessPolicies = new LoadableDetachableModel<>() { + protected final IModel> accessPolicies = new LoadableDetachableModel<>() { private static final long serialVersionUID = -2012833443695917883L; @Override protected Map load() { - return PolicyRestClient.list(PolicyType.ACCESS).stream(). - collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName)); + return policyRestClient.list(PolicyType.ACCESS).stream(). + collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new)); } }; - private final IModel> attrReleasePolicies = new LoadableDetachableModel<>() { + protected final IModel> attrReleasePolicies = new LoadableDetachableModel<>() { private static final long serialVersionUID = -2012833443695917883L; @Override protected Map load() { - return PolicyRestClient.list(PolicyType.ATTR_RELEASE).stream(). - collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName)); + return policyRestClient.list(PolicyType.ATTR_RELEASE).stream(). + collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new)); } }; - private final IModel> authPolicies = new LoadableDetachableModel<>() { + protected final IModel> authPolicies = new LoadableDetachableModel<>() { private static final long serialVersionUID = -2012833443695917883L; @Override protected Map load() { - return PolicyRestClient.list(PolicyType.AUTH).stream(). - collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName)); + return policyRestClient.list(PolicyType.AUTH).stream(). + collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new)); } }; - private final BaseModal modal; + protected final IModel> ticketExpirationPolicies = new LoadableDetachableModel<>() { - private final ClientAppType type; + private static final long serialVersionUID = -2012833443695917883L; + + @Override + protected Map load() { + return policyRestClient.list(PolicyType.TICKET_EXPIRATION).stream(). + collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new)); + } + }; + + protected final BaseModal modal; + + protected final ClientAppType type; + + protected final PolicyRestClient policyRestClient; + + protected final ClientAppRestClient clientAppRestClient; + + protected final RealmRestClient realmRestClient; public ClientAppModalPanelBuilder( - final ClientAppType type, final T defaultItem, final BaseModal modal, final PageReference pageRef) { + final ClientAppType type, + final T defaultItem, + final BaseModal modal, + final PolicyRestClient policyRestClient, + final ClientAppRestClient clientAppRestClient, + final RealmRestClient realmRestClient, + final PageReference pageRef) { super(defaultItem, pageRef); this.type = type; this.modal = modal; + this.policyRestClient = policyRestClient; + this.clientAppRestClient = clientAppRestClient; + this.realmRestClient = realmRestClient; } @Override @@ -141,10 +180,10 @@ private class Profile extends AbstractModalPanel { List fields = new ArrayList<>(); - boolean isSearchEnabled = RealmsUtils.isSearchEnabled(); + boolean fullRealmsTree = SyncopeWebApplication.get().fullRealmsTree(realmRestClient); AutoCompleteSettings settings = new AutoCompleteSettings(); - settings.setShowCompleteListOnFocusGain(!isSearchEnabled); - settings.setShowListOnEmptyInput(!isSearchEnabled); + settings.setShowCompleteListOnFocusGain(fullRealmsTree); + settings.setShowListOnEmptyInput(fullRealmsTree); AjaxSearchFieldPanel realm = new AjaxSearchFieldPanel( "field", "realm", new PropertyModel<>(clientAppTO, "realm"), settings) { @@ -152,11 +191,9 @@ private class Profile extends AbstractModalPanel { @Override protected Iterator getChoices(final String input) { - return (isSearchEnabled - ? RealmRestClient.search(RealmsUtils.buildQuery(input)).getResult() - : RealmRestClient.list(SyncopeConstants.ROOT_REALM)). - stream().filter(realm -> SyncopeConsoleSession.get().getAuthRealms().stream(). - anyMatch(authRealm -> realm.getFullPath().startsWith(authRealm))). + return realmRestClient.search(fullRealmsTree + ? RealmsUtils.buildBaseQuery() + : RealmsUtils.buildKeywordQuery(input)).getResult().stream(). map(RealmTO::getFullPath).collect(Collectors.toList()).iterator(); } }; @@ -168,41 +205,74 @@ protected Iterator getChoices(final String input) { fields.add(name.setRequired(true)); if (clientAppTO.getClientAppId() == null) { - Stream.of(ClientAppType.values()).map(ClientAppRestClient::list).flatMap(List::stream). + Stream.of(ClientAppType.values()).map(clientAppRestClient::list).flatMap(List::stream). max(Comparator.comparing(ClientAppTO::getClientAppId)). ifPresent(app -> clientAppTO.setClientAppId(app.getClientAppId() + 1)); } - fields.add(new AjaxSpinnerFieldPanel.Builder().build( + fields.add(new AjaxNumberFieldPanel.Builder().build( "field", "clientAppId", Long.class, new PropertyModel<>(clientAppTO, "clientAppId")).setRequired(true)); + fields.add(new AjaxNumberFieldPanel.Builder().build( + "field", "evaluationOrder", Integer.class, + new PropertyModel<>(clientAppTO, "evaluationOrder")).setRequired(true)); + fields.add(new AjaxTextFieldPanel( "field", Constants.DESCRIPTION_FIELD_NAME, new PropertyModel<>(clientAppTO, Constants.DESCRIPTION_FIELD_NAME), false)); + fields.add(new AjaxTextFieldPanel( + "field", "logo", + new PropertyModel<>(clientAppTO, "logo"), false)); + + fields.add(new AjaxTextFieldPanel( + "field", "theme", + new PropertyModel<>(clientAppTO, "theme"), false)); + + AjaxTextFieldPanel informationUrl = new AjaxTextFieldPanel( + "field", "informationUrl", + new PropertyModel<>(clientAppTO, "informationUrl"), false); + informationUrl.addValidator(new UrlValidator()); + fields.add(informationUrl); + + AjaxTextFieldPanel privacyUrl = new AjaxTextFieldPanel( + "field", "privacyUrl", + new PropertyModel<>(clientAppTO, "privacyUrl"), false); + privacyUrl.addValidator(new UrlValidator()); + fields.add(privacyUrl); + AjaxDropDownChoicePanel accessPolicy = new AjaxDropDownChoicePanel<>( "field", "accessPolicy", new PropertyModel<>(clientAppTO, "accessPolicy"), false); - accessPolicy.setChoiceRenderer(new PolicyRenderer(accessPolicies)); + accessPolicy.setChoiceRenderer(new PolicyRenderer(accessPolicies.getObject())); accessPolicy.setChoices(new ArrayList<>(accessPolicies.getObject().keySet())); ((AbstractSingleSelectChoice) accessPolicy.getField()).setNullValid(true); fields.add(accessPolicy); AjaxDropDownChoicePanel attrReleasePolicy = new AjaxDropDownChoicePanel<>( "field", "attrReleasePolicy", new PropertyModel<>(clientAppTO, "attrReleasePolicy"), false); - attrReleasePolicy.setChoiceRenderer(new PolicyRenderer(attrReleasePolicies)); + attrReleasePolicy.setChoiceRenderer(new PolicyRenderer(attrReleasePolicies.getObject())); attrReleasePolicy.setChoices(new ArrayList<>(attrReleasePolicies.getObject().keySet())); ((AbstractSingleSelectChoice) attrReleasePolicy.getField()).setNullValid(true); fields.add(attrReleasePolicy); AjaxDropDownChoicePanel authPolicy = new AjaxDropDownChoicePanel<>( "field", "authPolicy", new PropertyModel<>(clientAppTO, "authPolicy"), false); - authPolicy.setChoiceRenderer(new PolicyRenderer(authPolicies)); + authPolicy.setChoiceRenderer(new PolicyRenderer(authPolicies.getObject())); authPolicy.setChoices(new ArrayList<>(authPolicies.getObject().keySet())); - authPolicy.setRequired(true); - ((AbstractSingleSelectChoice) authPolicy.getField()).setNullValid(true); fields.add(authPolicy); - fields.add(new AjaxTextFieldPanel("field", "theme", new PropertyModel<>(clientAppTO, "theme"), false)); + AjaxDropDownChoicePanel ticketExpirationPolicy = new AjaxDropDownChoicePanel<>( + "field", "ticketExpirationPolicy", + new PropertyModel<>(clientAppTO, "ticketExpirationPolicy"), false); + ticketExpirationPolicy.setChoiceRenderer(new PolicyRenderer(ticketExpirationPolicies.getObject())); + ticketExpirationPolicy.setChoices(new ArrayList<>(ticketExpirationPolicies.getObject().keySet())); + ((AbstractSingleSelectChoice) ticketExpirationPolicy.getField()).setNullValid(true); + fields.add(ticketExpirationPolicy); + + AjaxDropDownChoicePanel logoutType = new AjaxDropDownChoicePanel<>( + "field", "logoutType", new PropertyModel<>(clientAppTO, "logoutType"), false); + logoutType.setChoices(List.of(LogoutType.values())); + fields.add(logoutType.setRequired(true)); switch (type) { case CASSP: @@ -230,24 +300,82 @@ protected void onUpdate(final AjaxRequestTarget target) { AjaxTextFieldPanel clientSecret = new AjaxTextFieldPanel( "field", "clientSecret", new PropertyModel<>(clientAppTO, "clientSecret"), false); - clientSecret.setChoices(List.of(RandomStringUtils.randomAlphanumeric(15))); + clientSecret.setChoices(List.of(RandomStringUtils.secure().nextNumeric(15))); fields.add(clientSecret.setRequired(true)); + AjaxTextFieldPanel idTokenIssuer = new AjaxTextFieldPanel( + "field", "idTokenIssuer", new PropertyModel<>(clientAppTO, "idTokenIssuer"), false); + fields.add(idTokenIssuer); + + AjaxCheckBoxPanel signIdToken = new AjaxCheckBoxPanel( + "field", "signIdToken", new PropertyModel<>(clientAppTO, "signIdToken")); + fields.add(signIdToken); + AjaxDropDownChoicePanel idTokenSigningAlg = new AjaxDropDownChoicePanel<>( + "field", "idTokenSigningAlg", new PropertyModel<>(clientAppTO, "idTokenSigningAlg"), false); + idTokenSigningAlg.setChoices(List.of(OIDCTokenSigningAlg.values())); + fields.add(idTokenSigningAlg.addRequiredLabel()); + fields.add(new AjaxCheckBoxPanel( - "field", "signIdToken", new PropertyModel<>(clientAppTO, "signIdToken"))); + "field", "encryptIdToken", new PropertyModel<>(clientAppTO, "encryptIdToken"))); + AjaxDropDownChoicePanel idTokenEncryptionAlg = + new AjaxDropDownChoicePanel<>( + "field", + "idTokenEncryptionAlg", + new PropertyModel<>(clientAppTO, "idTokenEncryptionAlg"), + false); + idTokenEncryptionAlg.setChoices(List.of(OIDCTokenEncryptionAlg.values())); + fields.add(idTokenEncryptionAlg.addRequiredLabel()); + AjaxDropDownChoicePanel idTokenEncryptionEncoding = + new AjaxDropDownChoicePanel<>( + "field", + "idTokenEncryptionEncoding", + new PropertyModel<>(clientAppTO, "idTokenEncryptionEncoding"), + false); + idTokenEncryptionEncoding.setChoices(List.of(OIDCTokenEncryptionEncoding.values())); + fields.add(idTokenEncryptionEncoding); + + AjaxDropDownChoicePanel userInfoSigningAlg = new AjaxDropDownChoicePanel<>( + "field", + "userInfoSigningAlg", + new PropertyModel<>(clientAppTO, "userInfoSigningAlg"), + false); + userInfoSigningAlg.setChoices(List.of(OIDCTokenSigningAlg.values())); + fields.add(userInfoSigningAlg); + AjaxDropDownChoicePanel userInfoEncryptedResponseAlg = + new AjaxDropDownChoicePanel<>( + "field", + "userInfoEncryptedResponseAlg", + new PropertyModel<>(clientAppTO, "userInfoEncryptedResponseAlg"), + false); + userInfoEncryptedResponseAlg.setChoices(List.of(OIDCTokenEncryptionAlg.values())); + fields.add(userInfoEncryptedResponseAlg); + AjaxDropDownChoicePanel userInfoEncryptedResponseEncoding = + new AjaxDropDownChoicePanel<>( + "field", + "userInfoEncryptedResponseEncoding", + new PropertyModel<>(clientAppTO, "userInfoEncryptedResponseEncoding"), + false); + userInfoEncryptedResponseEncoding.setChoices(List.of(OIDCTokenEncryptionEncoding.values())); + fields.add(userInfoEncryptedResponseEncoding); + fields.add(new AjaxCheckBoxPanel( "field", "jwtAccessToken", new PropertyModel<>(clientAppTO, "jwtAccessToken"))); fields.add(new AjaxCheckBoxPanel( "field", "bypassApprovalPrompt", new PropertyModel<>(clientAppTO, "bypassApprovalPrompt"))); + fields.add(new AjaxCheckBoxPanel( + "field", "generateRefreshToken", new PropertyModel<>(clientAppTO, "generateRefreshToken"))); AjaxDropDownChoicePanel subjectType = new AjaxDropDownChoicePanel<>( "field", "subjectType", new PropertyModel<>(clientAppTO, "subjectType"), false); subjectType.setChoices(List.of(OIDCSubjectType.values())); - subjectType.addRequiredLabel().setEnabled(true); - fields.add(subjectType); + fields.add(subjectType.addRequiredLabel().setEnabled(true)); + + AjaxDropDownChoicePanel applicationType = new AjaxDropDownChoicePanel<>( + "field", "applicationType", new PropertyModel<>(clientAppTO, "applicationType"), false); + applicationType.setChoices(List.of(OIDCApplicationType.values())); + fields.add(applicationType.addRequiredLabel().setEnabled(true)); AjaxTextFieldPanel redirectUri = new AjaxTextFieldPanel("panel", "redirectUris", new Model<>()); - redirectUri.addValidator(new UrlValidator()); fields.add(new MultiFieldPanel.Builder( new PropertyModel<>(clientAppTO, "redirectUris")).build( "field", @@ -264,16 +392,81 @@ protected void onUpdate(final AjaxRequestTarget target) { new PropertyModel<>(clientAppTO, "supportedResponseTypes"), new ListModel<>(List.of(OIDCResponseType.values())))); + AutoCompleteSettings scopesSettings = new AutoCompleteSettings(); + scopesSettings.setShowCompleteListOnFocusGain(true); + scopesSettings.setShowListOnEmptyInput(true); + AjaxSearchFieldPanel scopes = new AjaxSearchFieldPanel( + "panel", "scopes", new PropertyModel<>(clientAppTO, "scopes"), scopesSettings) { + + private static final long serialVersionUID = 7160878678968866138L; + + @Override + protected Iterator getChoices(final String input) { + List choices = new ArrayList<>(OIDCScopeConstants.ALL_STANDARD_SCOPES); + choices.add(OIDCScopeConstants.SYNCOPE); + return choices.iterator(); + } + }; + fields.add(new MultiFieldPanel.Builder( + new PropertyModel<>(clientAppTO, "scopes")).build( + "field", + "scopes", + scopes)); + AjaxTextFieldPanel logoutUri = new AjaxTextFieldPanel( "field", "logoutUri", new PropertyModel<>(clientAppTO, "logoutUri"), false); logoutUri.addValidator(new UrlValidator()); fields.add(logoutUri); + + BinaryFieldPanel jwks = new BinaryFieldPanel( + "field", + "jwks", + new Model<>() { + + private static final long serialVersionUID = 7666049400663637482L; + + @Override + public String getObject() { + OIDCRPClientAppTO oidcRPCA = (OIDCRPClientAppTO) clientAppTO; + return StringUtils.isBlank(oidcRPCA.getJwks()) + ? null + : Base64.getEncoder().encodeToString( + oidcRPCA.getJwks().getBytes(StandardCharsets.UTF_8)); + } + + @Override + public void setObject(final String object) { + OIDCRPClientAppTO oidcRPCA = (OIDCRPClientAppTO) clientAppTO; + if (StringUtils.isBlank(object)) { + oidcRPCA.setJwks(null); + } else { + oidcRPCA.setJwks( + new String(Base64.getDecoder().decode(object), StandardCharsets.UTF_8)); + } + } + }, + MediaType.APPLICATION_JSON, + "client-jwks"); + fields.add(jwks); + + AjaxTextFieldPanel jwksUri = new AjaxTextFieldPanel( + "field", "jwksUri", new PropertyModel<>(clientAppTO, "jwksUri"), false); + jwksUri.addValidator(new UrlValidator()); + fields.add(jwksUri); + + AjaxDropDownChoicePanel tokenEndpointAuthenticationMethod = + new AjaxDropDownChoicePanel<>( + "field", + "tokenEndpointAuthenticationMethod", + new PropertyModel<>(clientAppTO, "tokenEndpointAuthenticationMethod"), + false); + tokenEndpointAuthenticationMethod.setChoices(List.of(OIDCClientAuthenticationMethod.values())); + fields.add(tokenEndpointAuthenticationMethod); break; case SAML2SP: AjaxTextFieldPanel entityId = new AjaxTextFieldPanel( "field", "entityId", new PropertyModel<>(clientAppTO, "entityId"), false); - entityId.addValidator(new UrlValidator()); fields.add(entityId.setRequired(true)); fields.add(new AjaxTextFieldPanel("field", "metadataLocation", @@ -306,7 +499,7 @@ protected void onUpdate(final AjaxRequestTarget target) { requiredNameIdFormat.addRequiredLabel().setEnabled(true); fields.add(requiredNameIdFormat); - fields.add(new AjaxSpinnerFieldPanel.Builder().min(0).build( + fields.add(new AjaxNumberFieldPanel.Builder().min(0).build( "field", "skewAllowance", Integer.class, new PropertyModel<>(clientAppTO, "skewAllowance"))); @@ -381,9 +574,9 @@ protected void populateItem(final ListItem item) { public void onSubmit(final AjaxRequestTarget target) { try { if (clientAppTO.getKey() == null) { - ClientAppRestClient.create(type, clientAppTO); + clientAppRestClient.create(type, clientAppTO); } else { - ClientAppRestClient.update(type, clientAppTO); + clientAppRestClient.update(type, clientAppTO); } SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); Profile.this.modal.close(target); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppPropertiesDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppPropertiesDirectoryPanel.java index 08eafb66a53..89f6dea74f8 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppPropertiesDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppPropertiesDirectoryPanel.java @@ -42,22 +42,23 @@ public class ClientAppPropertiesDirectoryPanel extends AttrListDirectoryPanel { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 9072805604972532678L; - private final BaseModal propertiesModal; + protected final BaseModal propertiesModal; - private final ClientAppType type; + protected final ClientAppType type; - private final IModel model; + protected final IModel model; public ClientAppPropertiesDirectoryPanel( final String id, + final ClientAppRestClient restClient, final BaseModal propertiesModal, final ClientAppType type, final IModel model, final PageReference pageRef) { - super(id, pageRef, false); + super(id, restClient, pageRef, false); this.propertiesModal = propertiesModal; this.type = type; @@ -68,7 +69,8 @@ public ClientAppPropertiesDirectoryPanel( enableUtilityButton(); setFooterVisibility(false); - addNewItemPanelBuilder(new ClientAppPropertyWizardBuilder(type, model.getObject(), new Attr(), pageRef), true); + addNewItemPanelBuilder(new ClientAppPropertyWizardBuilder( + type, model.getObject(), new Attr(), restClient, pageRef), true); initResultTable(); } @@ -107,7 +109,7 @@ protected ActionsPanel getActions(final IModel model) { @Override public void onClick(final AjaxRequestTarget target, final Attr ignore) { send(ClientAppPropertiesDirectoryPanel.this, Broadcast.EXACT, - new AjaxWizard.EditItemActionEvent<>(model.getObject(), target)); + new AjaxWizard.EditItemActionEvent<>(model.getObject(), target)); } }, ActionLink.ActionType.EDIT, AMEntitlement.CLIENTAPP_UPDATE); @@ -119,7 +121,8 @@ public void onClick(final AjaxRequestTarget target, final Attr ignore) { public void onClick(final AjaxRequestTarget target, final Attr ignore) { try { ClientAppPropertiesDirectoryPanel.this.model.getObject().getProperties().remove(model.getObject()); - ClientAppRestClient.update(type, ClientAppPropertiesDirectoryPanel.this.model.getObject()); + ((ClientAppRestClient) restClient).update( + type, ClientAppPropertiesDirectoryPanel.this.model.getObject()); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); target.add(container); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppPropertyWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppPropertyWizardBuilder.java index c73b9a4be0c..0b717747bce 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppPropertyWizardBuilder.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppPropertyWizardBuilder.java @@ -28,21 +28,25 @@ public class ClientAppPropertyWizardBuilder extends AttrWizardBuilder { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = -91564005263775261L; - private final ClientAppType type; + protected final ClientAppType type; - private final ClientAppTO clientApp; + protected final ClientAppTO clientApp; + + protected final ClientAppRestClient clientAppRestClient; public ClientAppPropertyWizardBuilder( final ClientAppType type, final ClientAppTO clientApp, final Attr attr, + final ClientAppRestClient clientAppRestClient, final PageReference pageRef) { super(attr, pageRef); this.type = type; this.clientApp = clientApp; + this.clientAppRestClient = clientAppRestClient; } @Override @@ -50,7 +54,7 @@ protected Serializable onApplyInternal(final Attr modelObject) { clientApp.getProperties().removeIf(p -> modelObject.getSchema().equals(p.getSchema())); clientApp.getProperties().add(modelObject); - ClientAppRestClient.update(type, clientApp); + clientAppRestClient.update(type, clientApp); return null; } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientApps.java b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientApps.java index 8a694736036..851f808a0fa 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientApps.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientApps.java @@ -21,16 +21,21 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbedPanel; import java.util.ArrayList; import java.util.List; +import org.apache.syncope.client.console.rest.ClientAppRestClient; import org.apache.syncope.common.lib.types.ClientAppType; import org.apache.wicket.PageReference; import org.apache.wicket.extensions.markup.html.tabs.AbstractTab; import org.apache.wicket.extensions.markup.html.tabs.ITab; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.Model; +import org.apache.wicket.spring.injection.annot.SpringBean; public class ClientApps extends Panel { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 5755172996408318813L; + + @SpringBean + protected ClientAppRestClient clientAppRestClient; public ClientApps(final String id, final PageReference pageRef) { super(id); @@ -38,7 +43,7 @@ public ClientApps(final String id, final PageReference pageRef) { add(new AjaxBootstrapTabbedPanel<>("clientApps", buildTabList(pageRef))); } - private List buildTabList(final PageReference pageRef) { + protected List buildTabList(final PageReference pageRef) { List tabs = new ArrayList<>(3); tabs.add(new AbstractTab(Model.of(ClientAppType.CASSP.name())) { @@ -47,7 +52,7 @@ private List buildTabList(final PageReference pageRef) { @Override public Panel getPanel(final String panelId) { - return new CASSPDirectoryPanel(panelId, pageRef); + return new CASSPDirectoryPanel(panelId, clientAppRestClient, pageRef); } }); @@ -57,7 +62,7 @@ public Panel getPanel(final String panelId) { @Override public Panel getPanel(final String panelId) { - return new SAML2SPDirectoryPanel(panelId, pageRef); + return new SAML2SPDirectoryPanel(panelId, clientAppRestClient, pageRef); } }); @@ -67,7 +72,7 @@ public Panel getPanel(final String panelId) { @Override public Panel getPanel(final String panelId) { - return new OIDCRPDirectoryPanel(panelId, pageRef); + return new OIDCRPDirectoryPanel(panelId, clientAppRestClient, pageRef); } }); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/OIDCRPDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/OIDCRPDirectoryPanel.java index 92387b60959..14c20ddfb89 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/OIDCRPDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/OIDCRPDirectoryPanel.java @@ -20,6 +20,7 @@ import java.util.List; import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.client.console.rest.ClientAppRestClient; import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.BooleanConditionColumn; import org.apache.syncope.common.lib.to.OIDCRPClientAppTO; import org.apache.syncope.common.lib.types.AMEntitlement; @@ -35,13 +36,20 @@ public class OIDCRPDirectoryPanel extends ClientAppDirectoryPanel(ClientAppType.OIDCRP, defaultItem, modal, pageRef), true); + addNewItemPanelBuilder(new ClientAppModalPanelBuilder<>( + ClientAppType.OIDCRP, + defaultItem, + modal, + policyRestClient, + clientAppRestClient, + realmRestClient, + pageRef), + true); MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, AMEntitlement.CLIENTAPP_CREATE); initResultTable(); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/SAML2SPDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/SAML2SPDirectoryPanel.java index b14106d920b..6b2b2be34f0 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/SAML2SPDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/SAML2SPDirectoryPanel.java @@ -19,6 +19,7 @@ package org.apache.syncope.client.console.clientapps; import java.util.List; +import org.apache.syncope.client.console.rest.ClientAppRestClient; import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.BooleanPropertyColumn; import org.apache.syncope.common.lib.to.SAML2SPClientAppTO; import org.apache.syncope.common.lib.types.AMEntitlement; @@ -31,15 +32,22 @@ public class SAML2SPDirectoryPanel extends ClientAppDirectoryPanel { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 7724172966123776889L; - public SAML2SPDirectoryPanel(final String id, final PageReference pageRef) { - super(id, ClientAppType.SAML2SP, pageRef); + public SAML2SPDirectoryPanel(final String id, final ClientAppRestClient restClient, final PageReference pageRef) { + super(id, restClient, ClientAppType.SAML2SP, pageRef); SAML2SPClientAppTO defaultItem = new SAML2SPClientAppTO(); - this.addNewItemPanelBuilder( - new ClientAppModalPanelBuilder<>(ClientAppType.SAML2SP, defaultItem, modal, pageRef), true); + addNewItemPanelBuilder(new ClientAppModalPanelBuilder<>( + ClientAppType.SAML2SP, + defaultItem, + modal, + policyRestClient, + clientAppRestClient, + realmRestClient, + pageRef), + true); MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, AMEntitlement.CLIENTAPP_CREATE); initResultTable(); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/UsernameAttributeProviderModalPanelBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/UsernameAttributeProviderModalPanelBuilder.java new file mode 100644 index 00000000000..9b2b4fe28f2 --- /dev/null +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/UsernameAttributeProviderModalPanelBuilder.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.console.clientapps; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.SyncopeWebApplication; +import org.apache.syncope.client.console.panels.AbstractModalPanel; +import org.apache.syncope.client.console.panels.BeanPanel; +import org.apache.syncope.client.console.rest.ClientAppRestClient; +import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; +import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; +import org.apache.syncope.client.ui.commons.pages.BaseWebPage; +import org.apache.syncope.client.ui.commons.panels.WizardModalPanel; +import org.apache.syncope.client.ui.commons.wizards.AbstractModalPanelBuilder; +import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; +import org.apache.syncope.common.lib.clientapps.UsernameAttributeProviderConf; +import org.apache.syncope.common.lib.to.ClientAppTO; +import org.apache.syncope.common.lib.types.ClientAppType; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxEventBehavior; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.model.LoadableDetachableModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; +import org.springframework.util.ClassUtils; + +public class UsernameAttributeProviderModalPanelBuilder extends AbstractModalPanelBuilder { + + private static final long serialVersionUID = -4106998301911573852L; + + protected final LoadableDetachableModel> usernameAttributeProviderConfs = + new LoadableDetachableModel<>() { + + private static final long serialVersionUID = 5275935387613157437L; + + @Override + protected List load() { + return SyncopeWebApplication.get().getLookup().getClasses(UsernameAttributeProviderConf.class).stream(). + map(Class::getName).sorted().collect(Collectors.toList()); + } + }; + + protected final BaseModal modal; + + protected final ClientAppType type; + + protected final ClientAppRestClient clientAppRestClient; + + public UsernameAttributeProviderModalPanelBuilder( + final ClientAppType type, + final T defaultItem, + final BaseModal modal, + final ClientAppRestClient clientAppRestClient, + final PageReference pageRef) { + + super(defaultItem, pageRef); + this.type = type; + this.modal = modal; + this.clientAppRestClient = clientAppRestClient; + } + + @Override + public WizardModalPanel build(final String id, final int index, final AjaxWizard.Mode mode) { + return new Profile(newModelObject(), modal, pageRef); + } + + protected class Profile extends AbstractModalPanel { + + private static final long serialVersionUID = 7647959917047450318L; + + protected final T clientAppTO; + + Profile(final T clientAppTO, final BaseModal modal, final PageReference pageRef) { + super(modal, pageRef); + modal.setFormModel(clientAppTO); + + this.clientAppTO = clientAppTO; + + AjaxDropDownChoicePanel conf = new AjaxDropDownChoicePanel<>( + "conf", "conf", new Model<>()); + Optional.ofNullable(clientAppTO.getUsernameAttributeProviderConf()). + ifPresent(uapc -> conf.setModelObject(uapc.getClass().getName())); + conf.setChoices(usernameAttributeProviderConfs.getObject()); + conf.setNullValid(true); + add(conf); + + PropertyModel beanPanelModel = + new PropertyModel<>(clientAppTO, "usernameAttributeProviderConf"); + BeanPanel bean = new BeanPanel<>("bean", beanPanelModel, pageRef); + add(bean.setRenderBodyOnly(false)); + + conf.add(new AjaxEventBehavior(Constants.ON_CHANGE) { + + private static final long serialVersionUID = -7133385027739964990L; + + @SuppressWarnings("unchecked") + @Override + protected void onEvent(final AjaxRequestTarget target) { + if (conf.getModelObject() == null) { + beanPanelModel.setObject(null); + } else { + try { + Class clazz = + (Class) ClassUtils.resolveClassName( + conf.getModelObject(), ClassUtils.getDefaultClassLoader()); + + beanPanelModel.setObject(clazz.getConstructor().newInstance()); + } catch (Exception e) { + LOG.error("Cannot instantiate {}", conf.getModelObject(), e); + } + } + + target.add(bean); + } + }); + } + + @Override + public void onSubmit(final AjaxRequestTarget target) { + try { + clientAppRestClient.update(type, clientAppTO); + + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); + UsernameAttributeProviderModalPanelBuilder.Profile.this.modal.close(target); + } catch (Exception e) { + LOG.error("While creating/updating clientApp", e); + SyncopeConsoleSession.get().onException(e); + } + ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target); + } + } +} diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AccessMapFor.java b/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMAccessPolicyConfProvider.java similarity index 61% rename from wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AccessMapFor.java rename to client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMAccessPolicyConfProvider.java index 9ed25432884..78a66df4a05 100644 --- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AccessMapFor.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMAccessPolicyConfProvider.java @@ -16,17 +16,20 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.wa.starter.mapping; +package org.apache.syncope.client.console.commons; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import java.util.List; +import java.util.stream.Collectors; +import org.apache.syncope.client.console.SyncopeWebApplication; import org.apache.syncope.common.lib.policy.AccessPolicyConf; -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) -public @interface AccessMapFor { +public class AMAccessPolicyConfProvider implements AccessPolicyConfProvider { - Class accessPolicyConfClass(); + private static final long serialVersionUID = 5657864541765007494L; + + @Override + public List get() { + return SyncopeWebApplication.get().getLookup().getClasses(AccessPolicyConf.class).stream(). + map(Class::getName).sorted().collect(Collectors.toList()); + } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMConstants.java b/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMConstants.java index c185b55d1a6..08c9663fb58 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMConstants.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMConstants.java @@ -48,7 +48,11 @@ public final class AMConstants { public static final String PREF_AUTHPROFILE_GOOGLEMFAAUTHACCOUNTS_PAGINATOR_ROWS = "authprofile.googlemfaauthaccounts.paginator.rows"; - public static final String PREF_AUTHPROFILE_U2FDEVICES_PAGINATOR_ROWS = "authprofile.u2fdevices.paginator.rows"; + public static final String PREF_AUTHPROFILE_U2FDEVICES_PAGINATOR_ROWS = + "authprofile.u2fdevices.paginator.rows"; + + public static final String PREF_AUTHPROFILE_MFA_TRUSTED_FDEVICES_PAGINATOR_ROWS = + "authprofile.mfaTrustedDevices.paginator.rows"; public static final String PREF_AUTHPROFILE_WEBAUTHNDEVICECREDENTIALS_PAGINATOR_ROWS = "authprofile.webAuthnDeviceCredentials.paginator.rows"; diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMPolicyTabProvider.java b/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMPolicyTabProvider.java index 488548123ae..1dd2ddf300f 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMPolicyTabProvider.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMPolicyTabProvider.java @@ -23,6 +23,8 @@ import org.apache.syncope.client.console.policies.AccessPolicyDirectoryPanel; import org.apache.syncope.client.console.policies.AttrReleasePolicyDirectoryPanel; import org.apache.syncope.client.console.policies.AuthPolicyDirectoryPanel; +import org.apache.syncope.client.console.policies.TicketExpirationPolicyDirectoryPanel; +import org.apache.syncope.client.console.rest.PolicyRestClient; import org.apache.wicket.PageReference; import org.apache.wicket.extensions.markup.html.tabs.AbstractTab; import org.apache.wicket.extensions.markup.html.tabs.ITab; @@ -33,9 +35,10 @@ public class AMPolicyTabProvider implements PolicyTabProvider { private static final long serialVersionUID = 2822554006571803418L; - @Override - public int getOrder() { - return 200; + protected final PolicyRestClient policyRestClient; + + public AMPolicyTabProvider(final PolicyRestClient policyRestClient) { + this.policyRestClient = policyRestClient; } @Override @@ -48,7 +51,7 @@ public List buildTabList(final PageReference pageRef) { @Override public Panel getPanel(final String panelId) { - return new AccessPolicyDirectoryPanel(panelId, pageRef); + return new AccessPolicyDirectoryPanel(panelId, policyRestClient, pageRef); } }); @@ -58,7 +61,7 @@ public Panel getPanel(final String panelId) { @Override public Panel getPanel(final String panelId) { - return new AttrReleasePolicyDirectoryPanel(panelId, pageRef); + return new AttrReleasePolicyDirectoryPanel(panelId, policyRestClient, pageRef); } }); @@ -68,7 +71,17 @@ public Panel getPanel(final String panelId) { @Override public Panel getPanel(final String panelId) { - return new AuthPolicyDirectoryPanel(panelId, pageRef); + return new AuthPolicyDirectoryPanel(panelId, policyRestClient, pageRef); + } + }); + + tabs.add(new AbstractTab(new ResourceModel("policy.ticketExpiration")) { + + private static final long serialVersionUID = -6815067322125799251L; + + @Override + public Panel getPanel(final String panelId) { + return new TicketExpirationPolicyDirectoryPanel(panelId, policyRestClient, pageRef); } }); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMRealmPolicyProvider.java b/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMRealmPolicyProvider.java index 174d03153d0..e4d546ff931 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMRealmPolicyProvider.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/commons/AMRealmPolicyProvider.java @@ -19,6 +19,7 @@ package org.apache.syncope.client.console.commons; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.Map; import java.util.stream.Collectors; import org.apache.syncope.client.console.rest.PolicyRestClient; @@ -29,8 +30,6 @@ import org.apache.syncope.common.lib.types.PolicyType; import org.apache.wicket.markup.html.form.AbstractSingleSelectChoice; import org.apache.wicket.markup.repeater.RepeatingView; -import org.apache.wicket.model.IModel; -import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.ResourceModel; @@ -38,71 +37,60 @@ public class AMRealmPolicyProvider extends IdRepoRealmPolicyProvider { private static final long serialVersionUID = 1671878489700L; - private final IModel> accessPolicies = new LoadableDetachableModel<>() { - - private static final long serialVersionUID = -2012833443695917883L; - - @Override - protected Map load() { - return PolicyRestClient.list(PolicyType.ACCESS).stream(). - collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName)); - } - }; - - private final IModel> attrReleasePolicies = new LoadableDetachableModel<>() { - - private static final long serialVersionUID = -2012833443695917883L; - - @Override - protected Map load() { - return PolicyRestClient.list(PolicyType.ATTR_RELEASE).stream(). - collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName)); - } - }; - - private final IModel> authPolicies = new LoadableDetachableModel<>() { - - private static final long serialVersionUID = -2012833443695917883L; - - @Override - protected Map load() { - return PolicyRestClient.list(PolicyType.AUTH).stream(). - collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName)); - } - }; + public AMRealmPolicyProvider(final PolicyRestClient policyRestClient) { + super(policyRestClient); + } @Override public void add(final RealmTO realmTO, final RepeatingView view) { super.add(realmTO, view); + Map accessPolicies = policyRestClient.list(PolicyType.ACCESS).stream(). + collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new)); AjaxDropDownChoicePanel accessPolicy = new AjaxDropDownChoicePanel<>( view.newChildId(), new ResourceModel("accessPolicy", "accessPolicy").getObject(), new PropertyModel<>(realmTO, "accessPolicy"), false); accessPolicy.setChoiceRenderer(new PolicyRenderer(accessPolicies)); - accessPolicy.setChoices(new ArrayList<>(accessPolicies.getObject().keySet())); + accessPolicy.setChoices(new ArrayList<>(accessPolicies.keySet())); ((AbstractSingleSelectChoice) accessPolicy.getField()).setNullValid(true); view.add(accessPolicy); + Map attrReleasePolicies = policyRestClient.list(PolicyType.ATTR_RELEASE).stream(). + collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new)); AjaxDropDownChoicePanel attrReleasePolicy = new AjaxDropDownChoicePanel<>( view.newChildId(), new ResourceModel("attrReleasePolicy", "attrReleasePolicy").getObject(), new PropertyModel<>(realmTO, "attrReleasePolicy"), false); attrReleasePolicy.setChoiceRenderer(new PolicyRenderer(attrReleasePolicies)); - attrReleasePolicy.setChoices(new ArrayList<>(attrReleasePolicies.getObject().keySet())); + attrReleasePolicy.setChoices(new ArrayList<>(attrReleasePolicies.keySet())); ((AbstractSingleSelectChoice) attrReleasePolicy.getField()).setNullValid(true); view.add(attrReleasePolicy); + Map authPolicies = policyRestClient.list(PolicyType.AUTH).stream(). + collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new)); AjaxDropDownChoicePanel authPolicy = new AjaxDropDownChoicePanel<>( view.newChildId(), new ResourceModel("authPolicy", "authPolicy").getObject(), new PropertyModel<>(realmTO, "authPolicy"), false); authPolicy.setChoiceRenderer(new PolicyRenderer(authPolicies)); - authPolicy.setChoices(new ArrayList<>(authPolicies.getObject().keySet())); + authPolicy.setChoices(authPolicies.keySet().stream().collect(Collectors.toList())); ((AbstractSingleSelectChoice) authPolicy.getField()).setNullValid(true); view.add(authPolicy); + + Map ticketExpirationPolicies = policyRestClient.list(PolicyType.TICKET_EXPIRATION).stream(). + collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new)); + AjaxDropDownChoicePanel ticketExpirationPolicy = new AjaxDropDownChoicePanel<>( + view.newChildId(), + new ResourceModel("ticketExpirationPolicy", "ticketExpirationPolicy").getObject(), + new PropertyModel<>(realmTO, "ticketExpirationPolicy"), + false); + ticketExpirationPolicy.setChoiceRenderer(new PolicyRenderer(ticketExpirationPolicies)); + ticketExpirationPolicy.setChoices(ticketExpirationPolicies.keySet().stream().collect(Collectors.toList())); + ((AbstractSingleSelectChoice) ticketExpirationPolicy.getField()).setNullValid(true); + view.add(ticketExpirationPolicy); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/init/AMClassPathScanImplementationContributor.java b/client/am/console/src/main/java/org/apache/syncope/client/console/init/AMClassPathScanImplementationContributor.java index e7ca032553c..f995e5de2ad 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/init/AMClassPathScanImplementationContributor.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/init/AMClassPathScanImplementationContributor.java @@ -21,15 +21,25 @@ import java.util.Optional; import org.apache.syncope.common.lib.attr.AttrRepoConf; import org.apache.syncope.common.lib.auth.AuthModuleConf; +import org.apache.syncope.common.lib.clientapps.UsernameAttributeProviderConf; +import org.apache.syncope.common.lib.policy.AccessPolicyConf; +import org.apache.syncope.common.lib.policy.AttrReleasePolicyConf; +import org.apache.syncope.common.lib.policy.AuthPolicyConf; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.type.filter.AssignableTypeFilter; public class AMClassPathScanImplementationContributor implements ClassPathScanImplementationContributor { + private static final long serialVersionUID = 2493303413513242525L; + @Override public void extend(final ClassPathScanningCandidateComponentProvider scanner) { scanner.addIncludeFilter(new AssignableTypeFilter(AuthModuleConf.class)); scanner.addIncludeFilter(new AssignableTypeFilter(AttrRepoConf.class)); + scanner.addIncludeFilter(new AssignableTypeFilter(AccessPolicyConf.class)); + scanner.addIncludeFilter(new AssignableTypeFilter(AttrReleasePolicyConf.class)); + scanner.addIncludeFilter(new AssignableTypeFilter(AuthPolicyConf.class)); + scanner.addIncludeFilter(new AssignableTypeFilter(UsernameAttributeProviderConf.class)); } @Override @@ -40,6 +50,18 @@ public Optional getLabel(final Class clazz) { if (AttrRepoConf.class.isAssignableFrom(clazz)) { return Optional.of(AttrRepoConf.class.getName()); } + if (AccessPolicyConf.class.isAssignableFrom(clazz)) { + return Optional.of(AccessPolicyConf.class.getName()); + } + if (AttrReleasePolicyConf.class.isAssignableFrom(clazz)) { + return Optional.of(AttrReleasePolicyConf.class.getName()); + } + if (AuthPolicyConf.class.isAssignableFrom(clazz)) { + return Optional.of(AuthPolicyConf.class.getName()); + } + if (UsernameAttributeProviderConf.class.isAssignableFrom(clazz)) { + return Optional.of(UsernameAttributeProviderConf.class.getName()); + } return Optional.empty(); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/SRA.java b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/SRA.java index 9dc948cd48c..96bc50229f2 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/SRA.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/SRA.java @@ -23,13 +23,13 @@ import java.util.List; import org.apache.syncope.client.console.BookmarkablePageLinkBuilder; import org.apache.syncope.client.console.SyncopeConsoleSession; -import org.apache.syncope.client.console.annotations.AMPage; import org.apache.syncope.client.console.panels.AMSessionPanel; import org.apache.syncope.client.console.panels.SRARouteDirectoryPanel; import org.apache.syncope.client.console.panels.SRAStatisticsPanel; import org.apache.syncope.client.console.rest.SRARouteRestClient; import org.apache.syncope.client.console.rest.SRASessionRestClient; import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.annotations.AMPage; import org.apache.syncope.common.keymaster.client.api.ServiceOps; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.apache.syncope.common.lib.types.AMEntitlement; @@ -48,6 +48,9 @@ public class SRA extends BasePage { private static final long serialVersionUID = 9200112197134882164L; + @SpringBean + private SRARouteRestClient sraRouteRestClient; + @SpringBean private ServiceOps serviceOps; @@ -61,10 +64,12 @@ public SRA(final PageParameters parameters) { AjaxLink push = new AjaxLink<>("push") { + private static final long serialVersionUID = -817438685948164787L; + @Override public void onClick(final AjaxRequestTarget target) { try { - SRARouteRestClient.push(); + sraRouteRestClient.push(); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); } catch (Exception e) { LOG.error("While pushing to SRA", e); @@ -94,7 +99,7 @@ private List buildTabList(final List instances) { @Override public Panel getPanel(final String panelId) { - return new SRARouteDirectoryPanel(panelId, getPageReference()); + return new SRARouteDirectoryPanel(panelId, sraRouteRestClient, getPageReference()); } }); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java index f46871dd49f..3961a7280f1 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/pages/WA.java @@ -20,18 +20,18 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.json.JsonMapper; +import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal; import de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbedPanel; import java.io.InputStream; +import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.apache.commons.lang3.StringUtils; -import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.BookmarkablePageLinkBuilder; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.SyncopeWebApplication; -import org.apache.syncope.client.console.annotations.AMPage; import org.apache.syncope.client.console.authprofiles.AuthProfileDirectoryPanel; import org.apache.syncope.client.console.clientapps.ClientApps; import org.apache.syncope.client.console.panels.AMSessionPanel; @@ -40,10 +40,15 @@ import org.apache.syncope.client.console.panels.OIDC; import org.apache.syncope.client.console.panels.SAML2; import org.apache.syncope.client.console.panels.WAConfigDirectoryPanel; +import org.apache.syncope.client.console.panels.WAPushModalPanel; +import org.apache.syncope.client.console.rest.AttrRepoRestClient; +import org.apache.syncope.client.console.rest.AuthModuleRestClient; +import org.apache.syncope.client.console.rest.AuthProfileRestClient; import org.apache.syncope.client.console.rest.WAConfigRestClient; import org.apache.syncope.client.console.rest.WASessionRestClient; -import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.pages.BaseWebPage; +import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; +import org.apache.syncope.client.lib.WebClientBuilder; +import org.apache.syncope.client.ui.commons.annotations.AMPage; import org.apache.syncope.common.keymaster.client.api.ServiceOps; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.apache.syncope.common.lib.types.AMEntitlement; @@ -65,9 +70,23 @@ public class WA extends BasePage { protected static final JsonMapper MAPPER = JsonMapper.builder().findAndAddModules().build(); + @SpringBean + protected WAConfigRestClient waConfigRestClient; + + @SpringBean + protected AuthProfileRestClient authProfileRestClient; + + @SpringBean + protected AuthModuleRestClient authModuleRestClient; + + @SpringBean + protected AttrRepoRestClient attrRepoRestClient; + @SpringBean protected ServiceOps serviceOps; + protected final BaseModal modal; + protected String waPrefix = ""; public WA(final PageParameters parameters) { @@ -78,20 +97,21 @@ public WA(final PageParameters parameters) { List instances = serviceOps.list(NetworkService.Type.WA); + modal = new BaseModal<>("push-modal"); + modal.setWindowClosedCallback(target -> modal.show(false)); + modal.addSubmitButton(); + body.add(modal.size(Modal.Size.Large)); + AjaxLink push = new AjaxLink<>("push") { private static final long serialVersionUID = -817438685948164787L; @Override public void onClick(final AjaxRequestTarget target) { - try { - WAConfigRestClient.push(); - SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); - } catch (Exception e) { - LOG.error("While pushing to WA", e); - SyncopeConsoleSession.get().onException(e); - } - ((BaseWebPage) getPageReference().getPage()).getNotificationPanel().refresh(target); + modal.header(new ResourceModel("push.options")); + modal.setContent(new WAPushModalPanel(modal, instances, getPageReference())); + modal.show(true); + target.add(modal); } }; push.setEnabled(!instances.isEmpty() && SyncopeConsoleSession.get().owns(AMEntitlement.WA_CONFIG_PUSH)); @@ -106,14 +126,12 @@ public void onClick(final AjaxRequestTarget target) { body.add(content); if (!instances.isEmpty()) { - String actuatorEndpoint = instances.get(0).getAddress() + "actuator/env"; + String actuatorEndpoint = StringUtils.appendIfMissing(instances.get(0).getAddress(), "/") + "actuator/env"; try { - Response response = WebClient.create( - actuatorEndpoint, + Response response = WebClientBuilder.build(actuatorEndpoint, SyncopeWebApplication.get().getAnonymousUser(), SyncopeWebApplication.get().getAnonymousKey(), - null). - accept(MediaType.APPLICATION_JSON_TYPE).get(); + List.of()).accept(MediaType.APPLICATION_JSON_TYPE).get(); if (response.getStatus() == Response.Status.OK.getStatusCode()) { JsonNode env = MAPPER.readTree((InputStream) response.getEntity()); if (env.has("propertySources")) { @@ -150,7 +168,7 @@ protected List buildTabList(final List instances) { @Override public Panel getPanel(final String panelId) { - return new AuthModuleDirectoryPanel(panelId, getPageReference()); + return new AuthModuleDirectoryPanel(panelId, authModuleRestClient, getPageReference()); } }); } @@ -162,7 +180,7 @@ public Panel getPanel(final String panelId) { @Override public Panel getPanel(final String panelId) { - return new AttrRepoDirectoryPanel(panelId, getPageReference()); + return new AttrRepoDirectoryPanel(panelId, attrRepoRestClient, getPageReference()); } }); } @@ -206,7 +224,7 @@ public Panel getPanel(final String panelId) { @Override public Panel getPanel(final String panelId) { - return new WAConfigDirectoryPanel(panelId, getPageReference()); + return new WAConfigDirectoryPanel(panelId, waConfigRestClient, getPageReference()); } }); } @@ -218,7 +236,7 @@ public Panel getPanel(final String panelId) { @Override public Panel getPanel(final String panelId) { - return new AuthProfileDirectoryPanel(panelId, getPageReference()); + return new AuthProfileDirectoryPanel(panelId, authProfileRestClient, getPageReference()); } }); } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/AMSessionDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/AMSessionDirectoryPanel.java index 9ad20da11e2..852f53bf9d3 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/AMSessionDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/AMSessionDirectoryPanel.java @@ -26,6 +26,7 @@ import java.util.stream.Stream; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.commons.AMConstants; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.SortableDataProviderComparator; import org.apache.syncope.client.console.panels.AMSessionDirectoryPanel.AMSessionProvider; import org.apache.syncope.client.console.panels.AMSessionPanel.AMSessionSearchEvent; @@ -37,7 +38,6 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.console.wicket.markup.html.form.JsonEditorPanel; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.common.lib.AMSession; import org.apache.syncope.common.lib.SyncopeClientException; @@ -73,7 +73,7 @@ public AMSessionDirectoryPanel( final String deleteEntitlement, final PageReference pageRef) { - super(id, pageRef); + super(id, restClient, pageRef); this.listEntitlement = listEntitlement; this.deleteEntitlement = deleteEntitlement; @@ -92,7 +92,7 @@ protected void onConfigure() { } }; viewModal.size(Modal.Size.Extra_large); - viewModal.setWindowClosedCallback(target -> viewModal.show(false)); + setWindowClosedReloadCallback(viewModal); addOuterObject(viewModal); initResultTable(); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel.java index b8bd852c07d..5520b6b0368 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel.java @@ -19,56 +19,73 @@ package org.apache.syncope.client.console.panels; import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.audit.AuditHistoryModal; import org.apache.syncope.client.console.commons.AMConstants; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.SortableDataProviderComparator; +import org.apache.syncope.client.console.pages.BasePage; import org.apache.syncope.client.console.panels.AttrRepoDirectoryPanel.AttrRepoProvider; import org.apache.syncope.client.console.rest.AttrRepoRestClient; +import org.apache.syncope.client.console.rest.AuditRestClient; +import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.console.wizards.AttrRepoWizardBuilder; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; import org.apache.syncope.common.lib.to.AttrRepoTO; import org.apache.syncope.common.lib.types.AMEntitlement; +import org.apache.syncope.common.lib.types.AuditElements; +import org.apache.syncope.common.lib.types.IdRepoEntitlement; import org.apache.wicket.PageReference; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; import org.apache.wicket.event.Broadcast; import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; -import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class AttrRepoDirectoryPanel extends DirectoryPanel { private static final long serialVersionUID = 1005345990563741296L; - public AttrRepoDirectoryPanel(final String id, final PageReference pageRef) { - super(id, pageRef); + @SpringBean + protected AuditRestClient auditRestClient; + + protected final BaseModal historyModal; + + public AttrRepoDirectoryPanel(final String id, final AttrRepoRestClient restClient, final PageReference pageRef) { + super(id, restClient, pageRef); disableCheckBoxes(); - this.addNewItemPanelBuilder(new AttrRepoWizardBuilder(new AttrRepoTO(), pageRef), true); + this.addNewItemPanelBuilder(new AttrRepoWizardBuilder(new AttrRepoTO(), restClient, pageRef), true); MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, AMEntitlement.ATTR_REPO_CREATE); modal.size(Modal.Size.Extra_large); initResultTable(); + + historyModal = new BaseModal<>(Constants.OUTER); + historyModal.size(Modal.Size.Large); + addOuterObject(historyModal); } @Override @@ -126,10 +143,49 @@ public ActionsPanel getActions(final IModel model) { @Override public void onClick(final AjaxRequestTarget target, final AttrRepoTO ignore) { send(AttrRepoDirectoryPanel.this, Broadcast.EXACT, new AjaxWizard.EditItemActionEvent<>( - AttrRepoRestClient.read(model.getObject().getKey()), target)); + restClient.read(model.getObject().getKey()), target)); } }, ActionLink.ActionType.EDIT, AMEntitlement.ATTR_REPO_UPDATE); + panel.add(new ActionLink<>() { + + private static final long serialVersionUID = -5432034353017728756L; + + @Override + public void onClick(final AjaxRequestTarget target, final AttrRepoTO ignore) { + model.setObject(restClient.read(model.getObject().getKey())); + + target.add(historyModal.setContent(new AuditHistoryModal<>( + AuditElements.EventCategoryType.LOGIC, + "AttrRepoLogic", + model.getObject(), + AMEntitlement.ATTR_REPO_UPDATE, + auditRestClient) { + + private static final long serialVersionUID = -3712506022627033822L; + + @Override + protected void restore(final String json, final AjaxRequestTarget target) { + try { + AttrRepoTO updated = MAPPER.readValue(json, AttrRepoTO.class); + restClient.update(updated); + + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); + } catch (Exception e) { + LOG.error("While restoring AttrRepo {}", ((AttrRepoTO) model.getObject()).getKey(), e); + SyncopeConsoleSession.get().onException(e); + } + ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target); + } + })); + + historyModal.header(new Model<>(getString("auditHistory.title", new Model<>(model.getObject())))); + + historyModal.show(true); + } + }, ActionLink.ActionType.VIEW_AUDIT_HISTORY, String.format("%s,%s", AMEntitlement.ATTR_REPO_READ, + IdRepoEntitlement.AUDIT_LIST)); + panel.add(new ActionLink<>() { private static final long serialVersionUID = -3722207913631435501L; @@ -137,7 +193,7 @@ public void onClick(final AjaxRequestTarget target, final AttrRepoTO ignore) { @Override public void onClick(final AjaxRequestTarget target, final AttrRepoTO ignore) { try { - AttrRepoRestClient.delete(model.getObject().getKey()); + restClient.delete(model.getObject().getKey()); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); target.add(container); @@ -152,7 +208,7 @@ public void onClick(final AjaxRequestTarget target, final AttrRepoTO ignore) { return panel; } - protected static final class AttrRepoProvider extends DirectoryDataProvider { + protected final class AttrRepoProvider extends DirectoryDataProvider { private static final long serialVersionUID = -185944053385660794L; @@ -160,20 +216,19 @@ protected static final class AttrRepoProvider extends DirectoryDataProvider(this); } @Override public Iterator iterator(final long first, final long count) { - List result = AttrRepoRestClient.list(); - result.sort(comparator); - return result.subList((int) first, (int) first + (int) count).iterator(); + List attrRepos = restClient.list(); + attrRepos.sort(comparator); + return attrRepos.subList((int) first, (int) first + (int) count).iterator(); } @Override public long size() { - return AttrRepoRestClient.list().size(); + return restClient.list().size(); } @Override diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel.java index a196cbc3179..26569be550c 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel.java @@ -19,56 +19,77 @@ package org.apache.syncope.client.console.panels; import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.audit.AuditHistoryModal; import org.apache.syncope.client.console.commons.AMConstants; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.SortableDataProviderComparator; +import org.apache.syncope.client.console.pages.BasePage; import org.apache.syncope.client.console.panels.AuthModuleDirectoryPanel.AuthModuleProvider; +import org.apache.syncope.client.console.rest.AuditRestClient; import org.apache.syncope.client.console.rest.AuthModuleRestClient; +import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.console.wizards.AuthModuleWizardBuilder; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; import org.apache.syncope.common.lib.to.AuthModuleTO; import org.apache.syncope.common.lib.types.AMEntitlement; +import org.apache.syncope.common.lib.types.AuditElements; +import org.apache.syncope.common.lib.types.IdRepoEntitlement; import org.apache.wicket.PageReference; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; import org.apache.wicket.event.Broadcast; import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; -import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class AuthModuleDirectoryPanel extends DirectoryPanel { private static final long serialVersionUID = 1005345990563741296L; - public AuthModuleDirectoryPanel(final String id, final PageReference pageRef) { - super(id, pageRef); + @SpringBean + protected AuditRestClient auditRestClient; + + protected final BaseModal historyModal; + + public AuthModuleDirectoryPanel( + final String id, + final AuthModuleRestClient restClient, + final PageReference pageRef) { + + super(id, restClient, pageRef); disableCheckBoxes(); - this.addNewItemPanelBuilder(new AuthModuleWizardBuilder(new AuthModuleTO(), pageRef), true); + addNewItemPanelBuilder(new AuthModuleWizardBuilder(new AuthModuleTO(), restClient, pageRef), true); MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, AMEntitlement.AUTH_MODULE_CREATE); modal.size(Modal.Size.Extra_large); initResultTable(); + + historyModal = new BaseModal<>(Constants.OUTER); + historyModal.size(Modal.Size.Large); + addOuterObject(historyModal); } @Override @@ -126,10 +147,49 @@ public ActionsPanel getActions(final IModel model) { @Override public void onClick(final AjaxRequestTarget target, final AuthModuleTO ignore) { send(AuthModuleDirectoryPanel.this, Broadcast.EXACT, new AjaxWizard.EditItemActionEvent<>( - AuthModuleRestClient.read(model.getObject().getKey()), target)); + restClient.read(model.getObject().getKey()), target)); } }, ActionLink.ActionType.EDIT, AMEntitlement.AUTH_MODULE_UPDATE); + panel.add(new ActionLink<>() { + + private static final long serialVersionUID = -5432034353017728756L; + + @Override + public void onClick(final AjaxRequestTarget target, final AuthModuleTO ignore) { + model.setObject(restClient.read(model.getObject().getKey())); + + target.add(historyModal.setContent(new AuditHistoryModal<>( + AuditElements.EventCategoryType.LOGIC, + "AuthModuleLogic", + model.getObject(), + AMEntitlement.AUTH_MODULE_UPDATE, + auditRestClient) { + + private static final long serialVersionUID = -3712506022627033822L; + + @Override + protected void restore(final String json, final AjaxRequestTarget target) { + try { + AuthModuleTO updated = MAPPER.readValue(json, AuthModuleTO.class); + restClient.update(updated); + + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); + } catch (Exception e) { + LOG.error("While restoring AuthModule {}", model.getObject().getKey(), e); + SyncopeConsoleSession.get().onException(e); + } + ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target); + } + })); + + historyModal.header(new Model<>(getString("auditHistory.title", new Model<>(model.getObject())))); + + historyModal.show(true); + } + }, ActionLink.ActionType.VIEW_AUDIT_HISTORY, String.format("%s,%s", AMEntitlement.AUTH_MODULE_READ, + IdRepoEntitlement.AUDIT_LIST)); + panel.add(new ActionLink<>() { private static final long serialVersionUID = -3722207913631435501L; @@ -137,7 +197,7 @@ public void onClick(final AjaxRequestTarget target, final AuthModuleTO ignore) { @Override public void onClick(final AjaxRequestTarget target, final AuthModuleTO ignore) { try { - AuthModuleRestClient.delete(model.getObject().getKey()); + restClient.delete(model.getObject().getKey()); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); target.add(container); @@ -152,7 +212,7 @@ public void onClick(final AjaxRequestTarget target, final AuthModuleTO ignore) { return panel; } - protected static final class AuthModuleProvider extends DirectoryDataProvider { + protected final class AuthModuleProvider extends DirectoryDataProvider { private static final long serialVersionUID = -185944053385660794L; @@ -160,20 +220,19 @@ protected static final class AuthModuleProvider extends DirectoryDataProvider(this); } @Override public Iterator iterator(final long first, final long count) { - List result = AuthModuleRestClient.list(); - result.sort(comparator); - return result.subList((int) first, (int) first + (int) count).iterator(); + List authModules = restClient.list(); + authModules.sort(comparator); + return authModules.subList((int) first, (int) first + (int) count).iterator(); } @Override public long size() { - return AuthModuleRestClient.list().size(); + return restClient.list().size(); } @Override diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/OIDC.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/OIDC.java index e87a53f35bb..e439c263174 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/OIDC.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/OIDC.java @@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.rest.OIDCJWKSRestClient; +import org.apache.syncope.client.console.rest.WAConfigRestClient; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; import org.apache.syncope.client.console.wicket.markup.html.form.JsonEditorPanel; import org.apache.syncope.client.ui.commons.Constants; @@ -39,6 +40,7 @@ import org.apache.wicket.markup.html.link.ExternalLink; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.Model; +import org.apache.wicket.spring.injection.annot.SpringBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,9 +50,17 @@ public class OIDC extends Panel { private static final Logger LOG = LoggerFactory.getLogger(OIDC.class); - private static final JsonMapper MAPPER = JsonMapper.builder().findAndAddModules().build(); + protected static final JsonMapper MAPPER = JsonMapper.builder().findAndAddModules().build(); - private final BaseModal viewModal = new BaseModal<>("viewModal") { + @SpringBean + protected OIDCJWKSRestClient oidcJWKSRestClient; + + @SpringBean + protected WAConfigRestClient waConfigRestClient; + + protected final BaseModal generateModal = new BaseModal<>("generateModal"); + + protected final BaseModal viewModal = new BaseModal<>("viewModal") { private static final long serialVersionUID = 389935548143327858L; @@ -61,24 +71,24 @@ protected void onConfigure() { } }; - private final AjaxLink view; + protected final AjaxLink view; - private final AjaxLink generate; + protected final AjaxLink generate; - private final AjaxLink delete; + protected final AjaxLink delete; public OIDC(final String id, final String waPrefix, final PageReference pageRef) { super(id); setOutputMarkupId(true); - add(viewModal); - viewModal.size(Modal.Size.Extra_large); - viewModal.setWindowClosedCallback(target -> viewModal.show(false)); - WebMarkupContainer container = new WebMarkupContainer("container"); add(container.setOutputMarkupId(true)); - AtomicReference oidcjwksto = OIDCJWKSRestClient.get(); + AtomicReference oidcjwksto = oidcJWKSRestClient.get(); + + add(viewModal); + viewModal.size(Modal.Size.Extra_large); + viewModal.setWindowClosedCallback(target -> viewModal.show(false)); view = new AjaxLink<>("view") { @@ -119,18 +129,10 @@ protected void onComponentTag(final ComponentTag tag) { @Override public void onClick(final AjaxRequestTarget target) { - try { - oidcjwksto.set(OIDCJWKSRestClient.generate()); - generate.setEnabled(false); - view.setEnabled(true); - - SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); - target.add(container); - } catch (Exception e) { - LOG.error("While generating OIDC JWKS", e); - SyncopeConsoleSession.get().onException(e); - } - ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target); + generateModal.header(Model.of("Generate JSON Web Key Sets")); + target.add(generateModal.setContent(new OIDCJWKSGenerationPanel( + oidcJWKSRestClient, waConfigRestClient, generateModal, pageRef))); + generateModal.show(true); } @Override @@ -153,7 +155,7 @@ protected void onComponentTag(final ComponentTag tag) { @Override public void onClick(final AjaxRequestTarget target) { try { - OIDCJWKSRestClient.delete(); + oidcJWKSRestClient.delete(); oidcjwksto.set(null); generate.setEnabled(true); view.setEnabled(false); @@ -180,6 +182,17 @@ protected void onComponentTag(final ComponentTag tag) { container.add(delete.setOutputMarkupId(true)); MetaDataRoleAuthorizationStrategy.authorize(delete, ENABLE, AMEntitlement.OIDC_JWKS_DELETE); + generateModal.addSubmitButton(); + add(generateModal); + generateModal.setWindowClosedCallback(target -> { + oidcjwksto.set(oidcJWKSRestClient.get().get()); + view.setEnabled(oidcjwksto.get() != null); + delete.setEnabled(oidcjwksto.get() != null); + + target.add(container); + generateModal.show(false); + }); + String wellKnownURI = waPrefix + "/oidc/.well-known/openid-configuration"; container.add(new ExternalLink("wellKnownURI", wellKnownURI, wellKnownURI)); } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/OIDCJWKSGenerationPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/OIDCJWKSGenerationPanel.java new file mode 100644 index 00000000000..ae57f86be67 --- /dev/null +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/OIDCJWKSGenerationPanel.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.console.panels; + +import java.util.List; +import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.rest.OIDCJWKSRestClient; +import org.apache.syncope.client.console.rest.WAConfigRestClient; +import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxEventBehavior; +import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; +import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxNumberFieldPanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; +import org.apache.syncope.client.ui.commons.pages.BaseWebPage; +import org.apache.syncope.common.lib.SyncopeClientException; +import org.apache.syncope.common.lib.to.OIDCJWKSTO; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.model.Model; + +public class OIDCJWKSGenerationPanel extends AbstractModalPanel { + + private static final long serialVersionUID = -3372006007594607067L; + + protected final OIDCJWKSRestClient oidcJWKSRestClient; + + protected final Model jwksKeyIdM; + + protected final Model jwksTypeM; + + protected final Model jwksKeySizeM; + + public OIDCJWKSGenerationPanel( + final OIDCJWKSRestClient oidcJWKSRestClient, + final WAConfigRestClient waConfigRestClient, + final BaseModal modal, + final PageReference pageRef) { + + super(modal, pageRef); + this.oidcJWKSRestClient = oidcJWKSRestClient; + + jwksKeyIdM = Model.of("syncope"); + try { + jwksKeyIdM.setObject(waConfigRestClient.get("cas.authn.oidc.jwks.core.jwks-key-id").getValues().get(0)); + } catch (SyncopeClientException e) { + LOG.error("While reading cas.authn.oidc.jwks.core.jwks-key-id", e); + } + add(new AjaxTextFieldPanel("jwksKeyId", "jwksKeyId", jwksKeyIdM).setRequired(true)); + + jwksTypeM = Model.of("rsa"); + try { + jwksTypeM.setObject(waConfigRestClient.get("cas.authn.oidc.jwks.core.jwks-type").getValues().get(0)); + } catch (SyncopeClientException e) { + LOG.error("While reading cas.authn.oidc.jwks.core.jwks-type", e); + } + AjaxDropDownChoicePanel jwksType = new AjaxDropDownChoicePanel<>("jwksType", "jwksType", jwksTypeM). + setChoices(List.of("rsa", "ec")); + add(jwksType.setRequired(true)); + + jwksKeySizeM = Model.of(2048); + try { + jwksKeySizeM.setObject(Integer.valueOf( + waConfigRestClient.get("cas.authn.oidc.jwks.core.jwks-key-size").getValues().get(0))); + } catch (SyncopeClientException e) { + LOG.error("While reading cas.authn.oidc.jwks.core.jwks-key-size", e); + } + AjaxNumberFieldPanel jwksKeySize = new AjaxNumberFieldPanel.Builder().step(128). + build("jwksKeySize", "jwksKeySize", Integer.class, jwksKeySizeM); + add(jwksKeySize.setRequired(true)); + + jwksType.add(new IndicatorAjaxEventBehavior(Constants.ON_CHANGE) { + + private static final long serialVersionUID = -4255753643957306394L; + + @Override + protected void onEvent(final AjaxRequestTarget target) { + if ("ec".equals(jwksTypeM.getObject())) { + jwksKeySizeM.setObject(256); + } else { + jwksKeySizeM.setObject(2048); + } + target.add(jwksKeySize); + } + }); + } + + @Override + public void onSubmit(final AjaxRequestTarget target) { + try { + oidcJWKSRestClient.generate(jwksKeyIdM.getObject(), jwksTypeM.getObject(), jwksKeySizeM.getObject()); + + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); + modal.close(target); + } catch (Exception e) { + LOG.error("While generating OIDC JWKS", e); + SyncopeConsoleSession.get().onException(e); + } + ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target); + } +} diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2.java index 1082d5e96c1..04fa7d2c50a 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2.java @@ -22,6 +22,8 @@ import java.util.ArrayList; import java.util.List; import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.rest.SAML2IdPEntityRestClient; +import org.apache.syncope.client.console.rest.SAML2SPEntityRestClient; import org.apache.syncope.common.lib.SyncopeConstants; import org.apache.syncope.common.lib.types.AMEntitlement; import org.apache.wicket.PageReference; @@ -29,10 +31,17 @@ import org.apache.wicket.extensions.markup.html.tabs.ITab; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.Model; +import org.apache.wicket.spring.injection.annot.SpringBean; public class SAML2 extends Panel { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 7093557205333650002L; + + @SpringBean + protected SAML2IdPEntityRestClient saml2IdPEntityRestClient; + + @SpringBean + protected SAML2SPEntityRestClient saml2SPEntityRestClient; public SAML2(final String id, final String waPrefix, final PageReference pageRef) { super(id); @@ -40,7 +49,7 @@ public SAML2(final String id, final String waPrefix, final PageReference pageRef add(new AjaxBootstrapTabbedPanel<>("saml2", buildTabList(waPrefix, pageRef))); } - private List buildTabList(final String waPrefix, final PageReference pageRef) { + protected List buildTabList(final String waPrefix, final PageReference pageRef) { List tabs = new ArrayList<>(); if (SyncopeConsoleSession.get().owns(AMEntitlement.SAML2_IDP_ENTITY_LIST, SyncopeConstants.ROOT_REALM)) { @@ -50,7 +59,7 @@ private List buildTabList(final String waPrefix, final PageReference pageR @Override public Panel getPanel(final String panelId) { - return new SAML2IdPEntityDirectoryPanel(panelId, waPrefix, pageRef); + return new SAML2IdPEntityDirectoryPanel(panelId, saml2IdPEntityRestClient, waPrefix, pageRef); } }); } @@ -62,7 +71,7 @@ public Panel getPanel(final String panelId) { @Override public Panel getPanel(final String panelId) { - return new SAML2SPEntityDirectoryPanel(panelId, waPrefix, pageRef); + return new SAML2SPEntityDirectoryPanel(panelId, saml2SPEntityRestClient, waPrefix, pageRef); } }); } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2IdPEntityDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2IdPEntityDirectoryPanel.java index 9523053a71a..52244a75a23 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2IdPEntityDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2IdPEntityDirectoryPanel.java @@ -24,6 +24,7 @@ import java.util.Iterator; import java.util.List; import org.apache.syncope.client.console.commons.AMConstants; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.SortableDataProviderComparator; import org.apache.syncope.client.console.panels.SAML2IdPEntityDirectoryPanel.SAML2IdPEntityProvider; import org.apache.syncope.client.console.rest.SAML2IdPEntityRestClient; @@ -31,7 +32,6 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.console.wizards.SAML2IdPEntityWizardBuilder; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; import org.apache.syncope.common.lib.to.SAML2IdPEntityTO; import org.apache.syncope.common.lib.types.AMEntitlement; @@ -39,7 +39,6 @@ import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.event.Broadcast; import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; -import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; @@ -54,25 +53,26 @@ public class SAML2IdPEntityDirectoryPanel extends DirectoryPanel< SAML2IdPEntityTO, SAML2IdPEntityTO, SAML2IdPEntityProvider, SAML2IdPEntityRestClient> { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = -6535332920023200166L; private final String metadataURL; - public SAML2IdPEntityDirectoryPanel(final String id, final String waPrefix, final PageReference pageRef) { - super(id, pageRef); + public SAML2IdPEntityDirectoryPanel( + final String id, + final SAML2IdPEntityRestClient restClient, + final String waPrefix, + final PageReference pageRef) { + + super(id, restClient, pageRef); this.metadataURL = waPrefix + "/idp/metadata"; disableCheckBoxes(); modal.size(Modal.Size.Large); modal.addSubmitButton(); + setWindowClosedReloadCallback(modal, true); - modal.setWindowClosedCallback(target -> { - updateResultTable(target); - modal.show(false); - }); - - addNewItemPanelBuilder(new SAML2IdPEntityWizardBuilder(new SAML2IdPEntityTO(), pageRef), false); + addNewItemPanelBuilder(new SAML2IdPEntityWizardBuilder(new SAML2IdPEntityTO(), restClient, pageRef), false); initResultTable(); } @@ -86,16 +86,20 @@ protected List> getColumns() { Constants.KEY_FIELD_NAME, Constants.KEY_FIELD_NAME)); columns.add(new AbstractColumn<>(Model.of("URL")) { + private static final long serialVersionUID = -7226955670801277153L; + @Override public void populateItem( - final Item> cellItem, - final String componentId, - final IModel rowModel) { + final Item> cellItem, + final String componentId, + final IModel rowModel) { cellItem.add(new ExternalLink( - componentId, - Model.of(metadataURL), - Model.of(metadataURL)) { + componentId, + Model.of(metadataURL), + Model.of(metadataURL)) { + + private static final long serialVersionUID = -1919646533527005367L; @Override protected void onComponentTag(final ComponentTag tag) { @@ -125,8 +129,8 @@ protected ActionsPanel getActions(final IModel( - SAML2IdPEntityRestClient.get(model.getObject().getKey()), target)); + new AjaxWizard.EditItemActionEvent<>( + restClient.get(model.getObject().getKey()), target)); } }, ActionLink.ActionType.EDIT, AMEntitlement.SAML2_IDP_ENTITY_SET); @@ -148,7 +152,7 @@ protected String paginatorRowsKey() { return AMConstants.PREF_SAML2_IDP_ENTITY_PAGINATOR_ROWS; } - protected static final class SAML2IdPEntityProvider extends DirectoryDataProvider { + protected final class SAML2IdPEntityProvider extends DirectoryDataProvider { private static final long serialVersionUID = 5282134321828253058L; @@ -156,20 +160,19 @@ protected static final class SAML2IdPEntityProvider extends DirectoryDataProvide public SAML2IdPEntityProvider(final int paginatorRows) { super(paginatorRows); - setSort(Constants.KEY_FIELD_NAME, SortOrder.ASCENDING); comparator = new SortableDataProviderComparator<>(this); } @Override public Iterator iterator(final long first, final long count) { - List list = SAML2IdPEntityRestClient.list(); - list.sort(comparator); - return list.subList((int) first, (int) first + (int) count).iterator(); + List idps = restClient.list(); + idps.sort(comparator); + return idps.subList((int) first, (int) first + (int) count).iterator(); } @Override public long size() { - return SAML2IdPEntityRestClient.list().size(); + return restClient.list().size(); } @Override diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel.java index ad2ffee7d95..10f99409127 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SAML2SPEntityDirectoryPanel.java @@ -25,6 +25,7 @@ import java.util.List; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.commons.AMConstants; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.SortableDataProviderComparator; import org.apache.syncope.client.console.panels.SAML2SPEntityDirectoryPanel.SAML2SPEntityProvider; import org.apache.syncope.client.console.rest.SAML2SPEntityRestClient; @@ -32,7 +33,6 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.console.wizards.SAML2SPEntityWizardBuilder; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; import org.apache.syncope.common.lib.to.SAML2SPEntityTO; @@ -42,7 +42,6 @@ import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; import org.apache.wicket.event.Broadcast; import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; -import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; @@ -57,12 +56,17 @@ public class SAML2SPEntityDirectoryPanel extends DirectoryPanel< SAML2SPEntityTO, SAML2SPEntityTO, SAML2SPEntityProvider, SAML2SPEntityRestClient> { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = -3890622383545171017L; private final String waPrefix; - public SAML2SPEntityDirectoryPanel(final String id, final String waPrefix, final PageReference pageRef) { - super(id, pageRef); + public SAML2SPEntityDirectoryPanel( + final String id, + final SAML2SPEntityRestClient restClient, + final String waPrefix, + final PageReference pageRef) { + + super(id, restClient, pageRef); this.waPrefix = waPrefix; disableCheckBoxes(); @@ -75,7 +79,7 @@ public SAML2SPEntityDirectoryPanel(final String id, final String waPrefix, final modal.show(false); }); - addNewItemPanelBuilder(new SAML2SPEntityWizardBuilder(new SAML2SPEntityTO(), pageRef), true); + addNewItemPanelBuilder(new SAML2SPEntityWizardBuilder(new SAML2SPEntityTO(), restClient, pageRef), true); MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, AMEntitlement.SAML2_SP_ENTITY_SET); @@ -92,17 +96,21 @@ protected List> getColumns() { columns.add(new AbstractColumn<>(Model.of("URL")) { + private static final long serialVersionUID = -7226955670801277153L; + @Override public void populateItem( - final Item> cellItem, - final String componentId, - final IModel rowModel) { + final Item> cellItem, + final String componentId, + final IModel rowModel) { String metadataURL = waPrefix + "/sp/" + rowModel.getObject().getKey() + "/metadata"; cellItem.add(new ExternalLink( - componentId, - Model.of(metadataURL), - Model.of(metadataURL)) { + componentId, + Model.of(metadataURL), + Model.of(metadataURL)) { + + private static final long serialVersionUID = -1919646533527005367L; @Override protected void onComponentTag(final ComponentTag tag) { @@ -132,8 +140,8 @@ protected ActionsPanel getActions(final IModel @Override public void onClick(final AjaxRequestTarget target, final SAML2SPEntityTO ignore) { send(SAML2SPEntityDirectoryPanel.this, Broadcast.EXACT, - new AjaxWizard.EditItemActionEvent<>( - SAML2SPEntityRestClient.get(model.getObject().getKey()), target)); + new AjaxWizard.EditItemActionEvent<>( + restClient.get(model.getObject().getKey()), target)); } }, ActionLink.ActionType.EDIT, AMEntitlement.SAML2_SP_ENTITY_SET); @@ -144,7 +152,7 @@ public void onClick(final AjaxRequestTarget target, final SAML2SPEntityTO ignore @Override public void onClick(final AjaxRequestTarget target, final SAML2SPEntityTO ignore) { try { - SAML2SPEntityRestClient.delete(model.getObject().getKey()); + restClient.delete(model.getObject().getKey()); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); target.add(container); @@ -174,7 +182,7 @@ protected String paginatorRowsKey() { return AMConstants.PREF_SAML2_SP_ENTITY_PAGINATOR_ROWS; } - protected static final class SAML2SPEntityProvider extends DirectoryDataProvider { + protected final class SAML2SPEntityProvider extends DirectoryDataProvider { private static final long serialVersionUID = 5282134321828253058L; @@ -182,20 +190,19 @@ protected static final class SAML2SPEntityProvider extends DirectoryDataProvider public SAML2SPEntityProvider(final int paginatorRows) { super(paginatorRows); - setSort(Constants.KEY_FIELD_NAME, SortOrder.ASCENDING); comparator = new SortableDataProviderComparator<>(this); } @Override public Iterator iterator(final long first, final long count) { - List list = SAML2SPEntityRestClient.list(); - list.sort(comparator); - return list.subList((int) first, (int) first + (int) count).iterator(); + List sps = restClient.list(); + sps.sort(comparator); + return sps.subList((int) first, (int) first + (int) count).iterator(); } @Override public long size() { - return SAML2SPEntityRestClient.list().size(); + return restClient.list().size(); } @Override diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRARouteDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRARouteDirectoryPanel.java index b8f73fcf6f5..280026d2e8f 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRARouteDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRARouteDirectoryPanel.java @@ -26,6 +26,7 @@ import org.apache.commons.lang3.SerializationUtils; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.commons.AMConstants; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.SortableDataProviderComparator; import org.apache.syncope.client.console.panels.SRARouteDirectoryPanel.SRARouteProvider; import org.apache.syncope.client.console.rest.SRARouteRestClient; @@ -34,7 +35,6 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; import org.apache.syncope.common.lib.SyncopeClientException; @@ -55,19 +55,16 @@ public class SRARouteDirectoryPanel private static final long serialVersionUID = -2334397933375604015L; - public SRARouteDirectoryPanel(final String id, final PageReference pageRef) { - super(id, pageRef); + public SRARouteDirectoryPanel(final String id, final SRARouteRestClient restClient, final PageReference pageRef) { + super(id, restClient, pageRef); disableCheckBoxes(); modal.size(Modal.Size.Large); modal.addSubmitButton(); + setWindowClosedReloadCallback(modal, true); - modal.setWindowClosedCallback(target -> { - updateResultTable(target); - modal.show(false); - }); + addNewItemPanelBuilder(new SRARouteWizardBuilder(new SRARouteTO(), restClient, pageRef), true); - addNewItemPanelBuilder(new SRARouteWizardBuilder(new SRARouteTO(), pageRef), true); initResultTable(); } @@ -100,8 +97,8 @@ protected ActionsPanel getActions(final IModel model) { @Override public void onClick(final AjaxRequestTarget target, final SRARouteTO ignore) { send(SRARouteDirectoryPanel.this, Broadcast.EXACT, - new AjaxWizard.EditItemActionEvent<>( - SRARouteRestClient.read(model.getObject().getKey()), target)); + new AjaxWizard.EditItemActionEvent<>( + restClient.read(model.getObject().getKey()), target)); } }, ActionLink.ActionType.EDIT, AMEntitlement.SRA_ROUTE_UPDATE); @@ -114,7 +111,7 @@ public void onClick(final AjaxRequestTarget target, final SRARouteTO ignore) { SRARouteTO clone = SerializationUtils.clone(model.getObject()); clone.setKey(null); send(SRARouteDirectoryPanel.this, Broadcast.EXACT, - new AjaxWizard.EditItemActionEvent<>(clone, target)); + new AjaxWizard.EditItemActionEvent<>(clone, target)); } }, ActionLink.ActionType.CLONE, AMEntitlement.SRA_ROUTE_CREATE); @@ -126,7 +123,8 @@ public void onClick(final AjaxRequestTarget target, final SRARouteTO ignore) { public void onClick(final AjaxRequestTarget target, final SRARouteTO ignore) { SRARouteTO route = model.getObject(); try { - SRARouteRestClient.delete(route.getKey()); + restClient.delete(route.getKey()); + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); target.add(container); } catch (SyncopeClientException e) { @@ -155,7 +153,7 @@ protected String paginatorRowsKey() { return AMConstants.PREF_GATEWAYROUTE_PAGINATOR_ROWS; } - protected static final class SRARouteProvider extends DirectoryDataProvider { + protected final class SRARouteProvider extends DirectoryDataProvider { private static final long serialVersionUID = 5282134321828253058L; @@ -169,14 +167,14 @@ public SRARouteProvider(final int paginatorRows) { @Override public Iterator iterator(final long first, final long count) { - List list = SRARouteRestClient.list(); + List list = restClient.list(); list.sort(comparator); return list.subList((int) first, (int) first + (int) count).iterator(); } @Override public long size() { - return SRARouteRestClient.list().size(); + return restClient.list().size(); } @Override diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRARouteWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRARouteWizardBuilder.java index 66bba51a52d..1505753740f 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRARouteWizardBuilder.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRARouteWizardBuilder.java @@ -27,7 +27,7 @@ import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; -import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxNumberFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; import org.apache.syncope.common.lib.to.SRARouteTO; import org.apache.syncope.common.lib.types.SRARouteType; @@ -45,16 +45,23 @@ public class SRARouteWizardBuilder extends BaseAjaxWizardBuilder { private static final long serialVersionUID = 2060352959114706419L; - public SRARouteWizardBuilder(final SRARouteTO route, final PageReference pageRef) { + protected final SRARouteRestClient sraRouteRestClient; + + public SRARouteWizardBuilder( + final SRARouteTO route, + final SRARouteRestClient sraRouteRestClient, + final PageReference pageRef) { + super(route, pageRef); + this.sraRouteRestClient = sraRouteRestClient; } @Override protected Serializable onApplyInternal(final SRARouteTO modelObject) { if (modelObject.getKey() == null) { - SRARouteRestClient.create(modelObject); + sraRouteRestClient.create(modelObject); } else { - SRARouteRestClient.update(modelObject); + sraRouteRestClient.update(modelObject); } return modelObject; } @@ -147,7 +154,7 @@ public void setObject(final String object) { add(new AjaxCheckBoxPanel("csrf", "csrf", new PropertyModel<>(route, "csrf"))); - add(new AjaxSpinnerFieldPanel.Builder().min(0).build( + add(new AjaxNumberFieldPanel.Builder().min(0).build( "order", "order", Integer.class, new PropertyModel<>(route, "order")). setRequired(true)); } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRAStatisticsPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRAStatisticsPanel.java index 5709553adb3..c4a0a5a63ff 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRAStatisticsPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/SRAStatisticsPanel.java @@ -40,38 +40,46 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; +import org.apache.wicket.spring.injection.annot.SpringBean; public class SRAStatisticsPanel extends Panel { private static final long serialVersionUID = 23816535591360L; - private static final List TYPES = List.of( + protected static final List TYPES = List.of( Buttons.Type.Info, Buttons.Type.Success, Buttons.Type.Warning, Buttons.Type.Danger, Buttons.Type.Dark); - private final NumberWidget count; + @SpringBean + protected SRARouteRestClient sraRouteRestClient; - private final NumberWidget totalTime; + @SpringBean + protected SRAStatisticsRestClient sraStatisticsRestClient; - private final NumberWidget max; + protected final NumberWidget count; - private final List> selected = new ArrayList<>(); + protected final NumberWidget totalTime; - private final LoadableDetachableModel> routes = - new LoadableDetachableModel<>() { + protected final NumberWidget max; - @Override - protected Map load() { - return SRARouteRestClient.list().stream(). + protected final List> selected = new ArrayList<>(); + + protected final LoadableDetachableModel> routes = new LoadableDetachableModel<>() { + + private static final long serialVersionUID = 9089911876466472133L; + + @Override + protected Map load() { + return sraRouteRestClient.list().stream(). collect(Collectors.toMap(SRARouteTO::getKey, SRARouteTO::getName)); - } - }; + } + }; - private int current; + protected int current; public SRAStatisticsPanel(final String id, final List instances) { super(id); - SRAStatistics stats = SRAStatisticsRestClient.get(instances, selected); + SRAStatistics stats = sraStatisticsRestClient.get(instances, selected); count = new NumberWidget("count", "bg-green", stats.getMeasurement("COUNT").orElse(0F), "count", "fas fa-pen-nib"); @@ -87,27 +95,33 @@ public SRAStatisticsPanel(final String id, final List instances) ListView availableTags = new ListView<>("availableTags", stats.getAvailableTags()) { + private static final long serialVersionUID = -9112553137618363167L; + @Override protected void populateItem(final ListItem tag) { String btnCss = next().cssClassName(); tag.add(new Label("label", tag.getModelObject().getTag())); tag.add(new ListView<>("tag", tag.getModelObject().getValues()) { + private static final long serialVersionUID = -9112553137618363167L; + @Override protected void populateItem(final ListItem value) { AjaxLink valueLink = new AjaxLink<>("valueLink") { + private static final long serialVersionUID = 6250423506463465679L; + @Override public void onClick(final AjaxRequestTarget target) { Pair selection = - Pair.of(tag.getModelObject().getTag(), value.getModelObject()); + Pair.of(tag.getModelObject().getTag(), value.getModelObject()); if (selected.contains(selection)) { selected.remove(selection); } else { selected.add(selection); } - SRAStatistics refresh = SRAStatisticsRestClient.get(instances, selected); + SRAStatistics refresh = sraStatisticsRestClient.get(instances, selected); count.refresh(refresh.getMeasurement("COUNT").orElse(0F)); totalTime.refresh(refresh.getMeasurement("TOTAL_TIME").orElse(0F)); @@ -126,8 +140,8 @@ protected void onComponentTag(final ComponentTag tag) { }; IModel valueLabel = routes.getObject().containsKey(value.getModelObject()) - ? Model.of(routes.getObject().get(value.getModelObject())) - : value.getModel(); + ? Model.of(routes.getObject().get(value.getModelObject())) + : value.getModel(); valueLink.add(new Label("valueLabel", valueLabel)); value.add(valueLink); } @@ -137,7 +151,7 @@ protected void onComponentTag(final ComponentTag tag) { add(availableTags); } - private Buttons.Type next() { + protected Buttons.Type next() { if (current < TYPES.size()) { Buttons.Type type = TYPES.get(current); current++; diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WAConfigDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WAConfigDirectoryPanel.java index 9dfc8d7f724..bd008fdf79a 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WAConfigDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WAConfigDirectoryPanel.java @@ -40,8 +40,8 @@ public class WAConfigDirectoryPanel extends AttrListDirectoryPanel { private static final long serialVersionUID = 1538796157345L; - public WAConfigDirectoryPanel(final String id, final PageReference pageRef) { - super(id, pageRef, true); + public WAConfigDirectoryPanel(final String id, final WAConfigRestClient restClient, final PageReference pageRef) { + super(id, restClient, pageRef, true); this.addNewItemPanelBuilder(new AbstractModalPanelBuilder(new Attr(), pageRef) { @@ -78,7 +78,11 @@ public ActionsPanel getActions(final IModel model) { public void onClick(final AjaxRequestTarget target, final Attr ignore) { target.add(modal); modal.header(new StringResourceModel("any.edit")); - modal.setContent(new WAConfigModalPanel(modal, model.getObject(), AjaxWizard.Mode.EDIT, pageRef)); + modal.setContent(new WAConfigModalPanel( + modal, + ((WAConfigRestClient) restClient).get(model.getObject().getSchema()), + AjaxWizard.Mode.EDIT, + pageRef)); modal.show(true); } }, ActionLink.ActionType.EDIT, AMEntitlement.WA_CONFIG_SET); @@ -90,7 +94,7 @@ public void onClick(final AjaxRequestTarget target, final Attr ignore) { @Override public void onClick(final AjaxRequestTarget target, final Attr ignore) { try { - WAConfigRestClient.delete(model.getObject().getSchema()); + ((WAConfigRestClient) restClient).delete(model.getObject().getSchema()); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); target.add(container); @@ -105,7 +109,7 @@ public void onClick(final AjaxRequestTarget target, final Attr ignore) { return panel; } - protected static final class WAConfigProvider extends AttrListProvider { + protected final class WAConfigProvider extends AttrListProvider { private static final long serialVersionUID = -185944053385660794L; @@ -115,7 +119,7 @@ private WAConfigProvider(final int paginatorRows) { @Override protected List list() { - return WAConfigRestClient.list(); + return ((WAConfigRestClient) restClient).list(); } } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WAConfigModalPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WAConfigModalPanel.java index e95f3c9295b..a8f74609972 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WAConfigModalPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WAConfigModalPanel.java @@ -28,26 +28,30 @@ import org.apache.syncope.common.lib.types.AttrSchemaType; import org.apache.wicket.PageReference; import org.apache.wicket.extensions.wizard.WizardModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class WAConfigModalPanel extends AbstractModalPanel { private static final long serialVersionUID = 1690738212977L; - private static ConfParam toConfParam(final Attr attr) { + protected static ConfParam toConfParam(final Attr attr) { ConfParam param = new ConfParam(); param.setSchema(attr.getSchema()); param.getValues().addAll(attr.getValues()); return param; } - private static Attr toAttr(final ConfParam confParam) { + protected static Attr toAttr(final ConfParam confParam) { Attr attr = new Attr.Builder(confParam.getSchema()).build(); attr.getValues().addAll( confParam.getValues().stream().map(Serializable::toString).collect(Collectors.toList())); return attr; } - private final ParametersWizardPanel.ParametersForm form; + @SpringBean + protected WAConfigRestClient waConfigRestClient; + + protected final ParametersWizardPanel.ParametersForm form; public WAConfigModalPanel( final BaseModal modal, @@ -66,6 +70,8 @@ public WAConfigModalPanel( add(new ParametersWizardPanel(form, null, pageRef) { + private static final long serialVersionUID = -1469319240177117600L; + @Override protected WizardModel buildModelSteps(final ParametersForm modelObject, final WizardModel wizardModel) { wizardModel.add(new ParametersWizardAttrStep(mode, modelObject)); @@ -76,7 +82,7 @@ protected WizardModel buildModelSteps(final ParametersForm modelObject, final Wi protected Serializable onApplyInternal(final ParametersWizardPanel.ParametersForm modelObject) { modelObject.getParam().setMultivalue(modelObject.getSchema().isMultivalue()); try { - WAConfigRestClient.set(toAttr(modelObject.getParam())); + waConfigRestClient.set(toAttr(modelObject.getParam())); } catch (Exception e) { LOG.error("While setting {}", modelObject.getParam(), e); throw e; diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WAPushModalPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WAPushModalPanel.java new file mode 100644 index 00000000000..841a0c298d1 --- /dev/null +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/WAPushModalPanel.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.console.panels; + +import java.io.Serializable; +import java.util.List; +import java.util.stream.Collectors; +import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.pages.BasePage; +import org.apache.syncope.client.console.rest.WAConfigRestClient; +import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; +import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel; +import org.apache.syncope.common.keymaster.client.api.model.NetworkService; +import org.apache.syncope.common.rest.api.service.wa.WAConfigService; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.util.ListModel; +import org.apache.wicket.spring.injection.annot.SpringBean; + +public class WAPushModalPanel extends AbstractModalPanel { + + private static final long serialVersionUID = -8589310598889871801L; + + @SpringBean + protected WAConfigRestClient waConfigRestClient; + + protected final Model subjectModel = new Model<>(WAConfigService.PushSubject.conf); + + protected final ListModel servicesModel = new ListModel<>(); + + public WAPushModalPanel( + final BaseModal modal, + final List instances, + final PageReference pageRef) { + + super(modal, pageRef); + + List addresses = instances.stream(). + map(NetworkService::getAddress).distinct().sorted().collect(Collectors.toList()); + servicesModel.setObject(addresses); + + add(new AjaxPalettePanel.Builder().setName("services").setAllowMoveAll(true).build( + "services", + servicesModel, + new ListModel<>(addresses)).addRequiredLabel()); + + add(new AjaxDropDownChoicePanel<>( + "subject", getString("subject"), subjectModel). + setChoices(List.of(WAConfigService.PushSubject.values())). + setChoiceRenderer(s -> getString(s.name(), Model.of(), s.name())).setNullValid(false)); + } + + @Override + public void onSubmit(final AjaxRequestTarget target) { + try { + waConfigRestClient.push(subjectModel.getObject(), servicesModel.getObject()); + + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); + this.modal.close(target); + } catch (Exception e) { + LOG.error("While pushing to WA", e); + SyncopeConsoleSession.get().onException(e); + } + ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target); + } +} diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AccessPolicyAttrsDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AccessPolicyAttrsDirectoryPanel.java deleted file mode 100644 index e7c1c0720af..00000000000 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AccessPolicyAttrsDirectoryPanel.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.syncope.client.console.policies; - -import java.util.List; -import org.apache.syncope.client.console.SyncopeConsoleSession; -import org.apache.syncope.client.console.commons.AMConstants; -import org.apache.syncope.client.console.panels.AttrListDirectoryPanel; -import org.apache.syncope.client.console.rest.PolicyRestClient; -import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; -import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; -import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; -import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.pages.BaseWebPage; -import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; -import org.apache.syncope.common.lib.Attr; -import org.apache.syncope.common.lib.SyncopeClientException; -import org.apache.syncope.common.lib.policy.AccessPolicyConf; -import org.apache.syncope.common.lib.policy.AccessPolicyTO; -import org.apache.syncope.common.lib.types.IdRepoEntitlement; -import org.apache.syncope.common.lib.types.PolicyType; -import org.apache.wicket.PageReference; -import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.event.IEvent; -import org.apache.wicket.model.IModel; -import org.danekja.java.util.function.serializable.SerializableFunction; - -public class AccessPolicyAttrsDirectoryPanel extends AttrListDirectoryPanel { - - private static final long serialVersionUID = 33604877627114L; - - private final BaseModal wizardModal; - - private final IModel accessPolicyModel; - - private final SerializableFunction> attrsAccessor; - - public AccessPolicyAttrsDirectoryPanel( - final String id, - final BaseModal wizardModal, - final IModel model, - final SerializableFunction> attrsAccessor, - final PageReference pageRef) { - - super(id, pageRef, false); - - this.wizardModal = wizardModal; - this.accessPolicyModel = model; - this.attrsAccessor = attrsAccessor; - - setOutputMarkupId(true); - - enableUtilityButton(); - setFooterVisibility(false); - - addNewItemPanelBuilder( - new AccessPolicyAttrsWizardBuilder(model.getObject(), attrsAccessor, new Attr(), pageRef), true); - - initResultTable(); - } - - @Override - protected ActionsPanel getActions(final IModel model) { - ActionsPanel panel = super.getActions(model); - - panel.add(new ActionLink<>() { - - private static final long serialVersionUID = -3722207913631435501L; - - @Override - public void onClick(final AjaxRequestTarget target, final Attr ignore) { - try { - attrsAccessor.apply(accessPolicyModel.getObject().getConf()).remove(model.getObject()); - PolicyRestClient.update(PolicyType.ACCESS, accessPolicyModel.getObject()); - - SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); - target.add(container); - } catch (SyncopeClientException e) { - LOG.error("While updating {}", accessPolicyModel.getObject().getKey(), e); - SyncopeConsoleSession.get().onException(e); - } - ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target); - } - }, ActionLink.ActionType.DELETE, IdRepoEntitlement.POLICY_UPDATE, true); - - return panel; - } - - @Override - public void onEvent(final IEvent event) { - if (event.getPayload() instanceof ExitEvent) { - AjaxRequestTarget target = ExitEvent.class.cast(event.getPayload()).getTarget(); - wizardModal.close(target); - } else if (event.getPayload() instanceof AjaxWizard.EditItemActionEvent) { - @SuppressWarnings("unchecked") - AjaxWizard.EditItemActionEvent payload = (AjaxWizard.EditItemActionEvent) event.getPayload(); - payload.getTarget().ifPresent(actionTogglePanel::close); - } - super.onEvent(event); - } - - @Override - protected AttrListProvider dataProvider() { - return new AccessPolicyAttrsProvider(rows); - } - - @Override - protected String paginatorRowsKey() { - return AMConstants.PREF_ACCESS_POLICY_CONF_ATTRS_PAGINATOR_ROWS; - } - - protected final class AccessPolicyAttrsProvider extends AttrListProvider { - - private static final long serialVersionUID = -185944053385660794L; - - private AccessPolicyAttrsProvider(final int paginatorRows) { - super(paginatorRows); - } - - @Override - protected List list() { - return attrsAccessor.apply(accessPolicyModel.getObject().getConf()); - } - } -} diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AccessPolicyAttrsWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AccessPolicyAttrsWizardBuilder.java deleted file mode 100644 index a371e0328c2..00000000000 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AccessPolicyAttrsWizardBuilder.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.syncope.client.console.policies; - -import java.io.Serializable; -import java.util.List; -import org.apache.syncope.client.console.rest.PolicyRestClient; -import org.apache.syncope.client.console.wizards.AttrWizardBuilder; -import org.apache.syncope.common.lib.Attr; -import org.apache.syncope.common.lib.policy.AccessPolicyConf; -import org.apache.syncope.common.lib.policy.AccessPolicyTO; -import org.apache.syncope.common.lib.types.PolicyType; -import org.apache.wicket.PageReference; -import org.danekja.java.util.function.serializable.SerializableFunction; - -public class AccessPolicyAttrsWizardBuilder extends AttrWizardBuilder { - - private static final long serialVersionUID = 33625775269155L; - - private final AccessPolicyTO accessPolicy; - - private final SerializableFunction> attrsAccessor; - - public AccessPolicyAttrsWizardBuilder( - final AccessPolicyTO accessPolicy, - final SerializableFunction> attrsAccessor, - final Attr attr, - final PageReference pageRef) { - - super(attr, pageRef); - this.accessPolicy = accessPolicy; - this.attrsAccessor = attrsAccessor; - } - - @Override - protected Serializable onApplyInternal(final Attr modelObject) { - attrsAccessor.apply(accessPolicy.getConf()).removeIf(p -> modelObject.getSchema().equals(p.getSchema())); - attrsAccessor.apply(accessPolicy.getConf()).add(modelObject); - - PolicyRestClient.update(PolicyType.ACCESS, accessPolicy); - - return null; - } -} diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AccessPolicyDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AccessPolicyDirectoryPanel.java index 86fe8f41474..7743cf3c8b6 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AccessPolicyDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AccessPolicyDirectoryPanel.java @@ -19,12 +19,9 @@ package org.apache.syncope.client.console.policies; import java.util.List; -import org.apache.syncope.client.console.panels.ModalDirectoryPanel; import org.apache.syncope.client.console.rest.PolicyRestClient; -import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.BooleanPropertyColumn; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; -import org.apache.syncope.common.lib.policy.AccessPolicyConf; import org.apache.syncope.common.lib.policy.AccessPolicyTO; import org.apache.syncope.common.lib.policy.DefaultAccessPolicyConf; import org.apache.syncope.common.lib.types.IdRepoEntitlement; @@ -32,8 +29,11 @@ import org.apache.wicket.PageReference; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; +import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; +import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; -import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; @@ -42,13 +42,13 @@ public class AccessPolicyDirectoryPanel extends PolicyDirectoryPanel(PolicyType.ACCESS, defaultItem, modal, pageRef), true); + new PolicyModalPanelBuilder<>(PolicyType.ACCESS, defaultItem, modal, restClient, pageRef), true); MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, IdRepoEntitlement.POLICY_CREATE); initResultTable(); @@ -56,65 +56,40 @@ public AccessPolicyDirectoryPanel(final String id, final PageReference pageRef) @Override protected void addCustomColumnFields(final List> columns) { - columns.add(new PropertyColumn<>(new StringResourceModel("order", this), "order", "order")); - columns.add(new BooleanPropertyColumn<>( - new StringResourceModel("enabled", this), "enabled", "enabled")); - columns.add(new BooleanPropertyColumn<>( - new StringResourceModel("ssoEnabled", this), "ssoEnabled", "ssoEnabled")); - columns.add(new BooleanPropertyColumn<>( - new StringResourceModel("requireAllAttributes", this), "requireAllAttributes", "requireAllAttributes")); - columns.add(new BooleanPropertyColumn<>( - new StringResourceModel("caseInsensitive", this), "caseInsensitive", "caseInsensitive")); - } + columns.add(new AbstractColumn(new StringResourceModel("conf", this)) { - @Override - protected void addCustomActions(final ActionsPanel panel, final IModel model) { - panel.add(new ActionLink<>() { - - private static final long serialVersionUID = -3722207913631435501L; + private static final long serialVersionUID = -7226955670801277153L; @Override - public void onClick(final AjaxRequestTarget target, final AccessPolicyTO ignore) { - model.setObject(PolicyRestClient.read(type, model.getObject().getKey())); - if (model.getObject().getConf() == null) { - model.getObject().setConf(new DefaultAccessPolicyConf()); - } - target.add(ruleCompositionModal.setContent(new ModalDirectoryPanel<>( - ruleCompositionModal, - new AccessPolicyAttrsDirectoryPanel( - "panel", - ruleCompositionModal, - model, - AccessPolicyConf::getRequiredAttrs, - pageRef), - pageRef))); - ruleCompositionModal.header(new Model<>(getString("requiredAttrs.title", model))); - ruleCompositionModal.show(true); + public void populateItem( + final Item> cellItem, + final String componentId, + final IModel rowModel) { + + cellItem.add(new Label(componentId, rowModel.getObject().getConf() == null + ? "" + : rowModel.getObject().getConf().getClass().getName())); } - }, ActionLink.ActionType.TYPE_EXTENSIONS, IdRepoEntitlement.POLICY_UPDATE); + }); + } + @Override + protected void addCustomActions(final ActionsPanel panel, final IModel model) { panel.add(new ActionLink<>() { private static final long serialVersionUID = -3722207913631435501L; @Override public void onClick(final AjaxRequestTarget target, final AccessPolicyTO ignore) { - model.setObject(PolicyRestClient.read(type, model.getObject().getKey())); + model.setObject(restClient.read(type, model.getObject().getKey())); if (model.getObject().getConf() == null) { model.getObject().setConf(new DefaultAccessPolicyConf()); } - target.add(ruleCompositionModal.setContent(new ModalDirectoryPanel<>( - ruleCompositionModal, - new AccessPolicyAttrsDirectoryPanel( - "panel", - ruleCompositionModal, - model, - AccessPolicyConf::getRejectedAttrs, - pageRef), - pageRef))); - ruleCompositionModal.header(new Model<>(getString("rejectedAttrs.title", model))); - ruleCompositionModal.show(true); + target.add(policySpecModal.setContent( + new AccessPolicyModalPanel(policySpecModal, model, pageRef))); + policySpecModal.header(new Model<>(getString("accessPolicyConf.title", model))); + policySpecModal.show(true); } - }, ActionLink.ActionType.CLAIM, IdRepoEntitlement.POLICY_UPDATE); + }, ActionLink.ActionType.CHANGE_VIEW, IdRepoEntitlement.POLICY_UPDATE); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AccessPolicyModalPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AccessPolicyModalPanel.java new file mode 100644 index 00000000000..ec9e1c69fa2 --- /dev/null +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AccessPolicyModalPanel.java @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.console.policies; + +import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.panels.AbstractModalPanel; +import org.apache.syncope.client.console.panels.BeanPanel; +import org.apache.syncope.client.console.rest.PolicyRestClient; +import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; +import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.pages.BaseWebPage; +import org.apache.syncope.common.lib.policy.AccessPolicyTO; +import org.apache.syncope.common.lib.types.PolicyType; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.spring.injection.annot.SpringBean; + +public class AccessPolicyModalPanel extends AbstractModalPanel { + + private static final long serialVersionUID = -6446551344059681908L; + + @SpringBean + protected PolicyRestClient policyRestClient; + + protected final IModel model; + + public AccessPolicyModalPanel( + final BaseModal modal, + final IModel model, + final PageReference pageRef) { + + super(modal, pageRef); + this.model = model; + + add(new BeanPanel<>("bean", new PropertyModel<>(model, "conf"), pageRef).setRenderBodyOnly(true)); + } + + @Override + public void onSubmit(final AjaxRequestTarget target) { + try { + policyRestClient.update(PolicyType.ACCESS, model.getObject()); + + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); + modal.close(target); + } catch (Exception e) { + LOG.error("While updating Access Policy {}", model.getObject().getKey(), e); + SyncopeConsoleSession.get().onException(e); + } + ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target); + } +} diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AttrReleasePolicyDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AttrReleasePolicyDirectoryPanel.java index bb37ab5e59c..c1bf416bf21 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AttrReleasePolicyDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AttrReleasePolicyDirectoryPanel.java @@ -40,13 +40,17 @@ public class AttrReleasePolicyDirectoryPanel extends PolicyDirectoryPanel(PolicyType.ATTR_RELEASE, defaultItem, modal, pageRef), true); + new PolicyModalPanelBuilder<>(PolicyType.ATTR_RELEASE, defaultItem, modal, restClient, pageRef), true); MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, IdRepoEntitlement.POLICY_CREATE); initResultTable(); @@ -69,7 +73,7 @@ protected void addCustomActions( @Override public void onClick(final AjaxRequestTarget target, final AttrReleasePolicyTO ignore) { - model.setObject(PolicyRestClient.read(type, model.getObject().getKey())); + model.setObject(restClient.read(type, model.getObject().getKey())); if (model.getObject().getConf() == null) { model.getObject().setConf(new DefaultAttrReleasePolicyConf()); } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AttrReleasePolicyModalPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AttrReleasePolicyModalPanel.java index fcc98316b40..2995d794ca8 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AttrReleasePolicyModalPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AttrReleasePolicyModalPanel.java @@ -30,8 +30,9 @@ import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxGridFieldPanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxNumberFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel; -import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.common.lib.policy.AttrReleasePolicyTO; @@ -44,22 +45,29 @@ import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class AttrReleasePolicyModalPanel extends AbstractModalPanel { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2668291404983623500L; - private final IModel> allAttrRepos = new LoadableDetachableModel<>() { + @SpringBean + protected PolicyRestClient policyRestClient; + + @SpringBean + protected AttrRepoRestClient attrRepoRestClient; + + protected final IModel> allAttrRepos = new LoadableDetachableModel<>() { private static final long serialVersionUID = -2012833443695917883L; @Override protected List load() { - return AttrRepoRestClient.list().stream().map(AttrRepoTO::getKey).sorted().collect(Collectors.toList()); + return attrRepoRestClient.list().stream().map(AttrRepoTO::getKey).sorted().collect(Collectors.toList()); } }; - private final IModel model; + protected final IModel model; public AttrReleasePolicyModalPanel( final BaseModal modal, @@ -69,6 +77,10 @@ public AttrReleasePolicyModalPanel( super(modal, pageRef); this.model = model; + add(new AjaxGridFieldPanel<>( + "releaseAttrs", "releaseAttrs", + new PropertyModel<>(model.getObject().getConf(), "releaseAttrs"))); + AjaxTextFieldPanel allowedAttr = new AjaxTextFieldPanel("panel", "allowedAttrs", new Model<>()); add(new MultiFieldPanel.Builder( new PropertyModel<>(model.getObject().getConf(), "allowedAttrs")).build( @@ -108,7 +120,7 @@ public AttrReleasePolicyModalPanel( new PropertyModel<>(model.getObject().getConf(), "principalAttrRepoConf.ignoreResolvedAttributes"), false)); - add(new AjaxSpinnerFieldPanel.Builder().build( + add(new AjaxNumberFieldPanel.Builder().build( "expiration", "expiration", Long.class, @@ -131,7 +143,7 @@ public AttrReleasePolicyModalPanel( @Override public void onSubmit(final AjaxRequestTarget target) { try { - PolicyRestClient.update(PolicyType.ATTR_RELEASE, model.getObject()); + policyRestClient.update(PolicyType.ATTR_RELEASE, model.getObject()); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); modal.close(target); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AuthPolicyDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AuthPolicyDirectoryPanel.java index f3d51955f2a..7c720655703 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AuthPolicyDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AuthPolicyDirectoryPanel.java @@ -35,13 +35,13 @@ public class AuthPolicyDirectoryPanel extends PolicyDirectoryPanel private static final long serialVersionUID = 4984337552918213290L; - public AuthPolicyDirectoryPanel(final String id, final PageReference pageRef) { - super(id, PolicyType.AUTH, pageRef); + public AuthPolicyDirectoryPanel(final String id, final PolicyRestClient restClient, final PageReference pageRef) { + super(id, restClient, PolicyType.AUTH, pageRef); AuthPolicyTO defaultItem = new AuthPolicyTO(); this.addNewItemPanelBuilder( - new PolicyModalPanelBuilder<>(PolicyType.AUTH, defaultItem, modal, pageRef), true); + new PolicyModalPanelBuilder<>(PolicyType.AUTH, defaultItem, modal, restClient, pageRef), true); MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, IdRepoEntitlement.POLICY_CREATE); initResultTable(); @@ -56,7 +56,7 @@ protected void addCustomActions(final ActionsPanel panel, final IM @Override public void onClick(final AjaxRequestTarget target, final AuthPolicyTO ignore) { - model.setObject(PolicyRestClient.read(type, model.getObject().getKey())); + model.setObject(restClient.read(type, model.getObject().getKey())); if (model.getObject().getConf() == null) { model.getObject().setConf(new DefaultAuthPolicyConf()); } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AuthPolicyModalPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AuthPolicyModalPanel.java index 3f70f083637..d1bc313fd08 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AuthPolicyModalPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/AuthPolicyModalPanel.java @@ -28,6 +28,7 @@ import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.common.lib.policy.AuthPolicyTO; import org.apache.syncope.common.lib.to.AuthModuleTO; @@ -37,18 +38,25 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class AuthPolicyModalPanel extends AbstractModalPanel { private static final long serialVersionUID = -7210166323800567306L; - private final IModel> allAuthModules = new LoadableDetachableModel<>() { + @SpringBean + protected PolicyRestClient policyRestClient; + + @SpringBean + protected AuthModuleRestClient authModuleRestClient; + + protected final IModel> allAuthModules = new LoadableDetachableModel<>() { private static final long serialVersionUID = -2012833443695917883L; @Override protected List load() { - return AuthModuleRestClient.list().stream().map(AuthModuleTO::getKey).sorted().collect(Collectors.toList()); + return authModuleRestClient.list().stream().map(AuthModuleTO::getKey).sorted().collect(Collectors.toList()); } }; @@ -72,12 +80,36 @@ public AuthPolicyModalPanel( "authModules", new PropertyModel<>(model.getObject().getConf(), "authModules"), allAuthModules)); + + add(new AjaxCheckBoxPanel( + "bypassEnabled", + "bypassEnabled", + new PropertyModel<>(model.getObject().getConf(), "bypassEnabled"), + false)); + + add(new AjaxCheckBoxPanel( + "forceMfaExecution", + "forceMfaExecution", + new PropertyModel<>(model.getObject().getConf(), "forceMfaExecution"), + false)); + + add(new AjaxTextFieldPanel( + "bypassPrincipalAttributeName", + "bypassPrincipalAttributeName", + new PropertyModel<>(model.getObject().getConf(), "bypassPrincipalAttributeName"), + false)); + + add(new AjaxTextFieldPanel( + "bypassPrincipalAttributeValue", + "bypassPrincipalAttributeValue", + new PropertyModel<>(model.getObject().getConf(), "bypassPrincipalAttributeValue"), + false)); } @Override public void onSubmit(final AjaxRequestTarget target) { try { - PolicyRestClient.update(PolicyType.AUTH, model.getObject()); + policyRestClient.update(PolicyType.AUTH, model.getObject()); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); modal.close(target); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/TicketExpirationPolicyDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/TicketExpirationPolicyDirectoryPanel.java new file mode 100644 index 00000000000..36e629fb77d --- /dev/null +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/TicketExpirationPolicyDirectoryPanel.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.console.policies; + +import org.apache.syncope.client.console.rest.PolicyRestClient; +import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; +import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; +import org.apache.syncope.common.lib.policy.DefaultTicketExpirationPolicyConf; +import org.apache.syncope.common.lib.policy.TicketExpirationPolicyTO; +import org.apache.syncope.common.lib.types.IdRepoEntitlement; +import org.apache.syncope.common.lib.types.PolicyType; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; + +public class TicketExpirationPolicyDirectoryPanel extends PolicyDirectoryPanel { + + private static final long serialVersionUID = 4984337552918213290L; + + public TicketExpirationPolicyDirectoryPanel( + final String id, + final PolicyRestClient restClient, + final PageReference pageRef) { + + super(id, restClient, PolicyType.TICKET_EXPIRATION, pageRef); + + TicketExpirationPolicyTO defaultItem = new TicketExpirationPolicyTO(); + + this.addNewItemPanelBuilder(new PolicyModalPanelBuilder<>( + PolicyType.TICKET_EXPIRATION, defaultItem, modal, restClient, pageRef), true); + MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, IdRepoEntitlement.POLICY_CREATE); + + initResultTable(); + } + + @Override + protected void addCustomActions( + final ActionsPanel panel, + final IModel model) { + + panel.add(new ActionLink<>() { + + private static final long serialVersionUID = -3722207913631435501L; + + @Override + public void onClick(final AjaxRequestTarget target, final TicketExpirationPolicyTO ignore) { + model.setObject(restClient.read(type, model.getObject().getKey())); + if (model.getObject().getConf() == null) { + model.getObject().setConf(new DefaultTicketExpirationPolicyConf()); + } + target.add(policySpecModal.setContent( + new TicketExpirationPolicyModalPanel(policySpecModal, model, pageRef))); + policySpecModal.header(new Model<>(getString("ticketExpirationPolicyConf.title", model))); + policySpecModal.show(true); + } + }, ActionLink.ActionType.CHANGE_VIEW, IdRepoEntitlement.POLICY_UPDATE); + } +} diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/policies/TicketExpirationPolicyModalPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/TicketExpirationPolicyModalPanel.java new file mode 100644 index 00000000000..c62a3649406 --- /dev/null +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/policies/TicketExpirationPolicyModalPanel.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.console.policies; + +import java.io.Serializable; +import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.panels.AbstractModalPanel; +import org.apache.syncope.client.console.panels.BeanPanel; +import org.apache.syncope.client.console.rest.PolicyRestClient; +import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; +import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel; +import org.apache.syncope.client.ui.commons.pages.BaseWebPage; +import org.apache.syncope.common.lib.policy.DefaultTicketExpirationPolicyConf; +import org.apache.syncope.common.lib.policy.TicketExpirationPolicyTO; +import org.apache.syncope.common.lib.types.PolicyType; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.spring.injection.annot.SpringBean; + +public class TicketExpirationPolicyModalPanel extends AbstractModalPanel { + + private static final long serialVersionUID = 2668291404983623500L; + + @SpringBean + protected PolicyRestClient policyRestClient; + + protected final IModel model; + + public TicketExpirationPolicyModalPanel( + final BaseModal modal, + final IModel model, + final PageReference pageRef) { + + super(modal, pageRef); + this.model = model; + + conf("tgtConf", new DefaultTicketExpirationPolicyConf.TGTConf()); + conf("stConf", new DefaultTicketExpirationPolicyConf.STConf()); + conf("proxyTgtConf", new DefaultTicketExpirationPolicyConf.TGTConf()); + conf("proxyStConf", new DefaultTicketExpirationPolicyConf.STConf()); + } + + private void conf(final String field, final T newInstance) { + PropertyModel beanPanelModel = new PropertyModel<>(model.getObject(), "conf." + field); + + AjaxCheckBoxPanel enable = new AjaxCheckBoxPanel("enable." + field, "enable." + field, new IModel() { + + private static final long serialVersionUID = -7126718045816207110L; + + @Override + public Boolean getObject() { + return beanPanelModel.getObject() != null; + } + + @Override + public void setObject(final Boolean object) { + // nothing to do + } + }); + enable.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { + + private static final long serialVersionUID = -1107858522700306810L; + + @Override + protected void onUpdate(final AjaxRequestTarget target) { + if (beanPanelModel.getObject() == null) { + beanPanelModel.setObject(newInstance); + } else { + beanPanelModel.setObject(null); + } + target.add(TicketExpirationPolicyModalPanel.this); + } + }); + add(enable); + + add(new BeanPanel<>("bean." + field, beanPanelModel, pageRef).setRenderBodyOnly(true)); + } + + @Override + public void onSubmit(final AjaxRequestTarget target) { + try { + policyRestClient.update(PolicyType.TICKET_EXPIRATION, model.getObject()); + + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); + modal.close(target); + } catch (Exception e) { + LOG.error("While updating Ticket Expiration Policy {}", model.getObject().getKey(), e); + SyncopeConsoleSession.get().onException(e); + } + ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target); + } +} diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AMSessionRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AMSessionRestClient.java index 99617194768..78fad08fb2e 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AMSessionRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AMSessionRestClient.java @@ -23,8 +23,8 @@ import java.util.List; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.SyncopeWebApplication; +import org.apache.syncope.client.lib.WebClientBuilder; import org.apache.syncope.client.ui.commons.rest.RestClient; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.apache.syncope.common.lib.AMSession; @@ -56,13 +56,13 @@ public void delete(final String key) { SyncopeClientException sce = SyncopeClientException.build(ClientExceptionType.Unknown); try { - Response response = WebClient.create( - getActuatorEndpoint(), + Response response = WebClientBuilder.build(getActuatorEndpoint(), SyncopeWebApplication.get().getAnonymousUser(), SyncopeWebApplication.get().getAnonymousKey(), - null). - path(key). - accept(MediaType.APPLICATION_JSON_TYPE).type(MediaType.APPLICATION_JSON_TYPE).delete(); + List.of()). + accept(MediaType.APPLICATION_JSON_TYPE). + type(MediaType.APPLICATION_JSON_TYPE). + path(key).delete(); if (response.getStatus() != Response.Status.OK.getStatusCode() && response.getStatus() != Response.Status.NO_CONTENT.getStatusCode()) { diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AttrRepoRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AttrRepoRestClient.java index 318c1e38ea8..f14b21883da 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AttrRepoRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AttrRepoRestClient.java @@ -26,23 +26,23 @@ public class AttrRepoRestClient extends BaseRestClient { private static final long serialVersionUID = -7379778542101161274L; - public static List list() { + public List list() { return getService(AttrRepoService.class).list(); } - public static void create(final AttrRepoTO attrRepoTO) { + public void create(final AttrRepoTO attrRepoTO) { getService(AttrRepoService.class).create(attrRepoTO); } - public static AttrRepoTO read(final String key) { + public AttrRepoTO read(final String key) { return getService(AttrRepoService.class).read(key); } - public static void update(final AttrRepoTO attrRepoTO) { + public void update(final AttrRepoTO attrRepoTO) { getService(AttrRepoService.class).update(attrRepoTO); } - public static void delete(final String key) { + public void delete(final String key) { getService(AttrRepoService.class).delete(key); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthModuleRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthModuleRestClient.java index 29cdcb18995..516e1c537fb 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthModuleRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthModuleRestClient.java @@ -26,23 +26,23 @@ public class AuthModuleRestClient extends BaseRestClient { private static final long serialVersionUID = -7379778542101161274L; - public static List list() { + public List list() { return getService(AuthModuleService.class).list(); } - public static void create(final AuthModuleTO authModuleTO) { + public void create(final AuthModuleTO authModuleTO) { getService(AuthModuleService.class).create(authModuleTO); } - public static AuthModuleTO read(final String key) { + public AuthModuleTO read(final String key) { return getService(AuthModuleService.class).read(key); } - public static void update(final AuthModuleTO authModuleTO) { + public void update(final AuthModuleTO authModuleTO) { getService(AuthModuleService.class).update(authModuleTO); } - public static void delete(final String key) { + public void delete(final String key) { getService(AuthModuleService.class).delete(key); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthProfileRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthProfileRestClient.java index d526783030c..92f858e026b 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthProfileRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthProfileRestClient.java @@ -26,27 +26,23 @@ public class AuthProfileRestClient extends BaseRestClient { private static final long serialVersionUID = -7379778542101161274L; - public static int count() { + public int count() { return getService(AuthProfileService.class).list(1, 1).getTotalCount(); } - public static List list(final int page, final int size) { + public List list(final int page, final int size) { return getService(AuthProfileService.class).list(page, size).getResult(); } - public static AuthProfileTO read(final String key) { + public AuthProfileTO read(final String key) { return getService(AuthProfileService.class).read(key); } - public static void create(final AuthProfileTO authProfile) { - getService(AuthProfileService.class).create(authProfile); - } - - public static void update(final AuthProfileTO authProfile) { + public void update(final AuthProfileTO authProfile) { getService(AuthProfileService.class).update(authProfile); } - public static void delete(final String key) { + public void delete(final String key) { getService(AuthProfileService.class).delete(key); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/ClientAppRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/ClientAppRestClient.java index af861932360..56d7f725495 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/ClientAppRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/ClientAppRestClient.java @@ -29,9 +29,9 @@ public class ClientAppRestClient extends BaseRestClient { private static final long serialVersionUID = -1392090291817187902L; - private static final Comparator COMPARATOR = Comparator.comparing(ClientAppTO::getName); + protected static final Comparator COMPARATOR = Comparator.comparing(ClientAppTO::getName); - public static T read(final ClientAppType type, final String key) { + public T read(final ClientAppType type, final String key) { T policy = null; try { policy = getService(ClientAppService.class).read(type, key); @@ -42,7 +42,7 @@ public static T read(final ClientAppType type, final Str } @SuppressWarnings("unchecked") - public static List list(final ClientAppType type) { + public List list(final ClientAppType type) { try { return getService(ClientAppService.class).list(type).stream(). sorted(COMPARATOR). @@ -53,15 +53,15 @@ public static List list(final ClientAppType type) { } } - public static void create(final ClientAppType type, final T policy) { + public void create(final ClientAppType type, final T policy) { getService(ClientAppService.class).create(type, policy); } - public static void update(final ClientAppType type, final T policy) { + public void update(final ClientAppType type, final T policy) { getService(ClientAppService.class).update(type, policy); } - public static void delete(final ClientAppType type, final String key) { + public void delete(final ClientAppType type, final String key) { getService(ClientAppService.class).delete(type, key); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/OIDCJWKSRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/OIDCJWKSRestClient.java index 57c4e68ff27..a7abf44c8b1 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/OIDCJWKSRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/OIDCJWKSRestClient.java @@ -27,7 +27,7 @@ public class OIDCJWKSRestClient extends BaseRestClient { private static final long serialVersionUID = -1392090291817187902L; - public static AtomicReference get() { + public AtomicReference get() { AtomicReference result = new AtomicReference<>(); try { result.set(getService(OIDCJWKSService.class).get()); @@ -37,12 +37,12 @@ public static AtomicReference get() { return result; } - public static OIDCJWKSTO generate() { - Response response = getService(OIDCJWKSService.class).generate("syncope", "RSA", 2048); + public OIDCJWKSTO generate(final String jwksKeyId, final String jwksType, final int jwksKeySize) { + Response response = getService(OIDCJWKSService.class).generate(jwksKeyId, jwksType, jwksKeySize); return response.readEntity(OIDCJWKSTO.class); } - public static void delete() { + public void delete() { getService(OIDCJWKSService.class).delete(); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SAML2IdPEntityRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SAML2IdPEntityRestClient.java index 8f6ce3b90e5..8106fe41d22 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SAML2IdPEntityRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SAML2IdPEntityRestClient.java @@ -27,15 +27,15 @@ public class SAML2IdPEntityRestClient extends BaseRestClient { private static final long serialVersionUID = -1392090291817187902L; - public static List list() { + public List list() { return getService(SAML2IdPEntityService.class).list().stream().collect(Collectors.toList()); } - public static SAML2IdPEntityTO get(final String key) { + public SAML2IdPEntityTO get(final String key) { return getService(SAML2IdPEntityService.class).get(key); } - public static void set(final SAML2IdPEntityTO entityTO) { + public void set(final SAML2IdPEntityTO entityTO) { getService(SAML2IdPEntityService.class).set(entityTO); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SAML2SPEntityRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SAML2SPEntityRestClient.java index 98b38229c40..552d81c2a99 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SAML2SPEntityRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SAML2SPEntityRestClient.java @@ -27,19 +27,19 @@ public class SAML2SPEntityRestClient extends BaseRestClient { private static final long serialVersionUID = -1392090291817187902L; - public static List list() { + public List list() { return getService(SAML2SPEntityService.class).list().stream().collect(Collectors.toList()); } - public static SAML2SPEntityTO get(final String key) { + public SAML2SPEntityTO get(final String key) { return getService(SAML2SPEntityService.class).get(key); } - public static void set(final SAML2SPEntityTO entityTO) { + public void set(final SAML2SPEntityTO entityTO) { getService(SAML2SPEntityService.class).set(entityTO); } - public static void delete(final String key) { + public void delete(final String key) { getService(SAML2SPEntityService.class).delete(key); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRARouteRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRARouteRestClient.java index 47dfe63f16a..9504ad45706 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRARouteRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRARouteRestClient.java @@ -26,27 +26,27 @@ public class SRARouteRestClient extends BaseRestClient { private static final long serialVersionUID = -7379778542101161274L; - public static List list() { + public List list() { return getService(SRARouteService.class).list(); } - public static SRARouteTO read(final String key) { + public SRARouteTO read(final String key) { return getService(SRARouteService.class).read(key); } - public static void create(final SRARouteTO route) { + public void create(final SRARouteTO route) { getService(SRARouteService.class).create(route); } - public static void update(final SRARouteTO route) { + public void update(final SRARouteTO route) { getService(SRARouteService.class).update(route); } - public static void delete(final String key) { + public void delete(final String key) { getService(SRARouteService.class).delete(key); } - public static void push() { + public void push() { getService(SRARouteService.class).pushToSRA(); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRASessionRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRASessionRestClient.java index a45aa581ddf..a7f32c34738 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRASessionRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRASessionRestClient.java @@ -22,8 +22,8 @@ import javax.ws.rs.core.GenericType; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.SyncopeWebApplication; +import org.apache.syncope.client.lib.WebClientBuilder; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.apache.syncope.common.lib.AMSession; @@ -43,15 +43,10 @@ protected String getActuatorEndpoint() { @Override public List list() { try { - WebClient client = WebClient.create( - getActuatorEndpoint(), - JAX_RS_PROVIDERS, + Response response = WebClientBuilder.build(getActuatorEndpoint(), SyncopeWebApplication.get().getAnonymousUser(), SyncopeWebApplication.get().getAnonymousKey(), - null). - accept(MediaType.APPLICATION_JSON_TYPE); - - Response response = client.get(); + JAX_RS_PROVIDERS).accept(MediaType.APPLICATION_JSON_TYPE).get(); if (response.getStatus() == Response.Status.OK.getStatusCode()) { return response.readEntity(new GenericType<>() { }); diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatisticsRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatisticsRestClient.java index a16b6fd5f06..4233ca26ac2 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatisticsRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/SRAStatisticsRestClient.java @@ -26,6 +26,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.SyncopeWebApplication; +import org.apache.syncope.client.lib.WebClientBuilder; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,19 +38,16 @@ public final class SRAStatisticsRestClient { private static final List JAX_RS_PROVIDERS = List.of(new JacksonJsonProvider(JsonMapper.builder().findAndAddModules().build())); - private static String getActuatorEndpoint(final List instances) { + protected String getActuatorEndpoint(final List instances) { return instances.get(0).getAddress() + "actuator/metrics/spring.cloud.gateway.requests"; } - public static SRAStatistics get(final List instances, final List> selected) { + public SRAStatistics get(final List instances, final List> selected) { try { - WebClient client = WebClient.create( - getActuatorEndpoint(instances), - JAX_RS_PROVIDERS, + WebClient client = WebClientBuilder.build(getActuatorEndpoint(instances), SyncopeWebApplication.get().getAnonymousUser(), SyncopeWebApplication.get().getAnonymousKey(), - null). - accept(MediaType.APPLICATION_JSON_TYPE); + JAX_RS_PROVIDERS).accept(MediaType.APPLICATION_JSON_TYPE); if (!selected.isEmpty()) { client.query("tag", selected.stream().map(s -> s.getKey() + ":" + s.getValue()).toArray()); @@ -68,8 +66,4 @@ public static SRAStatistics get(final List instances, final List return new SRAStatistics(); } - - private SRAStatisticsRestClient() { - // private constructor for static utility class - } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WAConfigRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WAConfigRestClient.java index 8b683eaf788..4dce2e8b33e 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WAConfigRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WAConfigRestClient.java @@ -26,19 +26,23 @@ public class WAConfigRestClient extends BaseRestClient { private static final long serialVersionUID = -7379778542101161274L; - public static List list() { + public List list() { return getService(WAConfigService.class).list(); } - public static void set(final Attr value) { + public Attr get(final String schema) { + return getService(WAConfigService.class).get(schema); + } + + public void set(final Attr value) { getService(WAConfigService.class).set(value); } - public static void delete(final String schema) { + public void delete(final String schema) { getService(WAConfigService.class).delete(schema); } - public static void push() { - getService(WAConfigService.class).pushToWA(); + public void push(final WAConfigService.PushSubject subject, final List services) { + getService(WAConfigService.class).pushToWA(subject, services); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WASessionRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WASessionRestClient.java index 48f80e912a1..c527c7147e1 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WASessionRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/WASessionRestClient.java @@ -26,8 +26,8 @@ import java.util.List; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.SyncopeWebApplication; +import org.apache.syncope.client.lib.WebClientBuilder; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.apache.syncope.common.lib.AMSession; @@ -35,7 +35,7 @@ public final class WASessionRestClient extends AMSessionRestClient { private static final long serialVersionUID = 22118820292494L; - private static final JsonMapper MAPPER = JsonMapper.builder(). + protected static final JsonMapper MAPPER = JsonMapper.builder(). addModule(new SimpleModule().addDeserializer(AMSession.class, new AMSessionDeserializer())).build(); public WASessionRestClient(final List instances) { @@ -50,12 +50,10 @@ protected String getActuatorEndpoint() { @Override public List list() { try { - Response response = WebClient.create( - getActuatorEndpoint(), + Response response = WebClientBuilder.build(getActuatorEndpoint(), SyncopeWebApplication.get().getAnonymousUser(), SyncopeWebApplication.get().getAnonymousKey(), - null). - accept(MediaType.APPLICATION_JSON_TYPE).get(); + List.of()).accept(MediaType.APPLICATION_JSON_TYPE).get(); if (response.getStatus() == Response.Status.OK.getStatusCode()) { JsonNode node = MAPPER.readTree((InputStream) response.getEntity()); if (node.has("activeSsoSessions")) { diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AttrRepoWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AttrRepoWizardBuilder.java index 784b04d5dba..5253630e52d 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AttrRepoWizardBuilder.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AttrRepoWizardBuilder.java @@ -28,7 +28,7 @@ import org.apache.syncope.client.console.wizards.mapping.AttrRepoMappingPanel; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; -import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxNumberFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; import org.apache.syncope.common.lib.attr.AttrRepoConf; @@ -50,9 +50,14 @@ public class AttrRepoWizardBuilder extends BaseAjaxWizardBuilder { protected final LoadableDetachableModel> attrRepoConfs; - protected Model> attrRepoConfClass = Model.of(); + protected final AttrRepoRestClient attrRepoRestClient; - public AttrRepoWizardBuilder(final AttrRepoTO defaultItem, final PageReference pageRef) { + protected final Model> attrRepoConfClass = Model.of(); + + public AttrRepoWizardBuilder( + final AttrRepoTO defaultItem, + final AttrRepoRestClient attrRepoRestClient, + final PageReference pageRef) { super(defaultItem, pageRef); @@ -66,14 +71,15 @@ protected List load() { map(Class::getName).sorted().collect(Collectors.toList()); } }; + this.attrRepoRestClient = attrRepoRestClient; } @Override protected Serializable onApplyInternal(final AttrRepoTO modelObject) { if (mode == AjaxWizard.Mode.CREATE) { - AttrRepoRestClient.create(modelObject); + attrRepoRestClient.create(modelObject); } else { - AttrRepoRestClient.update(modelObject); + attrRepoRestClient.update(modelObject); } return modelObject; } @@ -119,7 +125,7 @@ Constants.DESCRIPTION_FIELD_NAME, getString(Constants.DESCRIPTION_FIELD_NAME), state.setNullValid(false); add(state); - add(new AjaxSpinnerFieldPanel.Builder().build( + add(new AjaxNumberFieldPanel.Builder().build( "order", "order", Integer.class, diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder.java index d976f5ab8a5..a0b7317bf42 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder.java @@ -30,11 +30,12 @@ import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; -import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxNumberFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; +import org.apache.syncope.common.lib.AbstractLDAPConf; import org.apache.syncope.common.lib.auth.AuthModuleConf; -import org.apache.syncope.common.lib.auth.GoogleMfaAuthModuleConf; +import org.apache.syncope.common.lib.auth.LDAPDependantAuthModuleConf; import org.apache.syncope.common.lib.to.AuthModuleTO; import org.apache.syncope.common.lib.types.AuthModuleState; import org.apache.wicket.PageReference; @@ -52,32 +53,36 @@ public class AuthModuleWizardBuilder extends BaseAjaxWizardBuilder private static final long serialVersionUID = -6163230263062920394L; - protected final LoadableDetachableModel> authModuleConfs; + protected final LoadableDetachableModel> authModuleConfs = new LoadableDetachableModel<>() { - protected Model> authModuleConfClass = Model.of(); + private static final long serialVersionUID = 5275935387613157437L; - public AuthModuleWizardBuilder(final AuthModuleTO defaultItem, final PageReference pageRef) { + @Override + protected List load() { + return SyncopeWebApplication.get().getLookup().getClasses(AuthModuleConf.class).stream(). + map(Class::getName).sorted().collect(Collectors.toList()); + } + }; - super(defaultItem, pageRef); + protected final AuthModuleRestClient authModuleRestClient; - authModuleConfs = new LoadableDetachableModel<>() { + protected final Model> authModuleConfClass = Model.of(); - private static final long serialVersionUID = 5275935387613157437L; + public AuthModuleWizardBuilder( + final AuthModuleTO defaultItem, + final AuthModuleRestClient authModuleRestClient, + final PageReference pageRef) { - @Override - protected List load() { - return SyncopeWebApplication.get().getLookup().getClasses(AuthModuleConf.class).stream(). - map(Class::getName).sorted().collect(Collectors.toList()); - } - }; + super(defaultItem, pageRef); + this.authModuleRestClient = authModuleRestClient; } @Override protected Serializable onApplyInternal(final AuthModuleTO modelObject) { if (mode == AjaxWizard.Mode.CREATE) { - AuthModuleRestClient.create(modelObject); + authModuleRestClient.create(modelObject); } else { - AuthModuleRestClient.update(modelObject); + authModuleRestClient.update(modelObject); } return modelObject; } @@ -86,7 +91,7 @@ protected Serializable onApplyInternal(final AuthModuleTO modelObject) { protected WizardModel buildModelSteps(final AuthModuleTO modelObject, final WizardModel wizardModel) { wizardModel.add(new Profile(modelObject, authModuleConfs, authModuleConfClass)); wizardModel.add(new Configuration(modelObject)); - wizardModel.add(new GoogleMfaAuthModuleConfLDAP(modelObject, authModuleConfClass)); + wizardModel.add(new AuthModuleConfLDAP(modelObject, authModuleConfClass)); wizardModel.add(new Mapping(modelObject)); return wizardModel; } @@ -124,7 +129,7 @@ Constants.DESCRIPTION_FIELD_NAME, getString(Constants.DESCRIPTION_FIELD_NAME), state.setNullValid(false); add(state); - add(new AjaxSpinnerFieldPanel.Builder().build( + add(new AjaxNumberFieldPanel.Builder().build( "order", "order", Integer.class, @@ -152,7 +157,7 @@ protected void onEvent(final AjaxRequestTarget target) { authModule.setConf(clazz.getConstructor().newInstance()); authModuleConfClass.setObject(clazz); } catch (Exception e) { - LOG.error("During deserialization", e); + LOG.error("Cannot instantiate {}", conf.getModelObject(), e); } } }); @@ -165,24 +170,24 @@ protected class Configuration extends WizardStep { private static final long serialVersionUID = -785981096328637758L; Configuration(final AuthModuleTO authModule) { - add(new BeanPanel<>( - "bean", new PropertyModel<>(authModule, "conf"), pageRef, "ldap").setRenderBodyOnly(true)); + add(new BeanPanel<>("bean", new PropertyModel<>(authModule, "conf"), pageRef, "ldap"). + setRenderBodyOnly(true)); } } - protected class GoogleMfaAuthModuleConfLDAP extends WizardStep implements WizardModel.ICondition { + protected class AuthModuleConfLDAP extends WizardStep implements WizardModel.ICondition { private static final long serialVersionUID = 5328049907748683944L; private final Model> authModuleConfClass; - GoogleMfaAuthModuleConfLDAP( + AuthModuleConfLDAP( final AuthModuleTO authModule, final Model> authModuleConfClass) { this.authModuleConfClass = authModuleConfClass; - PropertyModel beanPanelModel = new PropertyModel<>(authModule, "conf.ldap"); + PropertyModel beanPanelModel = new PropertyModel<>(authModule, "conf.ldap"); AjaxCheckBoxPanel enable = new AjaxCheckBoxPanel("enable", "enableLDAP", new IModel() { @@ -205,11 +210,16 @@ public void setObject(final Boolean object) { @Override protected void onUpdate(final AjaxRequestTarget target) { if (beanPanelModel.getObject() == null) { - beanPanelModel.setObject(new GoogleMfaAuthModuleConf.LDAP()); + try { + beanPanelModel.setObject((AbstractLDAPConf) authModuleConfClass.getObject(). + getMethod("ldapInstance", new Class[] {}).invoke(authModule.getConf())); + } catch (Exception e) { + LOG.warn("Error instantiating beanPanel model object", e); + } } else { beanPanelModel.setObject(null); } - target.add(GoogleMfaAuthModuleConfLDAP.this); + target.add(AuthModuleConfLDAP.this); } }); add(enable); @@ -220,7 +230,7 @@ protected void onUpdate(final AjaxRequestTarget target) { @Override public boolean evaluate() { - return GoogleMfaAuthModuleConf.class.equals(authModuleConfClass.getObject()); + return LDAPDependantAuthModuleConf.class.isAssignableFrom(authModuleConfClass.getObject()); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPEntityWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPEntityWizardBuilder.java index 16ff6d83275..9d88b52989a 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPEntityWizardBuilder.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2IdPEntityWizardBuilder.java @@ -30,10 +30,17 @@ public class SAML2IdPEntityWizardBuilder extends SAML2EntityWizardBuilder { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = -8013493490328546125L; + + protected final SAML2IdPEntityRestClient saml2IdPEntityRestClient; + + public SAML2IdPEntityWizardBuilder( + final SAML2IdPEntityTO defaultItem, + final SAML2IdPEntityRestClient saml2IdPEntityRestClient, + final PageReference pageRef) { - public SAML2IdPEntityWizardBuilder(final SAML2IdPEntityTO defaultItem, final PageReference pageRef) { super(defaultItem, pageRef); + this.saml2IdPEntityRestClient = saml2IdPEntityRestClient; } @Override @@ -58,7 +65,7 @@ protected Serializable onApplyInternal(final SAML2IdPEntityTO modelObject) { modelObject.setEncryptionKey(Base64.getEncoder().encodeToString( modelObject.getEncryptionKey().getBytes(StandardCharsets.UTF_8))); } - SAML2IdPEntityRestClient.set(modelObject); + saml2IdPEntityRestClient.set(modelObject); return modelObject; } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2SPEntityWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2SPEntityWizardBuilder.java index 4c2321dc6d3..b98db6910d1 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2SPEntityWizardBuilder.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/SAML2SPEntityWizardBuilder.java @@ -35,10 +35,17 @@ public class SAML2SPEntityWizardBuilder extends SAML2EntityWizardBuilder { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 2400472385439304277L; + + protected final SAML2SPEntityRestClient saml2SPEntityRestClient; + + public SAML2SPEntityWizardBuilder( + final SAML2SPEntityTO defaultItem, + final SAML2SPEntityRestClient saml2SPEntityRestClient, + final PageReference pageRef) { - public SAML2SPEntityWizardBuilder(final SAML2SPEntityTO defaultItem, final PageReference pageRef) { super(defaultItem, pageRef); + this.saml2SPEntityRestClient = saml2SPEntityRestClient; } @Override @@ -47,7 +54,7 @@ protected Serializable onApplyInternal(final SAML2SPEntityTO modelObject) { modelObject.setMetadata(Base64.getEncoder().encodeToString( modelObject.getMetadata().getBytes(StandardCharsets.UTF_8))); } - SAML2SPEntityRestClient.set(modelObject); + saml2SPEntityRestClient.set(modelObject); return modelObject; } diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel.properties index e095d91b2ba..49b21ba589d 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel.properties @@ -37,10 +37,15 @@ secretKey=Secret Key validationCode=Validation Code scratchCodes=Scratch Codes record=Record -fo_edit.class=fab fa-usb -fo_edit.title=u2f Devices +deprovision.class=fab fa-usb +deprovision.title=u2f Devices identifier=Identifier json=JSON html.class=fas fa-at html.title=webauthn webAuthnDeviceCredentials=WebAuthn Device Credentials +expirationDate=Expiration Date +recordDate=Record Date +mfaTrustedDevices=MFA Devices +down.title=mfa devices +down.class=fas fa-barcode diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_fr_CA.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_fr_CA.properties index 8a42e53c73a..5e1a601fa44 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_fr_CA.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_fr_CA.properties @@ -37,10 +37,15 @@ secretKey=Secret Key validationCode=Validation Code scratchCodes=Scratch Codes record=Record -fo_edit.class=fab fa-usb -fo_edit.title=u2f Devices +deprovision.class=fab fa-usb +deprovision.title=u2f Devices identifier=Identifier json=JSON html.class=fas fa-at html.title=webauthn webAuthnDeviceCredentials=WebAuthn Device Credentials +expirationDate=Expiration Date +recordDate=Record Date +mfaTrustedDevices=MFA Devices +down.title=mfa devices +down.class=fas fa-barcode diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_it.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_it.properties index 0fd02d5f98f..eeea47d4da6 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_it.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_it.properties @@ -37,10 +37,15 @@ secretKey=Chiave Segreta validationCode=Codice Validazione scratchCodes=Codici Scratch record=Record -fo_edit.class=fab fa-usb -fo_edit.title=dispositivi u2f +deprovision.class=fab fa-usb +deprovision.title=dispositivi u2f identifier=Identificativo json=JSON html.class=fas fa-at html.title=webauthn webAuthnDeviceCredentials=Dispositivi Credenziali WebAuthn +expirationDate=Scadenza +recordDate=Memorizzazione +mfaTrustedDevices=Dispositivi MFA +down.title=dispositivi mfa +down.class=fas fa-barcode diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_ja.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_ja.properties index d2fc5697f7e..a7a4938210f 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_ja.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_ja.properties @@ -37,10 +37,15 @@ secretKey=Secret Key validationCode=Validation Code scratchCodes=Scratch Codes record=Record -fo_edit.class=fab fa-usb -fo_edit.title=u2f Devices +deprovision.class=fab fa-usb +deprovision.title=u2f Devices identifier=Identifier json=JSON html.class=fas fa-at html.title=webauthn webAuthnDeviceCredentials=WebAuthn Device Credentials +expirationDate=Expiration Date +recordDate=Record Date +mfaTrustedDevices=MFA Devices +down.title=mfa devices +down.class=fas fa-barcode diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_pt_BR.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_pt_BR.properties index 8d919ed952b..623f5481b52 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_pt_BR.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_pt_BR.properties @@ -37,10 +37,15 @@ secretKey=Secret Key validationCode=Validation Code scratchCodes=Scratch Codes record=Record -fo_edit.class=fab fa-usb -fo_edit.title=u2f Devices +deprovision.class=fab fa-usb +deprovision.title=u2f Devices identifier=Identifier json=JSON html.class=fas fa-at html.title=webauthn webAuthnDeviceCredentials=WebAuthn Device Credentials +expirationDate=Expiration Date +recordDate=Record Date +mfaTrustedDevices=MFA Devices +down.title=mfa devices +down.class=fas fa-barcode diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_ru.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_ru.properties index b638d451d51..e11f42941cc 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_ru.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel_ru.properties @@ -38,10 +38,15 @@ secretKey=Secret Key validationCode=Validation Code scratchCodes=Scratch Codes record=Record -fo_edit.class=fab fa-usb -fo_edit.title=u2f Devices +deprovision.class=fab fa-usb +deprovision.title=u2f Devices identifier=Identifier json=JSON html.class=fas fa-at html.title=webauthn webAuthnDeviceCredentials=WebAuthn Device Credentials +expirationDate=Expiration Date +recordDate=Record Date +mfaTrustedDevices=MFA Devices +down.title=mfa devices +down.class=fas fa-barcode diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.properties index 625bcf3dab3..229c25a2629 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.properties @@ -58,3 +58,26 @@ attrReleasePolicy=Attribute Release Policy properties.title=Properties for ${name} type_extensions.title=properties bypassApprovalPrompt=Bypass Approval Prompt +scopes=Scopes +logo=Logo +informationUrl=Information URL +privacyUrl=Privacy URL +compose.title=username attribute provider +usernameAttributeProviderConf.title=Username Attribute Provider for ${name} +ticketExpirationPolicy=Ticket Expiration Policy +auditHistory.title=Configuration history +logoutType=Logout Type +jwks=JWKS +jwksUri=JWKS URI +tokenEndpointAuthenticationMethod=Token Endpoint Authentication Method +generateRefreshToken=Generate Refresh Token +idTokenIssuer=IdToken issuer +idTokenSigningAlg=IdToken signing algorithm +encryptIdToken=Encrypt IdToken +idTokenEncryptionAlg=IdToken encryption algorithm +idTokenEncryptionEncoding=IdToken encryption encoding +applicationType=Application Type +userInfoSigningAlg=UserInfo Signing Algorithm +userInfoEncryptedResponseAlg=UserInfo Encrypted Response Algorithm +userInfoEncryptedResponseEncoding=UserInfo Encrypted Response Encoding +evaluationOrder=Evaluation Order diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_fr_CA.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_fr_CA.properties index b90f283f438..b8f5fc87984 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_fr_CA.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_fr_CA.properties @@ -58,3 +58,26 @@ attrReleasePolicy=Attribute Release Policy properties.title=Properties for ${name} type_extensions.title=properties bypassApprovalPrompt=Bypass Approval Prompt +scopes=Scopes +logo=Logo +informationUrl=Information URL +privacyUrl=Privacy URL +compose.title=username attribute provider +usernameAttributeProviderConf.title=Username Attribute Provider for ${name} +ticketExpirationPolicy=Ticket Expiration Policy +auditHistory.title=Historique de configuration +logoutType=Logout Type +jwks=JWKS +jwksUri=JWKS URI +tokenEndpointAuthenticationMethod=Token Endpoint Authentication Method +generateRefreshToken=Generate Refresh Token +idTokenIssuer=IdToken issuer +idTokenSigningAlg=IdToken signing algorithm +encryptIdToken=Encrypt IdToken +idTokenEncryptionAlg=IdToken encryption algorithm +idTokenEncryptionEncoding=IdToken encryption encoding +applicationType=Application Type +userInfoSigningAlg=UserInfo Signing Algorithm +userInfoEncryptedResponseAlg=UserInfo Encrypted Response Algorithm +userInfoEncryptedResponseEncoding=UserInfo Encrypted Response Encoding +evaluationOrder=Evaluation Order diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_it.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_it.properties index d280a11c3c3..90bfaf968a8 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_it.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_it.properties @@ -58,3 +58,26 @@ attrReleasePolicy=Politica Rilascio Attributi properties.title=Propriet\u00e0 di ${name} type_extensions.title=propriet\u00e0 bypassApprovalPrompt=Salta richiesta approvazione +scopes=Scope +logo=Logo +informationUrl=URL informativa +privacyUrl=URL privacy +compose.title=username attribute provider +usernameAttributeProviderConf.title=Username Attribute Provider per ${name} +ticketExpirationPolicy=Politica Ticket Expiration +auditHistory.title=Storico delle configurazioni +logoutType=Tipo Logout +jwks=JWKS +jwksUri=JWKS URI +tokenEndpointAuthenticationMethod=Metodo di autenticazione dell'endpoint token +generateRefreshToken=Genera Refresh Token +idTokenIssuer=IdToken issuer +idTokenSigningAlg=Algoritmo di firma IdToken +encryptIdToken=Cifra IdToken +idTokenEncryptionAlg=Algoritmo di cifratura IdToken +idTokenEncryptionEncoding=Codifica di cifratura IdToken +applicationType=Tipo applicazione +userInfoSigningAlg=Algoritmo di firma UserInfo +userInfoEncryptedResponseAlg=Algoritmo di cifratura risposta UserInfo +userInfoEncryptedResponseEncoding=Codifica di cifratura risposta UserInfo +evaluationOrder=Ordine di valutazione diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ja.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ja.properties index d3d1364c84b..428c4dce872 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ja.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ja.properties @@ -58,3 +58,26 @@ attrReleasePolicy=Attribute Release Policy properties.title=Properties for ${name} type_extensions.title=properties bypassApprovalPrompt=Bypass Approval Prompt +scopes=Scopes +logo=Logo +informationUrl=Information URL +privacyUrl=Privacy URL +compose.title=username attribute provider +usernameAttributeProviderConf.title=Username Attribute Provider for ${name} +ticketExpirationPolicy=Ticket Expiration Policy +auditHistory.title=\u8a2d\u5b9a\u5c65\u6b74 +logoutType=Logout Type +jwks=JWKS +jwksUri=JWKS URI +tokenEndpointAuthenticationMethod=Token Endpoint Authentication Method +generateRefreshToken=Generate Refresh Token +idTokenIssuer=IdToken issuer +idTokenSigningAlg=IdToken signing algorithm +encryptIdToken=Encrypt IdToken +idTokenEncryptionAlg=IdToken encryption algorithm +idTokenEncryptionEncoding=IdToken encryption encoding +applicationType=Application Type +userInfoSigningAlg=UserInfo Signing Algorithm +userInfoEncryptedResponseAlg=UserInfo Encrypted Response Algorithm +userInfoEncryptedResponseEncoding=UserInfo Encrypted Response Encoding +evaluationOrder=Evaluation Order diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_pt_BR.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_pt_BR.properties index 625bcf3dab3..54383631234 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_pt_BR.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_pt_BR.properties @@ -58,3 +58,26 @@ attrReleasePolicy=Attribute Release Policy properties.title=Properties for ${name} type_extensions.title=properties bypassApprovalPrompt=Bypass Approval Prompt +scopes=Scopes +logo=Logo +informationUrl=Information URL +privacyUrl=Privacy URL +compose.title=username attribute provider +usernameAttributeProviderConf.title=Username Attribute Provider for ${name} +ticketExpirationPolicy=Ticket Expiration Policy +auditHistory.title=Hist\u00f3rico de configura\u00e7\u00e3o +logoutType=Logout Type +jwks=JWKS +jwksUri=JWKS URI +tokenEndpointAuthenticationMethod=Token Endpoint Authentication Method +generateRefreshToken=Generate Refresh Token +idTokenIssuer=IdToken issuer +idTokenSigningAlg=IdToken signing algorithm +encryptIdToken=Encrypt IdToken +idTokenEncryptionAlg=IdToken encryption algorithm +idTokenEncryptionEncoding=IdToken encryption encoding +applicationType=Application Type +userInfoSigningAlg=UserInfo Signing Algorithm +userInfoEncryptedResponseAlg=UserInfo Encrypted Response Algorithm +userInfoEncryptedResponseEncoding=UserInfo Encrypted Response Encoding +evaluationOrder=Evaluation Order diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ru.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ru.properties index 47b953f7518..09307c88255 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ru.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ru.properties @@ -59,3 +59,26 @@ attrReleasePolicy=Attribute Release Policy properties.title=Properties for ${name} type_extensions.title=properties bypassApprovalPrompt=Bypass Approval Prompt +scopes=Scopes +logo=Logo +informationUrl=Information URL +privacyUrl=Privacy URL +compose.title=username attribute provider +usernameAttributeProviderConf.title=Username Attribute Provider for ${name} +ticketExpirationPolicy=Ticket Expiration Policy +auditHistory.title=\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 +logoutType=Logout Type +jwks=JWKS +jwksUri=JWKS URI +tokenEndpointAuthenticationMethod=Token Endpoint Authentication Method +generateRefreshToken=Generate Refresh Token +idTokenIssuer=IdToken issuer +idTokenSigningAlg=IdToken signing algorithm +encryptIdToken=Encrypt IdToken +idTokenEncryptionAlg=IdToken encryption algorithm +idTokenEncryptionEncoding=IdToken encryption encoding +applicationType=Application Type +userInfoSigningAlg=UserInfo Signing Algorithm +userInfoEncryptedResponseAlg=UserInfo Encrypted Response Algorithm +userInfoEncryptedResponseEncoding=UserInfo Encrypted Response Encoding +evaluationOrder=Evaluation Order diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/UsernameAttributeProviderModalPanelBuilder$Profile.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/UsernameAttributeProviderModalPanelBuilder$Profile.html new file mode 100644 index 00000000000..d86e0019271 --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/UsernameAttributeProviderModalPanelBuilder$Profile.html @@ -0,0 +1,24 @@ + + + +
[conf]
+ +
+ diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA.html index a0f621f461e..3a3a410e40f 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA.html +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA.html @@ -45,5 +45,7 @@ + +
[modal]
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA.properties index 10acef86896..cdd3184c2bf 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA.properties @@ -22,3 +22,5 @@ sessions=Sessions authProfiles=Profiles push=Push attrRepos=Attribute Repositories +push.options=WA Push Options +submit=Push diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_fr_CA.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_fr_CA.properties index 10acef86896..cdd3184c2bf 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_fr_CA.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_fr_CA.properties @@ -22,3 +22,5 @@ sessions=Sessions authProfiles=Profiles push=Push attrRepos=Attribute Repositories +push.options=WA Push Options +submit=Push diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_it.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_it.properties index 7cb10b56f33..672aa66750e 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_it.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_it.properties @@ -22,3 +22,5 @@ sessions=Sessioni authProfiles=Profili push=Applica attrRepos=Depositi di Attributi +push.options=Applica a WA +submit=Applica diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_ja.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_ja.properties index 10acef86896..cdd3184c2bf 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_ja.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_ja.properties @@ -22,3 +22,5 @@ sessions=Sessions authProfiles=Profiles push=Push attrRepos=Attribute Repositories +push.options=WA Push Options +submit=Push diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_pt_BR.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_pt_BR.properties index 10acef86896..cdd3184c2bf 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_pt_BR.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_pt_BR.properties @@ -22,3 +22,5 @@ sessions=Sessions authProfiles=Profiles push=Push attrRepos=Attribute Repositories +push.options=WA Push Options +submit=Push diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_ru.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_ru.properties index 10acef86896..cdd3184c2bf 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_ru.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/pages/WA_ru.properties @@ -22,3 +22,5 @@ sessions=Sessions authProfiles=Profiles push=Push attrRepos=Attribute Repositories +push.options=WA Push Options +submit=Push diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel.properties index e819d53fc0b..d8bd31d7d06 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel.properties @@ -21,3 +21,4 @@ description=Description type=Type state=State order=Order +auditHistory.title=Configuration history diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_fr_CA.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_fr_CA.properties index e0e06db5c0a..8b6d0f09884 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_fr_CA.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_fr_CA.properties @@ -21,3 +21,4 @@ description=Description type=Type state=State order=Order +auditHistory.title=Historique de configuration diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_it.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_it.properties index 26c3438fd6d..1af05b62705 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_it.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_it.properties @@ -21,3 +21,5 @@ description=Descrizione type=Tipo state=Stato order=Ordinamento +auditHistory.title=Storico delle configurazioni + diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_ja.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_ja.properties index 3fe7748112f..3f46882e28f 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_ja.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_ja.properties @@ -21,3 +21,4 @@ description=Description type=Type state=State order=Order +auditHistory.title=\u8a2d\u5b9a\u5c65\u6b74 diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_pt_BR.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_pt_BR.properties index ad1a3f9640a..f0b9ac63fd4 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_pt_BR.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_pt_BR.properties @@ -21,3 +21,4 @@ description=Description type=Type state=State order=Order +auditHistory.title=Hist\u00f3rico de configura\u00e7\u00e3o diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_ru.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_ru.properties index 63cbbc9cfc5..5c45daf43ff 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_ru.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AttrRepoDirectoryPanel_ru.properties @@ -22,3 +22,4 @@ description=Description type=Type state=State order=Order +auditHistory.title=\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel.properties index b687db478f4..610c4ed6fde 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel.properties @@ -21,3 +21,4 @@ description=Description type=Type state=State order=Order +menu.history=Configuration history diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_fr_CA.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_fr_CA.properties index 8d286a176da..9ba36d0c21e 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_fr_CA.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_fr_CA.properties @@ -21,3 +21,4 @@ description=Description type=Type state=State order=Order +auditHistory.title=Historique de configuration diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_it.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_it.properties index c122cc5d98f..505b2c819d7 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_it.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_it.properties @@ -21,3 +21,5 @@ description=Descrizione type=Tipo state=Stato order=Ordinamento +auditHistory.title=Storico delle configurazioni + diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_ja.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_ja.properties index 60da8670c22..2bc655597e0 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_ja.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_ja.properties @@ -21,3 +21,4 @@ description=Description type=Type state=State order=Order +auditHistory.title=\u8a2d\u5b9a\u5c65\u6b74 diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_pt_BR.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_pt_BR.properties index 0f1790ab08f..8ec55efe7b1 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_pt_BR.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_pt_BR.properties @@ -21,3 +21,4 @@ description=Description type=Type state=State order=Order +auditHistory.title=Hist\u00f3rico de configura\u00e7\u00e3o diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_ru.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_ru.properties index f87847bcab6..18490680b24 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_ru.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/AuthModuleDirectoryPanel_ru.properties @@ -22,3 +22,4 @@ description=Description type=Type state=State order=Order +auditHistory.title=\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC.html index e95ce63322d..0e34db86e3f 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC.html +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDC.html @@ -49,6 +49,7 @@

Well-Known URI

+
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDCJWKSGenerationPanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDCJWKSGenerationPanel.html new file mode 100644 index 00000000000..cce9c66bf52 --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/OIDCJWKSGenerationPanel.html @@ -0,0 +1,27 @@ + + + +
+ + + +
+
+ diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel.html new file mode 100644 index 00000000000..d19dcc5a654 --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel.html @@ -0,0 +1,26 @@ + + + +
+ + +
+
+ diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/reports/ReportTemplateDirectoryPanel.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel.properties similarity index 88% rename from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/reports/ReportTemplateDirectoryPanel.properties rename to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel.properties index f1464667806..1c6402c1a5c 100644 --- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/reports/ReportTemplateDirectoryPanel.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel.properties @@ -14,8 +14,8 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -any.edit=Edit ${key} -any.new=New report template -any.finish=Submit -any.cancel=Cancel -text.title=csv +# +services=WA instances +subject=Push Subject +conf=Full Configuration +clientApps=Client Applications diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/reports/ReportletDirectoryPanel.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_fr_CA.properties similarity index 88% rename from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/reports/ReportletDirectoryPanel.properties rename to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_fr_CA.properties index d3e5cde376a..1c6402c1a5c 100644 --- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/reports/ReportletDirectoryPanel.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_fr_CA.properties @@ -14,7 +14,8 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -reportlet=Reportlet -profile=Profile -configuration=Configuration -noConf=No configuration available +# +services=WA instances +subject=Push Subject +conf=Full Configuration +clientApps=Client Applications diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_it.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_it.properties new file mode 100644 index 00000000000..e35d265472b --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_it.properties @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +services=Istanze di WA +subject=Oggetto +conf=Configurazione Completa +clientApps=Applicazioni Client diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/reports/ReportletDirectoryPanel_it.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_ja.properties similarity index 88% rename from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/reports/ReportletDirectoryPanel_it.properties rename to client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_ja.properties index 96bcb850f78..1c6402c1a5c 100644 --- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/reports/ReportletDirectoryPanel_it.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_ja.properties @@ -14,7 +14,8 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -reportlet=Reportlet -profile=Profilo -configuration=Configurazione -noConf=Nessuna configurazione +# +services=WA instances +subject=Push Subject +conf=Full Configuration +clientApps=Client Applications diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_pt_BR.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_pt_BR.properties new file mode 100644 index 00000000000..1c6402c1a5c --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_pt_BR.properties @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +services=WA instances +subject=Push Subject +conf=Full Configuration +clientApps=Client Applications diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_ru.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_ru.properties new file mode 100644 index 00000000000..1c6402c1a5c --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/WAPushModalPanel_ru.properties @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +services=WA instances +subject=Push Subject +conf=Full Configuration +clientApps=Client Applications diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel.html new file mode 100644 index 00000000000..793de99af09 --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel.html @@ -0,0 +1,23 @@ + + + + + + diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel.properties new file mode 100644 index 00000000000..33143bb412c --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel.properties @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +order=Order +ssoEnabled=SSO Enabled +enabled=Enabled +requireAllAttributes=Require All Attributes +caseInsensitive=Case Insensitive +ipAddress=IP Address +userAgent=User Agent +endpointUrl=Endpoint URL +start=Start +end=End +zoneId=Zone Id +requiredAttrs=Required Attributes +rejectedAttrs=Rejected Attributes diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_fr.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_fr.properties new file mode 100644 index 00000000000..33143bb412c --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_fr.properties @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +order=Order +ssoEnabled=SSO Enabled +enabled=Enabled +requireAllAttributes=Require All Attributes +caseInsensitive=Case Insensitive +ipAddress=IP Address +userAgent=User Agent +endpointUrl=Endpoint URL +start=Start +end=End +zoneId=Zone Id +requiredAttrs=Required Attributes +rejectedAttrs=Rejected Attributes diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_it.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_it.properties new file mode 100644 index 00000000000..7801c64fb8e --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_it.properties @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +order=Ordinamento +ssoEnabled=SSO Abilitato +enabled=Abilitata +requireAllAttributes=Richiedi Tutti gli Attributi +caseInsensitive=Case Insensitive +ipAddress=Indirizzo IP +userAgent=User Agent +endpointUrl=URL Endpoint +start=Inizio +end=Fine +zoneId=Zone Id +requiredAttrs=Attibuti Richiesti +rejectedAttrs=Attributi Rifiutati diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_ja.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_ja.properties new file mode 100644 index 00000000000..33143bb412c --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_ja.properties @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +order=Order +ssoEnabled=SSO Enabled +enabled=Enabled +requireAllAttributes=Require All Attributes +caseInsensitive=Case Insensitive +ipAddress=IP Address +userAgent=User Agent +endpointUrl=Endpoint URL +start=Start +end=End +zoneId=Zone Id +requiredAttrs=Required Attributes +rejectedAttrs=Rejected Attributes diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_pt_BR.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_pt_BR.properties new file mode 100644 index 00000000000..33143bb412c --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_pt_BR.properties @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +order=Order +ssoEnabled=SSO Enabled +enabled=Enabled +requireAllAttributes=Require All Attributes +caseInsensitive=Case Insensitive +ipAddress=IP Address +userAgent=User Agent +endpointUrl=Endpoint URL +start=Start +end=End +zoneId=Zone Id +requiredAttrs=Required Attributes +rejectedAttrs=Rejected Attributes diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_ru.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_ru.properties new file mode 100644 index 00000000000..33143bb412c --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AccessPolicyModalPanel_ru.properties @@ -0,0 +1,29 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +order=Order +ssoEnabled=SSO Enabled +enabled=Enabled +requireAllAttributes=Require All Attributes +caseInsensitive=Case Insensitive +ipAddress=IP Address +userAgent=User Agent +endpointUrl=Endpoint URL +start=Start +end=End +zoneId=Zone Id +requiredAttrs=Required Attributes +rejectedAttrs=Rejected Attributes diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AttrReleasePolicyModalPanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AttrReleasePolicyModalPanel.html index aa0da3f6f61..38daa422e49 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AttrReleasePolicyModalPanel.html +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AttrReleasePolicyModalPanel.html @@ -18,6 +18,9 @@ --> +
+ +
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AuthPolicyModalPanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AuthPolicyModalPanel.html index b71bbf3fe21..b5923fc5df6 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AuthPolicyModalPanel.html +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/AuthPolicyModalPanel.html @@ -24,5 +24,17 @@
+
+ +
+
+ +
+
+ +
+
+ +
diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/TicketExpirationPolicyModalPanel.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/TicketExpirationPolicyModalPanel.html new file mode 100644 index 00000000000..7416cfa810b --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/policies/TicketExpirationPolicyModalPanel.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP.html similarity index 100% rename from client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP.html rename to client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP.html diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP.properties similarity index 100% rename from client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP.properties rename to client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP.properties diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP_fr_CA.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP_fr_CA.properties similarity index 100% rename from client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP_fr_CA.properties rename to client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP_fr_CA.properties diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP_it.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP_it.properties similarity index 100% rename from client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP_it.properties rename to client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP_it.properties diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP_ja.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP_ja.properties similarity index 100% rename from client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP_ja.properties rename to client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP_ja.properties diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP_pt_BR.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP_pt_BR.properties similarity index 100% rename from client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP_pt_BR.properties rename to client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP_pt_BR.properties diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP_ru.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP_ru.properties similarity index 100% rename from client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$GoogleMfaAuthModuleConfLDAP_ru.properties rename to client/am/console/src/main/resources/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder$AuthModuleConfLDAP_ru.properties diff --git a/client/am/enduser/pom.xml b/client/am/enduser/pom.xml new file mode 100644 index 00000000000..16427dd2421 --- /dev/null +++ b/client/am/enduser/pom.xml @@ -0,0 +1,84 @@ + + + + + 4.0.0 + + + org.apache.syncope.client + syncope-client-am + 3.0.17-SNAPSHOT + + + Apache Syncope Client AM Enduser + Apache Syncope Client AM Enduser + org.apache.syncope.client.am + syncope-client-am-enduser + jar + + + ${basedir}/../../.. + + + + + jakarta.servlet + jakarta.servlet-api + provided + + + + org.apache.syncope.client.idrepo + syncope-client-idrepo-enduser + ${project.version} + + + org.apache.syncope.client.am + syncope-client-am-lib + ${project.version} + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + + + + src/main/resources + true + + org/apache/syncope/**/*.properties + + + + src/main/resources + false + + org/apache/syncope/**/*.properties + + + + + diff --git a/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/AMEnduserContext.java b/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/AMEnduserContext.java new file mode 100644 index 00000000000..3b840e520fd --- /dev/null +++ b/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/AMEnduserContext.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.enduser; + +import org.apache.syncope.client.enduser.rest.AuthProfileRestClient; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +public class AMEnduserContext { + + @ConditionalOnMissingBean + @Bean + public AuthProfileRestClient authProfileRestClient() { + return new AuthProfileRestClient(); + } +} diff --git a/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/pages/AuthProfile.java b/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/pages/AuthProfile.java new file mode 100644 index 00000000000..6446c112610 --- /dev/null +++ b/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/pages/AuthProfile.java @@ -0,0 +1,219 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.enduser.pages; + +import java.util.List; +import java.util.stream.Collectors; +import org.apache.syncope.client.enduser.rest.AuthProfileRestClient; +import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.annotations.AMPage; +import org.apache.syncope.client.ui.commons.markup.html.form.IndicatingOnConfirmAjaxLink; +import org.apache.syncope.common.lib.to.AuthProfileTO; +import org.apache.syncope.common.lib.wa.GoogleMfaAuthAccount; +import org.apache.syncope.common.lib.wa.GoogleMfaAuthToken; +import org.apache.syncope.common.lib.wa.ImpersonationAccount; +import org.apache.syncope.common.lib.wa.MfaTrustedDevice; +import org.apache.syncope.common.lib.wa.WebAuthnDeviceCredential; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigator; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.markup.repeater.data.DataView; +import org.apache.wicket.markup.repeater.data.ListDataProvider; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; + +@AMPage(label = "Auth Profile", icon = "fa fa-passport", listEntitlement = "") +public class AuthProfile extends BaseReauthPage { + + private static final long serialVersionUID = -3147262161518280928L; + + protected static final String AUTH_PROFILE = "page.authProfile"; + + protected static final int ROWS_PER_PAGE = 5; + + @SpringBean + protected AuthProfileRestClient restClient; + + public AuthProfile(final PageParameters parameters) { + super(parameters, AUTH_PROFILE); + + AuthProfileTO authProfile = restClient.read(); + + WebMarkupContainer container = new WebMarkupContainer("content"); + contentWrapper.add(container.setOutputMarkupId(true)); + + DataView impersonationAccounts = new DataView<>( + "impersonationAccounts", new ListDataProvider<>( + authProfile == null ? List.of() : authProfile.getImpersonationAccounts())) { + + private static final long serialVersionUID = 6127875313385810666L; + + @Override + public void populateItem(final Item item) { + item.add(new Label("impersonated", item.getModelObject().getImpersonated())); + item.add(new IndicatingOnConfirmAjaxLink<>( + "impersonationAccountDelete", Constants.CONFIRM_DELETE, true) { + + private static final long serialVersionUID = 1632838687547839512L; + + @Override + public void onClick(final AjaxRequestTarget target) { + if (authProfile != null) { + authProfile.getImpersonationAccounts().remove(item.getModelObject()); + restClient.update(authProfile); + target.add(container); + } + } + }); + } + }; + impersonationAccounts.setItemsPerPage(ROWS_PER_PAGE); + container.add(impersonationAccounts.setOutputMarkupPlaceholderTag(true)); + container.add(new AjaxPagingNavigator("impersonationAccountsNavigator", impersonationAccounts)); + + DataView googleMfaAuthTokens = new DataView<>( + "googleMfaAuthTokens", new ListDataProvider<>( + authProfile == null ? List.of() : authProfile.getGoogleMfaAuthTokens())) { + + private static final long serialVersionUID = 6127875313385810666L; + + @Override + public void populateItem(final Item item) { + item.add(new Label("otp", item.getModelObject().getOtp())); + item.add(new Label("issueDate", item.getModelObject().getIssueDate())); + item.add(new IndicatingOnConfirmAjaxLink<>( + "googleMfaAuthTokenDelete", Constants.CONFIRM_DELETE, true) { + + private static final long serialVersionUID = 1632838687547839512L; + + @Override + public void onClick(final AjaxRequestTarget target) { + if (authProfile != null) { + authProfile.getGoogleMfaAuthTokens().remove(item.getModelObject()); + restClient.update(authProfile); + target.add(container); + } + } + }); + } + }; + googleMfaAuthTokens.setItemsPerPage(ROWS_PER_PAGE); + container.add(googleMfaAuthTokens.setOutputMarkupPlaceholderTag(true)); + container.add(new AjaxPagingNavigator("googleMfaAuthTokensNavigator", googleMfaAuthTokens)); + + DataView googleMfaAuthAccounts = new DataView<>( + "googleMfaAuthAccounts", new ListDataProvider<>( + authProfile == null ? List.of() : authProfile.getGoogleMfaAuthAccounts())) { + + private static final long serialVersionUID = 6127875313385810666L; + + @Override + public void populateItem(final Item item) { + item.add(new Label("id", item.getModelObject().getId())); + item.add(new Label("name", item.getModelObject().getName())); + item.add(new Label("secretKey", item.getModelObject().getSecretKey())); + item.add(new Label("validationCode", item.getModelObject().getValidationCode())); + item.add(new Label("scratchCodes", item.getModelObject().getScratchCodes().stream(). + map(String::valueOf).collect(Collectors.joining(", ")))); + item.add(new Label("registrationDate", item.getModelObject().getRegistrationDate())); + item.add(new IndicatingOnConfirmAjaxLink<>( + "googleMfaAuthAccountDelete", Constants.CONFIRM_DELETE, true) { + + private static final long serialVersionUID = 1632838687547839512L; + + @Override + public void onClick(final AjaxRequestTarget target) { + if (authProfile != null) { + authProfile.getGoogleMfaAuthAccounts().remove(item.getModelObject()); + restClient.update(authProfile); + target.add(container); + } + } + }); + } + }; + googleMfaAuthAccounts.setItemsPerPage(ROWS_PER_PAGE); + container.add(googleMfaAuthAccounts.setOutputMarkupPlaceholderTag(true)); + container.add(new AjaxPagingNavigator("googleMfaAuthAccountsNavigator", googleMfaAuthAccounts)); + + DataView mfaTrustedDevices = new DataView<>( + "mfaTrustedDevices", new ListDataProvider<>( + authProfile == null ? List.of() : authProfile.getMfaTrustedDevices())) { + + private static final long serialVersionUID = 6127875313385810666L; + + @Override + public void populateItem(final Item item) { + item.add(new Label("id", item.getModelObject().getId())); + item.add(new Label("name", item.getModelObject().getName())); + item.add(new Label("deviceFingerprint", item.getModelObject().getDeviceFingerprint())); + item.add(new Label("recordDate", item.getModelObject().getRecordDate())); + item.add(new Label("expirationDate", item.getModelObject().getExpirationDate())); + item.add(new IndicatingOnConfirmAjaxLink<>( + "mfaTrustedDeviceDelete", Constants.CONFIRM_DELETE, true) { + + private static final long serialVersionUID = 1632838687547839512L; + + @Override + public void onClick(final AjaxRequestTarget target) { + if (authProfile != null) { + authProfile.getMfaTrustedDevices().remove(item.getModelObject()); + restClient.update(authProfile); + target.add(container); + } + } + }); + } + }; + mfaTrustedDevices.setItemsPerPage(ROWS_PER_PAGE); + container.add(mfaTrustedDevices.setOutputMarkupPlaceholderTag(true)); + container.add(new AjaxPagingNavigator("mfaTrustedDevicesNavigator", mfaTrustedDevices)); + + DataView webAuthnDeviceCredentials = new DataView<>( + "webAuthnDeviceCredentials", new ListDataProvider<>( + authProfile == null ? List.of() : authProfile.getWebAuthnDeviceCredentials())) { + + private static final long serialVersionUID = 6127875313385810666L; + + @Override + public void populateItem(final Item item) { + item.add(new Label("identifier", item.getModelObject().getIdentifier())); + item.add(new IndicatingOnConfirmAjaxLink<>( + "webAuthnDeviceCredentialDelete", Constants.CONFIRM_DELETE, true) { + + private static final long serialVersionUID = 1632838687547839512L; + + @Override + public void onClick(final AjaxRequestTarget target) { + if (authProfile != null) { + authProfile.getWebAuthnDeviceCredentials().remove(item.getModelObject()); + restClient.update(authProfile); + target.add(container); + } + } + }); + } + }; + webAuthnDeviceCredentials.setItemsPerPage(ROWS_PER_PAGE); + container.add(webAuthnDeviceCredentials.setOutputMarkupPlaceholderTag(true)); + container.add(new AjaxPagingNavigator("webAuthnDeviceCredentialsNavigator", webAuthnDeviceCredentials)); + } +} diff --git a/ext/flowable/client-enduser/src/main/java/org/apache/syncope/client/enduser/markup/html/form/BpmnProcessesAjaxPanel.java b/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/rest/AuthProfileRestClient.java similarity index 52% rename from ext/flowable/client-enduser/src/main/java/org/apache/syncope/client/enduser/markup/html/form/BpmnProcessesAjaxPanel.java rename to client/am/enduser/src/main/java/org/apache/syncope/client/enduser/rest/AuthProfileRestClient.java index 7ad531d8886..2714954ff59 100644 --- a/ext/flowable/client-enduser/src/main/java/org/apache/syncope/client/enduser/markup/html/form/BpmnProcessesAjaxPanel.java +++ b/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/rest/AuthProfileRestClient.java @@ -16,27 +16,29 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.client.enduser.markup.html.form; +package org.apache.syncope.client.enduser.rest; -import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; -import org.apache.wicket.behavior.Behavior; -import org.apache.wicket.model.IModel; +import org.apache.syncope.common.lib.to.AuthProfileTO; +import org.apache.syncope.common.rest.api.service.AuthProfileSelfService; -public class BpmnProcessesAjaxPanel extends AjaxTextFieldPanel { +public class AuthProfileRestClient extends BaseRestClient { - private static final long serialVersionUID = 9082907182704884397L; + private static final long serialVersionUID = 4139153766778113329L; - public BpmnProcessesAjaxPanel( - final String id, final String name, final IModel model) { - this(id, name, model, null); + public AuthProfileTO read() { + try { + return getService(AuthProfileSelfService.class).read(); + } catch (Exception e) { + LOG.debug("While attempting to read the auth profile", e); + return null; + } } - public BpmnProcessesAjaxPanel( - final String id, final String name, final IModel model, final Behavior behavior) { - super(id, name, model, false); - if (behavior != null) { - field.add(behavior); - } + public void update(final AuthProfileTO authProfile) { + getService(AuthProfileSelfService.class).update(authProfile); } + public void delete() { + getService(AuthProfileSelfService.class).delete(); + } } diff --git a/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile.html b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile.html new file mode 100644 index 00000000000..6c748cbacb1 --- /dev/null +++ b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile.html @@ -0,0 +1,255 @@ + + + + +
+
+
+
+
+
+

+
+
+
+
+ +
+
+
+
+
+ + + + + + + + + + + + + +
+ +
+ + + + + + +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ + + + + + + + + + + + + +
+ +
+ + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+ diff --git a/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile.properties b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile.properties new file mode 100644 index 00000000000..4caaab9284e --- /dev/null +++ b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile.properties @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +page.authProfile=Auth Profile +impersonation.accounts.title=Impersonation Accounts +google.mfa.authtokens.title=Google MFA Tokens +google.mfa.authaccounts.title=Google MFA Accounts +mfa.trusted.devices.title=MFA Trusted Devices +webauthn.device.credentials.title=WebAuthn Device Credentials +otp=OTP +issueDate=Issue Date +impersonated=Impersonated +id=Id +name=Name +secretKey=Secret Key +validationCode=Validation Code +scratchCodes=Scratch Codes +registrationDate=Registration Date +deviceFingerprint=Fingerprint +recordDate=Record Date +expirationDate=Expiration Date diff --git a/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_it.properties b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_it.properties new file mode 100644 index 00000000000..ae0822ff627 --- /dev/null +++ b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_it.properties @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +page.authProfile=Auth Profile +impersonation.accounts.title=Account di impersonificazione +google.mfa.authtokens.title=Token MFA Google +google.mfa.authaccounts.title=Account MFA Google +mfa.trusted.devices.title=Dispositivi MFA +webauthn.device.credentials.title=Credenziali dispositivi WebAuthn +otp=OTP +issueDate=Data di emissione +impersonated=Impersonificato +id=Id +name=Nome +secretKey=Chiave segreta +validationCode=Codice di validazione +scratchCodes=Codici Scratch +registrationDate=Data di registrazione +deviceFingerprint=Fingerprint +recordDate=Data di registrazione +expirationDate=Data di scadenza diff --git a/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_ja.properties b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_ja.properties new file mode 100644 index 00000000000..4caaab9284e --- /dev/null +++ b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_ja.properties @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +page.authProfile=Auth Profile +impersonation.accounts.title=Impersonation Accounts +google.mfa.authtokens.title=Google MFA Tokens +google.mfa.authaccounts.title=Google MFA Accounts +mfa.trusted.devices.title=MFA Trusted Devices +webauthn.device.credentials.title=WebAuthn Device Credentials +otp=OTP +issueDate=Issue Date +impersonated=Impersonated +id=Id +name=Name +secretKey=Secret Key +validationCode=Validation Code +scratchCodes=Scratch Codes +registrationDate=Registration Date +deviceFingerprint=Fingerprint +recordDate=Record Date +expirationDate=Expiration Date diff --git a/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_pt_BR.properties b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_pt_BR.properties new file mode 100644 index 00000000000..4caaab9284e --- /dev/null +++ b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_pt_BR.properties @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +page.authProfile=Auth Profile +impersonation.accounts.title=Impersonation Accounts +google.mfa.authtokens.title=Google MFA Tokens +google.mfa.authaccounts.title=Google MFA Accounts +mfa.trusted.devices.title=MFA Trusted Devices +webauthn.device.credentials.title=WebAuthn Device Credentials +otp=OTP +issueDate=Issue Date +impersonated=Impersonated +id=Id +name=Name +secretKey=Secret Key +validationCode=Validation Code +scratchCodes=Scratch Codes +registrationDate=Registration Date +deviceFingerprint=Fingerprint +recordDate=Record Date +expirationDate=Expiration Date diff --git a/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_ru.properties b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_ru.properties new file mode 100644 index 00000000000..4caaab9284e --- /dev/null +++ b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_ru.properties @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +page.authProfile=Auth Profile +impersonation.accounts.title=Impersonation Accounts +google.mfa.authtokens.title=Google MFA Tokens +google.mfa.authaccounts.title=Google MFA Accounts +mfa.trusted.devices.title=MFA Trusted Devices +webauthn.device.credentials.title=WebAuthn Device Credentials +otp=OTP +issueDate=Issue Date +impersonated=Impersonated +id=Id +name=Name +secretKey=Secret Key +validationCode=Validation Code +scratchCodes=Scratch Codes +registrationDate=Registration Date +deviceFingerprint=Fingerprint +recordDate=Record Date +expirationDate=Expiration Date diff --git a/client/am/lib/pom.xml b/client/am/lib/pom.xml index 31a0d450575..398266a65de 100644 --- a/client/am/lib/pom.xml +++ b/client/am/lib/pom.xml @@ -24,7 +24,7 @@ under the License. org.apache.syncope.client syncope-client-am - 3.0.1-SNAPSHOT + 3.0.17-SNAPSHOT Apache Syncope Client AM Lib diff --git a/client/am/pom.xml b/client/am/pom.xml index 8a66991e835..6eb708e9da8 100644 --- a/client/am/pom.xml +++ b/client/am/pom.xml @@ -24,7 +24,7 @@ under the License. org.apache.syncope syncope-client - 3.0.1-SNAPSHOT + 3.0.17-SNAPSHOT Apache Syncope Client AM @@ -40,5 +40,6 @@ under the License. lib console + enduser diff --git a/client/idm/console/pom.xml b/client/idm/console/pom.xml index 25a71b7b0fd..c1cddd42aba 100644 --- a/client/idm/console/pom.xml +++ b/client/idm/console/pom.xml @@ -24,7 +24,7 @@ under the License. org.apache.syncope.client syncope-client-idm - 3.0.1-SNAPSHOT + 3.0.17-SNAPSHOT Apache Syncope Client IdM Console diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/SyncopeIdMConsoleContext.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/IdMConsoleContext.java similarity index 56% rename from client/idm/console/src/main/java/org/apache/syncope/client/console/SyncopeIdMConsoleContext.java rename to client/idm/console/src/main/java/org/apache/syncope/client/console/IdMConsoleContext.java index 38d8681e371..ae5666f6d27 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/SyncopeIdMConsoleContext.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/IdMConsoleContext.java @@ -35,12 +35,22 @@ import org.apache.syncope.client.console.commons.StatusProvider; import org.apache.syncope.client.console.commons.VirSchemaDetailsPanelProvider; import org.apache.syncope.client.console.init.ClassPathScanImplementationContributor; +import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup; import org.apache.syncope.client.console.init.IdMClassPathScanImplementationContributor; +import org.apache.syncope.client.console.rest.ConnectorRestClient; +import org.apache.syncope.client.console.rest.ImplementationRestClient; +import org.apache.syncope.client.console.rest.PolicyRestClient; +import org.apache.syncope.client.console.rest.ReconciliationRestClient; +import org.apache.syncope.client.console.rest.RemediationRestClient; +import org.apache.syncope.client.console.rest.ResourceRestClient; +import org.apache.syncope.client.console.rest.UserRestClient; +import org.apache.syncope.client.console.status.ReconStatusUtils; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) -public class SyncopeIdMConsoleContext { +public class IdMConsoleContext { @Bean public ClassPathScanImplementationContributor idmClassPathScanImplementationContributor() { @@ -48,18 +58,24 @@ public ClassPathScanImplementationContributor idmClassPathScanImplementationCont } @Bean - public ExternalResourceProvider resourceProvider() { - return new IdMExternalResourceProvider(); + public ExternalResourceProvider resourceProvider(final ResourceRestClient resourceRestClient) { + return new IdMExternalResourceProvider(resourceRestClient); } @Bean - public AnyDirectoryPanelAdditionalActionsProvider anyDirectoryPanelAdditionalActionsProvider() { - return new IdMAnyDirectoryPanelAdditionalActionsProvider(); + public AnyDirectoryPanelAdditionalActionsProvider anyDirectoryPanelAdditionalActionsProvider( + final ReconciliationRestClient reconciliationRestClient, + final ImplementationRestClient implementationRestClient) { + + return new IdMAnyDirectoryPanelAdditionalActionsProvider(reconciliationRestClient, implementationRestClient); } @Bean - public AnyDirectoryPanelAdditionalActionLinksProvider anyDirectoryPanelAdditionalActionLinksProvider() { - return new IdMAnyDirectoryPanelAdditionalActionLinksProvider(); + public AnyDirectoryPanelAdditionalActionLinksProvider anyDirectoryPanelAdditionalActionLinksProvider( + final ResourceRestClient resourceRestClient, + final UserRestClient userRestClient) { + + return new IdMAnyDirectoryPanelAdditionalActionLinksProvider(resourceRestClient, userRestClient); } @Bean @@ -68,8 +84,8 @@ public AnyWizardBuilderAdditionalSteps anyWizardBuilderAdditionalSteps() { } @Bean - public StatusProvider statusProvider() { - return new IdMStatusProvider(); + public StatusProvider statusProvider(final ReconStatusUtils reconStatusUtils) { + return new IdMStatusProvider(reconStatusUtils); } @Bean @@ -78,12 +94,44 @@ public VirSchemaDetailsPanelProvider virSchemaDetailsPanelProvider() { } @Bean - public ImplementationInfoProvider implementationInfoProvider() { - return new IdMImplementationInfoProvider(); + public ImplementationInfoProvider implementationInfoProvider( + final ClassPathScanImplementationLookup lookup, + final ImplementationRestClient implementationRestClient) { + + return new IdMImplementationInfoProvider(lookup, implementationRestClient); + } + + @Bean + public PolicyTabProvider idmPolicyTabProvider(final PolicyRestClient policyRestClient) { + return new IdMPolicyTabProvider(policyRestClient); + } + + @Bean + public ReconStatusUtils reconStatusUtils(final ReconciliationRestClient reconciliationRestClient) { + return new ReconStatusUtils(reconciliationRestClient); + } + + @ConditionalOnMissingBean + @Bean + public ConnectorRestClient connectorRestClient() { + return new ConnectorRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public ReconciliationRestClient reconciliationRestClient() { + return new ReconciliationRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public RemediationRestClient remediationRestClient() { + return new RemediationRestClient(); } + @ConditionalOnMissingBean @Bean - public PolicyTabProvider idmPolicyTabProvider() { - return new IdMPolicyTabProvider(); + public ResourceRestClient resourceRestClient() { + return new ResourceRestClient(); } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/ConnectorDataProvider.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/ConnectorDataProvider.java index 8d7f7cb3886..5a652d80ced 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/ConnectorDataProvider.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/ConnectorDataProvider.java @@ -23,13 +23,11 @@ import java.util.Comparator; import java.util.Iterator; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.pages.BasePage; import org.apache.syncope.client.console.rest.ConnectorRestClient; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.common.lib.to.ConnInstanceTO; import org.apache.wicket.PageReference; import org.apache.wicket.ajax.AjaxRequestTarget; @@ -47,13 +45,16 @@ public class ConnectorDataProvider extends DirectoryDataProvider { protected static final Logger LOG = LoggerFactory.getLogger(ConnectorDataProvider.class); - private final PageReference pageRef; + protected final ConnectorRestClient connectorRestClient; + + protected final PageReference pageRef; protected int currentPage; - private final String keyword; + protected final String keyword; public ConnectorDataProvider( + final ConnectorRestClient connectorRestClient, final int paginatorRows, final PageReference pageRef, final String keyword) { @@ -61,6 +62,7 @@ public ConnectorDataProvider( super(paginatorRows); setSort("displayNameSortParam", SortOrder.ASCENDING); + this.connectorRestClient = connectorRestClient; this.pageRef = pageRef; this.keyword = keyword; } @@ -75,9 +77,9 @@ public Iterator iterator(final long first, final long count) { currentPage = 0; } if (StringUtils.isBlank(keyword)) { - result = ConnectorRestClient.getAllConnectors(); + result = connectorRestClient.getAllConnectors(); } else { - result = ConnectorRestClient.getAllConnectors().stream(). + result = connectorRestClient.getAllConnectors().stream(). filter(conn -> conn.getDisplayName().toLowerCase().contains(keyword)). collect(Collectors.toList()); } @@ -85,8 +87,8 @@ public Iterator iterator(final long first, final long count) { LOG.error("While searching", e); SyncopeConsoleSession.get().onException(e); - Optional target = RequestCycle.get().find(AjaxRequestTarget.class); - target.ifPresent(t -> ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(t)); + RequestCycle.get().find(AjaxRequestTarget.class). + ifPresent(t -> ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(t)); } SortParam sortParam = getSort(); @@ -126,9 +128,9 @@ public long size() { try { if (StringUtils.isBlank(keyword)) { - result = ConnectorRestClient.getAllConnectors().size(); + result = connectorRestClient.getAllConnectors().size(); } else { - result = ConnectorRestClient.getAllConnectors().stream().filter(conn + result = connectorRestClient.getAllConnectors().stream().filter(conn -> conn.getDisplayName().toLowerCase().contains(keyword)).count(); } } catch (Exception e) { diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMAnyDirectoryPanelAdditionalActionLinksProvider.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMAnyDirectoryPanelAdditionalActionLinksProvider.java index 6a17806fe35..8de14437590 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMAnyDirectoryPanelAdditionalActionLinksProvider.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMAnyDirectoryPanelAdditionalActionLinksProvider.java @@ -24,14 +24,18 @@ import org.apache.syncope.client.console.panels.GroupDirectoryPanel; import org.apache.syncope.client.console.panels.LinkedAccountModalPanel; import org.apache.syncope.client.console.panels.UserDirectoryPanel; +import org.apache.syncope.client.console.rest.ResourceRestClient; import org.apache.syncope.client.console.rest.UserRestClient; import org.apache.syncope.client.console.status.AnyStatusModal; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; import org.apache.syncope.client.console.wicket.markup.html.form.Action; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; +import org.apache.syncope.client.console.wizards.any.AnyObjectWrapper; +import org.apache.syncope.client.console.wizards.any.GroupWrapper; import org.apache.syncope.client.console.wizards.any.MergeLinkedAccountsWizardBuilder; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; import org.apache.syncope.client.ui.commons.wizards.any.AnyWrapper; +import org.apache.syncope.client.ui.commons.wizards.any.UserWrapper; import org.apache.syncope.common.lib.to.AnyObjectTO; import org.apache.syncope.common.lib.to.GroupTO; import org.apache.syncope.common.lib.to.UserTO; @@ -50,6 +54,18 @@ public class IdMAnyDirectoryPanelAdditionalActionLinksProvider private static final long serialVersionUID = -1698293704237878993L; + protected final ResourceRestClient resourceRestClient; + + protected final UserRestClient userRestClient; + + public IdMAnyDirectoryPanelAdditionalActionLinksProvider( + final ResourceRestClient resourceRestClient, + final UserRestClient userRestClient) { + + this.resourceRestClient = resourceRestClient; + this.userRestClient = userRestClient; + } + @Override public List> get( final IModel model, @@ -68,7 +84,7 @@ public List> get( @Override public void onClick(final AjaxRequestTarget target, final UserTO ignore) { IModel> formModel = new CompoundPropertyModel<>( - new AnyWrapper<>(model.getObject())); + new UserWrapper(model.getObject())); modal.setFormModel(formModel); target.add(modal.setContent(new AnyStatusModal<>( @@ -93,9 +109,9 @@ public void onClick(final AjaxRequestTarget target, final UserTO ignore) { @Override public void onClick(final AjaxRequestTarget target, final UserTO ignore) { - model.setObject(new UserRestClient().read(model.getObject().getKey())); + model.setObject(userRestClient.read(model.getObject().getKey())); IModel> formModel = new CompoundPropertyModel<>( - new AnyWrapper<>(model.getObject())); + new UserWrapper(model.getObject())); modal.setFormModel(formModel); target.add(modal.setContent(new AnyStatusModal<>( @@ -121,7 +137,7 @@ public void onClick(final AjaxRequestTarget target, final UserTO ignore) { @Override public void onClick(final AjaxRequestTarget target, final UserTO ignore) { - model.setObject(new UserRestClient().read(model.getObject().getKey())); + model.setObject(userRestClient.read(model.getObject().getKey())); modal.setFooterVisible(false); target.add(modal.setContent(new LinkedAccountModalPanel(model, pageRef, false))); @@ -142,9 +158,9 @@ public void onClick(final AjaxRequestTarget target, final UserTO ignore) { @Override public void onClick(final AjaxRequestTarget target, final UserTO ignore) { - model.setObject(new UserRestClient().read(model.getObject().getKey())); - MergeLinkedAccountsWizardBuilder builder = - new MergeLinkedAccountsWizardBuilder(model, pageRef, parentPanel, modal); + model.setObject(userRestClient.read(model.getObject().getKey())); + MergeLinkedAccountsWizardBuilder builder = new MergeLinkedAccountsWizardBuilder( + model, parentPanel, modal, resourceRestClient, userRestClient, pageRef); builder.setEventSink(builder); target.add(modal.setContent(builder.build(BaseModal.CONTENT_ID, AjaxWizard.Mode.CREATE))); modal.header(new StringResourceModel("mergeLinkedAccounts.title", model)); @@ -177,7 +193,7 @@ public List> get( @Override public void onClick(final AjaxRequestTarget target, final GroupTO ignore) { IModel> formModel = new CompoundPropertyModel<>( - new AnyWrapper<>(modelObject)); + new GroupWrapper(modelObject)); modal.setFormModel(formModel); target.add(modal.setContent(new AnyStatusModal<>( @@ -218,8 +234,8 @@ public List> get( @Override public void onClick(final AjaxRequestTarget target, final AnyObjectTO ignore) { - final IModel> formModel = new CompoundPropertyModel<>( - new AnyWrapper<>(modelObject)); + IModel> formModel = new CompoundPropertyModel<>( + new AnyObjectWrapper(modelObject)); modal.setFormModel(formModel); target.add(modal.setContent(new AnyStatusModal<>( diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMAnyDirectoryPanelAdditionalActionsProvider.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMAnyDirectoryPanelAdditionalActionsProvider.java index 02f6c48cf76..d62865addc2 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMAnyDirectoryPanelAdditionalActionsProvider.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMAnyDirectoryPanelAdditionalActionsProvider.java @@ -29,6 +29,8 @@ import org.apache.syncope.client.console.panels.AnyDirectoryPanel; import org.apache.syncope.client.console.panels.DisplayAttributesModalPanel; import org.apache.syncope.client.console.rest.BaseRestClient; +import org.apache.syncope.client.console.rest.ImplementationRestClient; +import org.apache.syncope.client.console.rest.ReconciliationRestClient; import org.apache.syncope.client.console.wicket.ajax.form.AjaxDownloadBehavior; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; import org.apache.syncope.client.console.wizards.CSVPullWizardBuilder; @@ -61,6 +63,18 @@ public class IdMAnyDirectoryPanelAdditionalActionsProvider implements AnyDirecto protected AjaxLink csvPullLink; + protected final ReconciliationRestClient reconciliationRestClient; + + protected final ImplementationRestClient implementationRestClient; + + public IdMAnyDirectoryPanelAdditionalActionsProvider( + final ReconciliationRestClient reconciliationRestClient, + final ImplementationRestClient implementationRestClient) { + + this.reconciliationRestClient = reconciliationRestClient; + this.implementationRestClient = implementationRestClient; + } + @Override public void add( final AnyDirectoryPanel panel, @@ -69,7 +83,7 @@ public void add( final WebMarkupContainer container, final String type, final String realm, - final String fiql, + final Model fiql, final int rows, final List pSchemaNames, final List dSchemaNames, @@ -91,8 +105,8 @@ public void onEvent(final IEvent event) { if (payload.getResult() instanceof ArrayList) { modal.setContent(new ResultPanel<>( - null, - payload.getResult()) { + null, + payload.getResult()) { private static final long serialVersionUID = -2630573849050255233L; @@ -103,7 +117,7 @@ protected void closeAction(final AjaxRequestTarget target) { @Override protected Panel customResultBody( - final String panelId, final Serializable item, final Serializable result) { + final String panelId, final Serializable item, final Serializable result) { @SuppressWarnings("unchecked") ArrayList reports = (ArrayList) result; @@ -122,10 +136,10 @@ protected Panel customResultBody( SyncopeConsoleSession.get().error(payload.getResult()); } - if (target.isPresent()) { - ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target.get()); - target.get().add(container); - } + target.ifPresent(t -> { + ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(t); + t.add(container); + }); } } }; @@ -138,11 +152,12 @@ protected Panel customResultBody( @Override public void onClick(final AjaxRequestTarget target) { CSVPushSpec spec = csvPushSpec(type, pSchemaNames, dSchemaNames); - AnyQuery query = csvAnyQuery(realm, fiql, rows, panel.getDataProvider()); + AnyQuery query = csvAnyQuery(realm, fiql.getObject(), rows, panel.getDataProvider()); - target.add(modal.setContent(new CSVPushWizardBuilder(spec, query, csvDownloadBehavior, pageRef). - setEventSink(csvEventSink). - build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT))); + target.add(modal.setContent(new CSVPushWizardBuilder( + spec, query, csvDownloadBehavior, reconciliationRestClient, implementationRestClient, pageRef). + setEventSink(csvEventSink). + build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT))); modal.header(new StringResourceModel("csvPush", panel, Model.of(spec))); modal.show(true); @@ -160,9 +175,10 @@ public void onClick(final AjaxRequestTarget target) { public void onClick(final AjaxRequestTarget target) { CSVPullSpec spec = csvPullSpec(type, realm); - target.add(modal.setContent(new CSVPullWizardBuilder(spec, pageRef). - setEventSink(csvEventSink). - build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT))); + target.add(modal.setContent( + new CSVPullWizardBuilder(spec, reconciliationRestClient, implementationRestClient, pageRef). + setEventSink(csvEventSink). + build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT))); modal.header(new StringResourceModel("csvPull", panel, Model.of(spec))); modal.show(true); @@ -179,25 +195,21 @@ protected CSVPushSpec csvPushSpec( final List pSchemaNames, final List dSchemaNames) { - CSVPushSpec spec = new CSVPushSpec.Builder(type).build(); - spec.setFields(PreferenceManager.getList( - DisplayAttributesModalPanel.getPrefDetailView(type)). - stream().filter(name -> !Constants.KEY_FIELD_NAME.equalsIgnoreCase(name)). - collect(Collectors.toList())); - spec.setPlainAttrs(PreferenceManager.getList( - DisplayAttributesModalPanel.getPrefPlainAttributeView(type)). - stream().filter(pSchemaNames::contains).collect(Collectors.toList())); - spec.setDerAttrs(PreferenceManager.getList( - DisplayAttributesModalPanel.getPrefPlainAttributeView(type)). - stream().filter(dSchemaNames::contains).collect(Collectors.toList())); - return spec; + return new CSVPushSpec.Builder(type). + fields(PreferenceManager.getList(DisplayAttributesModalPanel.getPrefDetailView(type)). + stream().filter(name -> !Constants.KEY_FIELD_NAME.equalsIgnoreCase(name)). + collect(Collectors.toList())). + plainAttrs(PreferenceManager.getList(DisplayAttributesModalPanel.getPrefPlainAttributeView(type)). + stream().filter(pSchemaNames::contains). + collect(Collectors.toList())). + derAttrs(PreferenceManager.getList(DisplayAttributesModalPanel.getPrefPlainAttributeView(type)). + stream().filter(dSchemaNames::contains). + collect(Collectors.toList())). + build(); } protected CSVPullSpec csvPullSpec(final String type, final String realm) { - CSVPullSpec spec = new CSVPullSpec(); - spec.setAnyTypeKey(type); - spec.setDestinationRealm(realm); - return spec; + return new CSVPullSpec.Builder(type, realm).build(); } protected AnyQuery csvAnyQuery( diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMExternalResourceProvider.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMExternalResourceProvider.java index d466abe3e07..236dbeee1f6 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMExternalResourceProvider.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMExternalResourceProvider.java @@ -22,13 +22,33 @@ import java.util.stream.Collectors; import org.apache.syncope.client.console.rest.ResourceRestClient; import org.apache.syncope.common.lib.to.ResourceTO; +import org.apache.syncope.common.lib.types.AnyTypeKind; public class IdMExternalResourceProvider implements ExternalResourceProvider { private static final long serialVersionUID = 6335503820405008093L; + private final ResourceRestClient resourceRestClient; + + public IdMExternalResourceProvider(final ResourceRestClient resourceRestClient) { + this.resourceRestClient = resourceRestClient; + } + + @Override + public List get(final String anyType) { + return resourceRestClient.list().stream(). + filter(r -> anyType == null + || AnyTypeKind.GROUP.name().equals(anyType) + || r.getProvision(anyType).isPresent()). + map(ResourceTO::getKey). + collect(Collectors.toList()); + } + @Override - public List get() { - return ResourceRestClient.list().stream().map(ResourceTO::getKey).collect(Collectors.toList()); + public List getForRealms() { + return resourceRestClient.list().stream(). + filter(r -> r.getOrgUnit() != null). + map(ResourceTO::getKey). + collect(Collectors.toList()); } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMImplementationInfoProvider.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMImplementationInfoProvider.java index bb77291f98d..e4949f000ec 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMImplementationInfoProvider.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMImplementationInfoProvider.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup; import org.apache.syncope.client.console.rest.ImplementationRestClient; import org.apache.syncope.common.lib.policy.PullCorrelationRuleConf; import org.apache.syncope.common.lib.policy.PushCorrelationRuleConf; @@ -34,6 +35,13 @@ public class IdMImplementationInfoProvider extends IdRepoImplementationInfoProvi private static final long serialVersionUID = -5385695412826366167L; + public IdMImplementationInfoProvider( + final ClassPathScanImplementationLookup lookup, + final ImplementationRestClient implementationRestClient) { + + super(lookup, implementationRestClient); + } + @Override public ViewMode getViewMode(final ImplementationTO implementation) { return IdMImplementationType.PULL_CORRELATION_RULE.equals(implementation.getType()) @@ -136,8 +144,8 @@ public IModel> getReconFilterBuilders() { @Override protected List load() { - return ImplementationRestClient.list(IdMImplementationType.RECON_FILTER_BUILDER).stream(). - map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); + return implementationRestClient.list(IdMImplementationType.RECON_FILTER_BUILDER).stream(). + map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); } }; } @@ -150,8 +158,8 @@ public IModel> getPullActions() { @Override protected List load() { - return ImplementationRestClient.list(IdMImplementationType.PULL_ACTIONS).stream(). - map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); + return implementationRestClient.list(IdMImplementationType.PULL_ACTIONS).stream(). + map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); } }; } @@ -164,8 +172,8 @@ public IModel> getPushActions() { @Override protected List load() { - return ImplementationRestClient.list(IdMImplementationType.PUSH_ACTIONS).stream(). - map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); + return implementationRestClient.list(IdMImplementationType.PUSH_ACTIONS).stream(). + map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); } }; } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMPolicyTabProvider.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMPolicyTabProvider.java index 0f2b92065f2..4a38f37ec0e 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMPolicyTabProvider.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMPolicyTabProvider.java @@ -23,6 +23,7 @@ import org.apache.syncope.client.console.policies.PropagationPolicyDirectoryPanel; import org.apache.syncope.client.console.policies.PullPolicyDirectoryPanel; import org.apache.syncope.client.console.policies.PushPolicyDirectoryPanel; +import org.apache.syncope.client.console.rest.PolicyRestClient; import org.apache.wicket.PageReference; import org.apache.wicket.extensions.markup.html.tabs.AbstractTab; import org.apache.wicket.extensions.markup.html.tabs.ITab; @@ -33,9 +34,10 @@ public class IdMPolicyTabProvider implements PolicyTabProvider { private static final long serialVersionUID = 2822554006571803418L; - @Override - public int getOrder() { - return 300; + protected final PolicyRestClient policyRestClient; + + public IdMPolicyTabProvider(final PolicyRestClient policyRestClient) { + this.policyRestClient = policyRestClient; } @Override @@ -48,7 +50,7 @@ public List buildTabList(final PageReference pageRef) { @Override public Panel getPanel(final String panelId) { - return new PropagationPolicyDirectoryPanel(panelId, pageRef); + return new PropagationPolicyDirectoryPanel(panelId, policyRestClient, pageRef); } }); @@ -58,7 +60,7 @@ public Panel getPanel(final String panelId) { @Override public Panel getPanel(final String panelId) { - return new PullPolicyDirectoryPanel(panelId, pageRef); + return new PullPolicyDirectoryPanel(panelId, policyRestClient, pageRef); } }); @@ -68,7 +70,7 @@ public Panel getPanel(final String panelId) { @Override public Panel getPanel(final String panelId) { - return new PushPolicyDirectoryPanel(panelId, pageRef); + return new PushPolicyDirectoryPanel(panelId, policyRestClient, pageRef); } }); diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMStatusProvider.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMStatusProvider.java index 88384af7586..05725f7b644 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMStatusProvider.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/IdMStatusProvider.java @@ -37,11 +37,17 @@ public class IdMStatusProvider implements StatusProvider { private static final long serialVersionUID = 1875374599950896631L; + protected final ReconStatusUtils reconStatusUtils; + + public IdMStatusProvider(final ReconStatusUtils reconStatusUtils) { + this.reconStatusUtils = reconStatusUtils; + } + @Override public Optional> get( final String anyTypeKey, final String connObjectKeyValue, final String resource) { - return ReconStatusUtils.getReconStatus(anyTypeKey, connObjectKeyValue, resource). + return reconStatusUtils.getReconStatus(anyTypeKey, connObjectKeyValue, resource). map(status -> Pair.of(status.getOnSyncope(), status.getOnResource())); } @@ -49,7 +55,7 @@ public Optional> get( public List> get( final AnyTO any, final Collection resources) { - return ReconStatusUtils.getReconStatuses( + return reconStatusUtils.getReconStatuses( any.getType(), any.getKey(), any.getResources()).stream(). map(status -> Triple.of( status.getRight().getOnSyncope(), diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/ResourceDataProvider.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/ResourceDataProvider.java index b19c8c11731..8a830c5ac30 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/ResourceDataProvider.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/ResourceDataProvider.java @@ -19,17 +19,14 @@ package org.apache.syncope.client.console.commons; import java.io.Serializable; -import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.pages.BasePage; import org.apache.syncope.client.console.rest.ResourceRestClient; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.common.lib.to.ResourceTO; import org.apache.wicket.PageReference; import org.apache.wicket.ajax.AjaxRequestTarget; @@ -47,13 +44,16 @@ public class ResourceDataProvider extends DirectoryDataProvider { protected static final Logger LOG = LoggerFactory.getLogger(ResourceDataProvider.class); - private final PageReference pageRef; + protected final ResourceRestClient resourceRestClient; + + protected final PageReference pageRef; protected int currentPage; - private final String keyword; + protected final String keyword; public ResourceDataProvider( + final ResourceRestClient resourceRestClient, final int paginatorRows, final PageReference pageRef, final String keyword) { @@ -61,13 +61,14 @@ public ResourceDataProvider( super(paginatorRows); setSort("keySortParam", SortOrder.ASCENDING); + this.resourceRestClient = resourceRestClient; this.pageRef = pageRef; this.keyword = keyword; } @Override public Iterator iterator(final long first, final long count) { - List result = Collections.emptyList(); + List result = List.of(); try { currentPage = ((int) first / paginatorRows); @@ -75,9 +76,9 @@ public Iterator iterator(final long first, final long count) { currentPage = 0; } if (StringUtils.isBlank(keyword)) { - result = ResourceRestClient.list(); + result = resourceRestClient.list(); } else { - result = ResourceRestClient.list().stream(). + result = resourceRestClient.list().stream(). filter(resource -> resource.getKey().toLowerCase().contains(keyword)). collect(Collectors.toList()); } @@ -85,9 +86,8 @@ public Iterator iterator(final long first, final long count) { LOG.error("While searching", e); SyncopeConsoleSession.get().onException(e); - Optional target = RequestCycle.get().find(AjaxRequestTarget.class); - target.ifPresent(ajaxRequestTarget - -> ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(ajaxRequestTarget)); + RequestCycle.get().find(AjaxRequestTarget.class). + ifPresent(t -> ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(t)); } SortParam sortParam = getSort(); @@ -127,9 +127,9 @@ public long size() { try { if (StringUtils.isBlank(keyword)) { - result = ResourceRestClient.list().size(); + result = resourceRestClient.list().size(); } else { - result = ResourceRestClient.list().stream().filter(resource + result = resourceRestClient.list().stream().filter(resource -> resource.getKey().toLowerCase().contains(keyword)).count(); } } catch (Exception e) { @@ -137,7 +137,7 @@ public long size() { SyncopeConsoleSession.get().onException(e); RequestCycle.get().find(AjaxRequestTarget.class). - ifPresent(target -> ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target)); + ifPresent(t -> ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(t)); } return result; diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/status/AbstractStatusBeanProvider.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/status/AbstractStatusBeanProvider.java index 53b9f1dc46e..afa78d589a7 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/status/AbstractStatusBeanProvider.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/commons/status/AbstractStatusBeanProvider.java @@ -20,8 +20,8 @@ import java.util.Iterator; import java.util.List; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.SortableDataProviderComparator; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.status.StatusBean; import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; import org.apache.wicket.model.IModel; diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/init/IdMClassPathScanImplementationContributor.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/init/IdMClassPathScanImplementationContributor.java index 45c9209f26b..28188f97562 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/init/IdMClassPathScanImplementationContributor.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/init/IdMClassPathScanImplementationContributor.java @@ -26,6 +26,8 @@ public class IdMClassPathScanImplementationContributor implements ClassPathScanImplementationContributor { + private static final long serialVersionUID = 4797723744170531042L; + @Override public void extend(final ClassPathScanningCandidateComponentProvider scanner) { scanner.addIncludeFilter(new AssignableTypeFilter(PullCorrelationRuleConf.class)); diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Connectors.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Connectors.java index 57cb4a3f770..eb54be299c5 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Connectors.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Connectors.java @@ -21,6 +21,7 @@ import java.io.Serializable; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.console.panels.ConnectorDirectoryPanel; +import org.apache.syncope.client.console.rest.ConnectorRestClient; import org.apache.syncope.client.console.wizards.WizardMgtPanel; import org.apache.syncope.client.console.wizards.resources.ConnectorWizardBuilder; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; @@ -33,11 +34,15 @@ import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.Model; +import org.apache.wicket.spring.injection.annot.SpringBean; public class Connectors extends Panel { private static final long serialVersionUID = 305521359617401936L; + @SpringBean + protected ConnectorRestClient connectorRestClient; + public Connectors(final String id, final PageReference pageRef) { super(id); @@ -66,9 +71,11 @@ protected void onSubmit(final AjaxRequestTarget target) { form.add(search); form.setDefaultButton(search); - WizardMgtPanel connectorDirectoryPanel = new ConnectorDirectoryPanel.Builder(pageRef). - addNewItemPanelBuilder(new ConnectorWizardBuilder(new ConnInstanceTO(), pageRef), true). - build("connectorDirectoryPanel"); + WizardMgtPanel connectorDirectoryPanel = + new ConnectorDirectoryPanel.Builder(connectorRestClient, pageRef). + addNewItemPanelBuilder(new ConnectorWizardBuilder( + new ConnInstanceTO(), connectorRestClient, pageRef), true). + build("connectorDirectoryPanel"); add(connectorDirectoryPanel.setOutputMarkupId(true)); } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Remediations.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Remediations.java index d5c20d3b2b8..c3089acba56 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Remediations.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Remediations.java @@ -20,13 +20,18 @@ import org.apache.syncope.client.console.BookmarkablePageLinkBuilder; import org.apache.syncope.client.console.panels.RemediationDirectoryPanel; +import org.apache.syncope.client.console.rest.RemediationRestClient; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; public class Remediations extends BasePage { private static final long serialVersionUID = -7940154016753661388L; + @SpringBean + protected RemediationRestClient remediationRestClient; + public Remediations(final PageParameters parameters) { super(parameters); @@ -36,6 +41,6 @@ public Remediations(final PageParameters parameters) { content.setOutputMarkupId(true); body.add(content); - content.add(new RemediationDirectoryPanel("remediations", getPageReference())); + content.add(new RemediationDirectoryPanel("remediations", remediationRestClient, getPageReference())); } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Resources.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Resources.java index a51441baa8b..0cf60a281be 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Resources.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/pages/Resources.java @@ -21,6 +21,8 @@ import java.io.Serializable; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.console.panels.ResourceDirectoryPanel; +import org.apache.syncope.client.console.rest.ConnectorRestClient; +import org.apache.syncope.client.console.rest.ResourceRestClient; import org.apache.syncope.client.console.wizards.WizardMgtPanel; import org.apache.syncope.client.console.wizards.resources.ResourceWizardBuilder; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; @@ -33,11 +35,18 @@ import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.Model; +import org.apache.wicket.spring.injection.annot.SpringBean; public class Resources extends Panel { private static final long serialVersionUID = 7240865652350993779L; + @SpringBean + protected ResourceRestClient resourceRestClient; + + @SpringBean + protected ConnectorRestClient connectorRestClient; + public Resources(final String id, final PageReference pageRef) { super(id); @@ -66,8 +75,9 @@ protected void onSubmit(final AjaxRequestTarget target) { form.add(search); form.setDefaultButton(search); - WizardMgtPanel resourceDirectoryPanel = new ResourceDirectoryPanel.Builder(pageRef). - addNewItemPanelBuilder(new ResourceWizardBuilder(new ResourceTO(), pageRef), true). + WizardMgtPanel resourceDirectoryPanel = new ResourceDirectoryPanel.Builder( + resourceRestClient, pageRef).addNewItemPanelBuilder(new ResourceWizardBuilder( + new ResourceTO(), resourceRestClient, connectorRestClient, pageRef), true). build("resourceDirectoryPanel"); add(resourceDirectoryPanel.setOutputMarkupId(true)); } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectListViewPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectListViewPanel.java index 529dd8037f2..5b552797d65 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectListViewPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectListViewPanel.java @@ -72,6 +72,7 @@ import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; import org.apache.wicket.model.util.ListModel; +import org.apache.wicket.spring.injection.annot.SpringBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -85,6 +86,15 @@ public abstract class ConnObjectListViewPanel extends Panel { protected static final String STATUS = "Status"; + @SpringBean + protected ReconciliationRestClient reconciliationRestClient; + + @SpringBean + protected ResourceRestClient resourceRestClient; + + @SpringBean + protected AnyTypeRestClient anyTypeRestClient; + protected String nextPageCookie; protected AbstractSearchPanel searchPanel; @@ -160,7 +170,7 @@ protected Component getValueComponent(final String key, final ConnObject bean) { if (StringUtils.equals(key, STATUS)) { ReconStatus status; try { - status = ReconciliationRestClient.status( + status = reconciliationRestClient.status( new ReconQuery.Builder(anyType, resource.getKey()).fiql(bean.getFiql()).build()); } catch (Exception e) { LOG.error("While requesting for reconciliation status of {} {} with FIQL '{}'", @@ -194,12 +204,11 @@ public void onComponentTag(final Component component, final ComponentTag tag) { } }); } else { - Optional attr = - bean.getAttrs().stream().filter(object -> object.getSchema().equals(key)).findAny(); - - return attr.isEmpty() || attr.get().getValues().isEmpty() - ? new Label("field", StringUtils.EMPTY) - : new CollectionPanel("field", attr.get().getValues()); + Optional attr = bean.getAttrs().stream(). + filter(object -> object.getSchema().equals(key)).findAny(); + return attr.filter(a -> !a.getValues().isEmpty()). + map(a -> (Component) new CollectionPanel("field", a.getValues())). + orElseGet(() -> new Label("field", StringUtils.EMPTY)); } } @@ -230,7 +239,7 @@ public void onClick(final AjaxRequestTarget target, final ConnObject modelObject @Override public void onClick(final AjaxRequestTarget target, final ConnObject modelObject) { try { - ReconStatus status = ReconciliationRestClient.status( + ReconStatus status = reconciliationRestClient.status( new ReconQuery.Builder(anyType, resource.getKey()).fiql(modelObject.getFiql()).build()); pullConnObject( @@ -307,7 +316,7 @@ protected List reloadItems( final String cookie, final String fiql) { - Pair> items = ResourceRestClient.searchConnObjects( + Pair> items = resourceRestClient.searchConnObjects( resource, anyType, new ConnObjectTOQuery.Builder(). @@ -332,7 +341,7 @@ protected AbstractSearchPanel getSearchPanel(final String id, final String anyTy AnyTypeKind anyTypeKind = StringUtils.equals(anyType, SyncopeConstants.REALM_ANYTYPE) || StringUtils.isEmpty(anyType) ? AnyTypeKind.ANY_OBJECT - : AnyTypeRestClient.read(anyType).getKind(); + : anyTypeRestClient.read(anyType).getKind(); return new ConnObjectSearchPanel.Builder(resource, anyTypeKind, anyType, new ListModel<>(clauses), pageRef).required(true).enableSearch().build(id); diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ConnectorDirectoryPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ConnectorDirectoryPanel.java index 915995d2b2d..9af5331b747 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ConnectorDirectoryPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ConnectorDirectoryPanel.java @@ -31,7 +31,9 @@ import org.apache.syncope.client.console.commons.ConnectorDataProvider; import org.apache.syncope.client.console.commons.IdRepoConstants; import org.apache.syncope.client.console.pages.BasePage; +import org.apache.syncope.client.console.rest.AuditRestClient; import org.apache.syncope.client.console.rest.ConnectorRestClient; +import org.apache.syncope.client.console.rest.ResourceRestClient; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; @@ -56,13 +58,20 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class ConnectorDirectoryPanel extends DirectoryPanel { private static final long serialVersionUID = 2041468935602350821L; - private String keyword; + @SpringBean + protected AuditRestClient auditRestClient; + + @SpringBean + protected ResourceRestClient resourceRestClient; + + protected String keyword; protected ConnectorDirectoryPanel(final String id, final ConnectorDirectoryPanel.Builder builder) { super(id, builder); @@ -76,8 +85,6 @@ protected ConnectorDirectoryPanel(final String id, final ConnectorDirectoryPanel setShowResultPanel(false); modal.size(Modal.Size.Large); initResultTable(); - - restClient = builder.restClient; } @Override @@ -96,7 +103,7 @@ public void onEvent(final IEvent event) { @Override protected ConnectorDataProvider dataProvider() { - dataProvider = new ConnectorDataProvider(rows, pageRef, keyword); + dataProvider = new ConnectorDataProvider(restClient, rows, pageRef, keyword); return dataProvider; } @@ -141,7 +148,8 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { final IModel model = new CompoundPropertyModel<>(modelObject); modal.setFormModel(model.getObject()); - target.add(modal.setContent(new ResourceWizardBuilder(modelObject, pageRef). + target.add(modal.setContent(new ResourceWizardBuilder( + modelObject, resourceRestClient, restClient, pageRef). build(BaseModal.CONTENT_ID, AjaxWizard.Mode.CREATE))); modal.header(new Model<>(MessageFormat.format(getString("resource.new"), @@ -159,17 +167,17 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { @Override public void onClick(final AjaxRequestTarget target, final Serializable ignore) { - ConnInstanceTO connInstance = ConnectorRestClient.read(((ConnInstanceTO) model.getObject()).getKey()); + ConnInstanceTO connInstance = restClient.read(((ConnInstanceTO) model.getObject()).getKey()); final IModel model = new CompoundPropertyModel<>(connInstance); modal.setFormModel(model); - target.add(modal.setContent(new ConnectorWizardBuilder(connInstance, pageRef). + target.add(modal.setContent(new ConnectorWizardBuilder(connInstance, restClient, pageRef). build(BaseModal.CONTENT_ID, SyncopeConsoleSession.get(). owns(IdMEntitlement.CONNECTOR_UPDATE, connInstance.getAdminRealm()) - ? AjaxWizard.Mode.EDIT - : AjaxWizard.Mode.READONLY))); + ? AjaxWizard.Mode.EDIT + : AjaxWizard.Mode.READONLY))); modal.header( new Model<>(MessageFormat.format(getString("connector.edit"), connInstance.getDisplayName()))); @@ -185,41 +193,41 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { @Override public void onClick(final AjaxRequestTarget target, final Serializable ignore) { - ConnInstanceTO modelObject = ConnectorRestClient.read(((ConnInstanceTO) model.getObject()).getKey()); - - target.add(altDefaultModal.setContent(new AuditHistoryModal<>( - AuditElements.EventCategoryType.LOGIC, - "ConnectorLogic", - modelObject, - IdMEntitlement.CONNECTOR_UPDATE) { - - private static final long serialVersionUID = -3225348282675513648L; - - @Override - protected void restore(final String json, final AjaxRequestTarget target) { - try { - ConnInstanceTO updated = MAPPER.readValue(json, ConnInstanceTO.class); - ConnectorRestClient.update(updated); - - SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); - } catch (Exception e) { - LOG.error("While restoring connector {}", - ((ConnInstanceTO) model.getObject()).getKey(), e); - SyncopeConsoleSession.get().onException(e); - } - ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target); - } - })); - - altDefaultModal.header( - new Model<>(MessageFormat.format(getString("connector.menu.history"), - ((ConnInstanceTO) model.getObject()).getDisplayName()))); - - altDefaultModal.show(true); + ConnInstanceTO modelObject = restClient.read(((ConnInstanceTO) model.getObject()).getKey()); + + target.add(altDefaultModal.setContent(new AuditHistoryModal<>( + AuditElements.EventCategoryType.LOGIC, + "ConnectorLogic", + modelObject, + IdMEntitlement.CONNECTOR_UPDATE, + auditRestClient) { + + private static final long serialVersionUID = -3225348282675513648L; + + @Override + protected void restore(final String json, final AjaxRequestTarget target) { + try { + ConnInstanceTO updated = MAPPER.readValue(json, ConnInstanceTO.class); + restClient.update(updated); + + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); + } catch (Exception e) { + LOG.error("While restoring connector {}", ((ConnInstanceTO) model.getObject()).getKey(), e); + SyncopeConsoleSession.get().onException(e); + } + ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target); + } + })); + + altDefaultModal.header( + new Model<>(MessageFormat.format(getString("connector.menu.history"), + ((ConnInstanceTO) model.getObject()).getDisplayName()))); + + altDefaultModal.show(true); } - }, ActionLink.ActionType.VIEW_AUDIT_HISTORY, - String.format("%s,%s", IdMEntitlement.CONNECTOR_READ, IdRepoEntitlement.AUDIT_LIST)); + }, ActionLink.ActionType.VIEW_AUDIT_HISTORY, + String.format("%s,%s", IdMEntitlement.CONNECTOR_READ, IdRepoEntitlement.AUDIT_LIST)); panel.add(new ActionLink<>() { @@ -228,9 +236,10 @@ protected void restore(final String json, final AjaxRequestTarget target) { @Override public void onClick(final AjaxRequestTarget target, final Serializable ignore) { try { - ConnectorRestClient.delete(((ConnInstanceTO) model.getObject()).getKey()); + restClient.delete(((ConnInstanceTO) model.getObject()).getKey()); target.appendJavaScript(String.format("jsPlumb.remove('%s');", ((ConnInstanceTO) model.getObject()).getKey())); + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); } catch (SyncopeClientException e) { LOG.error("While deleting resource {}", ((ConnInstanceTO) model.getObject()).getKey(), e); @@ -270,8 +279,8 @@ public static class Builder extends DirectoryPanel.Builder { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = -1328140415494501001L; + + @SpringBean + protected ConnectorRestClient connectorRestClient; public ConnidLocations(final String id, final Builder builder) { super(id, builder); @@ -112,7 +117,7 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { final IModel model = new CompoundPropertyModel<>(modelObject); modal.setFormModel(model); - target.add(modal.setContent(new ConnectorWizardBuilder(modelObject, pageRef). + target.add(modal.setContent(new ConnectorWizardBuilder(modelObject, connectorRestClient, pageRef). build(BaseModal.CONTENT_ID, AjaxWizard.Mode.CREATE))); modal.header(new Model<>(MessageFormat.format(getString("connector.new"), ignore))); @@ -129,21 +134,6 @@ protected Collection getBatches() { return Collections.emptyList(); } - public abstract static class Builder - extends DirectoryPanel.Builder { - - private static final long serialVersionUID = 4448348557808690524L; - - public Builder(final PageReference pageRef) { - super(null, pageRef); - } - - @Override - protected WizardMgtPanel newInstance(final String id, final boolean wizardInModal) { - return new ConnidLocations(id, this); - } - } - protected static class ConnidLocationsDataProvider extends DirectoryDataProvider { private static final long serialVersionUID = 3161906945317209169L; @@ -168,4 +158,19 @@ public IModel model(final Serializable object) { return new CompoundPropertyModel<>(object); } } + + public abstract static class Builder + extends DirectoryPanel.Builder { + + private static final long serialVersionUID = 4448348557808690524L; + + public Builder(final PageReference pageRef) { + super(null, pageRef); + } + + @Override + protected WizardMgtPanel newInstance(final String id, final boolean wizardInModal) { + return new ConnidLocations(id, this); + } + } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/LinkedAccountModalPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/LinkedAccountModalPanel.java index c3397359363..242009f4886 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/LinkedAccountModalPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/LinkedAccountModalPanel.java @@ -31,6 +31,7 @@ import org.apache.syncope.client.console.layout.LinkedAccountFormLayoutInfo; import org.apache.syncope.client.console.pages.BasePage; import org.apache.syncope.client.console.rest.AnyTypeRestClient; +import org.apache.syncope.client.console.rest.RoleRestClient; import org.apache.syncope.client.console.rest.UserRestClient; import org.apache.syncope.client.console.status.LinkedAccountStatusPanel; import org.apache.syncope.client.console.status.ReconTaskPanel; @@ -64,6 +65,7 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,19 +73,26 @@ public class LinkedAccountModalPanel extends Panel implements ModalPanel { private static final long serialVersionUID = -4603032036433309900L; - private static final Logger LOG = LoggerFactory.getLogger(LinkedAccountModalPanel.class); + protected static final Logger LOG = LoggerFactory.getLogger(LinkedAccountModalPanel.class); - private LinkedAccountForm wizard; + @SpringBean + protected AnyTypeRestClient anyTypeRestClient; - private final WizardMgtPanel list; + @SpringBean + protected RoleRestClient roleRestClient; + + @SpringBean + protected UserRestClient userRestClient; + + protected LinkedAccountForm wizard; + + protected final WizardMgtPanel list; private final AjaxLink addAjaxLink; protected ActionLinksTogglePanel actionTogglePanel; - private UserRestClient userRestClient = new UserRestClient(); - - private final List linkedAccountTOs; + protected final List linkedAccountTOs; @SuppressWarnings("unchecked") public LinkedAccountModalPanel( @@ -102,34 +111,40 @@ public LinkedAccountModalPanel( add(actionTogglePanel); AnyLayout anyLayout = AnyLayoutUtils.fetch( - AnyTypeRestClient.listAnyTypes().stream().map(AnyTypeTO::getKey).collect(Collectors.toList())); + roleRestClient, + anyTypeRestClient.listAnyTypes().stream().map(AnyTypeTO::getKey).collect(Collectors.toList())); LinkedAccountFormLayoutInfo linkedAccountFormLayoutInfo = anyLayout.getUser() instanceof IdMUserFormLayoutInfo ? IdMUserFormLayoutInfo.class.cast(anyLayout.getUser()).getLinkedAccountFormLayoutInfo() : new LinkedAccountFormLayoutInfo(); try { - wizard = linkedAccountFormLayoutInfo.getFormClass(). - getConstructor(model.getClass(), LinkedAccountFormLayoutInfo.class, PageReference.class). - newInstance(model, linkedAccountFormLayoutInfo, pageRef); + wizard = linkedAccountFormLayoutInfo.getFormClass().getConstructor( + IModel.class, + LinkedAccountFormLayoutInfo.class, + UserRestClient.class, + AnyTypeRestClient.class, + PageReference.class). + newInstance(model, linkedAccountFormLayoutInfo, userRestClient, anyTypeRestClient, pageRef); } catch (Exception e) { LOG.error("Error instantiating form layout", e); - wizard = new LinkedAccountWizardBuilder(model, linkedAccountFormLayoutInfo, pageRef); + wizard = new LinkedAccountWizardBuilder( + model, linkedAccountFormLayoutInfo, userRestClient, anyTypeRestClient, pageRef); } ListViewPanel.Builder builder = new ListViewPanel.Builder<>( - LinkedAccountTO.class, pageRef) { + LinkedAccountTO.class, pageRef) { private static final long serialVersionUID = -5322423525438435153L; @Override protected LinkedAccountTO getActualItem(final LinkedAccountTO item, final List list) { return item == null - ? null - : list.stream().filter( - in -> ((item.getKey() == null && in.getKey() == null) - || (in.getKey() != null && in.getKey().equals(item.getKey())))). - findAny().orElse(null); + ? null + : list.stream().filter( + in -> ((item.getKey() == null && in.getKey() == null) + || (in.getKey() != null && in.getKey().equals(item.getKey())))). + findAny().orElse(null); } @Override @@ -196,12 +211,12 @@ public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linked linkedAccountTO.getResource(), model.getObject().getType(), linkedAccountTO.getConnObjectKeyValue()), - target); + target); target.add(mlp); ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target); send(LinkedAccountModalPanel.this, Broadcast.BREADTH, - new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target)); + new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target)); } }, ActionLink.ActionType.VIEW, IdRepoEntitlement.USER_READ); @@ -214,9 +229,9 @@ public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linked public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linkedAccountTO) { try { send(LinkedAccountModalPanel.this, Broadcast.DEPTH, - new AjaxWizard.NewItemActionEvent<>(linkedAccountTO, 1, target). - setResourceModel(new StringResourceModel("inner.edit.linkedAccount", - LinkedAccountModalPanel.this, Model.of(linkedAccountTO)))); + new AjaxWizard.NewItemActionEvent<>(linkedAccountTO, 1, target). + setTitleModel(new StringResourceModel("inner.edit.linkedAccount", + LinkedAccountModalPanel.this, Model.of(linkedAccountTO)))); } catch (SyncopeClientException e) { LOG.error("While attempting to create new linked account", e); SyncopeConsoleSession.get().onException(e); @@ -224,7 +239,7 @@ public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linked } send(LinkedAccountModalPanel.this, Broadcast.BREADTH, - new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target)); + new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target)); } }, ActionLink.ActionType.EDIT, IdRepoEntitlement.USER_UPDATE); @@ -237,8 +252,8 @@ public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linked try { linkedAccountTO.setSuspended(!linkedAccountTO.isSuspended()); LinkedAccountUR linkedAccountUR = new LinkedAccountUR.Builder(). - operation(PatchOperation.ADD_REPLACE). - linkedAccountTO(linkedAccountTO).build(); + operation(PatchOperation.ADD_REPLACE). + linkedAccountTO(linkedAccountTO).build(); UserUR req = new UserUR(); req.setKey(model.getObject().getKey()); @@ -261,55 +276,55 @@ public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linked builder.addAction(new ActionLink<>() { - private static final long serialVersionUID = 2555747430358755813L; - - @Override - public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linkedAccountTO) { - mlp.next("PUSH " + linkedAccountTO.getResource(), - new ReconTaskPanel( - linkedAccountTO.getResource(), - new PushTaskTO(), - model.getObject().getType(), - null, - ConnIdSpecialName.UID + "==" + linkedAccountTO.getConnObjectKeyValue(), - true, - mlp, - pageRef), - target); - target.add(mlp); - - ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target); - send(LinkedAccountModalPanel.this, Broadcast.BREADTH, - new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target)); - } - }, ActionLink.ActionType.RECONCILIATION_PUSH, - String.format("%s,%s", IdRepoEntitlement.USER_READ, IdRepoEntitlement.TASK_EXECUTE)); + private static final long serialVersionUID = 2555747430358755813L; + + @Override + public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linkedAccountTO) { + mlp.next("PUSH " + linkedAccountTO.getResource(), + new ReconTaskPanel( + linkedAccountTO.getResource(), + new PushTaskTO(), + model.getObject().getType(), + null, + ConnIdSpecialName.UID + "==" + linkedAccountTO.getConnObjectKeyValue(), + true, + mlp, + pageRef), + target); + target.add(mlp); + + ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target); + send(LinkedAccountModalPanel.this, Broadcast.BREADTH, + new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target)); + } + }, ActionLink.ActionType.RECONCILIATION_PUSH, + String.format("%s,%s", IdRepoEntitlement.USER_READ, IdRepoEntitlement.TASK_EXECUTE)); builder.addAction(new ActionLink<>() { - private static final long serialVersionUID = 2555747430358755813L; - - @Override - public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linkedAccountTO) { - mlp.next("PULL " + linkedAccountTO.getResource(), - new ReconTaskPanel( - linkedAccountTO.getResource(), - new PullTaskTO(), - model.getObject().getType(), - null, - ConnIdSpecialName.UID + "==" + linkedAccountTO.getConnObjectKeyValue(), - true, - mlp, - pageRef), - target); - target.add(mlp); - - ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target); - send(LinkedAccountModalPanel.this, Broadcast.BREADTH, - new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target)); - } - }, ActionLink.ActionType.RECONCILIATION_PULL, - String.format("%s,%s", IdRepoEntitlement.USER_READ, IdRepoEntitlement.TASK_EXECUTE)); + private static final long serialVersionUID = 2555747430358755813L; + + @Override + public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linkedAccountTO) { + mlp.next("PULL " + linkedAccountTO.getResource(), + new ReconTaskPanel( + linkedAccountTO.getResource(), + new PullTaskTO(), + model.getObject().getType(), + null, + ConnIdSpecialName.UID + "==" + linkedAccountTO.getConnObjectKeyValue(), + true, + mlp, + pageRef), + target); + target.add(mlp); + + ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target); + send(LinkedAccountModalPanel.this, Broadcast.BREADTH, + new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target)); + } + }, ActionLink.ActionType.RECONCILIATION_PULL, + String.format("%s,%s", IdRepoEntitlement.USER_READ, IdRepoEntitlement.TASK_EXECUTE)); if (!recounciliationOnly) { builder.addAction(new ActionLink<>() { @@ -320,8 +335,8 @@ public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linked public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linkedAccountTO) { try { LinkedAccountUR linkedAccountUR = new LinkedAccountUR.Builder(). - operation(PatchOperation.DELETE). - linkedAccountTO(linkedAccountTO).build(); + operation(PatchOperation.DELETE). + linkedAccountTO(linkedAccountTO).build(); UserUR req = new UserUR(); req.setKey(model.getObject().getKey()); @@ -356,12 +371,12 @@ public void onClick(final AjaxRequestTarget target, final LinkedAccountTO linked @Override public void onClick(final AjaxRequestTarget target) { send(LinkedAccountModalPanel.this, Broadcast.BREADTH, - new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target)); + new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target)); // this opens the wizard (set above) in CREATE mode send(list, Broadcast.DEPTH, new AjaxWizard.NewItemActionEvent<>(new LinkedAccountTO(), target). - setResourceModel( - new StringResourceModel("inner.create.linkedAccount", LinkedAccountModalPanel.this))); + setTitleModel( + new StringResourceModel("inner.create.linkedAccount", LinkedAccountModalPanel.this))); } }; list.addOrReplaceInnerObject(addAjaxLink.setEnabled(!recounciliationOnly).setVisible(!recounciliationOnly)); diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ProvisionAuxClassesPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ProvisionAuxClassesPanel.java index 9025e07afcb..cd5391339c2 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ProvisionAuxClassesPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ProvisionAuxClassesPanel.java @@ -36,6 +36,7 @@ import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.util.ListModel; +import org.apache.wicket.spring.injection.annot.SpringBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -45,7 +46,16 @@ public class ProvisionAuxClassesPanel extends Panel { private static final Logger LOG = LoggerFactory.getLogger(ProvisionAuxClassesPanel.class); - private final Provision provision; + @SpringBean + protected AnyTypeRestClient anyTypeRestClient; + + @SpringBean + protected AnyTypeClassRestClient anyTypeClassRestClient; + + @SpringBean + protected SchemaRestClient schemaRestClient; + + protected final Provision provision; public ProvisionAuxClassesPanel(final String id, final Provision provision) { super(id); @@ -69,12 +79,12 @@ protected void onBeforeRender() { choices = new ArrayList<>(); try { - anyType = AnyTypeRestClient.read(provision.getAnyType()); + anyType = anyTypeRestClient.read(provision.getAnyType()); } catch (Exception e) { LOG.error("Could not read AnyType {}", provision.getAnyType(), e); } if (anyType != null) { - for (AnyTypeClassTO aux : AnyTypeClassRestClient.list()) { + for (AnyTypeClassTO aux : anyTypeClassRestClient.list()) { if (!anyType.getClasses().contains(aux.getKey())) { choices.add(aux.getKey()); } @@ -96,11 +106,11 @@ protected void onBeforeRender() { addOrReplace(uidOnCreate); } - private static List getSchemas(final AnyTypeTO anyType, final List anyTypeClasses) { + protected List getSchemas(final AnyTypeTO anyType, final List anyTypeClasses) { List classes = new ArrayList<>(anyType.getClasses()); classes.addAll(anyTypeClasses); - return SchemaRestClient.getSchemas( + return schemaRestClient.getSchemas( SchemaType.PLAIN, null, classes.toArray(String[]::new)). stream().map(PlainSchemaTO::getKey).collect(Collectors.toList()); } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/RemediationDirectoryPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/RemediationDirectoryPanel.java index aa06eefe61f..3d937cb5dd8 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/RemediationDirectoryPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/RemediationDirectoryPanel.java @@ -26,6 +26,7 @@ import java.util.List; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.IdMConstants; import org.apache.syncope.client.console.layout.AnyLayoutUtils; import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo; @@ -37,6 +38,7 @@ import org.apache.syncope.client.console.rest.AnyTypeRestClient; import org.apache.syncope.client.console.rest.GroupRestClient; import org.apache.syncope.client.console.rest.RemediationRestClient; +import org.apache.syncope.client.console.rest.RoleRestClient; import org.apache.syncope.client.console.rest.UserRestClient; import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn; import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.KeyPropertyColumn; @@ -47,7 +49,6 @@ import org.apache.syncope.client.console.wizards.any.GroupWizardBuilder; import org.apache.syncope.client.console.wizards.any.UserWizardBuilder; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; import org.apache.syncope.client.ui.commons.wizards.any.AnyWrapper; import org.apache.syncope.common.lib.AnyOperations; @@ -81,20 +82,38 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class RemediationDirectoryPanel extends DirectoryPanel { private static final long serialVersionUID = 8525204188127106587L; - public RemediationDirectoryPanel(final String id, final PageReference pageReference) { - super(id, pageReference, true); + @SpringBean + protected AnyTypeRestClient anyTypeRestClient; + + @SpringBean + protected RoleRestClient roleRestClient; + + @SpringBean + protected UserRestClient userRestClient; + + @SpringBean + protected GroupRestClient groupRestClient; + + @SpringBean + protected AnyObjectRestClient anyObjectRestClient; + + public RemediationDirectoryPanel( + final String id, + final RemediationRestClient restClient, + final PageReference pageRef) { + + super(id, restClient, pageRef, true); disableCheckBoxes(); setFooterVisibility(false); modal.size(Modal.Size.Large); - restClient = new RemediationRestClient(); - initResultTable(); MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, IdMEntitlement.REMEDIATION_REMEDY); @@ -153,7 +172,8 @@ public void onClick(final AjaxRequestTarget target, final RemediationTO ignore) @Override public void onClick(final AjaxRequestTarget target, final RemediationTO ignore) { try { - RemediationRestClient.remedy(model.getObject().getKey(), model.getObject().getKeyPayload()); + restClient.remedy(model.getObject().getKey(), model.getObject().getKeyPayload()); + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); target.add(container); } catch (SyncopeClientException e) { @@ -198,21 +218,21 @@ public void onClick(final AjaxRequestTarget target, final RemediationTO ignore) EntityTOUtils.toAnyTO(remediationTO.getAnyCRPayload(), newUserTO); previousUserTO = null; } else { - previousUserTO = new UserRestClient(). - read(remediationTO.getAnyURPayload().getKey()); + previousUserTO = userRestClient.read(remediationTO.getAnyURPayload().getKey()); newUserTO = AnyOperations.patch( - previousUserTO, (UserUR) remediationTO.getAnyURPayload()); + previousUserTO, (UserUR) remediationTO.getAnyURPayload()); } AjaxWizard.EditItemActionEvent userEvent = - new AjaxWizard.EditItemActionEvent<>(newUserTO, target); + new AjaxWizard.EditItemActionEvent<>(newUserTO, target); userEvent.forceModalPanel(new RemediationUserWizardBuilder( - model.getObject(), - previousUserTO, - newUserTO, - AnyTypeRestClient.read(remediationTO.getAnyType()).getClasses(), - AnyLayoutUtils.fetch(List.of(remediationTO.getAnyType())).getUser(), - pageRef + model.getObject(), + previousUserTO, + newUserTO, + anyTypeRestClient.read(remediationTO.getAnyType()).getClasses(), + AnyLayoutUtils.fetch(roleRestClient, List.of(remediationTO.getAnyType())).getUser(), + userRestClient, + pageRef ).build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT)); send(RemediationDirectoryPanel.this, Broadcast.EXACT, userEvent); break; @@ -225,21 +245,21 @@ public void onClick(final AjaxRequestTarget target, final RemediationTO ignore) EntityTOUtils.toAnyTO(remediationTO.getAnyCRPayload(), newGroupTO); previousGroupTO = null; } else { - previousGroupTO = new GroupRestClient(). - read(remediationTO.getAnyURPayload().getKey()); + previousGroupTO = groupRestClient.read(remediationTO.getAnyURPayload().getKey()); newGroupTO = AnyOperations.patch( - previousGroupTO, (GroupUR) remediationTO.getAnyURPayload()); + previousGroupTO, (GroupUR) remediationTO.getAnyURPayload()); } AjaxWizard.EditItemActionEvent groupEvent = - new AjaxWizard.EditItemActionEvent<>(newGroupTO, target); + new AjaxWizard.EditItemActionEvent<>(newGroupTO, target); groupEvent.forceModalPanel(new RemediationGroupWizardBuilder( - model.getObject(), - previousGroupTO, - newGroupTO, - AnyTypeRestClient.read(remediationTO.getAnyType()).getClasses(), - AnyLayoutUtils.fetch(List.of(remediationTO.getAnyType())).getGroup(), - pageRef + model.getObject(), + previousGroupTO, + newGroupTO, + anyTypeRestClient.read(remediationTO.getAnyType()).getClasses(), + AnyLayoutUtils.fetch( + roleRestClient, List.of(remediationTO.getAnyType())).getGroup(), + pageRef ).build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT)); send(RemediationDirectoryPanel.this, Broadcast.EXACT, groupEvent); break; @@ -252,22 +272,22 @@ public void onClick(final AjaxRequestTarget target, final RemediationTO ignore) EntityTOUtils.toAnyTO(remediationTO.getAnyCRPayload(), newAnyObjectTO); previousAnyObjectTO = null; } else { - previousAnyObjectTO = new AnyObjectRestClient(). - read(remediationTO.getAnyURPayload().getKey()); + previousAnyObjectTO = anyObjectRestClient. + read(remediationTO.getAnyURPayload().getKey()); newAnyObjectTO = AnyOperations.patch( - previousAnyObjectTO, (AnyObjectUR) remediationTO.getAnyURPayload()); + previousAnyObjectTO, (AnyObjectUR) remediationTO.getAnyURPayload()); } AjaxWizard.EditItemActionEvent anyObjectEvent = - new AjaxWizard.EditItemActionEvent<>(newAnyObjectTO, target); + new AjaxWizard.EditItemActionEvent<>(newAnyObjectTO, target); anyObjectEvent.forceModalPanel(new RemediationAnyObjectWizardBuilder( - model.getObject(), - previousAnyObjectTO, - newAnyObjectTO, - AnyTypeRestClient.read(remediationTO.getAnyType()).getClasses(), - AnyLayoutUtils.fetch(List.of(remediationTO.getAnyType())).getAnyObjects(). - get(remediationTO.getAnyType()), - pageRef + model.getObject(), + previousAnyObjectTO, + newAnyObjectTO, + anyTypeRestClient.read(remediationTO.getAnyType()).getClasses(), + AnyLayoutUtils.fetch(roleRestClient, List.of(remediationTO.getAnyType())). + getAnyObjects().get(remediationTO.getAnyType()), + pageRef ).build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT)); send(RemediationDirectoryPanel.this, Broadcast.EXACT, anyObjectEvent); } @@ -282,7 +302,8 @@ public void onClick(final AjaxRequestTarget target, final RemediationTO ignore) @Override public void onClick(final AjaxRequestTarget target, final RemediationTO ignore) { try { - RemediationRestClient.delete(model.getObject().getKey()); + restClient.delete(model.getObject().getKey()); + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); target.add(container); } catch (SyncopeClientException e) { @@ -311,7 +332,7 @@ protected Collection getBatches() { return List.of(); } - public static class RemediationProvider extends DirectoryDataProvider { + public class RemediationProvider extends DirectoryDataProvider { private static final long serialVersionUID = -2311716167583335852L; @@ -324,13 +345,13 @@ public RemediationProvider(final int paginatorRows) { @Override public Iterator iterator(final long first, final long count) { int page = ((int) first / paginatorRows); - return RemediationRestClient.getRemediations((page < 0 ? 0 : page) + 1, - paginatorRows, getSort()).iterator(); + return restClient.getRemediations((page < 0 ? 0 : page) + 1, + paginatorRows, getSort()).iterator(); } @Override public long size() { - return RemediationRestClient.countRemediations(); + return restClient.countRemediations(); } @Override @@ -347,7 +368,7 @@ public RemediationTO getObject() { } } - private static class RemediationUserWizardBuilder extends UserWizardBuilder { + private class RemediationUserWizardBuilder extends UserWizardBuilder { private static final long serialVersionUID = 6840699724316612700L; @@ -361,9 +382,10 @@ private static class RemediationUserWizardBuilder extends UserWizardBuilder { final UserTO userTO, final List anyTypeClasses, final UserFormLayoutInfo formLayoutInfo, + final UserRestClient userRestClient, final PageReference pageRef) { - super(previousUserTO, userTO, anyTypeClasses, formLayoutInfo, pageRef); + super(previousUserTO, userTO, anyTypeClasses, formLayoutInfo, userRestClient, pageRef); this.previousUserTO = previousUserTO; this.remediationTO = remediationTO; } @@ -378,7 +400,7 @@ protected Serializable onApplyInternal(final AnyWrapper modelObject) { UserCR req = new UserCR(); EntityTOUtils.toAnyCR(inner, req); - result = RemediationRestClient.remedy(remediationTO.getKey(), req); + result = restClient.remedy(remediationTO.getKey(), req); } else { UserUR req = AnyOperations.diff(inner, previousUserTO, false); @@ -394,7 +416,7 @@ protected Serializable onApplyInternal(final AnyWrapper modelObject) { result = new ProvisioningResult<>(); result.setEntity(inner); } else { - result = RemediationRestClient.remedy(remediationTO.getKey(), req); + result = restClient.remedy(remediationTO.getKey(), req); } } @@ -402,7 +424,7 @@ protected Serializable onApplyInternal(final AnyWrapper modelObject) { } } - private static class RemediationGroupWizardBuilder extends GroupWizardBuilder { + private class RemediationGroupWizardBuilder extends GroupWizardBuilder { private static final long serialVersionUID = -5233791906979150786L; @@ -433,7 +455,7 @@ protected Serializable onApplyInternal(final AnyWrapper modelObject) { GroupCR req = new GroupCR(); EntityTOUtils.toAnyCR(inner, req); - result = RemediationRestClient.remedy(remediationTO.getKey(), req); + result = restClient.remedy(remediationTO.getKey(), req); } else { GroupUR req = AnyOperations.diff(inner, previousGroupTO, false); @@ -442,7 +464,7 @@ protected Serializable onApplyInternal(final AnyWrapper modelObject) { result = new ProvisioningResult<>(); result.setEntity(inner); } else { - result = RemediationRestClient.remedy(remediationTO.getKey(), req); + result = restClient.remedy(remediationTO.getKey(), req); } } @@ -450,7 +472,7 @@ protected Serializable onApplyInternal(final AnyWrapper modelObject) { } } - private static class RemediationAnyObjectWizardBuilder extends AnyObjectWizardBuilder { + private class RemediationAnyObjectWizardBuilder extends AnyObjectWizardBuilder { private static final long serialVersionUID = 6993139499479015083L; @@ -481,7 +503,7 @@ protected Serializable onApplyInternal(final AnyWrapper modelObject AnyObjectCR req = new AnyObjectCR(); EntityTOUtils.toAnyCR(inner, req); - result = RemediationRestClient.remedy(remediationTO.getKey(), req); + result = restClient.remedy(remediationTO.getKey(), req); } else { AnyObjectUR req = AnyOperations.diff(inner, previousAnyObjectTO, false); @@ -490,7 +512,7 @@ protected Serializable onApplyInternal(final AnyWrapper modelObject result = new ProvisioningResult<>(); result.setEntity(inner); } else { - result = RemediationRestClient.remedy(remediationTO.getKey(), req); + result = restClient.remedy(remediationTO.getKey(), req); } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ResourceDirectoryPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ResourceDirectoryPanel.java index 6432ce3122f..8029cf1a555 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ResourceDirectoryPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/ResourceDirectoryPanel.java @@ -31,6 +31,7 @@ import org.apache.syncope.client.console.commons.IdRepoConstants; import org.apache.syncope.client.console.commons.ResourceDataProvider; import org.apache.syncope.client.console.pages.BasePage; +import org.apache.syncope.client.console.rest.AuditRestClient; import org.apache.syncope.client.console.rest.ConnectorRestClient; import org.apache.syncope.client.console.rest.ResourceRestClient; import org.apache.syncope.client.console.status.ResourceStatusModal; @@ -62,12 +63,19 @@ import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class ResourceDirectoryPanel extends DirectoryPanel { private static final long serialVersionUID = -5223129956783782225L; + @SpringBean + protected ConnectorRestClient connectorRestClient; + + @SpringBean + protected AuditRestClient auditRestClient; + protected String keyword; protected final BaseModal propTaskModal; @@ -136,7 +144,7 @@ public void onEvent(final IEvent event) { @Override protected ResourceDataProvider dataProvider() { - dataProvider = new ResourceDataProvider(rows, pageRef, keyword); + dataProvider = new ResourceDataProvider(restClient, rows, pageRef, keyword); return dataProvider; } @@ -174,13 +182,14 @@ public ActionsPanel getActions(final IModel model) { @Override public void onClick(final AjaxRequestTarget target, final Serializable ignore) { - ResourceTO resource = ResourceRestClient.read(((ResourceTO) model.getObject()).getKey()); - ConnInstanceTO connInstance = ConnectorRestClient.read(resource.getConnector()); + ResourceTO resource = restClient.read(((ResourceTO) model.getObject()).getKey()); + ConnInstanceTO connInstance = connectorRestClient.read(resource.getConnector()); IModel model = new CompoundPropertyModel<>(resource); modal.setFormModel(model); - target.add(modal.setContent(new ResourceWizardBuilder(resource, pageRef). + target.add(modal.setContent(new ResourceWizardBuilder( + resource, restClient, connectorRestClient, pageRef). build(BaseModal.CONTENT_ID, SyncopeConsoleSession.get(). owns(IdMEntitlement.RESOURCE_UPDATE, connInstance.getAdminRealm()) @@ -199,8 +208,8 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { @Override public void onClick(final AjaxRequestTarget target, final Serializable ignore) { - ResourceTO resource = ResourceRestClient.read(((ResourceTO) model.getObject()).getKey()); - ConnInstanceTO connInstance = ConnectorRestClient.read(resource.getConnector()); + ResourceTO resource = restClient.read(((ResourceTO) model.getObject()).getKey()); + ConnInstanceTO connInstance = connectorRestClient.read(resource.getConnector()); if (SyncopeConsoleSession.get(). owns(IdMEntitlement.RESOURCE_UPDATE, connInstance.getAdminRealm())) { @@ -229,7 +238,7 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { @Override public void onClick(final AjaxRequestTarget target, final Serializable ignore) { - ResourceTO resource = ResourceRestClient.read(((ResourceTO) model.getObject()).getKey()); + ResourceTO resource = restClient.read(((ResourceTO) model.getObject()).getKey()); target.add(propTaskModal.setContent(new ConnObjects(resource, pageRef))); propTaskModal.header(new StringResourceModel("resource.explore.list", Model.of(model.getObject()))); @@ -285,7 +294,7 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { @Override public void onClick(final AjaxRequestTarget target, final Serializable ignore) { - ResourceTO modelObject = ResourceRestClient.read(((ResourceTO) model.getObject()).getKey()); + ResourceTO modelObject = restClient.read(((ResourceTO) model.getObject()).getKey()); target.add(propTaskModal.setContent(new ResourceStatusModal(pageRef, modelObject))); propTaskModal.header(new Model<>(MessageFormat.format(getString("resource.reconciliation"), ((ResourceTO) model.getObject()).getKey()))); @@ -299,13 +308,14 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { @Override public void onClick(final AjaxRequestTarget target, final Serializable ignore) { - ResourceTO modelObject = ResourceRestClient.read(((ResourceTO) model.getObject()).getKey()); + ResourceTO modelObject = restClient.read(((ResourceTO) model.getObject()).getKey()); target.add(historyModal.setContent(new AuditHistoryModal<>( AuditElements.EventCategoryType.LOGIC, "ResourceLogic", modelObject, - IdMEntitlement.RESOURCE_UPDATE) { + IdMEntitlement.RESOURCE_UPDATE, + auditRestClient) { private static final long serialVersionUID = -3712506022627033811L; @@ -313,7 +323,7 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { protected void restore(final String json, final AjaxRequestTarget target) { try { ResourceTO updated = MAPPER.readValue(json, ResourceTO.class); - ResourceRestClient.update(updated); + restClient.update(updated); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); } catch (Exception e) { @@ -340,7 +350,7 @@ protected void restore(final String json, final AjaxRequestTarget target) { @Override public void onClick(final AjaxRequestTarget target, final Serializable ignore) { try { - ResourceTO resource = ResourceRestClient.read(((ResourceTO) model.getObject()).getKey()); + ResourceTO resource = restClient.read(((ResourceTO) model.getObject()).getKey()); resource.setKey("Copy of " + resource.getKey()); // reset some resource objects keys resource.getProvisions().forEach(provision -> { @@ -349,7 +359,8 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { } provision.getVirSchemas().clear(); }); - target.add(modal.setContent(new ResourceWizardBuilder(resource, pageRef). + target.add(modal.setContent(new ResourceWizardBuilder( + resource, restClient, connectorRestClient, pageRef). build(BaseModal.CONTENT_ID, AjaxWizard.Mode.CREATE))); modal.header(new Model<>(MessageFormat.format(getString("resource.clone"), resource.getKey()))); @@ -369,9 +380,10 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { @Override public void onClick(final AjaxRequestTarget target, final Serializable ignore) { try { - ResourceRestClient.delete(((ResourceTO) model.getObject()).getKey()); + restClient.delete(((ResourceTO) model.getObject()).getKey()); target.appendJavaScript(String.format("jsPlumb.remove('%s');", ((ResourceTO) model.getObject()).getKey())); + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); } catch (SyncopeClientException e) { LOG.error("While deleting resource {}", ((ResourceTO) model.getObject()).getKey(), e); @@ -410,8 +422,8 @@ public static class Builder extends DirectoryPanel.Builder anyTypes = new HashMap<>(); + @SpringBean + protected ResourceRestClient resourceRestClient; - private final AjaxDropDownChoicePanel anyType; + @SpringBean + protected ConnectorRestClient connectorRestClient; - private ResourceTO selectedResource; + protected final Map anyTypes = new HashMap<>(); + + protected final AjaxDropDownChoicePanel anyType; + + protected ResourceTO selectedResource; public VirSchemaDetails(final String id, final VirSchemaTO schemaTO) { super(id, schemaTO); @@ -58,7 +65,7 @@ public VirSchemaDetails(final String id, final VirSchemaTO schemaTO) { AjaxDropDownChoicePanel resource = new AjaxDropDownChoicePanel<>( "resource", getString("resource"), new PropertyModel(schemaTO, "resource"), false). setNullValid(false); - resource.setChoices(ResourceRestClient.list().stream().map(ResourceTO::getKey).collect(Collectors.toList())); + resource.setChoices(resourceRestClient.list().stream().map(ResourceTO::getKey).collect(Collectors.toList())); resource.setOutputMarkupId(true); resource.addRequiredLabel(); if (resource.getModelObject() != null) { @@ -122,10 +129,10 @@ protected void onUpdate(final AjaxRequestTarget target) { }); } - private String getAdminRealm(final String connectorKey) { + protected String getAdminRealm(final String connectorKey) { String adminRealm = null; try { - adminRealm = ConnectorRestClient.read(connectorKey).getAdminRealm(); + adminRealm = connectorRestClient.read(connectorKey).getAdminRealm(); } catch (Exception e) { LOG.error("Could not read Admin Realm for External Resource {}", selectedResource.getKey()); } @@ -133,10 +140,10 @@ private String getAdminRealm(final String connectorKey) { return adminRealm; } - private void populateAnyTypes(final String resourceKey) { + protected void populateAnyTypes(final String resourceKey) { anyTypes.clear(); if (resourceKey != null) { - ResourceTO resource = ResourceRestClient.read(resourceKey); + ResourceTO resource = resourceRestClient.read(resourceKey); String adminRealm = getAdminRealm(resource.getConnector()); if (SyncopeConsoleSession.get().owns(IdMEntitlement.RESOURCE_READ, adminRealm)) { @@ -147,8 +154,8 @@ private void populateAnyTypes(final String resourceKey) { } } - private List getExtAttrNames() { - return ConnectorRestClient.getExtAttrNames( + protected List getExtAttrNames() { + return connectorRestClient.getExtAttrNames( SyncopeConstants.ROOT_REALM, anyTypes.get(anyType.getModelObject()), selectedResource.getConnector(), diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/search/ConnObjectSearchPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/search/ConnObjectSearchPanel.java index 0ae25e60281..fcebeb51985 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/search/ConnObjectSearchPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/panels/search/ConnObjectSearchPanel.java @@ -32,6 +32,7 @@ import org.apache.wicket.PageReference; import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class ConnObjectSearchPanel extends AbstractSearchPanel { @@ -68,6 +69,9 @@ public ConnObjectSearchPanel build(final String id) { } } + @SpringBean + protected ConnectorRestClient connectorRestClient; + protected ConnObjectSearchPanel(final String id, final AnyTypeKind kind, final Builder builder) { super(id, kind, builder); this.resource = builder.resource; @@ -116,8 +120,8 @@ protected Map load() { @Override protected Map load() { - return ConnectorRestClient.buildObjectClassInfo( - ConnectorRestClient.read(resource.getConnector()), false).stream(). + return connectorRestClient.buildObjectClassInfo( + connectorRestClient.read(resource.getConnector()), false).stream(). map(ConnIdObjectClass::getAttributes). flatMap(List::stream). collect(Collectors.toMap( diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/PropagationPolicyDirectoryPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/PropagationPolicyDirectoryPanel.java index 29d24a41215..570c93be2d4 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/PropagationPolicyDirectoryPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/PropagationPolicyDirectoryPanel.java @@ -19,6 +19,7 @@ package org.apache.syncope.client.console.policies; import java.util.List; +import org.apache.syncope.client.console.rest.PolicyRestClient; import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.BooleanPropertyColumn; import org.apache.syncope.common.lib.policy.PropagationPolicyTO; import org.apache.syncope.common.lib.types.IdRepoEntitlement; @@ -33,13 +34,17 @@ public class PropagationPolicyDirectoryPanel extends PolicyDirectoryPanel(PolicyType.PROPAGATION, defaultItem, modal, pageRef), true); + new PolicyModalPanelBuilder<>(PolicyType.PROPAGATION, defaultItem, modal, restClient, pageRef), true); MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, IdRepoEntitlement.POLICY_CREATE); initResultTable(); diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/ProvisioningPolicyModalPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/ProvisioningPolicyModalPanel.java index 6911359f4c7..77765d4bebd 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/ProvisioningPolicyModalPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/ProvisioningPolicyModalPanel.java @@ -63,14 +63,27 @@ import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class ProvisioningPolicyModalPanel extends AbstractModalPanel { private static final long serialVersionUID = 2988891313881271124L; - private static final JsonMapper MAPPER = JsonMapper.builder().findAndAddModules().build(); + protected static final JsonMapper MAPPER = JsonMapper.builder().findAndAddModules().build(); - private final IModel> implementations; + @SpringBean + protected ImplementationRestClient implementationRestClient; + + @SpringBean + protected PolicyRestClient policyRestClient; + + @SpringBean + protected AnyTypeRestClient anyTypeRestClient; + + @SpringBean + protected SchemaRestClient schemaRestClient; + + protected final IModel> implementations; private final IModel> model; @@ -89,7 +102,7 @@ public ProvisioningPolicyModalPanel( @Override protected Map load() { - return ImplementationRestClient.list(policyTO instanceof PullPolicyTO + return implementationRestClient.list(policyTO instanceof PullPolicyTO ? IdMImplementationType.PULL_CORRELATION_RULE : IdMImplementationType.PUSH_CORRELATION_RULE).stream(). collect(Collectors.toMap(ImplementationTO::getKey, Function.identity())); @@ -153,13 +166,13 @@ public void onSubmit(final AjaxRequestTarget target) { if (rule.getImpl().getEngine() == ImplementationEngine.JAVA && rule.getDefaultRuleConf() != null) { try { - ImplementationRestClient.update(rule.getImpl()); + implementationRestClient.update(rule.getImpl()); } catch (Exception e) { throw new WicketRuntimeException(e); } } }); - PolicyRestClient.update(getItem() instanceof PullPolicyTO + policyRestClient.update(getItem() instanceof PullPolicyTO ? PolicyType.PULL : PolicyType.PUSH, getItem()); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); @@ -181,7 +194,7 @@ protected class CorrelationRulePanel extends Panel { AjaxDropDownChoicePanel anyType = new AjaxDropDownChoicePanel<>( "anyType", "anyType", new PropertyModel(correlationRule.getObject(), "anyType")). setNullValid(true). - setChoices(AnyTypeRestClient.list()); + setChoices(anyTypeRestClient.list()); anyType.setNullValid(false); anyType.setRequired(true); anyType.setOutputMarkupId(true); @@ -308,7 +321,7 @@ protected void onUpdate(final AjaxRequestTarget target) { private List getSchemas(final CorrelationRule rule) { List choices = StringUtils.isEmpty(rule.getAnyType()) ? new ArrayList<>() - : SchemaRestClient.getSchemas(SchemaType.PLAIN, + : schemaRestClient.getSchemas(SchemaType.PLAIN, rule.getAnyType().equals(AnyTypeKind.USER.name()) ? AnyTypeKind.USER : rule.getAnyType().equals(AnyTypeKind.GROUP.name()) diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java index 3f299868203..f98b74655d9 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/PullPolicyDirectoryPanel.java @@ -19,6 +19,7 @@ package org.apache.syncope.client.console.policies; import java.util.List; +import org.apache.syncope.client.console.rest.PolicyRestClient; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.common.lib.policy.PullPolicyTO; @@ -40,13 +41,11 @@ public class PullPolicyDirectoryPanel extends PolicyDirectoryPanel private static final long serialVersionUID = 4984337552918213290L; - public PullPolicyDirectoryPanel(final String id, final PageReference pageRef) { - super(id, PolicyType.PULL, pageRef); - - PullPolicyTO defaultItem = new PullPolicyTO(); + public PullPolicyDirectoryPanel(final String id, final PolicyRestClient restClient, final PageReference pageRef) { + super(id, restClient, PolicyType.PULL, pageRef); this.addNewItemPanelBuilder( - new PolicyModalPanelBuilder<>(PolicyType.PULL, defaultItem, modal, pageRef), true); + new PolicyModalPanelBuilder<>(PolicyType.PULL, new PullPolicyTO(), modal, restClient, pageRef), true); MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, IdRepoEntitlement.POLICY_CREATE); initResultTable(); @@ -67,13 +66,13 @@ protected void addCustomActions(final ActionsPanel panel, final IM @Override public void onClick(final AjaxRequestTarget target, final PullPolicyTO ignore) { target.add(policySpecModal.setContent( - new ProvisioningPolicyModalPanel(model.getObject(), policySpecModal, pageRef))); + new ProvisioningPolicyModalPanel(model.getObject(), policySpecModal, pageRef))); policySpecModal.header(new StringResourceModel( - "policy.rules", PullPolicyDirectoryPanel.this, Model.of(model.getObject()))); + "policy.rules", PullPolicyDirectoryPanel.this, Model.of(model.getObject()))); MetaDataRoleAuthorizationStrategy.authorize( - policySpecModal.getForm(), ENABLE, IdRepoEntitlement.POLICY_UPDATE); + policySpecModal.getForm(), ENABLE, IdRepoEntitlement.POLICY_UPDATE); policySpecModal.show(true); } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/PushPolicyDirectoryPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/PushPolicyDirectoryPanel.java index 0f0faa4836e..0c31b1541a6 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/PushPolicyDirectoryPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/policies/PushPolicyDirectoryPanel.java @@ -19,6 +19,7 @@ package org.apache.syncope.client.console.policies; import java.util.List; +import org.apache.syncope.client.console.rest.PolicyRestClient; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.common.lib.policy.PushPolicyTO; @@ -40,13 +41,11 @@ public class PushPolicyDirectoryPanel extends PolicyDirectoryPanel private static final long serialVersionUID = 4984337552918213290L; - public PushPolicyDirectoryPanel(final String id, final PageReference pageRef) { - super(id, PolicyType.PUSH, pageRef); - - PushPolicyTO defaultItem = new PushPolicyTO(); + public PushPolicyDirectoryPanel(final String id, final PolicyRestClient restClient, final PageReference pageRef) { + super(id, restClient, PolicyType.PUSH, pageRef); this.addNewItemPanelBuilder( - new PolicyModalPanelBuilder<>(PolicyType.PUSH, defaultItem, modal, pageRef), true); + new PolicyModalPanelBuilder<>(PolicyType.PUSH, new PushPolicyTO(), modal, restClient, pageRef), true); MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, IdRepoEntitlement.POLICY_CREATE); initResultTable(); @@ -67,13 +66,13 @@ protected void addCustomActions(final ActionsPanel panel, final IM @Override public void onClick(final AjaxRequestTarget target, final PushPolicyTO ignore) { target.add(policySpecModal.setContent( - new ProvisioningPolicyModalPanel(model.getObject(), policySpecModal, pageRef))); + new ProvisioningPolicyModalPanel(model.getObject(), policySpecModal, pageRef))); policySpecModal.header(new StringResourceModel( - "policy.rules", PushPolicyDirectoryPanel.this, Model.of(model.getObject()))); + "policy.rules", PushPolicyDirectoryPanel.this, Model.of(model.getObject()))); MetaDataRoleAuthorizationStrategy.authorize( - policySpecModal.getForm(), ENABLE, IdRepoEntitlement.POLICY_UPDATE); + policySpecModal.getForm(), ENABLE, IdRepoEntitlement.POLICY_UPDATE); policySpecModal.show(true); } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ConnectorRestClient.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ConnectorRestClient.java index f34ef84e2ab..70486bc2f3e 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ConnectorRestClient.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ConnectorRestClient.java @@ -32,6 +32,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.lib.WebClientBuilder; import org.apache.syncope.common.lib.SyncopeClientException; import org.apache.syncope.common.lib.to.ConnIdBundle; import org.apache.syncope.common.lib.to.ConnIdObjectClass; @@ -49,7 +50,7 @@ public class ConnectorRestClient extends BaseRestClient { private static final long serialVersionUID = -6870366819966266617L; - public static List getAllConnectors() { + public List getAllConnectors() { List connectors = List.of(); try { connectors = getService(ConnectorService.class).list(SyncopeConsoleSession.get().getLocale().toString()); @@ -59,7 +60,7 @@ public static List getAllConnectors() { return connectors; } - public static ConnInstanceTO create(final ConnInstanceTO connectorTO) { + public ConnInstanceTO create(final ConnInstanceTO connectorTO) { List filteredConf = filterProperties(connectorTO.getConf()); connectorTO.getConf().clear(); connectorTO.getConf().addAll(filteredConf); @@ -70,7 +71,7 @@ public static ConnInstanceTO create(final ConnInstanceTO connectorTO) { return getObject(service, response.getLocation(), ConnInstanceTO.class); } - public static List getObjectClasses(final String connectorKey) { + public List getObjectClasses(final String connectorKey) { List result = new ArrayList<>(); try { ConnectorService service = getService(ConnectorService.class); @@ -86,7 +87,7 @@ public static List getObjectClasses(final String connectorKey) { return result; } - public static List getExtAttrNames( + public List getExtAttrNames( final String adminRealm, final String objectClass, final String connectorKey, @@ -103,7 +104,7 @@ public static List getExtAttrNames( findAny(); return connIdObjectClass.map(connIdObjectClassTO -> connIdObjectClassTO.getAttributes().stream(). - map(PlainSchemaTO::getKey).collect(Collectors.toList())).orElseGet(List::of); + map(PlainSchemaTO::getKey).collect(Collectors.toList())).orElseGet(List::of); } /** @@ -112,7 +113,7 @@ public static List getExtAttrNames( * @param key the id * @return ConnInstanceTO */ - public static ConnInstanceTO read(final String key) { + public ConnInstanceTO read(final String key) { ConnInstanceTO connectorTO = null; try { @@ -125,21 +126,21 @@ public static ConnInstanceTO read(final String key) { return connectorTO; } - public static void update(final ConnInstanceTO connectorTO) { + public void update(final ConnInstanceTO connectorTO) { List filteredConf = filterProperties(connectorTO.getConf()); connectorTO.getConf().clear(); connectorTO.getConf().addAll(filteredConf); getService(ConnectorService.class).update(connectorTO); } - public static ConnInstanceTO delete(final String key) { + public ConnInstanceTO delete(final String key) { ConnInstanceTO connectorTO = getService(ConnectorService.class). read(key, SyncopeConsoleSession.get().getLocale().toString()); getService(ConnectorService.class).delete(key); return connectorTO; } - public static List getAllBundles() { + public List getAllBundles() { List bundles = List.of(); try { @@ -151,7 +152,7 @@ public static List getAllBundles() { return bundles; } - private static List filterProperties(final Collection properties) { + protected List filterProperties(final Collection properties) { List newProperties = new ArrayList<>(); properties.stream().map(property -> { @@ -170,10 +171,11 @@ private static List filterProperties(final Collection check(final ConnInstanceTO connectorTO) { + public Pair check(final ConnInstanceTO connectorTO) { ConnInstanceTO toBeChecked = new ConnInstanceTO(); BeanUtils.copyProperties(connectorTO, toBeChecked, new String[] { "configuration", "configurationMap" }); toBeChecked.getConf().addAll(filterProperties(connectorTO.getConf())); @@ -205,7 +207,7 @@ public static Pair check(final ConnInstanceTO connectorTO) { return Pair.of(check, errorMessage); } - public static List buildObjectClassInfo( + public List buildObjectClassInfo( final ConnInstanceTO connInstanceTO, final boolean includeSpecial) { List result = List.of(); @@ -218,7 +220,7 @@ public static List buildObjectClassInfo( return result; } - public static void reload() { + public void reload() { getService(ConnectorService.class).reload(); } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java index a341569a534..50496d1fde5 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ReconciliationRestClient.java @@ -24,7 +24,6 @@ import javax.ws.rs.core.Response; import org.apache.cxf.jaxrs.client.Client; import org.apache.cxf.jaxrs.client.WebClient; -import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.common.lib.to.ProvisioningReport; import org.apache.syncope.common.lib.to.PullTaskTO; import org.apache.syncope.common.lib.to.PushTaskTO; @@ -40,31 +39,31 @@ public class ReconciliationRestClient extends BaseRestClient { private static final long serialVersionUID = -3161863874876938094L; - public static ReconStatus status(final ReconQuery reconQuery) { + public ReconStatus status(final ReconQuery reconQuery) { return getService(ReconciliationService.class).status(reconQuery); } - public static void push(final ReconQuery reconQuery, final PushTaskTO pushTask) { + public void push(final ReconQuery reconQuery, final PushTaskTO pushTask) { getService(ReconciliationService.class).push(reconQuery, pushTask); } - public static void pull(final ReconQuery reconQuery, final PullTaskTO pullTask) { + public void pull(final ReconQuery reconQuery, final PullTaskTO pullTask) { getService(ReconciliationService.class).pull(reconQuery, pullTask); } - public static Response push(final AnyQuery anyQuery, final CSVPushSpec spec) { + public Response push(final AnyQuery anyQuery, final CSVPushSpec spec) { ReconciliationService service = getService(ReconciliationService.class); Client client = WebClient.client(service); client.accept(RESTHeaders.TEXT_CSV); Response response = service.push(anyQuery, spec); - SyncopeConsoleSession.get().resetClient(ReconciliationService.class); + resetClient(ReconciliationService.class); return response; } - public static ArrayList pull(final CSVPullSpec spec, final InputStream csv) { + public ArrayList pull(final CSVPullSpec spec, final InputStream csv) { ReconciliationService service = getService(ReconciliationService.class); Client client = WebClient.client(service); client.type(RESTHeaders.TEXT_CSV); @@ -72,7 +71,7 @@ public static ArrayList pull(final CSVPullSpec spec, final I ArrayList result = service.pull(spec, csv).stream(). collect(Collectors.toCollection(ArrayList::new)); - SyncopeConsoleSession.get().resetClient(ReconciliationService.class); + resetClient(ReconciliationService.class); return result; } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/RemediationRestClient.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/RemediationRestClient.java index 4b6dae8482e..437c27d6247 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/RemediationRestClient.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/RemediationRestClient.java @@ -34,41 +34,41 @@ public class RemediationRestClient extends BaseRestClient { private static final long serialVersionUID = -7033745375669316378L; - public static int countRemediations() { + public int countRemediations() { return getService(RemediationService.class). list(new RemediationQuery.Builder().page(1).size(0).build()). getTotalCount(); } - public static List getRemediations(final int page, final int size, final SortParam sort) { + public List getRemediations(final int page, final int size, final SortParam sort) { return getService(RemediationService.class). list(new RemediationQuery.Builder().page(page).size(size).orderBy(toOrderBy(sort)).build()). getResult(); } - public static RemediationTO getRemediation(final String key) { + public RemediationTO getRemediation(final String key) { return getService(RemediationService.class).read(key); } - public static ProvisioningResult remedy(final String key, final C anyCR) { + public ProvisioningResult remedy(final String key, final C anyCR) { Response response = getService(RemediationService.class).remedy(key, anyCR); return response.readEntity(new GenericType<>() { }); } - public static ProvisioningResult remedy(final String key, final AnyUR anyUR) { + public ProvisioningResult remedy(final String key, final AnyUR anyUR) { Response response = getService(RemediationService.class).remedy(key, anyUR); return response.readEntity(new GenericType<>() { }); } - public static ProvisioningResult remedy(final String key, final String anyKey) { + public ProvisioningResult remedy(final String key, final String anyKey) { Response response = getService(RemediationService.class).remedy(key, anyKey); return response.readEntity(new GenericType<>() { }); } - public static void delete(final String remediation) { + public void delete(final String remediation) { getService(RemediationService.class).delete(remediation); } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ResourceRestClient.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ResourceRestClient.java index 908a5ca2cf8..0930cd38d62 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ResourceRestClient.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/rest/ResourceRestClient.java @@ -29,6 +29,7 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.tuple.Pair; import org.apache.cxf.jaxrs.client.WebClient; +import org.apache.syncope.client.lib.WebClientBuilder; import org.apache.syncope.common.lib.to.ConnObject; import org.apache.syncope.common.lib.to.PagedConnObjectResult; import org.apache.syncope.common.lib.to.ResourceTO; @@ -44,10 +45,11 @@ public class ResourceRestClient extends BaseRestClient { private static final long serialVersionUID = -6898907679835668987L; - public static boolean check(final String coreAddress, final String domain, final String jwt, final String key) + public boolean check(final String coreAddress, final String domain, final String jwt, final String key) throws IOException { - WebClient client = WebClient.create(coreAddress).path("resources"). + WebClient client = WebClientBuilder.build(coreAddress). + path("resources"). accept(MediaType.APPLICATION_JSON_TYPE). type(MediaType.APPLICATION_JSON_TYPE). header(RESTHeaders.DOMAIN, domain). @@ -61,7 +63,7 @@ public static boolean check(final String coreAddress, final String domain, final return false; } - public static Pair check(final ResourceTO resourceTO) { + public Pair check(final ResourceTO resourceTO) { boolean check = false; String errorMessage = null; try { @@ -75,11 +77,11 @@ public static Pair check(final ResourceTO resourceTO) { return Pair.of(check, errorMessage); } - public static ConnObject readConnObject(final String resource, final String anyTypeKey, final String anyKey) { + public ConnObject readConnObject(final String resource, final String anyTypeKey, final String anyKey) { return getService(ResourceService.class).readConnObject(resource, anyTypeKey, anyKey); } - public static String getConnObjectKeyValue(final String resource, final String anyTypeKey, final String anyKey) { + public String getConnObjectKeyValue(final String resource, final String anyTypeKey, final String anyKey) { try { Response response = getService(ResourceService.class).getConnObjectKeyValue(resource, anyTypeKey, anyKey); if (response.getStatusInfo().getFamily() == Response.Status.Family.SUCCESSFUL) { @@ -93,7 +95,7 @@ public static String getConnObjectKeyValue(final String resource, final String a return null; } - public static Pair> searchConnObjects( + public Pair> searchConnObjects( final String resource, final String anyTypeKey, final ConnObjectTOQuery.Builder queryBuilder, @@ -117,11 +119,11 @@ public static Pair> searchConnObjects( return Pair.of(nextPageResultCookie, result); } - public static ResourceTO read(final String name) { + public ResourceTO read(final String name) { return getService(ResourceService.class).read(name); } - public static List list() { + public List list() { List resources = List.of(); try { resources = getService(ResourceService.class).list(); @@ -133,25 +135,25 @@ public static List list() { return resources; } - public static ResourceTO create(final ResourceTO resourceTO) { + public ResourceTO create(final ResourceTO resourceTO) { ResourceService service = getService(ResourceService.class); Response response = service.create(resourceTO); return getObject(service, response.getLocation(), ResourceTO.class); } - public static void update(final ResourceTO resourceTO) { + public void update(final ResourceTO resourceTO) { getService(ResourceService.class).update(resourceTO); } - public static void delete(final String name) { + public void delete(final String name) { getService(ResourceService.class).delete(name); } - public static void setLatestSyncToken(final String key, final String anyType) { + public void setLatestSyncToken(final String key, final String anyType) { getService(ResourceService.class).setLatestSyncToken(key, anyType); } - public static void removeSyncToken(final String key, final String anyType) { + public void removeSyncToken(final String key, final String anyType) { getService(ResourceService.class).removeSyncToken(key, anyType); } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java index 0b8007c45b8..ebd98628435 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusDirectoryPanel.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.Pair; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.IdMConstants; import org.apache.syncope.client.console.commons.status.AbstractStatusBeanProvider; import org.apache.syncope.client.console.panels.AjaxDataTablePanel; @@ -37,7 +38,6 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.panels.ModalPanel; import org.apache.syncope.client.ui.commons.status.Status; import org.apache.syncope.client.ui.commons.status.StatusBean; @@ -65,6 +65,7 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class AnyStatusDirectoryPanel extends DirectoryPanel, AbstractAnyRestClient> @@ -72,13 +73,28 @@ public class AnyStatusDirectoryPanel private static final long serialVersionUID = -9148734710505211261L; - private final MultilevelPanel multiLevelPanelRef; + @SpringBean + protected ResourceRestClient resourceRestClient; - private final AnyTO anyTO; + @SpringBean + protected ReconStatusUtils reconStatusUtils; - private final AnyTypeKind anyTypeKind; + @SpringBean + protected UserRestClient userRestClient; - private final boolean statusOnly; + @SpringBean + protected GroupRestClient groupRestClient; + + @SpringBean + protected AnyObjectRestClient anyObjectRestClient; + + protected final MultilevelPanel multiLevelPanelRef; + + protected final AnyTO anyTO; + + protected final AnyTypeKind anyTypeKind; + + protected final boolean statusOnly; private final List resources; @@ -89,24 +105,24 @@ public AnyStatusDirectoryPanel( final String itemKeyFieldName, final boolean statusOnly) { - super(MultilevelPanel.FIRST_LEVEL_ID, pageRef); + super(MultilevelPanel.FIRST_LEVEL_ID, null, pageRef); this.multiLevelPanelRef = multiLevelPanelRef; this.statusOnly = statusOnly; this.anyTO = anyTO; this.itemKeyFieldName = itemKeyFieldName; if (anyTO instanceof UserTO) { - this.restClient = new UserRestClient(); + this.restClient = userRestClient; anyTypeKind = AnyTypeKind.USER; } else if (anyTO instanceof GroupTO) { - this.restClient = new GroupRestClient(); + this.restClient = groupRestClient; anyTypeKind = AnyTypeKind.GROUP; } else { - this.restClient = new AnyObjectRestClient(); + this.restClient = anyObjectRestClient; anyTypeKind = AnyTypeKind.ANY_OBJECT; } - resources = ResourceRestClient.list().stream(). + resources = resourceRestClient.list().stream(). filter(resource -> resource.getProvision(anyTO.getType()).isPresent()). map(ResourceTO::getKey).collect(Collectors.toList()); @@ -313,7 +329,7 @@ protected List getStatusBeans(final long first, final long count) { List statusBeans = actual.getResources().stream().map(resource -> { List> statuses = List.of(); if (statusOnly) { - statuses = ReconStatusUtils.getReconStatuses(anyTO.getType(), anyTO.getKey(), List.of(resource)); + statuses = reconStatusUtils.getReconStatuses(anyTO.getType(), anyTO.getKey(), List.of(resource)); } return StatusUtils.getStatusBean(actual, diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusModal.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusModal.java index 166996da5b3..397cf84c539 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusModal.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/AnyStatusModal.java @@ -18,10 +18,10 @@ */ package org.apache.syncope.client.console.status; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.panels.DirectoryPanel; import org.apache.syncope.client.console.panels.MultilevelPanel; import org.apache.syncope.client.console.rest.AbstractAnyRestClient; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.status.StatusBean; import org.apache.syncope.common.lib.to.AnyTO; import org.apache.wicket.PageReference; diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/LinkedAccountStatusPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/LinkedAccountStatusPanel.java index beb6146a519..4b73d9cf5c3 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/LinkedAccountStatusPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/LinkedAccountStatusPanel.java @@ -28,16 +28,20 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class LinkedAccountStatusPanel extends RemoteObjectPanel { private static final long serialVersionUID = 7662852503618434902L; - private final String resource; + @SpringBean + protected ReconStatusUtils reconStatusUtils; - private final String anyTypeKey; + protected final String resource; - private final String connObjectKeyValue; + protected final String anyTypeKey; + + protected final String connObjectKeyValue; public LinkedAccountStatusPanel( final String resource, @@ -57,7 +61,7 @@ public LinkedAccountStatusPanel( @Override protected Pair getConnObjectTOs() { - Optional status = ReconStatusUtils.getReconStatus(anyTypeKey, connObjectKeyValue, resource); + Optional status = reconStatusUtils.getReconStatus(anyTypeKey, connObjectKeyValue, resource); return status.map(reconStatus -> Pair.of(reconStatus.getOnSyncope(), reconStatus.getOnResource())).orElse(null); } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusPanel.java index 5a737f7b5f6..b7080c0032a 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusPanel.java @@ -28,16 +28,20 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class ReconStatusPanel extends RemoteObjectPanel { private static final long serialVersionUID = 8000309881812037770L; - private final String resource; + @SpringBean + protected ReconStatusUtils reconStatusUtils; - private final String anyTypeKey; + protected final String resource; - private final String anyKey; + protected final String anyTypeKey; + + protected final String anyKey; public ReconStatusPanel( final String resource, @@ -58,7 +62,7 @@ public ReconStatusPanel( @Override protected Pair getConnObjectTOs() { List> statuses = - ReconStatusUtils.getReconStatuses(anyTypeKey, anyKey, List.of(resource)); + reconStatusUtils.getReconStatuses(anyTypeKey, anyKey, List.of(resource)); return statuses.isEmpty() ? null diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusUtils.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusUtils.java index 81d7879c27d..c42a10ab428 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusUtils.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconStatusUtils.java @@ -32,18 +32,24 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public final class ReconStatusUtils implements Serializable { +public class ReconStatusUtils implements Serializable { private static final long serialVersionUID = -5411720003057109354L; private static final Logger LOG = LoggerFactory.getLogger(ReconStatusUtils.class); - public static Optional getReconStatus( + protected final ReconciliationRestClient reconciliationRestClient; + + public ReconStatusUtils(final ReconciliationRestClient reconciliationRestClient) { + this.reconciliationRestClient = reconciliationRestClient; + } + + public Optional getReconStatus( final String anyTypeKey, final String connObjectKeyValue, final String resource) { ReconStatus result = null; try { - result = ReconciliationRestClient.status(new ReconQuery.Builder(anyTypeKey, resource). + result = reconciliationRestClient.status(new ReconQuery.Builder(anyTypeKey, resource). fiql(ConnIdSpecialName.UID + "==" + connObjectKeyValue).build()); } catch (Exception e) { LOG.warn("Unexpected error for {} {} on {}", anyTypeKey, connObjectKeyValue, resource, e); @@ -51,12 +57,12 @@ public static Optional getReconStatus( return Optional.ofNullable(result); } - public static List> getReconStatuses( + public List> getReconStatuses( final String anyTypeKey, final String anyKey, final Collection resources) { return resources.stream().map(resource -> { try { - return Pair.of(resource, ReconciliationRestClient.status( + return Pair.of(resource, reconciliationRestClient.status( new ReconQuery.Builder(anyTypeKey, resource).anyKey(anyKey).build())); } catch (Exception e) { LOG.warn("Unexpected error for {} {} on {}", anyTypeKey, anyKey, resource, e); @@ -64,8 +70,4 @@ public static List> getReconStatuses( } }).filter(Objects::nonNull).collect(Collectors.toList()); } - - private ReconStatusUtils() { - // private constructor for static utility class - } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java index 1b7e76f473a..f30c6022f0e 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ReconTaskPanel.java @@ -18,12 +18,12 @@ */ package org.apache.syncope.client.console.status; -import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.SyncopeWebApplication; import org.apache.syncope.client.console.commons.RealmsUtils; import org.apache.syncope.client.console.pages.BasePage; import org.apache.syncope.client.console.panels.MultilevelPanel; @@ -56,6 +56,7 @@ import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.util.ListModel; +import org.apache.wicket.spring.injection.annot.SpringBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,25 +66,34 @@ public class ReconTaskPanel extends MultilevelPanel.SecondLevel { protected static final Logger LOG = LoggerFactory.getLogger(ReconTaskPanel.class); - private final IModel> pullActions = new LoadableDetachableModel<>() { + @SpringBean + protected ImplementationRestClient implementationRestClient; + + @SpringBean + protected RealmRestClient realmRestClient; + + @SpringBean + protected ReconciliationRestClient reconciliationRestClient; + + protected final IModel> pullActions = new LoadableDetachableModel<>() { private static final long serialVersionUID = 5275935387613157437L; @Override protected List load() { - return ImplementationRestClient.list(IdMImplementationType.PULL_ACTIONS).stream(). - map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); + return implementationRestClient.list(IdMImplementationType.PULL_ACTIONS).stream(). + map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); } }; - private final IModel> pushActions = new LoadableDetachableModel<>() { + protected final IModel> pushActions = new LoadableDetachableModel<>() { private static final long serialVersionUID = 5275935387613157437L; @Override protected List load() { - return ImplementationRestClient.list(IdMImplementationType.PUSH_ACTIONS).stream(). - map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); + return implementationRestClient.list(IdMImplementationType.PUSH_ACTIONS).stream(). + map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); } }; @@ -116,10 +126,10 @@ public ReconTaskPanel( form.add(new Label("realm", "")); form.add(new Label("remediation", "")); } else { - boolean isSearchEnabled = RealmsUtils.isSearchEnabled(); + boolean fullRealmsTree = SyncopeWebApplication.get().fullRealmsTree(realmRestClient); AutoCompleteSettings settings = new AutoCompleteSettings(); - settings.setShowCompleteListOnFocusGain(!isSearchEnabled); - settings.setShowListOnEmptyInput(!isSearchEnabled); + settings.setShowCompleteListOnFocusGain(fullRealmsTree); + settings.setShowListOnEmptyInput(fullRealmsTree); AjaxSearchFieldPanel realm = new AjaxSearchFieldPanel( "realm", "destinationRealm", new PropertyModel<>(taskTO, "destinationRealm"), settings) { @@ -129,11 +139,10 @@ public ReconTaskPanel( @Override protected Iterator getChoices(final String input) { return (RealmsUtils.checkInput(input) - ? (isSearchEnabled - ? RealmRestClient.search(RealmsUtils.buildQuery(input)).getResult() - : RealmRestClient.list(SyncopeConstants.ROOT_REALM)) + ? (realmRestClient.search(fullRealmsTree + ? RealmsUtils.buildBaseQuery() + : RealmsUtils.buildKeywordQuery(input)).getResult()) : List.of()).stream(). - sorted(Comparator.comparing(RealmTO::getName)). map(RealmTO::getFullPath).collect(Collectors.toList()).iterator(); } }; @@ -202,9 +211,9 @@ protected void onSubmit(final AjaxRequestTarget target) { ReconQuery reconQuery = new ReconQuery.Builder(anyType, resource).anyKey(anyKey).fiql(fiql).build(); try { if (taskTO instanceof PushTaskTO) { - ReconciliationRestClient.push(reconQuery, (PushTaskTO) form.getModelObject()); + reconciliationRestClient.push(reconQuery, (PushTaskTO) form.getModelObject()); } else { - ReconciliationRestClient.pull(reconQuery, (PullTaskTO) form.getModelObject()); + reconciliationRestClient.pull(reconQuery, (PullTaskTO) form.getModelObject()); } SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ResourceStatusDirectoryPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ResourceStatusDirectoryPanel.java index bff2bbba544..0711f28066b 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ResourceStatusDirectoryPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ResourceStatusDirectoryPanel.java @@ -24,6 +24,7 @@ import java.util.Optional; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.IdMConstants; import org.apache.syncope.client.console.commons.status.AbstractStatusBeanProvider; import org.apache.syncope.client.console.panels.AjaxDataTablePanel; @@ -37,7 +38,6 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.lib.SyncopeClient; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.panels.ModalPanel; import org.apache.syncope.client.ui.commons.status.StatusBean; import org.apache.syncope.client.ui.commons.status.StatusUtils; @@ -57,6 +57,7 @@ import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; import org.apache.wicket.model.IModel; import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class ResourceStatusDirectoryPanel extends DirectoryPanel, AbstractAnyRestClient> @@ -64,11 +65,20 @@ public class ResourceStatusDirectoryPanel private static final long serialVersionUID = -9148734710505211261L; - private final MultilevelPanel multiLevelPanelRef; + @SpringBean + protected UserRestClient userRestClient; - private String type; + @SpringBean + protected GroupRestClient groupRestClient; - private final ResourceTO resource; + @SpringBean + protected AnyObjectRestClient anyObjectRestClient; + + protected final MultilevelPanel multiLevelPanelRef; + + protected String type; + + protected final ResourceTO resource; public ResourceStatusDirectoryPanel( final MultilevelPanel multiLevelPanelRef, @@ -76,7 +86,7 @@ public ResourceStatusDirectoryPanel( final String type, final ResourceTO resource) { - super(MultilevelPanel.FIRST_LEVEL_ID, pageRef); + super(MultilevelPanel.FIRST_LEVEL_ID, null, pageRef); this.multiLevelPanelRef = multiLevelPanelRef; this.type = type; this.resource = resource; @@ -184,18 +194,22 @@ public void updateResultTable(final String type, final AjaxRequestTarget target) if (StringUtils.isNotBlank(type)) { switch (type) { case "USER": - this.restClient = new UserRestClient(); + restClient = userRestClient; break; case "GROUP": - this.restClient = new GroupRestClient(); + restClient = groupRestClient; break; default: - this.restClient = new AnyObjectRestClient(); + restClient = anyObjectRestClient; } } + synchronized (this) { + dataProvider = dataProvider(); + } + super.updateResultTable(target); } @@ -241,17 +255,17 @@ public ResourceStatusDataProvider(final int paginatorRows) { switch (type) { case "USER": bld = SyncopeClient.getUserSearchConditionBuilder(); - restClient = new UserRestClient(); + restClient = userRestClient; break; case "GROUP": bld = SyncopeClient.getGroupSearchConditionBuilder(); - restClient = new GroupRestClient(); + restClient = groupRestClient; break; default: bld = SyncopeClient.getAnyObjectSearchConditionBuilder(type); - restClient = new AnyObjectRestClient(); + restClient = anyObjectRestClient; } fiql = bld.isNotNull(Constants.KEY_FIELD_NAME).query(); } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ResourceStatusModal.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ResourceStatusModal.java index 3ab581b962b..4f63ecd5a48 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ResourceStatusModal.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/ResourceStatusModal.java @@ -20,12 +20,12 @@ import java.util.List; import java.util.stream.Collectors; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.panels.DirectoryPanel; import org.apache.syncope.client.console.panels.MultilevelPanel; import org.apache.syncope.client.console.rest.AbstractAnyRestClient; import org.apache.syncope.client.console.rest.AnyTypeRestClient; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; import org.apache.syncope.client.ui.commons.status.StatusBean; import org.apache.syncope.common.lib.to.Provision; diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/StatusModal.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/StatusModal.java index a723ffaea31..5665cb223d8 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/status/StatusModal.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/status/StatusModal.java @@ -18,11 +18,11 @@ */ package org.apache.syncope.client.console.status; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.panels.DirectoryPanel; import org.apache.syncope.client.console.panels.MultilevelPanel; import org.apache.syncope.client.console.rest.AbstractAnyRestClient; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.client.ui.commons.panels.ModalPanel; import org.apache.syncope.client.ui.commons.status.StatusBean; import org.apache.syncope.common.lib.to.EntityTO; diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TabularTopology.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TabularTopology.java index 02ae460c80e..58eae319b48 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TabularTopology.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TabularTopology.java @@ -21,11 +21,11 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbedPanel; import java.util.ArrayList; import java.util.List; -import org.apache.syncope.client.console.annotations.IdMPage; import org.apache.syncope.client.console.pages.BasePage; import org.apache.syncope.client.console.pages.Connectors; import org.apache.syncope.client.console.pages.Resources; import org.apache.syncope.client.console.panels.ConnidLocations; +import org.apache.syncope.client.ui.commons.annotations.IdMPage; import org.apache.syncope.common.lib.types.IdMEntitlement; import org.apache.wicket.extensions.markup.html.tabs.AbstractTab; import org.apache.wicket.extensions.markup.html.tabs.ITab; diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java index 28b6e60d111..7ee69b6aff1 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/Topology.java @@ -37,9 +37,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.SyncopeConsoleSession; -import org.apache.syncope.client.console.annotations.IdMPage; import org.apache.syncope.client.console.pages.BasePage; -import org.apache.syncope.client.console.rest.BaseRestClient; import org.apache.syncope.client.console.rest.ConnectorRestClient; import org.apache.syncope.client.console.rest.ResourceRestClient; import org.apache.syncope.client.console.wicket.markup.html.WebMarkupContainerNoVeil; @@ -48,9 +46,11 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.console.wizards.resources.AbstractResourceWizardBuilder.CreateEvent; import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.annotations.IdMPage; import org.apache.syncope.common.lib.to.ConnInstanceTO; import org.apache.syncope.common.lib.to.ResourceTO; import org.apache.syncope.common.lib.types.IdMEntitlement; +import org.apache.syncope.common.rest.api.service.SyncopeService; import org.apache.wicket.Component; import org.apache.wicket.ajax.AbstractAjaxTimerBehavior; import org.apache.wicket.ajax.AjaxEventBehavior; @@ -63,6 +63,7 @@ import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.model.LoadableDetachableModel; +import org.apache.wicket.spring.injection.annot.SpringBean; @IdMPage(label = "Topology", icon = "fas fa-plug", listEntitlement = IdMEntitlement.RESOURCE_LIST, priority = 0) public class Topology extends BasePage { @@ -71,73 +72,79 @@ public class Topology extends BasePage { public static final String CONNECTOR_SERVER_LOCATION_PREFIX = "connid://"; - private final int origX = 3100; + @SpringBean + protected ResourceRestClient resourceRestClient; - private final int origY = 2800; + @SpringBean + protected ConnectorRestClient connectorRestClient; - private final BaseModal modal; + protected final int origX = 3100; - private final WebMarkupContainer newlyCreatedContainer; + protected final int origY = 2800; - private final ListView newlyCreated; + protected final BaseModal modal; - private final TopologyTogglePanel togglePanel; + protected final WebMarkupContainer newlyCreatedContainer; - private final LoadableDetachableModel> resModel = new LoadableDetachableModel<>() { + protected final ListView newlyCreated; + + protected final TopologyTogglePanel togglePanel; + + protected final LoadableDetachableModel> resModel = new LoadableDetachableModel<>() { private static final long serialVersionUID = 5275935387613157431L; @Override protected List load() { - return ResourceRestClient.list(); + return resourceRestClient.list(); } }; - private final LoadableDetachableModel>> connModel = - new LoadableDetachableModel<>() { - - private static final long serialVersionUID = 5275935387613157432L; - - @Override - protected Map> load() { - final Map> res = new HashMap<>(); + protected final LoadableDetachableModel>> connModel = + new LoadableDetachableModel<>() { - ConnectorRestClient.getAllConnectors().forEach(conn -> { - List conns; - if (res.containsKey(conn.getLocation())) { - conns = res.get(conn.getLocation()); - } else { - conns = new ArrayList<>(); - res.put(conn.getLocation(), conns); - } - conns.add(conn); - }); + private static final long serialVersionUID = 5275935387613157432L; - return res; - } - }; + @Override + protected Map> load() { + final Map> res = new HashMap<>(); + + connectorRestClient.getAllConnectors().forEach(conn -> { + List conns; + if (res.containsKey(conn.getLocation())) { + conns = res.get(conn.getLocation()); + } else { + conns = new ArrayList<>(); + res.put(conn.getLocation(), conns); + } + conns.add(conn); + }); - private final LoadableDetachableModel, List>> csModel = - new LoadableDetachableModel<>() { + return res; + } + }; - private static final long serialVersionUID = 5275935387613157433L; + protected final LoadableDetachableModel, List>> csModel = + new LoadableDetachableModel<>() { - @Override - protected Pair, List> load() { - final List connectorServers = new ArrayList<>(); - final List filePaths = new ArrayList<>(); + private static final long serialVersionUID = 5275935387613157433L; - SyncopeConsoleSession.get().getPlatformInfo().getConnIdLocations().forEach(location -> { - if (location.startsWith(CONNECTOR_SERVER_LOCATION_PREFIX)) { - connectorServers.add(URI.create(location)); - } else { - filePaths.add(URI.create(location)); - } - }); + @Override + protected Pair, List> load() { + final List connectorServers = new ArrayList<>(); + final List filePaths = new ArrayList<>(); + + SyncopeConsoleSession.get().getPlatformInfo().getConnIdLocations().forEach(location -> { + if (location.startsWith(CONNECTOR_SERVER_LOCATION_PREFIX)) { + connectorServers.add(URI.create(location)); + } else { + filePaths.add(URI.create(location)); + } + }); - return Pair.of(connectorServers, filePaths); - } - }; + return Pair.of(connectorServers, filePaths); + } + }; protected enum SupportedOperation { @@ -193,7 +200,7 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { syncopeTopologyNode.setX(origX); syncopeTopologyNode.setY(origY); - URI uri = WebClient.client(BaseRestClient.getSyncopeService()).getBaseURI(); + URI uri = WebClient.client(SyncopeConsoleSession.get().getService(SyncopeService.class)).getBaseURI(); syncopeTopologyNode.setHost(uri.getHost()); syncopeTopologyNode.setPort(uri.getPort()); @@ -290,65 +297,65 @@ protected void populateItem(final ListItem item) { // Add Connector Intances // ----------------------------------------- ListView> conns = - new ListView<>("conns", new ArrayList<>(connModel.getObject().values())) { + new ListView<>("conns", new ArrayList<>(connModel.getObject().values())) { - private static final long serialVersionUID = 697862187148836036L; + private static final long serialVersionUID = 697862187148836036L; - @Override - protected void populateItem(final ListItem> item) { - int size = item.getModelObject().size() + 1; + @Override + protected void populateItem(final ListItem> item) { + int size = item.getModelObject().size() + 1; - ListView conns = new ListView<>("conns", item.getModelObject()) { + ListView conns = new ListView<>("conns", item.getModelObject()) { - private static final long serialVersionUID = 6978621871488360381L; + private static final long serialVersionUID = 6978621871488360381L; - @Override - protected void populateItem(final ListItem item) { - ConnInstanceTO conn = item.getModelObject(); + @Override + protected void populateItem(final ListItem item) { + ConnInstanceTO conn = item.getModelObject(); - TopologyNode topologynode = new TopologyNode( + TopologyNode topologynode = new TopologyNode( conn.getKey(), StringUtils.isBlank(conn.getDisplayName()) // [SYNCOPE-1233] - ? conn.getBundleName() : conn.getDisplayName(), + ? conn.getBundleName() : conn.getDisplayName(), TopologyNode.Kind.CONNECTOR); - // Define the parent note - TopologyNode parent = servers.get(conn.getLocation()); + // Define the parent note + TopologyNode parent = servers.get(conn.getLocation()); - // Set the position - int kx = size >= 6 ? 800 : (130 * size); + // Set the position + int kx = size >= 6 ? 800 : (130 * size); - double hpos = conn.getLocation(). + double hpos = conn.getLocation(). startsWith(CONNECTOR_SERVER_LOCATION_PREFIX) ? Math.PI : 0.0; - int x = (int) Math.round((Optional.ofNullable(parent).map(TopologyNode::getX).orElse(origX)) + int x = (int) Math.round((Optional.ofNullable(parent).map(TopologyNode::getX).orElse(origX)) + kx * Math.cos(hpos + Math.PI * (item.getIndex() + 1) / size)); - int y = (int) Math.round((Optional.ofNullable(parent).map(TopologyNode::getY).orElse(origY)) + int y = (int) Math.round((Optional.ofNullable(parent).map(TopologyNode::getY).orElse(origY)) + 100 * Math.sin(hpos + Math.PI * (item.getIndex() + 1) / size)); - topologynode.setConnectionDisplayName(conn.getBundleName()); - topologynode.setX(x); - topologynode.setY(y); - - connectors.put(String.class.cast(topologynode.getKey()), topologynode); - item.add(topologyNodePanel("conn", topologynode, conn.isErrored())); - - // Update connections - Map remoteConnections; - if (connections.containsKey(conn.getLocation())) { - remoteConnections = connections.get(conn.getLocation()); - } else { - remoteConnections = new HashMap<>(); - connections.put(conn.getLocation(), remoteConnections); - } - remoteConnections.put(conn.getKey(), topologynode); + topologynode.setConnectionDisplayName(conn.getBundleName()); + topologynode.setX(x); + topologynode.setY(y); + + connectors.put(String.class.cast(topologynode.getKey()), topologynode); + item.add(topologyNodePanel("conn", topologynode, conn.isErrored())); + + // Update connections + Map remoteConnections; + if (connections.containsKey(conn.getLocation())) { + remoteConnections = connections.get(conn.getLocation()); + } else { + remoteConnections = new HashMap<>(); + connections.put(conn.getLocation(), remoteConnections); } - }; + remoteConnections.put(conn.getKey(), topologynode); + } + }; - conns.setOutputMarkupId(true); - item.add(conns); - } - }; + conns.setOutputMarkupId(true); + item.add(conns); + } + }; conns.setOutputMarkupId(true); body.add(conns); @@ -394,7 +401,7 @@ protected void populateItem(final ListItem item) { String connectorKey = item.getModelObject(); ListView innerListView = new ListView<>("resources", - new ArrayList<>(connections.get(connectorKey).values())) { + new ArrayList<>(connections.get(connectorKey).values())) { private static final long serialVersionUID = -3447760771863754342L; @@ -412,9 +419,9 @@ protected void populateItem(final ListItem item) { double hpos = (parent == null || parent.getY() < syncopeTopologyNode.getY()) ? Math.PI : 0.0; int x = (int) Math.round((Optional.ofNullable(parent).map(TopologyNode::getX).orElse(origX)) - + kx * Math.cos(hpos + Math.PI * (item.getIndex() + 1) / size)); + + kx * Math.cos(hpos + Math.PI * (item.getIndex() + 1) / size)); int y = (int) Math.round((Optional.ofNullable(parent).map(TopologyNode::getY).orElse(origY)) - + ky * Math.sin(hpos + Math.PI * (item.getIndex() + 1) / size)); + + ky * Math.sin(hpos + Math.PI * (item.getIndex() + 1) / size)); topologynode.setX(x); topologynode.setY(y); diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java index 6613f475408..e2f773deb86 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java @@ -30,14 +30,18 @@ import org.apache.wicket.event.IEvent; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class TopologyNodePanel extends Panel implements IAjaxIndicatorAware { private static final long serialVersionUID = -8775095410207013913L; - private final Label label; + @SpringBean + protected ConnectorRestClient connectorRestClient; - private final TopologyNode node; + protected final Label label; + + protected final TopologyNode node; protected enum Status { ACTIVE, @@ -105,7 +109,7 @@ public void onEvent(final IEvent event) { String key = updateEvent.getKey(); if (node.getKind() == Kind.CONNECTOR && key.equalsIgnoreCase(node.getKey())) { - ConnInstanceTO conn = ConnectorRestClient.read(key); + ConnInstanceTO conn = connectorRestClient.read(key); // [SYNCOPE-1233] String displayName = StringUtils.isBlank(conn.getDisplayName()) diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java index aeb8ec3e641..de6097868b3 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java @@ -27,6 +27,7 @@ import org.apache.syncope.client.console.audit.AuditHistoryModal; import org.apache.syncope.client.console.panels.ConnObjects; import org.apache.syncope.client.console.panels.TogglePanel; +import org.apache.syncope.client.console.rest.AuditRestClient; import org.apache.syncope.client.console.rest.ConnectorRestClient; import org.apache.syncope.client.console.rest.ResourceRestClient; import org.apache.syncope.client.console.status.ResourceStatusModal; @@ -34,12 +35,12 @@ import org.apache.syncope.client.console.tasks.PullTasks; import org.apache.syncope.client.console.tasks.PushTasks; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; -import org.apache.syncope.client.console.wicket.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.syncope.client.console.wizards.resources.ConnectorWizardBuilder; import org.apache.syncope.client.console.wizards.resources.ResourceProvision; import org.apache.syncope.client.console.wizards.resources.ResourceProvisionPanel; import org.apache.syncope.client.console.wizards.resources.ResourceWizardBuilder; import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; import org.apache.syncope.common.lib.SyncopeClientException; @@ -62,14 +63,24 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class TopologyTogglePanel extends TogglePanel { private static final long serialVersionUID = -2025535531121434056L; - private static final JsonMapper MAPPER = JsonMapper.builder().findAndAddModules().build(); + protected static final JsonMapper MAPPER = JsonMapper.builder().findAndAddModules().build(); - private final WebMarkupContainer container; + @SpringBean + protected ConnectorRestClient connectorRestClient; + + @SpringBean + protected ResourceRestClient resourceRestClient; + + @SpringBean + protected AuditRestClient auditRestClient; + + protected final WebMarkupContainer container; protected final BaseModal propTaskModal; @@ -77,7 +88,7 @@ public class TopologyTogglePanel extends TogglePanel { protected final BaseModal provisionModal; - private final BaseModal historyModal; + protected final BaseModal historyModal; public TopologyTogglePanel(final String id, final PageReference pageRef) { super(id, "topologyTogglePanel", pageRef); @@ -176,7 +187,7 @@ private Fragment getSyncopeFragment(final PageReference pageRef) { @Override public void onClick(final AjaxRequestTarget target) { try { - ConnectorRestClient.reload(); + connectorRestClient.reload(); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); } catch (Exception e) { LOG.error("While reloading all connectors", e); @@ -206,7 +217,7 @@ public void onClick(final AjaxRequestTarget target) { final IModel model = new CompoundPropertyModel<>(modelObject); modal.setFormModel(model); - target.add(modal.setContent(new ConnectorWizardBuilder(modelObject, pageRef). + target.add(modal.setContent(new ConnectorWizardBuilder(modelObject, connectorRestClient, pageRef). build(BaseModal.CONTENT_ID, AjaxWizard.Mode.CREATE))); modal.header(new Model<>(MessageFormat.format(getString("connector.new"), node.getKey()))); @@ -227,14 +238,14 @@ public String getAjaxIndicatorMarkupId() { private Fragment getConnectorFragment(final TopologyNode node, final PageReference pageRef) { Fragment fragment = new Fragment("actions", "connectorActions", this); - AjaxLink delete = new IndicatingOnConfirmAjaxLink<>("delete", true) { + AjaxLink delete = new IndicatingOnConfirmAjaxLink<>("delete", Constants.CONFIRM_DELETE, true) { private static final long serialVersionUID = 3776750333491622263L; @Override public void onClick(final AjaxRequestTarget target) { try { - ConnectorRestClient.delete(String.class.cast(node.getKey())); + connectorRestClient.delete(String.class.cast(node.getKey())); target.appendJavaScript(String.format("jsPlumb.remove('%s');", node.getKey())); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); toggle(target, false); @@ -261,7 +272,8 @@ public void onClick(final AjaxRequestTarget target) { final IModel model = new CompoundPropertyModel<>(modelObject); modal.setFormModel(model); - target.add(modal.setContent(new ResourceWizardBuilder(modelObject, pageRef). + target.add(modal.setContent(new ResourceWizardBuilder( + modelObject, resourceRestClient, connectorRestClient, pageRef). build(BaseModal.CONTENT_ID, AjaxWizard.Mode.CREATE))); modal.header(new Model<>(MessageFormat.format(getString("resource.new"), node.getKey()))); @@ -283,12 +295,12 @@ public String getAjaxIndicatorMarkupId() { @Override public void onClick(final AjaxRequestTarget target) { - ConnInstanceTO connInstance = ConnectorRestClient.read(String.class.cast(node.getKey())); + ConnInstanceTO connInstance = connectorRestClient.read(String.class.cast(node.getKey())); final IModel model = new CompoundPropertyModel<>(connInstance); modal.setFormModel(model); - target.add(modal.setContent(new ConnectorWizardBuilder(connInstance, pageRef). + target.add(modal.setContent(new ConnectorWizardBuilder(connInstance, connectorRestClient, pageRef). build(BaseModal.CONTENT_ID, SyncopeConsoleSession.get(). owns(IdMEntitlement.CONNECTOR_UPDATE, connInstance.getAdminRealm()) @@ -314,13 +326,14 @@ public String getAjaxIndicatorMarkupId() { @Override public void onClick(final AjaxRequestTarget target) { - ConnInstanceTO modelObject = ConnectorRestClient.read(node.getKey()); + ConnInstanceTO modelObject = connectorRestClient.read(node.getKey()); target.add(historyModal.setContent(new AuditHistoryModal<>( AuditElements.EventCategoryType.LOGIC, "ConnectorLogic", modelObject, - IdMEntitlement.CONNECTOR_UPDATE) { + IdMEntitlement.CONNECTOR_UPDATE, + auditRestClient) { private static final long serialVersionUID = -3225348282675513648L; @@ -328,7 +341,7 @@ public void onClick(final AjaxRequestTarget target) { protected void restore(final String json, final AjaxRequestTarget target) { try { ConnInstanceTO updated = MAPPER.readValue(json, ConnInstanceTO.class); - ConnectorRestClient.update(updated); + connectorRestClient.update(updated); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); toggle(target, false); @@ -361,14 +374,14 @@ public String getAjaxIndicatorMarkupId() { private Fragment getResourceFragment(final TopologyNode node, final PageReference pageRef) { Fragment fragment = new Fragment("actions", "resourceActions", this); - AjaxLink delete = new IndicatingOnConfirmAjaxLink<>("delete", true) { + AjaxLink delete = new IndicatingOnConfirmAjaxLink<>("delete", Constants.CONFIRM_DELETE, true) { private static final long serialVersionUID = 3776750333491622263L; @Override public void onClick(final AjaxRequestTarget target) { try { - ResourceRestClient.delete(node.getKey()); + resourceRestClient.delete(node.getKey()); target.appendJavaScript(String.format("jsPlumb.remove('%s');", node.getKey())); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); toggle(target, false); @@ -388,13 +401,14 @@ public void onClick(final AjaxRequestTarget target) { @Override public void onClick(final AjaxRequestTarget target) { - ResourceTO resource = ResourceRestClient.read(node.getKey()); - ConnInstanceTO connInstance = ConnectorRestClient.read(resource.getConnector()); + ResourceTO resource = resourceRestClient.read(node.getKey()); + ConnInstanceTO connInstance = connectorRestClient.read(resource.getConnector()); IModel model = new CompoundPropertyModel<>(resource); modal.setFormModel(model); - target.add(modal.setContent(new ResourceWizardBuilder(resource, pageRef). + target.add(modal.setContent(new ResourceWizardBuilder( + resource, resourceRestClient, connectorRestClient, pageRef). build(BaseModal.CONTENT_ID, SyncopeConsoleSession.get(). owns(IdMEntitlement.RESOURCE_UPDATE, connInstance.getAdminRealm()) @@ -419,7 +433,7 @@ public String getAjaxIndicatorMarkupId() { @Override public void onClick(final AjaxRequestTarget target) { - ResourceTO modelObject = ResourceRestClient.read(node.getKey()); + ResourceTO modelObject = resourceRestClient.read(node.getKey()); target.add(propTaskModal.setContent(new ResourceStatusModal(pageRef, modelObject))); propTaskModal.header( new Model<>(MessageFormat.format(getString("resource.reconciliation"), node.getKey()))); @@ -440,8 +454,8 @@ public String getAjaxIndicatorMarkupId() { @Override public void onClick(final AjaxRequestTarget target) { - ResourceTO resource = ResourceRestClient.read(node.getKey()); - ConnInstanceTO connInstance = ConnectorRestClient.read(resource.getConnector()); + ResourceTO resource = resourceRestClient.read(node.getKey()); + ConnInstanceTO connInstance = connectorRestClient.read(resource.getConnector()); if (SyncopeConsoleSession.get(). owns(IdMEntitlement.RESOURCE_UPDATE, connInstance.getAdminRealm())) { @@ -475,7 +489,7 @@ public String getAjaxIndicatorMarkupId() { @Override public void onClick(final AjaxRequestTarget target) { - ResourceTO resource = ResourceRestClient.read(node.getKey()); + ResourceTO resource = resourceRestClient.read(node.getKey()); target.add(propTaskModal.setContent(new ConnObjects(resource, pageRef))); propTaskModal.header(new StringResourceModel("resource.explore.list", Model.of(node))); @@ -556,13 +570,14 @@ public String getAjaxIndicatorMarkupId() { @Override public void onClick(final AjaxRequestTarget target) { - ResourceTO modelObject = ResourceRestClient.read(node.getKey()); + ResourceTO modelObject = resourceRestClient.read(node.getKey()); target.add(historyModal.setContent(new AuditHistoryModal<>( AuditElements.EventCategoryType.LOGIC, "ResourceLogic", modelObject, - IdMEntitlement.RESOURCE_UPDATE) { + IdMEntitlement.RESOURCE_UPDATE, + auditRestClient) { private static final long serialVersionUID = -3712506022627033811L; @@ -570,7 +585,7 @@ public void onClick(final AjaxRequestTarget target) { protected void restore(final String json, final AjaxRequestTarget target) { try { ResourceTO updated = MAPPER.readValue(json, ResourceTO.class); - ResourceRestClient.update(updated); + resourceRestClient.update(updated); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); toggle(target, false); @@ -605,7 +620,7 @@ public String getAjaxIndicatorMarkupId() { @Override public void onClick(final AjaxRequestTarget target) { try { - ResourceTO resource = ResourceRestClient.read(node.getKey()); + ResourceTO resource = resourceRestClient.read(node.getKey()); resource.setKey("Copy of " + node.getKey()); for (Provision provision : resource.getProvisions()) { @@ -614,7 +629,8 @@ public void onClick(final AjaxRequestTarget target) { } provision.getVirSchemas().clear(); } - target.add(modal.setContent(new ResourceWizardBuilder(resource, pageRef). + target.add(modal.setContent(new ResourceWizardBuilder( + resource, resourceRestClient, connectorRestClient, pageRef). build(BaseModal.CONTENT_ID, AjaxWizard.Mode.CREATE))); modal.header(new Model<>(MessageFormat.format(getString("resource.clone"), node.getKey()))); @@ -639,13 +655,12 @@ public void onEvent(final IEvent event) { super.onEvent(event); if (event.getPayload() instanceof AjaxWizard.NewItemFinishEvent) { - final AjaxWizard.NewItemFinishEvent item = AjaxWizard.NewItemFinishEvent.class.cast(event.getPayload()); - final Serializable result = item.getResult(); - final Optional target = item.getTarget(); - if (result != null && result instanceof ConnInstanceTO && target.isPresent()) { + AjaxWizard.NewItemFinishEvent item = AjaxWizard.NewItemFinishEvent.class.cast(event.getPayload()); + Serializable result = item.getResult(); + Optional target = item.getTarget(); + if (result instanceof ConnInstanceTO) { // update Toggle Panel header - ConnInstanceTO conn = ConnInstanceTO.class.cast(result); - setHeader(target.get(), conn.getDisplayName()); + target.ifPresent(t -> setHeader(t, ConnInstanceTO.class.cast(result).getDisplayName())); } } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyWebSocketBehavior.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyWebSocketBehavior.java index 64c9637777c..c68e0359c42 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyWebSocketBehavior.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyWebSocketBehavior.java @@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; @@ -42,74 +43,51 @@ import org.apache.wicket.spring.injection.annot.SpringBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.task.SimpleAsyncTaskExecutor; public class TopologyWebSocketBehavior extends WebSocketBehavior { private static final long serialVersionUID = -1653665542635275551L; - private static final Logger LOG = LoggerFactory.getLogger(TopologyWebSocketBehavior.class); + protected static final Logger LOG = LoggerFactory.getLogger(TopologyWebSocketBehavior.class); - private static final JsonMapper MAPPER = JsonMapper.builder().findAndAddModules().build(); + protected static final JsonMapper MAPPER = JsonMapper.builder().findAndAddModules().build(); - private static final String CONNECTOR_TEST_TIMEOUT_PARAMETER = "connector.test.timeout"; + protected static final String CONNECTOR_TEST_TIMEOUT_PARAMETER = "connector.test.timeout"; - private static final String RESOURCE_TEST_TIMEOUT_PARAMETER = "resource.test.timeout"; + protected static final String RESOURCE_TEST_TIMEOUT_PARAMETER = "resource.test.timeout"; - private static void timeoutHandlingConnectionChecker( - final Checker checker, - final Integer timeout, - final Map responses, - final Set running) { - - String response = null; - try { - if (timeout == null || timeout < 0) { - LOG.debug("No timeouts for resource connection checking ... "); - response = checker.call(); - } else if (timeout > 0) { - LOG.debug("Timeouts provided for resource connection checking ... "); - response = SyncopeConsoleSession.get().execute(checker).get(timeout, TimeUnit.SECONDS); - } - } catch (InterruptedException | TimeoutException e) { - LOG.warn("Connection with {} timed out", checker.key); - response = String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", - TopologyNode.Status.UNREACHABLE, checker.key); - } catch (Exception e) { - LOG.error("Unexpected exception conneting to {}", checker.key, e); - response = String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", - TopologyNode.Status.FAILURE, checker.key); - } - - if (response != null) { - responses.put(checker.key, response); - } + @SpringBean + protected ServiceOps serviceOps; - running.remove(checker.key); - } + @SpringBean + protected ConfParamOps confParamOps; @SpringBean - private ServiceOps serviceOps; + protected ConnectorRestClient connectorRestClient; @SpringBean - private ConfParamOps confParamOps; + protected ResourceRestClient resourceRestClient; + + protected final Map connectors = Collections.synchronizedMap(new HashMap<>()); - private final Map connectors = Collections.synchronizedMap(new HashMap<>()); + protected final Set runningConnCheck = Collections.synchronizedSet(new HashSet<>()); - private final Set runningConnCheck = Collections.synchronizedSet(new HashSet<>()); + protected final Map resources = Collections.synchronizedMap(new HashMap<>()); - private final Map resources = Collections.synchronizedMap(new HashMap<>()); + protected final Set runningResCheck = Collections.synchronizedSet(new HashSet<>()); - private final Set runningResCheck = Collections.synchronizedSet(new HashSet<>()); + protected final transient SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor(); - private String coreAddress; + protected String coreAddress; - private String domain; + protected String domain; - private String jwt; + protected String jwt; - private Integer connectorTestTimeout = null; + protected Integer connectorTestTimeout = null; - private Integer resourceTestTimeout = null; + protected Integer resourceTestTimeout = null; public TopologyWebSocketBehavior() { coreAddress = serviceOps.get(NetworkService.Type.CORE).getAddress(); @@ -126,6 +104,36 @@ public TopologyWebSocketBehavior() { } } + protected void timeoutHandlingConnectionChecker( + final Checker checker, + final Integer timeout, + final Map responses, + final Set running) { + + String response; + try { + if (timeout == null || timeout < 0) { + LOG.debug("No timeouts for resource connection checking ... "); + response = checker.call(); + } else { + LOG.debug("Timeouts provided for resource connection checking ... "); + response = executor.submit(checker).get(timeout, TimeUnit.SECONDS); + } + } catch (InterruptedException | TimeoutException e) { + LOG.warn("Connection with {} timed out", checker.key); + response = String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", + TopologyNode.Status.UNREACHABLE, checker.key); + } catch (Exception e) { + LOG.error("Unexpected exception connecting to {}", checker.key, e); + response = String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", + TopologyNode.Status.FAILURE, checker.key); + } + + Optional.ofNullable(response).ifPresent(r -> responses.put(checker.key, r)); + + running.remove(checker.key); + } + @Override protected void onMessage(final WebSocketRequestHandler handler, final TextMessage message) { try { @@ -145,8 +153,8 @@ protected void onMessage(final WebSocketRequestHandler handler, final TextMessag LOG.debug("Running connection check for connector {}", ckey); } else { try { - SyncopeConsoleSession.get().execute(() -> timeoutHandlingConnectionChecker( - new ConnectorChecker(ckey), connectorTestTimeout, connectors, runningConnCheck)); + timeoutHandlingConnectionChecker( + new ConnectorChecker(ckey), connectorTestTimeout, connectors, runningConnCheck); runningConnCheck.add(ckey); } catch (Exception e) { @@ -169,8 +177,8 @@ protected void onMessage(final WebSocketRequestHandler handler, final TextMessag LOG.debug("Running connection check for resource {}", rkey); } else { try { - SyncopeConsoleSession.get().execute(() -> timeoutHandlingConnectionChecker( - new ResourceChecker(rkey), resourceTestTimeout, resources, runningResCheck)); + timeoutHandlingConnectionChecker( + new ResourceChecker(rkey), resourceTestTimeout, resources, runningResCheck); runningResCheck.add(rkey); } catch (Exception e) { @@ -201,7 +209,7 @@ public boolean resCheckDone(final Collection resources) { return this.resources.keySet().containsAll(resources); } - private abstract class Checker implements Callable { + protected abstract class Checker implements Callable { protected final String key; @@ -210,7 +218,7 @@ private abstract class Checker implements Callable { } } - private class ConnectorChecker extends Checker { + protected class ConnectorChecker extends Checker { ConnectorChecker(final String key) { super(key); @@ -220,17 +228,16 @@ private class ConnectorChecker extends Checker { public String call() throws Exception { try { return String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", - ConnectorRestClient.check(coreAddress, domain, jwt, key) + connectorRestClient.check(coreAddress, domain, jwt, key) ? TopologyNode.Status.REACHABLE : TopologyNode.Status.UNREACHABLE, key); } catch (Exception e) { LOG.warn("Error checking connection for {}", key, e); - return String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", - TopologyNode.Status.FAILURE, key); + return String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", TopologyNode.Status.FAILURE, key); } } } - private class ResourceChecker extends Checker { + protected class ResourceChecker extends Checker { ResourceChecker(final String key) { super(key); @@ -240,12 +247,11 @@ private class ResourceChecker extends Checker { public String call() throws Exception { try { return String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", - ResourceRestClient.check(coreAddress, domain, jwt, key) + resourceRestClient.check(coreAddress, domain, jwt, key) ? TopologyNode.Status.REACHABLE : TopologyNode.Status.UNREACHABLE, key); } catch (Exception e) { LOG.warn("Error checking connection for {}", key, e); - return String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", - TopologyNode.Status.FAILURE, key); + return String.format("{ \"status\": \"%s\", \"target\": \"%s\"}", TopologyNode.Status.FAILURE, key); } } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/ConnConfPropertyListView.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/ConnConfPropertyListView.java index 59bd19b46af..f45b5d8472f 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/ConnConfPropertyListView.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/list/ConnConfPropertyListView.java @@ -30,8 +30,8 @@ import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior; import org.apache.syncope.client.ui.commons.markup.html.form.AbstractFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxNumberFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPasswordFieldPanel; -import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.FieldPanel; import org.apache.syncope.common.lib.types.ConnConfProperty; @@ -83,7 +83,7 @@ protected void populateItem(final ListItem item) { || IdMConstants.GUARDED_STRING.equalsIgnoreCase(property.getSchema().getType()) || IdMConstants.GUARDED_BYTE_ARRAY.equalsIgnoreCase(property.getSchema().getType())) { - field = new AjaxPasswordFieldPanel("panel", label, new Model<>(), false); + field = new AjaxPasswordFieldPanel("panel", label, Model.of(), false); ((PasswordTextField) field.getField()).setResetPassword(false); required = property.getSchema().isRequired(); @@ -100,9 +100,8 @@ protected void populateItem(final ListItem item) { } if (ClassUtils.isAssignable(Number.class, propertySchemaClass)) { - @SuppressWarnings("unchecked") - Class numberClass = (Class) propertySchemaClass; - field = new AjaxSpinnerFieldPanel.Builder<>().build("panel", label, numberClass, new Model<>()); + field = new AjaxNumberFieldPanel.Builder<>().build( + "panel", label, AjaxNumberFieldPanel.cast(propertySchemaClass), new Model<>()); required = property.getSchema().isRequired(); } else if (ClassUtils.isAssignable(Boolean.class, propertySchemaClass)) { field = new AjaxCheckBoxPanel("panel", label, new Model<>()); diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/widgets/RemediationsWidget.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/widgets/RemediationsWidget.java index ba66c699591..a26d890db0f 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/widgets/RemediationsWidget.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/widgets/RemediationsWidget.java @@ -41,13 +41,17 @@ import org.apache.wicket.markup.html.link.BookmarkablePageLink; import org.apache.wicket.model.IModel; import org.apache.wicket.model.util.ListModel; +import org.apache.wicket.spring.injection.annot.SpringBean; @ExtWidget(priority = 0) public class RemediationsWidget extends ExtAlertWidget { private static final long serialVersionUID = 1817429725840355068L; - private final List lastRemediations = new ArrayList<>(); + @SpringBean + protected RemediationRestClient remediationRestClient; + + protected final List lastRemediations = new ArrayList<>(); public RemediationsWidget(final String id, final PageReference pageRef) { super(id, pageRef); @@ -87,7 +91,7 @@ public final void refreshLatestAlerts(final AjaxRequestTarget target) { protected int getLatestAlertsSize() { return SyncopeConsoleSession.get().owns(IdMEntitlement.REMEDIATION_LIST) && SyncopeConsoleSession.get().owns(IdMEntitlement.REMEDIATION_READ) - ? RemediationRestClient.countRemediations() + ? remediationRestClient.countRemediations() : 0; } @@ -101,10 +105,10 @@ protected IModel> getLatestAlerts() { public List getObject() { List updatedRemediations; if (SyncopeConsoleSession.get().owns(IdMEntitlement.REMEDIATION_LIST) - && SyncopeConsoleSession.get().owns(IdMEntitlement.REMEDIATION_READ)) { + && SyncopeConsoleSession.get().owns(IdMEntitlement.REMEDIATION_READ)) { - updatedRemediations = RemediationRestClient.getRemediations(1, - MAX_SIZE, new SortParam<>("instant", true)); + updatedRemediations = remediationRestClient.getRemediations( + 1, MAX_SIZE, new SortParam<>("instant", true)); } else { updatedRemediations = List.of(); } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder.java index 00e45bb94dd..7870fa55f35 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder.java @@ -93,13 +93,24 @@ public static LineSeparator byRepr(final String repr) { } } - private final Model csv = new Model<>(); + protected final Model csv = new Model<>(); - private final Bytes maxUploadSize; + protected final ReconciliationRestClient reconciliationRestClient; + + protected final ImplementationRestClient implementationRestClient; + + protected final Bytes maxUploadSize; + + public CSVPullWizardBuilder( + final CSVPullSpec defaultItem, + final ReconciliationRestClient reconciliationRestClient, + final ImplementationRestClient implementationRestClient, + final PageReference pageRef) { - public CSVPullWizardBuilder(final CSVPullSpec defaultItem, final PageReference pageRef) { super(defaultItem, pageRef); + this.reconciliationRestClient = reconciliationRestClient; + this.implementationRestClient = implementationRestClient; this.maxUploadSize = Bytes.megabytes(SyncopeWebApplication.get().getMaxUploadFileSizeMB()); } @@ -111,7 +122,7 @@ public CSVPullWizardBuilder setEventSink(final IEventSink eventSink) { @Override protected ArrayList onApplyInternal(final CSVPullSpec modelObject) { - return ReconciliationRestClient.pull(modelObject, new ByteArrayInputStream(csv.getObject())); + return reconciliationRestClient.pull(modelObject, new ByteArrayInputStream(csv.getObject())); } @Override @@ -235,8 +246,8 @@ public class PullTask extends WizardStep { @Override protected List load() { - return ImplementationRestClient.list(IdMImplementationType.PULL_ACTIONS).stream(). - map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); + return implementationRestClient.list(IdMImplementationType.PULL_ACTIONS).stream(). + map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); } }; @@ -246,8 +257,8 @@ protected List load() { @Override protected List load() { - return ImplementationRestClient.list(IdMImplementationType.PULL_CORRELATION_RULE).stream(). - map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); + return implementationRestClient.list(IdMImplementationType.PULL_CORRELATION_RULE).stream(). + map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); } }; diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder.java index 189217bef35..1035c4e5198 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder.java @@ -51,19 +51,28 @@ public class CSVPushWizardBuilder extends BaseAjaxWizardBuilder { private static final long serialVersionUID = -8890710681835661962L; - private final AnyQuery query; + protected final AnyQuery query; - private final AjaxDownloadBehavior downloadBehavior; + protected final AjaxDownloadBehavior downloadBehavior; + + protected final ReconciliationRestClient reconciliationRestClient; + + protected final ImplementationRestClient implementationRestClient; public CSVPushWizardBuilder( final CSVPushSpec defaultItem, final AnyQuery query, final AjaxDownloadBehavior downloadBehavior, + final ReconciliationRestClient reconciliationRestClient, + final ImplementationRestClient implementationRestClient, final PageReference pageRef) { super(defaultItem, pageRef); + this.query = query; this.downloadBehavior = downloadBehavior; + this.reconciliationRestClient = reconciliationRestClient; + this.implementationRestClient = implementationRestClient; } @Override @@ -76,7 +85,7 @@ public CSVPushWizardBuilder setEventSink(final IEventSink eventSink) { protected Serializable onApplyInternal(final CSVPushSpec modelObject) { return RequestCycle.get().find(AjaxRequestTarget.class).map(target -> { try { - downloadBehavior.setResponse(new ResponseHolder(ReconciliationRestClient.push(query, modelObject))); + downloadBehavior.setResponse(new ResponseHolder(reconciliationRestClient.push(query, modelObject))); downloadBehavior.initiate(target); return Constants.OPERATION_SUCCEEDED; @@ -103,7 +112,7 @@ public Details(final CSVPushSpec spec) { } } - public static class PushTask extends WizardStep { + public class PushTask extends WizardStep { private static final long serialVersionUID = -2747583614435078452L; @@ -113,7 +122,7 @@ public static class PushTask extends WizardStep { @Override protected List load() { - return ImplementationRestClient.list(IdMImplementationType.PROPAGATION_ACTIONS).stream(). + return implementationRestClient.list(IdMImplementationType.PROPAGATION_ACTIONS).stream(). map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); } }; @@ -124,7 +133,7 @@ protected List load() { @Override protected List load() { - return ImplementationRestClient.list(IdMImplementationType.PUSH_ACTIONS).stream(). + return implementationRestClient.list(IdMImplementationType.PUSH_ACTIONS).stream(). map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); } }; diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel.java index 0bbe9be3c48..e5d8d65847e 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountDetailsPanel.java @@ -21,6 +21,8 @@ import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; @@ -46,6 +48,7 @@ import org.apache.wicket.extensions.markup.html.repeater.util.SortParam; import org.apache.wicket.extensions.wizard.WizardStep; import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.spring.injection.annot.SpringBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,11 +56,14 @@ public class LinkedAccountDetailsPanel extends WizardStep { private static final long serialVersionUID = 1221037007528732347L; - private static final Logger LOG = LoggerFactory.getLogger(LinkedAccountDetailsPanel.class); + @SpringBean + protected ResourceRestClient resourceRestClient; - private static final int SEARCH_SIZE = 20; + protected static final Logger LOG = LoggerFactory.getLogger(LinkedAccountDetailsPanel.class); - private List connObjectKeyFieldValues; + protected static final int SEARCH_SIZE = 20; + + protected List connObjectKeyFieldValues; public LinkedAccountDetailsPanel(final LinkedAccountTO linkedAccountTO) { super(); @@ -68,19 +74,16 @@ public LinkedAccountDetailsPanel(final LinkedAccountTO linkedAccountTO) { "resource", new PropertyModel<>(linkedAccountTO, "resource"), false); - dropdownResourceField.setChoices(ResourceRestClient.list().stream(). - filter(resource -> resource.getProvision(AnyTypeKind.USER.name()).isPresent() - && resource.getProvision(AnyTypeKind.USER.name()).get().getMapping() != null - && !resource.getProvision(AnyTypeKind.USER.name()).get().getMapping().getItems().isEmpty()). + + dropdownResourceField.setChoices(resourceRestClient.list().stream(). + filter(resource -> resource.getProvision(AnyTypeKind.USER.name()). + flatMap(provision -> Optional.ofNullable(provision.getMapping())). + filter(mapping -> !mapping.getItems().isEmpty()).isPresent()). map(ResourceTO::getKey). collect(Collectors.toList())); - dropdownResourceField.setOutputMarkupId(true); - dropdownResourceField.addRequiredLabel(); - dropdownResourceField.setNullValid(false); - dropdownResourceField.setRequired(true); - add(dropdownResourceField); + add(dropdownResourceField.setNullValid(false).addRequiredLabel().setOutputMarkupId(true)); - final String connObjectKeyFieldId = "connObjectKeyValue"; + String connObjectKeyFieldId = "connObjectKeyValue"; AjaxTextFieldPanel connObjectKeyField = new AjaxTextFieldPanel( "connObjectKeyValue", "connObjectKeyValue", @@ -157,8 +160,10 @@ private void setConnObjectFieldChoices( AtomicReference resourceRemoteKey = new AtomicReference<>(ConnIdSpecialName.NAME); try { - resourceRemoteKey.set(ResourceRestClient.read(resource).getProvision(AnyTypeKind.USER.name()).get(). - getMapping().getConnObjectKeyItem().get().getExtAttrName()); + resourceRestClient.read(resource).getProvision(AnyTypeKind.USER.name()). + flatMap(provision -> Optional.ofNullable(provision.getMapping())). + flatMap(mapping -> mapping.getConnObjectKeyItem()). + ifPresent(connObjectKeyItem -> resourceRemoteKey.set(connObjectKeyItem.getExtAttrName())); } catch (Exception ex) { LOG.error("While reading mapping for resource {}", resource, ex); } @@ -168,16 +173,16 @@ private void setConnObjectFieldChoices( builder.fiql(SyncopeClient.getConnObjectTOFiqlSearchConditionBuilder(). is(resourceRemoteKey.get()).equalTo(searchTerm + "*").query()).build(); } - Pair> items = ResourceRestClient.searchConnObjects( + Pair> items = resourceRestClient.searchConnObjects( resource, AnyTypeKind.USER.name(), builder, new SortParam<>(resourceRemoteKey.get(), true)); connObjectKeyFieldValues = items.getRight().stream(). - map(item -> item.getAttr(resourceRemoteKey.get()).get().getValues().get(0)). + map(item -> item.getAttr(resourceRemoteKey.get()).map(attr -> attr.getValues().get(0)).orElse(null)). + filter(Objects::nonNull). collect(Collectors.toList()); ajaxTextFieldPanel.setChoices(connObjectKeyFieldValues); } - } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPlainAttrsPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPlainAttrsPanel.java index 402567ee9ce..fff4551eece 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPlainAttrsPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPlainAttrsPanel.java @@ -28,7 +28,6 @@ import java.util.Set; import java.util.stream.Collectors; import org.apache.syncope.client.console.commons.LinkedAccountPlainAttrProperty; -import org.apache.syncope.client.console.rest.AnyTypeRestClient; import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior; @@ -61,22 +60,23 @@ public class LinkedAccountPlainAttrsPanel extends AbstractAttrsWizardStep fixedAttrs = new HashSet<>(); + protected final Set fixedAttrs = new HashSet<>(); - private final List accountPlainAttrProperties = new ArrayList<>(); + protected final List accountPlainAttrProperties = new ArrayList<>(); public LinkedAccountPlainAttrsPanel( final EntityWrapper modelObject, final UserTO userTO, + final List anyTypeClasses, final List whichPlainAttrs) throws IllegalArgumentException { super(userTO, AjaxWizard.Mode.EDIT, - AnyTypeRestClient.read(userTO.getType()).getClasses(), + anyTypeClasses, whichPlainAttrs); this.linkedAccountTO = modelObject.getInnerObject(); @@ -216,13 +216,9 @@ protected List getAttrsFromTO() { } private void setFixedAttr(final Collection values) { - values.forEach(schema -> { - if (linkedAccountTO.getPlainAttr(schema.getKey()).isPresent()) { - fixedAttrs.add(linkedAccountTO.getPlainAttr(schema.getKey()).get()); - } else if (userTO.getPlainAttr(schema.getKey()).isPresent()) { - fixedAttrs.add(userTO.getPlainAttr(schema.getKey()).get()); - } - }); + values.forEach(schema -> linkedAccountTO.getPlainAttr(schema.getKey()).ifPresentOrElse( + fixedAttrs::add, + () -> userTO.getPlainAttr(schema.getKey()).ifPresent(fixedAttrs::add))); } private boolean checkIsReadonlyAttr(final String schema) { @@ -250,9 +246,9 @@ protected void populateItem(final ListItem item) { final boolean isMultivalue = schemas.get(attrTO.getSchema()).isMultivalue(); AbstractFieldPanel panel = setPanel( - schemas, - item, - linkedAccountTO.getPlainAttr(attrTO.getSchema()).isEmpty()); + schemas, + item, + linkedAccountTO.getPlainAttr(attrTO.getSchema()).isEmpty()); panel.showExternAction(checkboxToggle(attrTO, panel, isMultivalue)); } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel.java index 7acd107744a..df38cf0fae2 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountPrivilegesPanel.java @@ -28,27 +28,31 @@ import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.util.ListModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class LinkedAccountPrivilegesPanel extends WizardStep { private static final long serialVersionUID = 3388483585148725922L; + @SpringBean + protected ApplicationRestClient applicationRestClient; + public LinkedAccountPrivilegesPanel(final LinkedAccountTO linkedAccountTO) { super(); setOutputMarkupId(true); - final LoadableDetachableModel> availablePrivilges = new LoadableDetachableModel<>() { + LoadableDetachableModel> availablePrivilges = new LoadableDetachableModel<>() { private static final long serialVersionUID = 5275935387613157437L; @Override protected List load() { - return ApplicationRestClient.list().stream(). - flatMap(app -> app.getPrivileges().stream()). - map(PrivilegeTO::getKey). - distinct(). - sorted(). - collect(Collectors.toList()); + return applicationRestClient.list().stream(). + flatMap(app -> app.getPrivileges().stream()). + map(PrivilegeTO::getKey). + distinct(). + sorted(). + collect(Collectors.toList()); } }; AjaxPalettePanel privilegesPanel = new AjaxPalettePanel.Builder(). diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountWizardBuilder.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountWizardBuilder.java index 705fa0f876a..9fe3fae61ab 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountWizardBuilder.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/LinkedAccountWizardBuilder.java @@ -24,6 +24,7 @@ import java.util.stream.Collectors; import org.apache.syncope.client.console.layout.LinkedAccountForm; import org.apache.syncope.client.console.layout.LinkedAccountFormLayoutInfo; +import org.apache.syncope.client.console.rest.AnyTypeRestClient; import org.apache.syncope.client.console.rest.UserRestClient; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal.ModalEvent; import org.apache.syncope.client.console.wizards.BaseAjaxWizardBuilder; @@ -46,19 +47,27 @@ public class LinkedAccountWizardBuilder extends BaseAjaxWizardBuilder model; + protected final IModel model; protected LinkedAccountFormLayoutInfo formLayoutInfo; + protected final UserRestClient userRestClient; + + protected final AnyTypeRestClient anyTypeRestClient; + public LinkedAccountWizardBuilder( final IModel model, final LinkedAccountFormLayoutInfo formLayoutInfo, + final UserRestClient userRestClient, + final AnyTypeRestClient anyTypeRestClient, final PageReference pageRef) { + super(new LinkedAccountTO(), pageRef); + this.model = model; this.formLayoutInfo = formLayoutInfo; + this.userRestClient = userRestClient; + this.anyTypeRestClient = anyTypeRestClient; } @Override @@ -76,7 +85,10 @@ protected WizardModel buildModelSteps(final LinkedAccountTO modelObject, final W if (formLayoutInfo.isPlainAttrs()) { wizardModel.add(new LinkedAccountPlainAttrsPanel( - new EntityWrapper<>(modelObject), model.getObject(), formLayoutInfo.getWhichPlainAttrs())); + new EntityWrapper<>(modelObject), + model.getObject(), + anyTypeRestClient.read(model.getObject().getType()).getClasses(), + formLayoutInfo.getWhichPlainAttrs())); } if (formLayoutInfo.isPrivileges()) { diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsResourcesPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsResourcesPanel.java index a5bc48ba5ec..b12a06900d6 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsResourcesPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsResourcesPanel.java @@ -24,6 +24,7 @@ import java.util.Iterator; import java.util.List; import org.apache.syncope.client.console.SyncopeWebApplication; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.IdMConstants; import org.apache.syncope.client.console.commons.SortableDataProviderComparator; import org.apache.syncope.client.console.pages.BasePage; @@ -32,7 +33,6 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.console.wizards.any.MergeLinkedAccountsResourcesPanel.ResourceSelectionDirectoryPanel.ResourcesDataProvider; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.common.lib.to.ResourceTO; import org.apache.syncope.common.lib.types.IdMEntitlement; import org.apache.wicket.PageReference; @@ -47,19 +47,25 @@ import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class MergeLinkedAccountsResourcesPanel extends WizardStep implements ICondition { private static final long serialVersionUID = 1221037007528732347L; - private final MergeLinkedAccountsWizardModel wizardModel; + @SpringBean + protected ResourceRestClient resourceRestClient; + + protected final MergeLinkedAccountsWizardModel wizardModel; + + public MergeLinkedAccountsResourcesPanel( + final MergeLinkedAccountsWizardModel wizardModel, + final PageReference pageRef) { - public MergeLinkedAccountsResourcesPanel(final MergeLinkedAccountsWizardModel wizardModel, - final PageReference pageReference) { super(); setOutputMarkupId(true); this.wizardModel = wizardModel; - add(new ResourceSelectionDirectoryPanel("resources", pageReference)); + add(new ResourceSelectionDirectoryPanel("resources", resourceRestClient, pageRef)); } @Override @@ -82,8 +88,12 @@ protected class ResourceSelectionDirectoryPanel extends private static final long serialVersionUID = 6005711052393825472L; - ResourceSelectionDirectoryPanel(final String id, final PageReference pageRef) { - super(id, pageRef, true); + ResourceSelectionDirectoryPanel( + final String id, + final ResourceRestClient restClient, + final PageReference pageRef) { + + super(id, restClient, pageRef, true); modal.size(Modal.Size.Large); setOutputMarkupId(true); @@ -118,20 +128,20 @@ protected ActionsPanel getActions(final IModel model) { @Override public void onClick(final AjaxRequestTarget target, final ResourceTO resource) { MergeLinkedAccountsWizardModel model = MergeLinkedAccountsResourcesPanel.this.wizardModel; - String connObjectKeyValue = ResourceRestClient.getConnObjectKeyValue( - resource.getKey(), - model.getMergingUser().getType(), - model.getMergingUser().getKey()); + String connObjectKeyValue = restClient.getConnObjectKeyValue( + resource.getKey(), + model.getMergingUser().getType(), + model.getMergingUser().getKey()); if (connObjectKeyValue != null) { model.setResource(resource); String tableId = MergeLinkedAccountsResourcesPanel.this. - get("resources:container:content:searchContainer:resultTable" - + ":tablePanel:groupForm:checkgroup:dataTable"). - getMarkupId(); + get("resources:container:content:searchContainer:resultTable" + + ":tablePanel:groupForm:checkgroup:dataTable"). + getMarkupId(); String js = "$('#" + tableId + "').removeClass('active');"; js += "$('#" + tableId + " tbody tr td div').filter(function() " - + "{return $(this).text() === \"" + resource.getKey() + "\";})" - + ".parent().parent().addClass('active');"; + + "{return $(this).text() === \"" + resource.getKey() + "\";})" + + ".parent().parent().addClass('active');"; target.prependJavaScript(js); } else { @@ -162,14 +172,14 @@ private ResourcesDataProvider(final int paginatorRows) { @Override public Iterator iterator(final long first, final long count) { - List list = ResourceRestClient.list(); + List list = restClient.list(); list.sort(comparator); return list.subList((int) first, (int) first + (int) count).iterator(); } @Override public long size() { - return ResourceRestClient.list().size(); + return restClient.list().size(); } @Override diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel.java index 955ba56aab7..26d78fc0f19 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel.java @@ -24,6 +24,7 @@ import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; +import org.apache.syncope.client.console.commons.DirectoryDataProvider; import org.apache.syncope.client.console.commons.SortableDataProviderComparator; import org.apache.syncope.client.console.panels.DirectoryPanel; import org.apache.syncope.client.console.rest.ResourceRestClient; @@ -31,7 +32,6 @@ import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wizards.any.MergeLinkedAccountsReviewPanel.LinkedAccountsReviewDirectoryPanel.LinkedAccountsDataProvider; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.DirectoryDataProvider; import org.apache.syncope.common.lib.to.LinkedAccountTO; import org.apache.syncope.common.lib.to.UserTO; import org.apache.wicket.PageReference; @@ -43,17 +43,23 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class MergeLinkedAccountsReviewPanel extends WizardStep { private static final long serialVersionUID = 1221037007528732347L; - public MergeLinkedAccountsReviewPanel(final MergeLinkedAccountsWizardModel wizardModel, - final PageReference pageReference) { + @SpringBean + protected ResourceRestClient resourceRestClient; + + public MergeLinkedAccountsReviewPanel( + final MergeLinkedAccountsWizardModel wizardModel, + final PageReference pageRef) { + super(); setOutputMarkupId(true); setTitleModel(new StringResourceModel("mergeLinkedAccounts.reviewAccounts.title")); - add(new LinkedAccountsReviewDirectoryPanel("linkedAccounts", pageReference, wizardModel)); + add(new LinkedAccountsReviewDirectoryPanel("linkedAccounts", resourceRestClient, pageRef, wizardModel)); } protected static class LinkedAccountsReviewDirectoryPanel extends @@ -67,10 +73,11 @@ protected static class LinkedAccountsReviewDirectoryPanel extends LinkedAccountsReviewDirectoryPanel( final String id, + final ResourceRestClient restClient, final PageReference pageRef, final MergeLinkedAccountsWizardModel wizardModel) { - super(id, pageRef, true); + super(id, restClient, pageRef, true); this.wizardModel = wizardModel; modal.size(Modal.Size.Large); setOutputMarkupId(true); @@ -107,7 +114,7 @@ protected Collection getBatches() { return List.of(); } - private List previewAccounts() { + protected List previewAccounts() { UserTO mergingUser = wizardModel.getMergingUser(); // Move linked accounts into the target/base user as linked accounts @@ -125,13 +132,13 @@ private List previewAccounts() { // Move merging user's resources into the target/base user as a linked account accounts.addAll(mergingUser.getResources().stream().map(resource -> { - String connObjectKeyValue = ResourceRestClient.getConnObjectKeyValue(resource, + String connObjectKeyValue = restClient.getConnObjectKeyValue(resource, mergingUser.getType(), mergingUser.getKey()); return new LinkedAccountTO.Builder(resource, connObjectKeyValue).build(); }).collect(Collectors.toList())); // Move merging user into target/base user as a linked account - String connObjectKeyValue = ResourceRestClient.getConnObjectKeyValue( + String connObjectKeyValue = restClient.getConnObjectKeyValue( wizardModel.getResource().getKey(), mergingUser.getType(), mergingUser.getKey()); LinkedAccountTO linkedAccount = diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsSearchPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsSearchPanel.java index e73e5c97282..2c194b9f67c 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsSearchPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsSearchPanel.java @@ -41,22 +41,35 @@ import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; import org.apache.wicket.model.util.ListModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class MergeLinkedAccountsSearchPanel extends WizardStep { private static final long serialVersionUID = 1221037007528732347L; - private final WebMarkupContainer ownerContainer; + @SpringBean + protected AnyTypeRestClient anyTypeRestClient; - private final UserSearchPanel userSearchPanel; + @SpringBean + protected AnyTypeClassRestClient anyTypeClassRestClient; - private final UserSelectionDirectoryPanel userDirectoryPanel; + @SpringBean + protected UserRestClient userRestClient; - private final Fragment userSearchFragment; + protected final WebMarkupContainer ownerContainer; - private final MergeLinkedAccountsWizardModel wizardModel; + protected final UserSearchPanel userSearchPanel; + + protected final UserSelectionDirectoryPanel userDirectoryPanel; + + protected final Fragment userSearchFragment; + + protected final MergeLinkedAccountsWizardModel wizardModel; + + public MergeLinkedAccountsSearchPanel( + final MergeLinkedAccountsWizardModel model, + final PageReference pageRef) { - public MergeLinkedAccountsSearchPanel(final MergeLinkedAccountsWizardModel model, final PageReference pageRef) { super(); setOutputMarkupId(true); @@ -73,9 +86,9 @@ public MergeLinkedAccountsSearchPanel(final MergeLinkedAccountsWizardModel model build("usersearch")); userSearchFragment.add(userSearchPanel); - AnyTypeTO anyTypeTO = AnyTypeRestClient.read(AnyTypeKind.USER.name()); + AnyTypeTO anyTypeTO = anyTypeRestClient.read(AnyTypeKind.USER.name()); userDirectoryPanel = UserSelectionDirectoryPanel.class.cast(new UserSelectionDirectoryPanel.Builder( - AnyTypeClassRestClient.list(anyTypeTO.getClasses()), anyTypeTO.getKey(), pageRef). + anyTypeClassRestClient.list(anyTypeTO.getClasses()), userRestClient, anyTypeTO.getKey(), pageRef). build("searchResult")); userSearchFragment.add(userDirectoryPanel); @@ -95,7 +108,7 @@ public void onEvent(final IEvent event) { (AnySelectionDirectoryPanel.ItemSelection) event.getPayload(); AnyTO sel = payload.getSelection(); - wizardModel.setMergingUser(new UserRestClient().read(sel.getKey())); + wizardModel.setMergingUser(userRestClient.read(sel.getKey())); String tableId = ((Component) event.getSource()). get("container:content:searchContainer:resultTable:tablePanel:groupForm:checkgroup:dataTable"). diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsWizardBuilder.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsWizardBuilder.java index fffe2596dea..50b68ca7e2b 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsWizardBuilder.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsWizardBuilder.java @@ -55,23 +55,32 @@ public class MergeLinkedAccountsWizardBuilder extends BaseAjaxWizardBuilder modal; + protected final BaseModal modal; - private MergeLinkedAccountsWizardModel model; + protected MergeLinkedAccountsWizardModel model; + + protected final ResourceRestClient resourceRestClient; + + protected final UserRestClient userRestClient; public MergeLinkedAccountsWizardBuilder( final IModel model, - final PageReference pageRef, final UserDirectoryPanel parentPanel, - final BaseModal modal) { + final BaseModal modal, + final ResourceRestClient resourceRestClient, + final UserRestClient userRestClient, + final PageReference pageRef) { super(model.getObject(), pageRef); + this.parentPanel = parentPanel; this.modal = modal; + this.resourceRestClient = resourceRestClient; + this.userRestClient = userRestClient; } @Override @@ -132,8 +141,8 @@ private void mergeAccounts() throws Exception { // Move merging user's resources into the target/base user as a linked account mergingUserTO.getResources().forEach(resource -> { - String connObjectKeyValue = ResourceRestClient.getConnObjectKeyValue(resource, - mergingUserTO.getType(), mergingUserTO.getKey()); + String connObjectKeyValue = resourceRestClient.getConnObjectKeyValue( + resource, mergingUserTO.getType(), mergingUserTO.getKey()); LinkedAccountTO linkedAccount = new LinkedAccountTO.Builder(resource, connObjectKeyValue).build(); linkedAccount.getPlainAttrs().addAll(mergingUserTO.getPlainAttrs()); linkedAccount.getPrivileges().addAll(mergingUserTO.getPrivileges()); @@ -145,7 +154,7 @@ private void mergeAccounts() throws Exception { }); // Move merging user into target/base user as a linked account - String connObjectKeyValue = ResourceRestClient.getConnObjectKeyValue( + String connObjectKeyValue = resourceRestClient.getConnObjectKeyValue( model.getResource().getKey(), mergingUserTO.getType(), mergingUserTO.getKey()); LinkedAccountTO linkedAccount = new LinkedAccountTO.Builder(model.getResource().getKey(), connObjectKeyValue). @@ -182,7 +191,7 @@ private void mergeAccounts() throws Exception { updateUser.setContent(updateUserPayload); batchRequest.getItems().add(updateUser); - Map batchResponse = UserRestClient.batch(batchRequest); + Map batchResponse = userRestClient.batch(batchRequest); batchResponse.forEach((key, value) -> { if (!value.equalsIgnoreCase("success")) { throw new IllegalArgumentException("Unable to report a success operation status for " + key); diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/Resources.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/Resources.java index ac1d1e131cd..db2aeec6351 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/Resources.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/any/Resources.java @@ -47,10 +47,10 @@ public Resources(final AnyWrapper modelObject) { public boolean evaluate() { if (SyncopeWebApplication.get().getSecuritySettings(). getAuthorizationStrategy().isActionAuthorized(this, RENDER)) { - available.setObject(SyncopeWebApplication.get().getResourceProvider().get()); + + available.setObject(SyncopeWebApplication.get().getResourceProvider().get(anyTO.getType())); return !available.getObject().isEmpty(); - } else { - return false; } + return false; } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorConfPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorConfPanel.java index 4574260c8d2..a9588bf7363 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorConfPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorConfPanel.java @@ -45,13 +45,7 @@ protected List load() { ConnectorConfPanel.this.modelObject.getConf().clear(); // re-order properties - properties.sort((o1, o2) -> { - if (o1 == null) { - return -1; - } else { - return o1.compareTo(o2); - } - }); + properties.sort((o1, o2) -> o1 == null ? -1 : o1.compareTo(o2)); ConnectorConfPanel.this.modelObject.getConf().addAll(properties); return properties; diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java index e285ed2bc98..a4931c2161a 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.java @@ -18,22 +18,20 @@ */ package org.apache.syncope.client.console.wizards.resources; -import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; -import org.apache.commons.lang3.StringUtils; -import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.syncope.client.console.SyncopeWebApplication; import org.apache.syncope.client.console.commons.RealmsUtils; -import org.apache.syncope.client.console.rest.ConnectorRestClient; import org.apache.syncope.client.console.rest.RealmRestClient; import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSearchFieldPanel; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; -import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxNumberFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; -import org.apache.syncope.common.lib.SyncopeConstants; import org.apache.syncope.common.lib.to.ConnIdBundle; import org.apache.syncope.common.lib.to.ConnInstanceTO; import org.apache.syncope.common.lib.to.ConnPoolConfTO; @@ -41,22 +39,25 @@ import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings; import org.apache.wicket.extensions.wizard.WizardStep; -import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class ConnectorDetailsPanel extends WizardStep { private static final long serialVersionUID = -2435937897614232137L; + @SpringBean + protected RealmRestClient realmRestClient; + public ConnectorDetailsPanel(final ConnInstanceTO connInstanceTO, final List bundles) { super(); setOutputMarkupId(true); - boolean isSearchEnabled = RealmsUtils.isSearchEnabled(); + boolean fullRealmsTree = SyncopeWebApplication.get().fullRealmsTree(realmRestClient); AutoCompleteSettings settings = new AutoCompleteSettings(); - settings.setShowCompleteListOnFocusGain(!isSearchEnabled); - settings.setShowListOnEmptyInput(!isSearchEnabled); + settings.setShowCompleteListOnFocusGain(fullRealmsTree); + settings.setShowListOnEmptyInput(fullRealmsTree); AjaxSearchFieldPanel realm = new AjaxSearchFieldPanel( "adminRealm", "adminRealm", new PropertyModel<>(connInstanceTO, "adminRealm"), settings) { @@ -65,90 +66,51 @@ public ConnectorDetailsPanel(final ConnInstanceTO connInstanceTO, final List getChoices(final String input) { - return (isSearchEnabled - ? RealmRestClient.search(RealmsUtils.buildQuery(input)).getResult() - : RealmRestClient.list(SyncopeConstants.ROOT_REALM)). - stream().filter(realm -> SyncopeConsoleSession.get().getAuthRealms().stream(). - anyMatch(authRealm -> realm.getFullPath().startsWith(authRealm))). + return (RealmsUtils.checkInput(input) + ? (realmRestClient.search(fullRealmsTree + ? RealmsUtils.buildBaseQuery() + : RealmsUtils.buildKeywordQuery(input)).getResult()) + : List.of()).stream(). map(RealmTO::getFullPath).collect(Collectors.toList()).iterator(); } }; add(realm.addRequiredLabel().setOutputMarkupId(true)); AjaxTextFieldPanel displayName = new AjaxTextFieldPanel( - "displayName", "displayName", new PropertyModel<>(connInstanceTO, "displayName"), false); - displayName.setOutputMarkupId(true); - displayName.addRequiredLabel(); - add(displayName); + "displayName", + "displayName", + new PropertyModel<>(connInstanceTO, "displayName"), false); + add(displayName.addRequiredLabel().setOutputMarkupId(true)); + + AjaxTextFieldPanel location = new AjaxTextFieldPanel( + "location", "location", new PropertyModel<>(connInstanceTO, "location"), false); + add(location.addRequiredLabel().setOutputMarkupId(true).setEnabled(false)); - final AjaxDropDownChoicePanel bundleName = new AjaxDropDownChoicePanel<>( + AjaxDropDownChoicePanel bundleName = new AjaxDropDownChoicePanel<>( "bundleName", "bundleName", new PropertyModel<>(connInstanceTO, "bundleName"), false); - - if (StringUtils.isNotBlank(connInstanceTO.getLocation())) { - AjaxTextFieldPanel location = new AjaxTextFieldPanel( - "location", "location", new PropertyModel<>(connInstanceTO, "location"), false); - location.addRequiredLabel(); - location.setOutputMarkupId(true); - location.setEnabled(false); - add(location); - } else { - final AjaxDropDownChoicePanel location = new AjaxDropDownChoicePanel<>( - "location", "location", new PropertyModel<>(connInstanceTO, "location"), false); - location.setChoices(new ArrayList<>(SyncopeConsoleSession.get().getPlatformInfo().getConnIdLocations())); - location.addRequiredLabel(); - location.setOutputMarkupId(true); - location.getField().setOutputMarkupId(true); - add(location); - - location.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { - - private static final long serialVersionUID = -5609231641453245929L; - - @Override - protected void onUpdate(final AjaxRequestTarget target) { - ((DropDownChoice) location.getField()).setNullValid(false); - bundleName.setEnabled(true); - - List bundles = ConnectorRestClient.getAllBundles().stream(). - filter(object -> object.getLocation().equals(connInstanceTO.getLocation())). - collect(Collectors.toList()); - - List listBundles = getBundles(connInstanceTO, bundles); - if (listBundles.size() == 1) { - connInstanceTO.setBundleName(listBundles.get(0)); - bundleName.getField().setModelObject(listBundles.get(0)); - } - bundleName.setChoices(listBundles); - - target.add(bundleName); - } - }); - } - - ((DropDownChoice) bundleName.getField()).setNullValid(true); - - List bundleNames = new ArrayList<>(); - bundles.stream(). - filter(bundle -> (!bundleNames.contains(bundle.getBundleName()))). - forEachOrdered(bundle -> bundleNames.add(bundle.getBundleName())); - - bundleName.setChoices(bundleNames); - bundleName.addRequiredLabel(); - bundleName.setOutputMarkupId(true); - bundleName.setEnabled(connInstanceTO.getKey() == null); + bundleName.setEnabled(connInstanceTO.getKey() == null || connInstanceTO.isErrored()); + bundleName.setChoices(bundles.stream().map(ConnIdBundle::getBundleName). + distinct().sorted().collect(Collectors.toList())); bundleName.getField().setOutputMarkupId(true); - add(bundleName); - - final AjaxDropDownChoicePanel version = new AjaxDropDownChoicePanel<>( + add(bundleName.addRequiredLabel().setOutputMarkupId(true)); + + AjaxDropDownChoicePanel connectorName = new AjaxDropDownChoicePanel<>( + "connectorName", + "connectorName", + new PropertyModel<>(connInstanceTO, "connectorName"), false); + connectorName.setEnabled(connInstanceTO.getBundleName() == null || connInstanceTO.isErrored()); + Optional.ofNullable(connInstanceTO.getConnectorName()).ifPresent(v -> connectorName.setChoices(List.of(v))); + connectorName.getField().setOutputMarkupId(true); + add(connectorName.addRequiredLabel().setOutputMarkupId(true)); + + AjaxDropDownChoicePanel version = new AjaxDropDownChoicePanel<>( "version", "version", new PropertyModel<>(connInstanceTO, "version"), false); - version.setChoices(getVersions(connInstanceTO, bundles)); - version.addRequiredLabel(); - version.setEnabled(connInstanceTO.getBundleName() != null); - version.setOutputMarkupId(true); + version.setEnabled(connInstanceTO.getConnectorName() == null || connInstanceTO.isErrored()); + Optional.ofNullable(connInstanceTO.getVersion()).ifPresent(v -> version.setChoices(List.of(v))); version.getField().setOutputMarkupId(true); - add(version); + add(version.addRequiredLabel().setOutputMarkupId(true)); bundleName.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { @@ -156,18 +118,54 @@ protected void onUpdate(final AjaxRequestTarget target) { @Override protected void onUpdate(final AjaxRequestTarget target) { - ((DropDownChoice) bundleName.getField()).setNullValid(false); - version.setEnabled(true); - - List versions; - if (bundles.isEmpty()) { - List bundles = ConnectorRestClient.getAllBundles().stream(). - filter(object -> object.getLocation().equals(connInstanceTO.getLocation())). - collect(Collectors.toList()); - versions = getVersions(connInstanceTO, bundles); + connectorName.setEnabled(true); + + List> connectors = bundles.stream(). + filter(bundle -> bundle.getBundleName().equals(connInstanceTO.getBundleName())). + map(bundle -> Pair.of(bundle.getConnectorName(), bundle.getVersion())). + collect(Collectors.toList()); + if (connectors.size() == 1) { + Pair entry = connectors.get(0); + + connInstanceTO.setConnectorName(entry.getLeft()); + connectorName.getField().setModelObject(entry.getLeft()); + connectorName.setChoices(List.of(entry.getLeft())); + + connInstanceTO.setVersion(entry.getRight()); + version.getField().setModelObject(entry.getRight()); + version.setChoices(List.of(entry.getRight())); } else { - versions = getVersions(connInstanceTO, bundles); + connectorName.setChoices(connectors.stream(). + map(Pair::getLeft).distinct().sorted().collect(Collectors.toList())); + + List versions = connectors.stream(). + map(Pair::getRight).distinct().sorted().collect(Collectors.toList()); + version.setChoices(versions); + + if (versions.size() == 1) { + connInstanceTO.setVersion(versions.get(0)); + version.getField().setModelObject(versions.get(0)); + } else { + connInstanceTO.setVersion(null); + version.getField().setModelObject(null); + } } + + target.add(version); + target.add(connectorName); + } + }); + + connectorName.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { + + private static final long serialVersionUID = -1107858522700306810L; + + @Override + protected void onUpdate(final AjaxRequestTarget target) { + List versions = bundles.stream(). + filter(bundle -> bundle.getBundleName().equals(connInstanceTO.getBundleName()) + && bundle.getConnectorName().equals(connInstanceTO.getConnectorName())). + map(ConnIdBundle::getVersion).collect(Collectors.toList()); if (versions.size() == 1) { connInstanceTO.setVersion(versions.get(0)); version.getField().setModelObject(versions.get(0)); @@ -182,39 +180,28 @@ protected void onUpdate(final AjaxRequestTarget target) { connInstanceTO.setPoolConf(new ConnPoolConfTO()); } - add(new AjaxSpinnerFieldPanel.Builder().min(0).max(Integer.MAX_VALUE).build( + add(new AjaxNumberFieldPanel.Builder().min(0).max(Integer.MAX_VALUE).build( "connRequestTimeout", "connRequestTimeout", Integer.class, new PropertyModel<>(connInstanceTO, "connRequestTimeout"))); - add(new AjaxSpinnerFieldPanel.Builder().min(0).max(Integer.MAX_VALUE).build( + add(new AjaxNumberFieldPanel.Builder().min(0).max(Integer.MAX_VALUE).build( "poolMaxObjects", "poolMaxObjects", Integer.class, new PropertyModel<>(connInstanceTO.getPoolConf(), "maxObjects"))); - add(new AjaxSpinnerFieldPanel.Builder().min(0).max(Integer.MAX_VALUE).build( + add(new AjaxNumberFieldPanel.Builder().min(0).max(Integer.MAX_VALUE).build( "poolMinIdle", "poolMinIdle", Integer.class, new PropertyModel<>(connInstanceTO.getPoolConf(), "minIdle"))); - add(new AjaxSpinnerFieldPanel.Builder().min(0).max(Integer.MAX_VALUE).build( + add(new AjaxNumberFieldPanel.Builder().min(0).max(Integer.MAX_VALUE).build( "poolMaxIdle", "poolMaxIdle", Integer.class, new PropertyModel<>(connInstanceTO.getPoolConf(), "maxIdle"))); - add(new AjaxSpinnerFieldPanel.Builder().min(0L).max(Long.MAX_VALUE).build( + add(new AjaxNumberFieldPanel.Builder().min(0L).max(Long.MAX_VALUE).build( "poolMaxWait", "poolMaxWait", Long.class, new PropertyModel<>(connInstanceTO.getPoolConf(), "maxWait"))); - add(new AjaxSpinnerFieldPanel.Builder().min(0L).max(Long.MAX_VALUE).build( + add(new AjaxNumberFieldPanel.Builder().min(0L).max(Long.MAX_VALUE).build( "poolMinEvictableIdleTime", "poolMinEvictableIdleTime", Long.class, new PropertyModel<>(connInstanceTO.getPoolConf(), "minEvictableIdleTimeMillis"))); } - - private static List getVersions(final ConnInstanceTO connInstanceTO, final List bundles) { - return bundles.stream().filter(object -> object.getLocation().equals(connInstanceTO.getLocation()) - && object.getBundleName().equals(connInstanceTO.getBundleName())). - map(ConnIdBundle::getVersion).collect(Collectors.toList()); - } - - private List getBundles(final ConnInstanceTO connInstanceTO, final List bundles) { - return bundles.stream().filter(object -> object.getLocation().equals(connInstanceTO.getLocation())). - map(ConnIdBundle::getBundleName).collect(Collectors.toList()); - } } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorWizardBuilder.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorWizardBuilder.java index 7fc06a4dd1f..7ecef671068 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorWizardBuilder.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ConnectorWizardBuilder.java @@ -41,12 +41,20 @@ public class ConnectorWizardBuilder extends AbstractResourceWizardBuilder bundles; + protected final List bundles; + + protected final ConnectorRestClient connectorRestClient; + + public ConnectorWizardBuilder( + final ConnInstanceTO defaultItem, + final ConnectorRestClient connectorRestClient, + final PageReference pageRef) { - public ConnectorWizardBuilder(final ConnInstanceTO defaultItem, final PageReference pageRef) { super(defaultItem, pageRef); - this.bundles = ConnectorRestClient.getAllBundles().stream(). + + this.bundles = connectorRestClient.getAllBundles().stream(). filter(object -> object.getLocation().equals(defaultItem.getLocation())).collect(Collectors.toList()); + this.connectorRestClient = connectorRestClient; } @Override @@ -66,7 +74,7 @@ protected Pair check(final AjaxRequestTarget target) { connInstanceTO.setBundleName(bundleTO.getBundleName()); connInstanceTO.setVersion(bundleTO.getVersion()); - return ConnectorRestClient.check(connInstanceTO); + return connectorRestClient.check(connInstanceTO); } @Override @@ -99,39 +107,32 @@ protected Serializable onApplyInternal(final Serializable modelObject) { connInstanceTO.setPoolConf(null); } - ConnInstanceTO res; + ConnInstanceTO connInstance; if (mode == AjaxWizard.Mode.CREATE) { - res = ConnectorRestClient.create(connInstanceTO); + connInstance = connectorRestClient.create(connInstanceTO); } else { - ConnectorRestClient.update(connInstanceTO); - res = connInstanceTO; + connectorRestClient.update(connInstanceTO); + connInstance = connInstanceTO; } - return res; + return connInstance; } @Override protected Serializable getCreateCustomPayloadEvent(final Serializable afterObject, final AjaxRequestTarget target) { - final ConnInstanceTO actual = ConnInstanceTO.class.cast(afterObject); + ConnInstanceTO connInstance = ConnInstanceTO.class.cast(afterObject); return new CreateEvent( - actual.getKey(), - actual.getDisplayName(), + connInstance.getKey(), + connInstance.getDisplayName(), TopologyNode.Kind.CONNECTOR, - URI.create(actual.getLocation()).toASCIIString(), + URI.create(connInstance.getLocation()).toASCIIString(), target); } protected static ConnIdBundle getBundle(final ConnInstanceTO connInstanceTO, final List bundles) { - List bundlesList; - if (bundles.isEmpty()) { - bundlesList = ConnectorRestClient.getAllBundles().stream(). - filter(object -> object.getLocation().equals(connInstanceTO.getLocation())). - collect(Collectors.toList()); - } else { - bundlesList = bundles; - } - return bundlesList.stream().filter(bundle - -> bundle.getBundleName().equals(connInstanceTO.getBundleName()) + return bundles.stream(). + filter(bundle -> bundle.getBundleName().equals(connInstanceTO.getBundleName()) + && bundle.getConnectorName().equals(connInstanceTO.getConnectorName()) && bundle.getVersion().equals(connInstanceTO.getVersion())). findFirst().orElse(null); } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ProvisionWizardBuilder.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ProvisionWizardBuilder.java index 06e70654d34..b7db1ee1680 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ProvisionWizardBuilder.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ProvisionWizardBuilder.java @@ -50,59 +50,14 @@ public class ProvisionWizardBuilder extends BaseAjaxWizardBuilder(resourceProvision)); - - WebMarkupContainer container = new WebMarkupContainer("container"); - container.setOutputMarkupId(true); - add(container); - - clazz = new AjaxTextFieldPanel( - "clazz", "clazz", new PropertyModel<>(resourceProvision, "objectClass")); - clazz.setRequired(true); - clazz.setChoices(ConnectorRestClient.getObjectClasses(resourceTO.getConnector())); - container.add(clazz); - - AjaxCheckBoxPanel ignoreCaseMatch = new AjaxCheckBoxPanel( - "ignoreCaseMatch", "ignoreCaseMatch", new PropertyModel<>(resourceProvision, "ignoreCaseMatch")); - container.add(ignoreCaseMatch); - } - } - - protected void setObjectClassModelObject(final String type) { - if (clazz != null) { - if (AnyTypeKind.USER.name().equals(type)) { - clazz.setModelObject(ConnIdSpecialName.ACCOUNT); - } else if (AnyTypeKind.GROUP.name().equals(type)) { - clazz.setModelObject(ConnIdSpecialName.GROUP); - } else { - clazz.setModelObject(""); - } - } - } - /** * AuxClasses definition step. */ - private static final class AuxClasses extends WizardStep implements ICondition { + protected static final class AuxClasses extends WizardStep implements ICondition { private static final long serialVersionUID = 5315236191866427500L; - private final ResourceProvision provision; + protected final ResourceProvision provision; AuxClasses(final ResourceProvision resourceProvision) { this.provision = resourceProvision; @@ -121,7 +76,7 @@ public boolean evaluate() { /** * Mapping definition step. */ - private static final class Mapping extends WizardStep { + protected static final class Mapping extends WizardStep { private static final long serialVersionUID = 3454904947720856253L; @@ -134,7 +89,7 @@ private static final class Mapping extends WizardStep { /** * AccountLink specification step. */ - private static final class ConnObjectLink extends WizardStep { + protected static final class ConnObjectLink extends WizardStep { private static final long serialVersionUID = 2359955465172450478L; @@ -185,16 +140,63 @@ protected void onUpdate(final AjaxRequestTarget target) { } /** - * Construct. - * - * @param resourceTO external resource to be updated. - * @param adminRealm admin realm - * @param pageRef Caller page reference. + * The object type specification step. */ - public ProvisionWizardBuilder(final ResourceTO resourceTO, final String adminRealm, final PageReference pageRef) { + protected final class ObjectType extends WizardStep { + + private static final long serialVersionUID = -1657800545799468278L; + + ObjectType(final ResourceProvision resourceProvision) { + super(new ResourceModel("clazz.title", StringUtils.EMPTY), + new ResourceModel("clazz.summary", StringUtils.EMPTY), new Model<>(resourceProvision)); + + WebMarkupContainer container = new WebMarkupContainer("container"); + container.setOutputMarkupId(true); + add(container); + + clazz = new AjaxTextFieldPanel( + "clazz", "clazz", new PropertyModel<>(resourceProvision, "objectClass")); + clazz.setRequired(true); + clazz.setChoices(connectorRestClient.getObjectClasses(resourceTO.getConnector())); + container.add(clazz); + + AjaxCheckBoxPanel ignoreCaseMatch = new AjaxCheckBoxPanel( + "ignoreCaseMatch", "ignoreCaseMatch", new PropertyModel<>(resourceProvision, "ignoreCaseMatch")); + container.add(ignoreCaseMatch); + } + } + + protected final ResourceTO resourceTO; + + protected final String adminRealm; + + protected AjaxTextFieldPanel clazz; + + protected final ConnectorRestClient connectorRestClient; + + public ProvisionWizardBuilder( + final ResourceTO resourceTO, + final String adminRealm, + final ConnectorRestClient connectorRestClient, + final PageReference pageRef) { + super(new ResourceProvision(), pageRef); + this.resourceTO = resourceTO; this.adminRealm = adminRealm; + this.connectorRestClient = connectorRestClient; + } + + protected void setObjectClassModelObject(final String type) { + if (clazz != null) { + if (AnyTypeKind.USER.name().equals(type)) { + clazz.setModelObject(ConnIdSpecialName.ACCOUNT); + } else if (AnyTypeKind.GROUP.name().equals(type)) { + clazz.setModelObject(ConnIdSpecialName.GROUP); + } else { + clazz.setModelObject(""); + } + } } @Override diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceConnConfPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceConnConfPanel.java index f4e04df457e..c86859c757b 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceConnConfPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceConnConfPanel.java @@ -28,16 +28,17 @@ import org.apache.wicket.ajax.markup.html.form.AjaxButton; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public abstract class ResourceConnConfPanel extends AbstractConnConfPanel { private static final long serialVersionUID = -7982691107029848579L; - private final boolean createFlag; + @SpringBean + protected ConnectorRestClient connectorRestClient; - public ResourceConnConfPanel(final ResourceTO resourceTO, final boolean createFlag) { + public ResourceConnConfPanel(final ResourceTO resourceTO) { super(resourceTO); - this.createFlag = createFlag; model = new LoadableDetachableModel<>() { @@ -89,7 +90,7 @@ protected final List getConnProperties(final ResourceTO resour List props = new ArrayList<>(); if (resourceTO.getConnector() != null) { - ConnectorRestClient.read(resourceTO.getConnector()).getConf().stream(). + connectorRestClient.read(resourceTO.getConnector()).getConf().stream(). filter(ConnConfProperty::isOverridable). forEachOrdered(props::add); } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel.java index 03bb66fbbb5..3aced1c64e1 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel.java @@ -18,20 +18,20 @@ */ package org.apache.syncope.client.console.wizards.resources; -import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import org.apache.syncope.client.console.rest.ConnectorRestClient; import org.apache.syncope.client.console.rest.ImplementationRestClient; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxNumberFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel; -import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; +import org.apache.syncope.common.lib.to.ConnInstanceTO; import org.apache.syncope.common.lib.to.ImplementationTO; import org.apache.syncope.common.lib.to.ResourceTO; import org.apache.syncope.common.lib.types.IdMImplementationType; @@ -45,31 +45,38 @@ import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.util.ListModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class ResourceDetailsPanel extends WizardStep { private static final long serialVersionUID = -7982691107029848579L; - private AjaxDropDownChoicePanel connector; + @SpringBean + protected ImplementationRestClient implementationRestClient; - private final IModel> propagationActions = new LoadableDetachableModel<>() { + @SpringBean + protected ConnectorRestClient connectorRestClient; + + protected AjaxDropDownChoicePanel connector; + + protected final IModel> propagationActions = new LoadableDetachableModel<>() { private static final long serialVersionUID = 5275935387613157437L; @Override protected List load() { - return ImplementationRestClient.list(IdMImplementationType.PROPAGATION_ACTIONS).stream(). + return implementationRestClient.list(IdMImplementationType.PROPAGATION_ACTIONS).stream(). map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); } }; - private final IModel> provisionSorters = new LoadableDetachableModel<>() { + protected final IModel> provisionSorters = new LoadableDetachableModel<>() { private static final long serialVersionUID = 4659376149825914247L; @Override protected List load() { - return ImplementationRestClient.list(IdMImplementationType.PROVISION_SORTER).stream(). + return implementationRestClient.list(IdMImplementationType.PROVISION_SORTER).stream(). map(ImplementationTO::getKey).sorted().collect(Collectors.toList()); } }; @@ -95,17 +102,12 @@ public ResourceDetailsPanel(final ResourceTO resourceTO, final boolean createFla new PropertyModel<>(resourceTO, "enforceMandatoryCondition"), false)); - container.add(new AjaxSpinnerFieldPanel.Builder().build( + container.add(new AjaxNumberFieldPanel.Builder().build( "propagationPriority", "propagationPriority", Integer.class, new PropertyModel<>(resourceTO, "propagationPriority"))); - container.add(new AjaxCheckBoxPanel("randomPwdIfNotProvided", - new ResourceModel("randomPwdIfNotProvided", "randomPwdIfNotProvided").getObject(), - new PropertyModel<>(resourceTO, "randomPwdIfNotProvided"), - false)); - container.add(new AjaxPalettePanel.Builder(). setAllowMoveAll(true).setAllowOrder(true). build("propagationActions", @@ -157,10 +159,9 @@ public ResourceDetailsPanel(final ResourceTO resourceTO, final boolean createFla "connector", new ResourceModel("connector", "connector").getObject(), new PropertyModel<>(resourceTO, "connector"), false); - Map connectorsMap = new HashMap<>(); - ConnectorRestClient.getAllConnectors().forEach(conn -> connectorsMap.put(conn.getKey(), - conn.getDisplayName())); - connector.setChoices(new ArrayList<>(connectorsMap.keySet())); + Map connectorsMap = connectorRestClient.getAllConnectors().stream(). + collect(Collectors.toMap(ConnInstanceTO::getKey, ConnInstanceTO::getDisplayName)); + connector.setChoices(connectorsMap.keySet().stream().sorted().collect(Collectors.toList())); connector.setChoiceRenderer(new IChoiceRenderer<>() { private static final long serialVersionUID = 91313845533448846L; @@ -169,7 +170,7 @@ public ResourceDetailsPanel(final ResourceTO resourceTO, final boolean createFla @Override public String getDisplayValue(final String value) { - return valueMap.get(value) == null ? value : valueMap.get(value); + return Optional.ofNullable(valueMap.get(value)).orElse(null); } @Override diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java index de84e722a60..1441795726d 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceMappingPanel.java @@ -41,6 +41,7 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.util.ListModel; +import org.apache.wicket.spring.injection.annot.SpringBean; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,14 +52,23 @@ public class ResourceMappingPanel extends AbstractMappingPanel { private static final long serialVersionUID = -7982691107029848579L; - private static final Logger LOG = LoggerFactory.getLogger(ResourceMappingPanel.class); + protected static final Logger LOG = LoggerFactory.getLogger(ResourceMappingPanel.class); + + @SpringBean + protected ConnectorRestClient connectorRestClient; + + @SpringBean + protected AnyTypeRestClient anyTypeRestClient; + + @SpringBean + protected AnyTypeClassRestClient anyTypeClassRestClient; /** * External resource provisioning configuration instance to be updated. */ - private final ResourceProvision provision; + protected final ResourceProvision provision; - private final LoadableDetachableModel> extAttrNames; + protected final LoadableDetachableModel> extAttrNames; /** * Attribute Mapping Panel. @@ -81,7 +91,7 @@ public ResourceMappingPanel( super(id, itemTransformers, jexlTransformers, - new ListModel<>(provision.getItems()), + new ListModel<>(provision.getItems()), resourceTO.getConnector() != null, MappingPurpose.BOTH); @@ -95,11 +105,11 @@ public ResourceMappingPanel( @Override protected List load() { - return ConnectorRestClient.getExtAttrNames( - adminRealm, - provision.getObjectClass(), - resourceTO.getConnector(), - resourceTO.getConfOverride()); + return connectorRestClient.getExtAttrNames( + adminRealm, + provision.getObjectClass(), + resourceTO.getConnector(), + resourceTO.getConfOverride()); } }; } @@ -133,7 +143,7 @@ protected void setAttrNames(final AjaxTextFieldPanel toBeUpdated) { } else { AnyTypeTO anyType = null; try { - anyType = AnyTypeRestClient.read(provision.getAnyType()); + anyType = anyTypeRestClient.read(provision.getAnyType()); } catch (Exception e) { LOG.error("Could not read AnyType {}", provision.getAnyType(), e); } @@ -141,14 +151,14 @@ protected void setAttrNames(final AjaxTextFieldPanel toBeUpdated) { List anyTypeClassTOs = new ArrayList<>(); if (anyType != null) { try { - anyTypeClassTOs.addAll(AnyTypeClassRestClient.list(anyType.getClasses())); + anyTypeClassTOs.addAll(anyTypeClassRestClient.list(anyType.getClasses())); } catch (Exception e) { LOG.error("Could not read AnyType classes for {}", anyType.getClasses(), e); } } provision.getAuxClasses().forEach(auxClass -> { try { - anyTypeClassTOs.add(AnyTypeClassRestClient.read(auxClass)); + anyTypeClassTOs.add(anyTypeClassRestClient.read(auxClass)); } catch (Exception e) { LOG.error("Could not read AnyTypeClass for {}", auxClass, e); } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceProvisionPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceProvisionPanel.java index 3c593960288..96f49011d2b 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceProvisionPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceProvisionPanel.java @@ -29,6 +29,7 @@ import org.apache.syncope.client.console.panels.ListViewPanel; import org.apache.syncope.client.console.panels.ListViewPanel.ListViewReload; import org.apache.syncope.client.console.rest.AnyTypeRestClient; +import org.apache.syncope.client.console.rest.ConnectorRestClient; import org.apache.syncope.client.console.rest.ResourceRestClient; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; @@ -49,22 +50,32 @@ import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class ResourceProvisionPanel extends AbstractModalPanel { private static final long serialVersionUID = -7982691107029848579L; - private final ResourceTO resourceTO; + @SpringBean + protected ResourceRestClient resourceRestClient; - private final List provisions; + @SpringBean + protected ConnectorRestClient connectorRestClient; - private final ObjectTypeTogglePanel objectTypeTogglePanel; + @SpringBean + protected AnyTypeRestClient anyTypeRestClient; - private final WizardMgtPanel list; + protected final ResourceTO resourceTO; - private final ProvisionWizardBuilder wizard; + protected final List provisions; - private final AjaxLink addAjaxLink; + protected final ObjectTypeTogglePanel objectTypeTogglePanel; + + protected final WizardMgtPanel list; + + protected final ProvisionWizardBuilder wizard; + + protected final AjaxLink addAjaxLink; protected ActionLinksTogglePanel actionTogglePanel; @@ -82,23 +93,23 @@ public ResourceProvisionPanel( actionTogglePanel = new ActionLinksTogglePanel<>("toggle", pageRef); add(actionTogglePanel); - wizard = new ProvisionWizardBuilder(resourceTO, adminRealm, pageRef); + wizard = new ProvisionWizardBuilder(resourceTO, adminRealm, connectorRestClient, pageRef); ListViewPanel.Builder builder = new ListViewPanel.Builder<>( - ResourceProvision.class, pageRef) { + ResourceProvision.class, pageRef) { private static final long serialVersionUID = 4907732721283972943L; @Override protected ResourceProvision getActualItem( - final ResourceProvision item, final List list) { + final ResourceProvision item, final List list) { return Optional.ofNullable(item).flatMap(resourceProvision -> list.stream() - .filter(in -> ((resourceProvision.getKey() == null && in.getKey() == null) + .filter(in -> ((resourceProvision.getKey() == null && in.getKey() == null) || (in.getKey() != null && in.getKey().equals(resourceProvision.getKey()))) && ((resourceProvision.getAnyType() == null && in.getAnyType() == null) || (in.getAnyType() != null && in.getAnyType().equals(resourceProvision.getAnyType())))). - findAny()).orElse(null); + findAny()).orElse(null); } @Override @@ -150,10 +161,10 @@ protected ActionLinksTogglePanel getTogglePanel() { public void onClick(final AjaxRequestTarget target, final ResourceProvision provision) { try { send(ResourceProvisionPanel.this, Broadcast.DEPTH, - new AjaxWizard.NewItemActionEvent<>(provision, 1, target).setResourceModel( - new StringResourceModel("inner.provision.mapping", - ResourceProvisionPanel.this, - Model.of(provision)))); + new AjaxWizard.NewItemActionEvent<>(provision, 1, target).setTitleModel( + new StringResourceModel("inner.provision.mapping", + ResourceProvisionPanel.this, + Model.of(provision)))); } catch (SyncopeClientException e) { LOG.error("While contacting resource", e); SyncopeConsoleSession.get().onException(e); @@ -168,11 +179,11 @@ public void onClick(final AjaxRequestTarget target, final ResourceProvision prov @Override public void onClick(final AjaxRequestTarget target, final ResourceProvision provision) { try { - ResourceRestClient.setLatestSyncToken(resourceTO.getKey(), provision.getAnyType()); + resourceRestClient.setLatestSyncToken(resourceTO.getKey(), provision.getAnyType()); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); } catch (Exception e) { LOG.error("While setting latest sync token for {}/{}", - resourceTO.getKey(), provision.getAnyType(), e); + resourceTO.getKey(), provision.getAnyType(), e); SyncopeConsoleSession.get().onException(e); } ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target); @@ -185,11 +196,11 @@ public void onClick(final AjaxRequestTarget target, final ResourceProvision prov @Override public void onClick(final AjaxRequestTarget target, final ResourceProvision provision) { try { - ResourceRestClient.removeSyncToken(resourceTO.getKey(), provision.getAnyType()); + resourceRestClient.removeSyncToken(resourceTO.getKey(), provision.getAnyType()); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); } catch (Exception e) { LOG.error("While removing sync token for {}/{}", - resourceTO.getKey(), provision.getAnyType(), e); + resourceTO.getKey(), provision.getAnyType(), e); SyncopeConsoleSession.get().onException(e); } ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target); @@ -224,7 +235,7 @@ public void onClick(final AjaxRequestTarget target, final ResourceProvision prov @Override public void onClick(final AjaxRequestTarget target) { send(ResourceProvisionPanel.this, Broadcast.BREADTH, - new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target)); + new ActionLinksTogglePanel.ActionLinkToggleCloseEventPayload(target)); objectTypeTogglePanel.setHeaderLabel(target); objectTypeTogglePanel.toggle(target, true); } @@ -283,7 +294,7 @@ public void onSubmit(final AjaxRequestTarget target) { } }); - ResourceRestClient.update(resourceTO); + resourceRestClient.update(resourceTO); SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); modal.close(target); } catch (Exception e) { @@ -304,9 +315,9 @@ private LoadableDetachableModel> getAnyTypes() { @Override protected List load() { - List anyTypes = AnyTypeRestClient.list().stream(). - filter(anyType -> resourceTO.getProvision(anyType).isEmpty()). - collect(Collectors.toList()); + List anyTypes = anyTypeRestClient.list().stream(). + filter(anyType -> resourceTO.getProvision(anyType).isEmpty()). + collect(Collectors.toList()); if (resourceTO.getOrgUnit() == null) { anyTypes.add(SyncopeConstants.REALM_ANYTYPE); } diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceSecurityPanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceSecurityPanel.java index ef9dae064f4..f1981be7543 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceSecurityPanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceSecurityPanel.java @@ -19,6 +19,7 @@ package org.apache.syncope.client.console.wizards.resources; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.Map; import java.util.stream.Collectors; import org.apache.syncope.client.console.rest.PolicyRestClient; @@ -34,62 +35,66 @@ import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.ResourceModel; +import org.apache.wicket.spring.injection.annot.SpringBean; public class ResourceSecurityPanel extends WizardStep { private static final long serialVersionUID = -7982691107029848579L; - private final IModel> passwordPolicies = new LoadableDetachableModel<>() { + @SpringBean + protected PolicyRestClient policyRestClient; + + protected final IModel> passwordPolicies = new LoadableDetachableModel<>() { private static final long serialVersionUID = 5275935387613157437L; @Override protected Map load() { - return PolicyRestClient.list(PolicyType.PASSWORD).stream(). - collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName)); + return policyRestClient.list(PolicyType.PASSWORD).stream(). + collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new)); } }; - private final IModel> accountPolicies = new LoadableDetachableModel<>() { + protected final IModel> accountPolicies = new LoadableDetachableModel<>() { private static final long serialVersionUID = -2012833443695917883L; @Override protected Map load() { - return PolicyRestClient.list(PolicyType.ACCOUNT).stream(). - collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName)); + return policyRestClient.list(PolicyType.ACCOUNT).stream(). + collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new)); } }; - private final IModel> propagationPolicies = new LoadableDetachableModel<>() { + protected final IModel> propagationPolicies = new LoadableDetachableModel<>() { private static final long serialVersionUID = -2012833443695917883L; @Override protected Map load() { - return PolicyRestClient.list(PolicyType.PROPAGATION).stream(). - collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName)); + return policyRestClient.list(PolicyType.PROPAGATION).stream(). + collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new)); } }; - private final IModel> pullPolicies = new LoadableDetachableModel<>() { + protected final IModel> pullPolicies = new LoadableDetachableModel<>() { private static final long serialVersionUID = -2012833443695917883L; @Override protected Map load() { - return PolicyRestClient.list(PolicyType.PULL).stream(). - collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName)); + return policyRestClient.list(PolicyType.PULL).stream(). + collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new)); } }; - private final IModel> pushPolicies = new LoadableDetachableModel<>() { + protected final IModel> pushPolicies = new LoadableDetachableModel<>() { private static final long serialVersionUID = 9089911876466472133L; @Override protected Map load() { - return PolicyRestClient.list(PolicyType.PUSH).stream(). + return policyRestClient.list(PolicyType.PUSH).stream(). collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName)); } }; @@ -111,7 +116,7 @@ public ResourceSecurityPanel(final ResourceTO resourceTO) { new ResourceModel("passwordPolicy", "passwordPolicy").getObject(), new PropertyModel<>(resourceTO, "passwordPolicy"), false); - passwordPolicy.setChoiceRenderer(new PolicyRenderer(passwordPolicies)); + passwordPolicy.setChoiceRenderer(new PolicyRenderer(passwordPolicies.getObject())); passwordPolicy.setChoices(new ArrayList<>(passwordPolicies.getObject().keySet())); ((DropDownChoice) passwordPolicy.getField()).setNullValid(true); container.add(passwordPolicy); @@ -125,7 +130,7 @@ public ResourceSecurityPanel(final ResourceTO resourceTO) { new ResourceModel("accountPolicy", "accountPolicy").getObject(), new PropertyModel<>(resourceTO, "accountPolicy"), false); - accountPolicy.setChoiceRenderer(new PolicyRenderer(accountPolicies)); + accountPolicy.setChoiceRenderer(new PolicyRenderer(accountPolicies.getObject())); accountPolicy.setChoices(new ArrayList<>(accountPolicies.getObject().keySet())); ((DropDownChoice) accountPolicy.getField()).setNullValid(true); container.add(accountPolicy); @@ -139,7 +144,7 @@ public ResourceSecurityPanel(final ResourceTO resourceTO) { new ResourceModel("propagationPolicy", "propagationPolicy").getObject(), new PropertyModel<>(resourceTO, "propagationPolicy"), false); - propagationPolicy.setChoiceRenderer(new PolicyRenderer(propagationPolicies)); + propagationPolicy.setChoiceRenderer(new PolicyRenderer(propagationPolicies.getObject())); propagationPolicy.setChoices(new ArrayList<>(propagationPolicies.getObject().keySet())); ((DropDownChoice) propagationPolicy.getField()).setNullValid(true); container.add(propagationPolicy); @@ -153,7 +158,7 @@ public ResourceSecurityPanel(final ResourceTO resourceTO) { new ResourceModel("pullPolicy", "pullPolicy").getObject(), new PropertyModel<>(resourceTO, "pullPolicy"), false); - pullPolicy.setChoiceRenderer(new PolicyRenderer(pullPolicies)); + pullPolicy.setChoiceRenderer(new PolicyRenderer(pullPolicies.getObject())); pullPolicy.setChoices(new ArrayList<>(pullPolicies.getObject().keySet())); ((DropDownChoice) pullPolicy.getField()).setNullValid(true); container.add(pullPolicy); @@ -167,7 +172,7 @@ public ResourceSecurityPanel(final ResourceTO resourceTO) { new ResourceModel("pushPolicy", "pushPolicy").getObject(), new PropertyModel<>(resourceTO, "pushPolicy"), false); - pushPolicy.setChoiceRenderer(new PolicyRenderer(pushPolicies)); + pushPolicy.setChoiceRenderer(new PolicyRenderer(pushPolicies.getObject())); pushPolicy.setChoices(new ArrayList<>(pushPolicies.getObject().keySet())); ((DropDownChoice) pushPolicy.getField()).setNullValid(true); container.add(pushPolicy); diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceWizardBuilder.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceWizardBuilder.java index 1fd264204d9..cfc8493e101 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceWizardBuilder.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/wizards/resources/ResourceWizardBuilder.java @@ -45,10 +45,22 @@ public class ResourceWizardBuilder extends AbstractResourceWizardBuilder check(final AjaxRequestTarget target) { - return ResourceRestClient.check(modelObject); + return resourceRestClient.check(modelObject); } @Override protected void onComponentTag(final ComponentTag tag) { tag.append("class", "scrollable-tab-content", " "); } - }; if (createFlag && resourceDetailsPanel.getConnector() != null) { resourceDetailsPanel.getConnector().getField().add( - new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { - - private static final long serialVersionUID = 4600298808455564695L; - - @Override - protected void onUpdate(final AjaxRequestTarget target) { - resourceTO.setConnector(resourceDetailsPanel.getConnector().getModelObject()); - - LoadableDetachableModel> model = - new LoadableDetachableModel<>() { - - private static final long serialVersionUID = -2965284931860212687L; - - @Override - protected List load() { - List confOverride = - resourceConnConfPanel.getConnProperties(resourceTO); - resourceTO.getConfOverride().clear(); - resourceTO.getConfOverride().addAll(confOverride); - - return new PropertyModel>(modelObject, "confOverride") { - - private static final long serialVersionUID = -7809699384012595307L; - - @Override - public List getObject() { - List res = new ArrayList<>(super.getObject()); - - // re-order properties - Collections.sort(res, (left, right) -> { - if (left == null) { - return -1; - } else { - return left.compareTo(right); - } - }); - - return res; - } - }.getObject(); - } - }; - resourceConnConfPanel.setConfPropertyListView(model, true); - target.add(resourceConnConfPanel.getCheck().setVisible(true).setEnabled(true)); - } - }); + new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { + + private static final long serialVersionUID = 4600298808455564695L; + + @Override + protected void onUpdate(final AjaxRequestTarget target) { + resourceTO.setConnector(resourceDetailsPanel.getConnector().getModelObject()); + + LoadableDetachableModel> model = new LoadableDetachableModel<>() { + + private static final long serialVersionUID = -2965284931860212687L; + + @Override + protected List load() { + List confOverride = + resourceConnConfPanel.getConnProperties(resourceTO); + resourceTO.getConfOverride().clear(); + resourceTO.getConfOverride().addAll(confOverride); + + return new PropertyModel>(modelObject, "confOverride") { + + private static final long serialVersionUID = -7809699384012595307L; + + @Override + public List getObject() { + List res = new ArrayList<>(super.getObject()); + + // re-order properties + Collections.sort(res, (left, right) -> { + if (left == null) { + return -1; + } else { + return left.compareTo(right); + } + }); + + return res; + } + }.getObject(); + } + }; + resourceConnConfPanel.setConfPropertyListView(model, true); + target.add(resourceConnConfPanel.getCheck().setVisible(true).setEnabled(true)); + } + }); } wizardModel.add(resourceDetailsPanel); wizardModel.add(resourceConnConfPanel); if (resourceTO.getConnector() != null) { wizardModel.add(new ResourceConnCapabilitiesPanel( - resourceTO, ConnectorRestClient.read(resourceTO.getConnector()).getCapabilities())); + resourceTO, connectorRestClient.read(resourceTO.getConnector()).getCapabilities())); } else { wizardModel.add(new ResourceConnCapabilitiesPanel(resourceTO, Collections.emptySet())); } @@ -144,9 +154,9 @@ public List getObject() { protected ResourceTO onApplyInternal(final Serializable modelObject) { ResourceTO resourceTO = (ResourceTO) modelObject; if (createFlag) { - resourceTO = ResourceRestClient.create(resourceTO); + resourceTO = resourceRestClient.create(resourceTO); } else { - ResourceRestClient.update(resourceTO); + resourceRestClient.update(resourceTO); } return resourceTO; } diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/topology/TopologyTogglePanel_fr_CA.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/topology/TopologyTogglePanel_fr_CA.properties index fde8651859d..74874f3e28e 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/topology/TopologyTogglePanel_fr_CA.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/topology/TopologyTogglePanel_fr_CA.properties @@ -20,6 +20,7 @@ connector.menu.add=Ajouter un nouveau connecteur connector.menu.remove=Retirer le connecteur connector.menu.edit=Modifier le connecteur connector.menu.history=Historique de configuration + resource.new=Nouvelle ressource resource.edit=Modifier la ressource {0} resource.clone=Cloner la ressource {0} diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_it.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_it.properties index fddd717b91c..70de8695e0a 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_it.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPullWizardBuilder$PullTask_it.properties @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. remediation=Bonifiche -matchingRule=Regola di matrching +matchingRule=Regola di matching unmatchingRule=Regola di unmatching provisioningActions=Azioni di pull conflictResolutionAction=Azione di Risoluzione Conflitti diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_it.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_it.properties index c26816b2fd8..e10932ba5b0 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_it.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/CSVPushWizardBuilder$PushTask_it.properties @@ -14,7 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -matchingRule=Regola di matrching +matchingRule=Regola di matching unmatchingRule=Regola di unmatching provisioningActions=Azioni di push ignorePaging=Includere tutte le pagine? diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_fr_CA.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_fr_CA.properties index c2d89faeafe..3fd66399971 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_fr_CA.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_fr_CA.properties @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. mergeLinkedAccounts.reviewAccounts.title=Preview finalized linked accounts -connObjectKeyValue=Connector +connObjectKeyValue=Connector Key resource=Resource key=Key username=Username diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_it.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_it.properties index c2d89faeafe..bd2fcc6be87 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_it.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_it.properties @@ -14,9 +14,9 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -mergeLinkedAccounts.reviewAccounts.title=Preview finalized linked accounts -connObjectKeyValue=Connector -resource=Resource -key=Key +mergeLinkedAccounts.reviewAccounts.title=Anteprima linked account +connObjectKeyValue=Chiave esterna +resource=Risorsa +key=Chiave interna username=Username -suspended=Suspended +suspended=Sospeso diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_ja.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_ja.properties index c2d89faeafe..3fd66399971 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_ja.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_ja.properties @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. mergeLinkedAccounts.reviewAccounts.title=Preview finalized linked accounts -connObjectKeyValue=Connector +connObjectKeyValue=Connector Key resource=Resource key=Key username=Username diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_pt_BR.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_pt_BR.properties index c2d89faeafe..3fd66399971 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_pt_BR.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_pt_BR.properties @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. mergeLinkedAccounts.reviewAccounts.title=Preview finalized linked accounts -connObjectKeyValue=Connector +connObjectKeyValue=Connector Key resource=Resource key=Key username=Username diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_ru.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_ru.properties index c2d89faeafe..3fd66399971 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_ru.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/any/MergeLinkedAccountsReviewPanel_ru.properties @@ -15,7 +15,7 @@ # specific language governing permissions and limitations # under the License. mergeLinkedAccounts.reviewAccounts.title=Preview finalized linked accounts -connObjectKeyValue=Connector +connObjectKeyValue=Connector Key resource=Resource key=Key username=Username diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html index 01ac5124706..0a032723bf9 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.html @@ -38,6 +38,10 @@ [bundleName]
+
+ [bundleName] +
+
[version]
diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties index 23711a979af..65edc08dd03 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel.properties @@ -25,3 +25,4 @@ poolMaxIdle=Max idle objects poolMaxWait=Max waiting time (msec) poolMinEvictableIdleTime=Min eviction time (msec) adminRealm=Administration Realm +connectorName=Connector diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_fr_CA.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_fr_CA.properties index 05fd6a980b2..9407d943c45 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_fr_CA.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_fr_CA.properties @@ -16,12 +16,13 @@ # under the License. displayName=Afficher nom location=Emplacement -bundleName=Offre groupée +bundleName=Offre group\u00e9e version=Version -connRequestTimeout=Délai de demande (sec) +connRequestTimeout=D\u00e9lai de demande (sec) poolMaxObjects=Nombre maximum d'objets (inactif+actif) poolMinIdle=Nombre minimum d'objets inactifs poolMaxIdle=Nombre maximal d'objets inactifs poolMaxWait=Temps d'attente max (msec) poolMinEvictableIdleTime=Temps minimum d'expulsion (msec) adminRealm=Domaine de l'administration +connectorName=Connector diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties index 0fd9aa775c7..b162f30e211 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_it.properties @@ -25,3 +25,4 @@ poolMaxIdle=Max oggetti inattivi poolMaxWait=Tempo max attesa poolMinEvictableIdleTime=Tempo min espulsione adminRealm=Realm di amministrazione +connectorName=Connettore diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ja.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ja.properties index d12baa207d3..3ce4e9cd206 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ja.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ja.properties @@ -25,3 +25,4 @@ poolMaxIdle=\u6700\u5927\u30a2\u30a4\u30c9\u30eb\u30aa\u30d6\u30b8\u30a7\u30af\u poolMaxWait=\u6700\u5927\u5f85\u6a5f\u6642\u9593 (\u30df\u30ea\u79d2) poolMinEvictableIdleTime=\u6700\u5c0f\u6392\u51fa\u6642\u9593 (\u30df\u30ea\u79d2) adminRealm=\u7ba1\u7406\u30ec\u30eb\u30e0 +connectorName=Connector diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties index db06733e5d9..23c3a09ec63 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_pt_BR.properties @@ -25,3 +25,4 @@ poolMaxIdle=Max idle objects poolMaxWait=Max waiting time (msec) poolMinEvictableIdleTime=Min eviction time (msec) adminRealm=Administration Realm +connectorName=Connector diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties index c5d4b3f6fa9..81db5b8f32c 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ConnectorDetailsPanel_ru.properties @@ -26,3 +26,4 @@ poolMaxIdle=\u041c\u0430\u043a\u0441\u0438\u043c\u0443\u043c \u043e\u0431\u044a\ poolMaxWait=\u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f (\u043c\u0441) poolMinEvictableIdleTime=\u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f (\u043c\u0441) adminRealm=Administration Realm +connectorName=Connector diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel.html b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel.html index 081b5d86d5b..62446d0e998 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel.html +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel.html @@ -35,10 +35,6 @@ [propagationPriority]
-
- [randomPwdIfNotProvided] -
-
[propagationActions]
diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel.properties index 004dd025628..ba05a4f9889 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel.properties @@ -18,7 +18,6 @@ name=Resource name connector=Connector enforceMandatoryCondition=Enforce mandatory condition propagationPriority=Propagation priority -randomPwdIfNotProvided=Generate random passwords when missing propagationActions=Propagation Actions provisionSorter=Provision Sorter createTraceLevel=Propagation: create trace level diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_fr_CA.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_fr_CA.properties index 587a5f2a7eb..7ef6ca26872 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_fr_CA.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_fr_CA.properties @@ -18,7 +18,6 @@ name=Nom de la ressource connector=Raccordement enforceMandatoryCondition=Application de la condition obligatoire propagationPriority=Priorit\u00e9 de propagation -randomPwdIfNotProvided=G\u00e9n\u00e9rer des mots de passe al\u00e9atoires si manquants. propagationActions=Actions de propagation provisionSorter=Trieur de provision createTraceLevel=Propagation : cr\u00e9ation d'un niveau de trace diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_it.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_it.properties index 3d69ca0e5fc..654804181c9 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_it.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_it.properties @@ -18,7 +18,6 @@ name=Nome risorsa connector=Connettore enforceMandatoryCondition=Abilita mandatory condition propagationPriority=Priorit\u00e0 in propagazione -randomPwdIfNotProvided=Genera password casuali se mancanti propagationActions=Azioni di Propagazione provisionSorter=Provision Sorter createTraceLevel=Propagazione: tracciamento creazione diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_ja.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_ja.properties index 477b0e8167e..89fca8b99b2 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_ja.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_ja.properties @@ -18,7 +18,6 @@ name=\u30ea\u30bd\u30fc\u30b9\u540d connector=\u30b3\u30cd\u30af\u30bf\u30fc enforceMandatoryCondition=\u5fc5\u9808\u6761\u4ef6\u306b\u5f93\u3046 propagationPriority=\u4f1d\u64ad\u512a\u5148\u5ea6 -randomPwdIfNotProvided=\u898b\u3064\u304b\u3089\u306a\u3044\u5834\u5408\u306f\u30e9\u30f3\u30c0\u30e0\u306a\u30d1\u30b9\u30ef\u30fc\u30c9\u3092\u751f\u6210 propagationActions=\u4f1d\u64ad\u30a2\u30af\u30b7\u30e7\u30f3 provisionSorter=\u30bd\u30fc\u30bf\u30fc\u306e\u30d7\u30ed\u30d3\u30b8\u30e7\u30cb\u30f3\u30b0 createTraceLevel=\u4f1d\u64ad: \u4f5c\u6210\u30c8\u30ec\u30fc\u30b9\u30ec\u30d9\u30eb diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_pt_BR.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_pt_BR.properties index 79ac8ed1f34..6ef95cfa41d 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_pt_BR.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_pt_BR.properties @@ -18,7 +18,6 @@ name=Nome recurso connector=Conector enforceMandatoryCondition=Aplicar condi\u00e7\u00e3o obrigat\u00f3ria propagationPriority=Prioridade de propaga\u00e7\u00e3o -randomPwdIfNotProvided=Gerar senhas aleat\u00f3rias quando n\u00e3o houver propagationActions=A\u00e7\u00f5es de Propaga\u00e7\u00e3o provisionSorter=Classificador de Provis\u00f5es createTraceLevel=Propagation: create trace level diff --git a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_ru.properties b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_ru.properties index c2ef730c0b1..e967f476119 100644 --- a/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_ru.properties +++ b/client/idm/console/src/main/resources/org/apache/syncope/client/console/wizards/resources/ResourceDetailsPanel_ru.properties @@ -19,7 +19,6 @@ name=\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0441\u0443\u connector=\u041a\u043e\u043d\u043d\u0435\u043a\u0442\u043e\u0440 enforceMandatoryCondition=\u041e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 (\u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e) propagationPriority=\u041f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 -randomPwdIfNotProvided=\u0421\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c, \u0435\u0441\u043b\u0438 \u043e\u043d \u043d\u0435 \u0437\u0430\u0434\u0430\u043d propagationActions=\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f provisionSorter=\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0449\u0438\u043a \u043f\u0440\u043e\u0432\u0438\u0437\u0438\u0438 createTraceLevel=\u0412\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439: \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043f\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e diff --git a/client/idm/lib/pom.xml b/client/idm/lib/pom.xml index 80aaeed323b..1024cf87cac 100644 --- a/client/idm/lib/pom.xml +++ b/client/idm/lib/pom.xml @@ -24,7 +24,7 @@ under the License. org.apache.syncope.client syncope-client-idm - 3.0.1-SNAPSHOT + 3.0.17-SNAPSHOT Apache Syncope Client IdM Lib diff --git a/client/idm/pom.xml b/client/idm/pom.xml index 6f5e8bb6ecd..5565ab112bd 100644 --- a/client/idm/pom.xml +++ b/client/idm/pom.xml @@ -24,7 +24,7 @@ under the License. org.apache.syncope syncope-client - 3.0.1-SNAPSHOT + 3.0.17-SNAPSHOT Apache Syncope Client IdM diff --git a/client/idrepo/common-ui/pom.xml b/client/idrepo/common-ui/pom.xml index a2a97f2f1fe..608d5e126bd 100644 --- a/client/idrepo/common-ui/pom.xml +++ b/client/idrepo/common-ui/pom.xml @@ -22,7 +22,7 @@ under the License. org.apache.syncope.client syncope-client-idrepo - 3.0.1-SNAPSHOT + 3.0.17-SNAPSHOT Apache Syncope Client IdRepo Common UI @@ -40,6 +40,10 @@ under the License. org.springframework.boot spring-boot-actuator
+ + org.springframework.boot + spring-boot-autoconfigure + org.apache.wicket @@ -100,11 +104,21 @@ under the License. byte-buddy + + org.objenesis + objenesis + + org.apache.pdfbox pdfbox - + + + org.apache.commons + commons-text + + org.apache.syncope.common.keymaster syncope-common-keymaster-client-api diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/BaseLogin.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/BaseLogin.java index bc0f008d6a4..d64e068a6e1 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/BaseLogin.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/BaseLogin.java @@ -27,6 +27,8 @@ import java.util.stream.Collectors; import javax.ws.rs.core.HttpHeaders; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.apache.syncope.client.ui.commons.panels.BaseSSOLoginFormPanel; import org.apache.syncope.client.ui.commons.panels.NotificationPanel; import org.apache.syncope.common.keymaster.client.api.DomainOps; import org.apache.syncope.common.keymaster.client.api.model.Domain; @@ -46,7 +48,6 @@ import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; -import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.LoadableDetachableModel; import org.apache.wicket.model.Model; @@ -63,26 +64,26 @@ public abstract class BaseLogin extends WebPage { protected static final Logger LOG = LoggerFactory.getLogger(BaseLogin.class); - public static final List SUPPORTED_LOCALES = List.of( - Locale.ENGLISH, Locale.CANADA_FRENCH, Locale.ITALIAN, Locale.JAPANESE, new Locale("pt", "BR"), - new Locale("ru")); - @SpringBean - private DomainOps domainOps; + protected DomainOps domainOps; protected final NotificationPanel notificationPanel; protected final StatelessForm form; - private final TextField usernameField; + protected final TextField usernameField; + + protected final TextField passwordField; + + protected final LocaleDropDown languageSelect; - private final TextField passwordField; + protected final DomainDropDown domainSelect; protected String notificationMessage; protected String notificationLevel; - private final LoadableDetachableModel> domains = new LoadableDetachableModel<>() { + protected final LoadableDetachableModel> domains = new LoadableDetachableModel<>() { private static final long serialVersionUID = 4659376149825914247L; @@ -102,7 +103,7 @@ public BaseLogin(final PageParameters parameters) { notificationPanel = new NotificationPanel(Constants.FEEDBACK); add(notificationPanel); - if (!parameters.get("notificationMessage").isNull()) { + if (!parameters.get(Constants.NOTIFICATION_MSG_PARAM).isNull()) { notificationMessage = parameters.get(Constants.NOTIFICATION_MSG_PARAM).toString(); notificationLevel = parameters.get(Constants.NOTIFICATION_LEVEL_PARAM).isEmpty() ? Notification.SUCCESS @@ -128,7 +129,7 @@ public BaseLogin(final PageParameters parameters) { passwordField.setMarkupId("password"); form.add(passwordField); - LocaleDropDown languageSelect = new LocaleDropDown("language"); + languageSelect = new LocaleDropDown("language"); languageSelect.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_BLUR) { private static final long serialVersionUID = -1107858522700306810L; @@ -148,7 +149,7 @@ protected void onUpdate(final AjaxRequestTarget target) { }); form.add(languageSelect.setOutputMarkupId(true)); - DomainDropDown domainSelect = new DomainDropDown("domain", domains); + domainSelect = new DomainDropDown("domain", domains); domainSelect.add(new AjaxFormComponentUpdatingBehavior(Constants.ON_BLUR) { private static final long serialVersionUID = -1107858522700306810L; @@ -174,21 +175,19 @@ protected void onUpdate(final AjaxRequestTarget target) { @Override protected void onSubmit(final AjaxRequestTarget target) { - authenticate(usernameField.getRawInput(), passwordField.getRawInput(), target); + authenticate(usernameField.getValue(), passwordField.getRawInput(), target); } - }; submitButton.setDefaultFormProcessing(false); form.add(submitButton); form.setDefaultButton(submitButton); - List ssoLoginFormPanels = getSSOLoginFormPanels(); - ListView ssoLogins = new ListView<>("ssoLogins", ssoLoginFormPanels) { + ListView ssoLogins = new ListView<>("ssoLogins", getSSOLoginFormPanels()) { private static final long serialVersionUID = -9180479401817023838L; @Override - protected void populateItem(final ListItem item) { + protected void populateItem(final ListItem item) { item.add(item.getModelObject()); } }; @@ -208,21 +207,22 @@ protected Collection getDomainOnChangeComponents() { @Override public void renderHead(final IHeaderResponse response) { super.renderHead(response); + if (StringUtils.isNotBlank(notificationMessage)) { - response.render(OnLoadHeaderItem.forScript(StyledNotificationBehavior.jQueryShow(notificationMessage, + response.render(OnLoadHeaderItem.forScript(StyledNotificationBehavior.jQueryShow( + StringEscapeUtils.escapeEcmaScript(notificationMessage), String.format("jQuery('#%s').data('kendoNotification')", - notificationPanel.getNotificationMarkupId()), notificationLevel))); + notificationPanel.getNotificationMarkupId()), + notificationLevel))); } } protected abstract BaseSession getBaseSession(); - protected abstract List getSSOLoginFormPanels(); + protected abstract List getSSOLoginFormPanels(); protected abstract void sendError(String error); - protected abstract String getAnonymousUser(); - protected abstract void authenticate( String username, String password, @@ -232,11 +232,11 @@ protected abstract void authenticate( /** * Inner class which implements (custom) Locale DropDownChoice component. */ - private class LocaleDropDown extends DropDownChoice { + protected class LocaleDropDown extends DropDownChoice { private static final long serialVersionUID = 2349382679992357202L; - private class LocaleRenderer extends ChoiceRenderer { + protected class LocaleRenderer extends ChoiceRenderer { private static final long serialVersionUID = -3657529581555164741L; @@ -246,8 +246,8 @@ public String getDisplayValue(final Locale locale) { } } - LocaleDropDown(final String id) { - super(id, SUPPORTED_LOCALES); + protected LocaleDropDown(final String id) { + super(id, getBaseSession().getSupportedLocales()); setChoiceRenderer(new LocaleRenderer()); setModel(new IModel<>() { @@ -277,7 +277,9 @@ public void detach() { getHeader(HttpHeaders.ACCEPT_LANGUAGE); if (StringUtils.isNotBlank(acceptLanguage)) { try { - filtered = Locale.filter(Locale.LanguageRange.parse(acceptLanguage), SUPPORTED_LOCALES); + filtered = Locale.filter( + Locale.LanguageRange.parse(acceptLanguage), + getBaseSession().getSupportedLocales()); } catch (Exception e) { LOG.debug("Could not parse {} HTTP header value '{}'", HttpHeaders.ACCEPT_LANGUAGE, acceptLanguage, e); diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/BaseSession.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/BaseSession.java index acd67b4b66c..44fad9b0e9e 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/BaseSession.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/BaseSession.java @@ -18,9 +18,12 @@ */ package org.apache.syncope.client.ui.commons; +import java.util.List; +import java.util.Locale; import java.util.concurrent.Callable; import java.util.concurrent.Future; -import org.apache.syncope.client.lib.SyncopeClient; +import org.apache.syncope.client.lib.SyncopeAnonymousClient; +import org.apache.wicket.model.ResourceModel; public interface BaseSession { @@ -38,12 +41,8 @@ enum Error { this.fallback = fallback; } - public String key() { - return key; - } - - public String fallback() { - return fallback; + public String message() { + return new ResourceModel(key, fallback).getObject(); } } @@ -53,7 +52,7 @@ public String fallback() { String getJWT(); - SyncopeClient getAnonymousClient(); + SyncopeAnonymousClient getAnonymousClient(); T getAnonymousService(Class serviceClass); @@ -76,4 +75,14 @@ public String fallback() { void onException(Exception e); Future execute(Callable command); + + default List getSupportedLocales() { + return List.of( + Locale.ENGLISH, + Locale.CANADA_FRENCH, + Locale.ITALIAN, + Locale.JAPANESE, + new Locale("pt", "BR"), + new Locale("ru")); + } } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/CommonUIProperties.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/CommonUIProperties.java index 8e24a69c2b2..4d4fa048a9d 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/CommonUIProperties.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/CommonUIProperties.java @@ -24,6 +24,8 @@ public abstract class CommonUIProperties extends SyncopeProperties { + private static final long serialVersionUID = -4338560769317806322L; + private String adminUser = "admin"; private boolean xForward = true; diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/Constants.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/Constants.java index 789fa418721..16b31890ddb 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/Constants.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/Constants.java @@ -55,6 +55,8 @@ public final class Constants { public static final String ON_CLICK = "click"; + public static final String ON_DOUBLE_CLICK = "dblclick"; + public static final String ON_CHANGE = "change"; public static final String ON_KEYUP = "keyup"; @@ -71,6 +73,8 @@ public final class Constants { public static final String OPERATION_ERROR = "operation_error"; + public static final String OPERATION_NO_OP = "operation_no_op"; + public static final String CAPTCHA_ERROR = "captcha_error"; public static final String SEARCH_ERROR = "search_error"; @@ -108,7 +112,7 @@ public final class Constants { public static final String UNDEFINED_ICON = "fas fa-question-circle"; public static final String NOT_FOUND_ICON = "fas fa-minus-circle"; - + public static final String WARNING_ICON = "fas fa-exclamation-circle"; public static final int MAX_GROUP_LIST_SIZE = 30; @@ -122,7 +126,7 @@ public final class Constants { public static final String NOTIFICATION_LEVEL_PARAM = "notificationLevel"; public static final String ENDUSER_ANYLAYOUT = "enduser.anylayout"; - + public static final String CONTENT_ID = "content"; public static Component getJEXLPopover(final Component caller, final TooltipConfig.Placement placement) { diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/DateOps.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/DateOps.java index f68187b4cb7..1f23abe89e7 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/DateOps.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/DateOps.java @@ -19,8 +19,11 @@ package org.apache.syncope.client.ui.commons; import java.io.Serializable; +import java.time.LocalDateTime; import java.time.OffsetDateTime; +import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.util.Date; import java.util.Optional; import org.apache.commons.lang3.StringUtils; @@ -44,41 +47,102 @@ public String format(final Date date) { } public String format(final OffsetDateTime date) { - return Optional.ofNullable(date).map(v -> fdf.format(convert(date))).orElse(StringUtils.EMPTY); + return Optional.ofNullable(date).map(v -> fdf.format(convert(v))).orElse(StringUtils.EMPTY); + } + + public String format(final ZonedDateTime date) { + return Optional.ofNullable(date).map(v -> fdf.format(convert(v))).orElse(StringUtils.EMPTY); + } + + public String format(final LocalDateTime date) { + return Optional.ofNullable(date).map(v -> fdf.format(convert(v))).orElse(StringUtils.EMPTY); } } - public static class WrappedDateModel implements IModel, Serializable { + public static final class WrappedDateModel implements IModel, Serializable { private static final long serialVersionUID = 31027882183172L; - private final IModel wrapped; + public static WrappedDateModel ofOffset(final IModel offset) { + WrappedDateModel instance = new WrappedDateModel(); + instance.offset = offset; + return instance; + } + + public static WrappedDateModel ofZoned(final IModel zoned) { + WrappedDateModel instance = new WrappedDateModel(); + instance.zoned = zoned; + return instance; + } + + public static WrappedDateModel ofLocal(final IModel local) { + WrappedDateModel instance = new WrappedDateModel(); + instance.local = local; + return instance; + } + + private IModel local; + + private IModel offset; - public WrappedDateModel(final IModel wrapped) { - this.wrapped = wrapped; + private IModel zoned; + + private WrappedDateModel() { + // private constructor for static utility class } @Override public Date getObject() { - return convert(wrapped.getObject()); + if (offset != null) { + return convert(offset.getObject()); + } else if (zoned != null) { + return convert(zoned.getObject()); + } else if (local != null) { + return convert(local.getObject()); + } + return null; } @Override public void setObject(final Date object) { - wrapped.setObject(convert(object)); + if (offset != null) { + offset.setObject(toOffsetDateTime(object)); + } else if (zoned != null) { + zoned.setObject(toZonedDateTime(object)); + } else if (local != null) { + local.setObject(toLocalDateTime(object)); + } } } public static final ZoneOffset DEFAULT_OFFSET = OffsetDateTime.now().getOffset(); + public static final ZoneId DEFAULT_ZONE = ZonedDateTime.now().getZone(); + public static Date convert(final OffsetDateTime date) { return Optional.ofNullable(date).map(v -> new Date(v.toInstant().toEpochMilli())).orElse(null); } - public static OffsetDateTime convert(final Date date) { + public static Date convert(final ZonedDateTime date) { + return Optional.ofNullable(date).map(v -> new Date(v.toInstant().toEpochMilli())).orElse(null); + } + + public static Date convert(final LocalDateTime date) { + return Optional.ofNullable(date).map(v -> Date.from(v.atZone(DEFAULT_ZONE).toInstant())).orElse(null); + } + + public static OffsetDateTime toOffsetDateTime(final Date date) { return Optional.ofNullable(date).map(v -> v.toInstant().atOffset(DEFAULT_OFFSET)).orElse(null); } + public static ZonedDateTime toZonedDateTime(final Date date) { + return Optional.ofNullable(date).map(v -> ZonedDateTime.ofInstant(v.toInstant(), DEFAULT_ZONE)).orElse(null); + } + + public static LocalDateTime toLocalDateTime(final Date date) { + return Optional.ofNullable(date).map(v -> LocalDateTime.ofInstant(v.toInstant(), DEFAULT_ZONE)).orElse(null); + } + private DateOps() { // private constructor for static utility class } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/MIMETypesLoader.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/MIMETypesLoader.java index fc825eec99f..a41082b611a 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/MIMETypesLoader.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/MIMETypesLoader.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.json.JsonMapper; +import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -29,7 +30,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class MIMETypesLoader { +public class MIMETypesLoader implements Serializable { + + private static final long serialVersionUID = -1865866358622817499L; protected static final Logger LOG = LoggerFactory.getLogger(MIMETypesLoader.class); diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/StyledNotificationBehavior.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/StyledNotificationBehavior.java index 82b97da06bb..da3cfd32d5b 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/StyledNotificationBehavior.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/StyledNotificationBehavior.java @@ -39,17 +39,25 @@ public StyledNotificationBehavior(final String selector, final Options options) @Override public void show(final IPartialPageRequestHandler handler, final Serializable message, final String level) { if (handler != null) { - handler.appendJavaScript(jQueryShow(this.format(String.valueOf(message), level), this.widget(), level)); + handler.appendJavaScript(jQueryShow(format(String.valueOf(message), level), widget(), level)); } } public static String jQueryShow(final CharSequence message, final String widget, final String level) { + String actual = Notification.INFO.equalsIgnoreCase(level) + ? Notification.INFO + : Notification.SUCCESS.equalsIgnoreCase(level) + ? Notification.SUCCESS + : Notification.ERROR.equalsIgnoreCase(level) + ? Notification.ERROR + : Notification.WARNING; + return String.format("%s.options.autoHideAfter = %s; %s.show( { message: '%s' } , '%s');", widget, - Notification.SUCCESS.equalsIgnoreCase(level) || Notification.INFO.equalsIgnoreCase(level) + Notification.SUCCESS.equals(actual) || Notification.INFO.equals(actual) ? AUTOHIDEAFTER_GOOD : AUTOHIDEAFTER_BAD, widget, message, - level.toLowerCase()); + actual); } } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/SyncopeUIRequestCycleListener.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/SyncopeUIRequestCycleListener.java index 05cce591c36..07e0a93e278 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/SyncopeUIRequestCycleListener.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/SyncopeUIRequestCycleListener.java @@ -19,11 +19,14 @@ package org.apache.syncope.client.ui.commons; import java.security.AccessControlException; +import java.util.Optional; +import java.util.stream.Collectors; import javax.ws.rs.BadRequestException; import javax.ws.rs.ForbiddenException; import javax.xml.ws.WebServiceException; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.common.lib.SyncopeClientException; +import org.apache.syncope.common.lib.types.ClientExceptionType; import org.apache.wicket.authorization.UnauthorizedInstantiationException; import org.apache.wicket.core.request.handler.PageProvider; import org.apache.wicket.core.request.handler.RenderPageRequestHandler; @@ -41,15 +44,23 @@ public abstract class SyncopeUIRequestCycleListener implements IRequestCycleList private static final Logger LOG = LoggerFactory.getLogger(SyncopeUIRequestCycleListener.class); - private static Throwable instanceOf(final Exception e, final Class clazz) { - return clazz.isAssignableFrom(e.getClass()) - ? e - : e.getCause() != null && clazz.isAssignableFrom(e.getCause().getClass()) - ? e.getCause() - : e.getCause() != null && e.getCause().getCause() != null - && clazz.isAssignableFrom(e.getCause().getCause().getClass()) - ? e.getCause().getCause() - : null; + @SuppressWarnings("unchecked") + private static Optional instanceOf(final Exception e, final Class clazz) { + if (clazz.isAssignableFrom(e.getClass())) { + return Optional.of((T) e); + } + + if (e.getCause() != null && clazz.isAssignableFrom(e.getCause().getClass())) { + return Optional.of((T) e.getCause()); + } + + if (e.getCause() != null && e.getCause().getCause() != null + && clazz.isAssignableFrom(e.getCause().getCause().getClass())) { + + return Optional.of((T) e.getCause().getCause()); + } + + return Optional.empty(); } @Override @@ -59,33 +70,40 @@ public IRequestHandler onException(final RequestCycle cycle, final Exception e) PageParameters errorParameters = new PageParameters(); IRequestablePage errorPage; - if (instanceOf(e, UnauthorizedInstantiationException.class) != null) { - errorParameters.add("errorMessage", BaseSession.Error.AUTHORIZATION.fallback()); + if (instanceOf(e, UnauthorizedInstantiationException.class).isPresent()) { + errorParameters.add("errorMessage", BaseSession.Error.AUTHORIZATION.message()); errorPage = getErrorPage(errorParameters); - } else if (instanceOf(e, AccessControlException.class) != null) { - if (StringUtils.containsIgnoreCase(instanceOf(e, AccessControlException.class).getMessage(), "expired")) { - errorParameters.add("errorMessage", BaseSession.Error.SESSION_EXPIRED.fallback()); + } else if (instanceOf(e, AccessControlException.class).isPresent()) { + AccessControlException ace = instanceOf(e, AccessControlException.class).get(); + if (StringUtils.containsIgnoreCase(ace.getMessage(), "expired")) { + errorParameters.add("errorMessage", BaseSession.Error.SESSION_EXPIRED.message()); } else { - errorParameters.add("errorMessage", BaseSession.Error.AUTHORIZATION.fallback()); + errorParameters.add("errorMessage", BaseSession.Error.AUTHORIZATION.message()); } errorPage = getErrorPage(errorParameters); - } else if (instanceOf(e, PageExpiredException.class) != null || !isSignedIn()) { - errorParameters.add("errorMessage", BaseSession.Error.SESSION_EXPIRED.fallback()); + } else if (instanceOf(e, SyncopeClientException.class).isPresent()) { + SyncopeClientException sce = instanceOf(e, SyncopeClientException.class).get(); + String errorMessage = sce.getType() == ClientExceptionType.Unknown + ? sce.getElements().stream().collect(Collectors.joining()) + : sce.getMessage(); + errorParameters.add("errorMessage", errorMessage); errorPage = getErrorPage(errorParameters); - } else if (instanceOf(e, BadRequestException.class) != null - || instanceOf(e, WebServiceException.class) != null - || instanceOf(e, SyncopeClientException.class) != null) { + } else if (instanceOf(e, BadRequestException.class).isPresent() + || instanceOf(e, WebServiceException.class).isPresent()) { - errorParameters.add("errorMessage", BaseSession.Error.REST.fallback()); + errorParameters.add("errorMessage", BaseSession.Error.REST.message()); + errorPage = getErrorPage(errorParameters); + } else if (instanceOf(e, PageExpiredException.class).isPresent() || !isSignedIn()) { + errorParameters.add("errorMessage", BaseSession.Error.SESSION_EXPIRED.message()); errorPage = getErrorPage(errorParameters); } else { - Throwable cause = instanceOf(e, ForbiddenException.class); - if (cause == null) { + Optional cause = instanceOf(e, ForbiddenException.class); + if (cause.isPresent()) { + errorParameters.add("errorMessage", cause.get().getMessage()); + errorPage = getErrorPage(errorParameters); + } else { // redirect to default Wicket error page errorPage = new ExceptionErrorPage(e, null); - } else { - errorParameters.add("errorMessage", cause.getMessage()); - errorPage = getErrorPage(errorParameters); } } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/actuate/SyncopeCoreHealthIndicator.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/actuate/SyncopeCoreHealthIndicator.java index 3ac380f22a6..b340bcb4201 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/actuate/SyncopeCoreHealthIndicator.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/actuate/SyncopeCoreHealthIndicator.java @@ -41,6 +41,8 @@ public class SyncopeCoreHealthIndicator implements HealthIndicator { protected final boolean useGZIPCompression; + private UserSelfService service; + public SyncopeCoreHealthIndicator( final ServiceOps serviceOps, final String anonymousUser, @@ -53,16 +55,25 @@ public SyncopeCoreHealthIndicator( this.useGZIPCompression = useGZIPCompression; } + protected UserSelfService service() { + synchronized (this) { + if (service == null) { + service = new SyncopeClientFactoryBean(). + setAddress(serviceOps.get(NetworkService.Type.CORE).getAddress()). + setUseCompression(useGZIPCompression). + create(new AnonymousAuthenticationHandler(anonymousUser, anonymousKey)). + getService(UserSelfService.class); + } + } + return service; + } + @Override public Health health() { Health.Builder builder = new Health.Builder(); try { - new SyncopeClientFactoryBean(). - setAddress(serviceOps.get(NetworkService.Type.CORE).getAddress()). - setUseCompression(useGZIPCompression). - create(new AnonymousAuthenticationHandler(anonymousUser, anonymousKey)). - getService(UserSelfService.class).read(); + service().read(); builder.status(Status.UP); } catch (Exception e) { LOG.debug("When attempting to connect to Syncope Core", e); diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/ajax/form/IndicatorAjaxFormComponentUpdatingBehavior.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/ajax/form/IndicatorAjaxFormComponentUpdatingBehavior.java index 93b58565d6f..b38e1ea7f6b 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/ajax/form/IndicatorAjaxFormComponentUpdatingBehavior.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/ajax/form/IndicatorAjaxFormComponentUpdatingBehavior.java @@ -23,7 +23,7 @@ import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; /** - * An {@link AjaxFormComponentUpdatingBehavior} not showin veil. + * An {@link AjaxFormComponentUpdatingBehavior} not showing veil. */ public abstract class IndicatorAjaxFormComponentUpdatingBehavior extends AjaxFormComponentUpdatingBehavior implements IAjaxIndicatorAware { diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/annotations/AMPage.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/annotations/AMPage.java similarity index 96% rename from client/idrepo/console/src/main/java/org/apache/syncope/client/console/annotations/AMPage.java rename to client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/annotations/AMPage.java index 86a9c6d6b54..d4404c8483d 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/annotations/AMPage.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/annotations/AMPage.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.client.console.annotations; +package org.apache.syncope.client.ui.commons.annotations; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/annotations/IdMPage.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/annotations/IdMPage.java similarity index 96% rename from client/idrepo/console/src/main/java/org/apache/syncope/client/console/annotations/IdMPage.java rename to client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/annotations/IdMPage.java index 69436364043..239f5cefd47 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/annotations/IdMPage.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/annotations/IdMPage.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.client.console.annotations; +package org.apache.syncope.client.ui.commons.annotations; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/layout/AbstractAnyFormLayout.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/layout/AbstractAnyFormLayout.java index 87462253ae1..3e2ba898205 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/layout/AbstractAnyFormLayout.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/layout/AbstractAnyFormLayout.java @@ -45,5 +45,4 @@ public List getWhichDerAttrs() { public List getWhichVirAttrs() { return whichVirAttrs; } - } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AbstractMultiPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AbstractMultiPanel.java index 1e317eeea4d..e403729c262 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AbstractMultiPanel.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AbstractMultiPanel.java @@ -66,32 +66,65 @@ public AbstractMultiPanel( view = new InnerView("view", name, model); if (CollectionUtils.isEmpty(model.getObject())) { - form.addOrReplace(getNoDataFragment(model, name)); + form.addOrReplace(getNoDataFragment(name)); } else { form.addOrReplace(getDataFragment()); } } - // SYNCOPE-1476 public AbstractMultiPanel setFormAsMultipart(final boolean multipart) { form.setMultiPart(multipart); return this; } - private Fragment getNoDataFragment(final IModel> model, final String label) { + private Fragment getNoDataFragment(final String label) { Fragment fragment = new Fragment("content", "noDataFragment", AbstractMultiPanel.this); fragment.add(new Label("field-label", new ResourceModel(label, label))); - fragment.add(getPlusFragment(model)); + fragment.add(getFragmentPlus()); return fragment; } private Fragment getDataFragment() { - Fragment contentFragment = new Fragment("content", "dataFragment", AbstractMultiPanel.this); - contentFragment.add(view.setOutputMarkupId(true)); - return contentFragment; + Fragment fragment = new Fragment("content", "dataFragment", AbstractMultiPanel.this); + fragment.add(view.setOutputMarkupId(true)); + return fragment; } - private Fragment getPlusFragment(final IModel> model) { + private Fragment getFragmentMinus(final ListItem item, final Panel panel, final String label) { + IndicatorAjaxSubmitLink minus = new IndicatorAjaxSubmitLink("drop") { + + private static final long serialVersionUID = -7978723352517770644L; + + @Override + protected void onSubmit(final AjaxRequestTarget target) { + // drop the current component + view.getModel().getObject().remove(item.getModelObject()); + clearInput(panel); + + if (view.getModel().getObject().isEmpty()) { + form.addOrReplace(getNoDataFragment(label)); + } + + target.add(container); + } + + @Override + protected void onError(final AjaxRequestTarget target) { + onSubmit(target); + } + }; + + Fragment fragment = new Fragment("panelMinus", "fragmentMinus", AbstractMultiPanel.this); + fragment.addOrReplace(minus); + fragment.setRenderBodyOnly(true); + + fragment.setOutputMarkupPlaceholderTag(true); + fragment.setVisible(container.isEnabled() && form.isEnabled()); + + return fragment; + } + + private Fragment getFragmentPlus() { IndicatorAjaxSubmitLink plus = new IndicatorAjaxSubmitLink("add") { private static final long serialVersionUID = -7978723352517770644L; @@ -99,9 +132,9 @@ private Fragment getPlusFragment(final IModel> model) { @Override protected void onSubmit(final AjaxRequestTarget target) { //Add current component - model.getObject().add(newModelObject()); + view.getModel().getObject().add(newModelObject()); - if (model.getObject().size() == 1) { + if (view.getModel().getObject().size() == 1) { form.addOrReplace(getDataFragment()); } @@ -121,6 +154,9 @@ protected void onError(final AjaxRequestTarget target) { fragment.addOrReplace(plus); fragment.setRenderBodyOnly(true); + fragment.setOutputMarkupPlaceholderTag(true); + fragment.setVisible(container.isEnabled() && form.isEnabled()); + return fragment; } @@ -158,36 +194,12 @@ protected void populateItem(final ListItem item) { item.add(panel.setRenderBodyOnly(true)); - IndicatorAjaxSubmitLink minus = new IndicatorAjaxSubmitLink("drop") { - - private static final long serialVersionUID = -7978723352517770644L; + item.add(getFragmentMinus(item, panel, label)); - @Override - protected void onSubmit(final AjaxRequestTarget target) { - //Drop current component - model.getObject().remove(item.getModelObject()); - clearInput(panel); - - if (model.getObject().isEmpty()) { - form.addOrReplace(getNoDataFragment(model, label)); - } - - target.add(container); - } - - @Override - protected void onError(final AjaxRequestTarget target) { - onSubmit(target); - } - }; - - item.add(minus); - - Fragment fragment = item.getIndex() == model.getObject().size() - 1 - ? getPlusFragment(model) + Fragment plus = item.getIndex() == model.getObject().size() - 1 + ? getFragmentPlus() : new Fragment("panelPlus", "emptyFragment", AbstractMultiPanel.this); - - item.add(fragment.setRenderBodyOnly(true)); + item.add(plus.setRenderBodyOnly(true)); } } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxCheckBoxPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxCheckBoxPanel.java index a398e9b01ae..af581d4af8d 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxCheckBoxPanel.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxCheckBoxPanel.java @@ -21,8 +21,10 @@ import java.io.Serializable; import java.util.List; import java.util.Optional; +import java.util.function.Predicate; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior; +import org.apache.syncope.common.lib.Attr; import org.apache.syncope.common.lib.Attributable; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.markup.html.form.CheckBox; @@ -118,7 +120,7 @@ public Boolean getObject() { @SuppressWarnings("unchecked") public void setObject(final Boolean object) { item.setModelObject(Optional.ofNullable(object) - .map(Object::toString).orElseGet(Boolean.FALSE::toString)); + .map(Object::toString).orElseGet(Boolean.FALSE::toString)); } }; @@ -128,27 +130,25 @@ public void setObject(final Boolean object) { @SuppressWarnings({ "rawtypes", "unchecked" }) @Override - public FieldPanel setNewModel(final Attributable attributableTO, final String schema) { + public FieldPanel setNewModel(final Attributable attributable, final String schema) { field.setModel(new Model() { private static final long serialVersionUID = -4214654722524358000L; @Override public Serializable getObject() { - if (!attributableTO.getPlainAttr(schema).get().getValues().isEmpty()) { - return Boolean.TRUE.toString().equalsIgnoreCase( - attributableTO.getPlainAttr(schema).get().getValues().get(0)); - } - return null; + return attributable.getPlainAttr(schema).map(Attr::getValues).filter(Predicate.not(List::isEmpty)). + map(values -> Boolean.TRUE.toString().equalsIgnoreCase(values.get(0))). + orElse(null); } @Override public void setObject(final Serializable object) { - attributableTO.getPlainAttr(schema).get().getValues().clear(); - attributableTO.getPlainAttr(schema).get().getValues().add( - object == null ? Boolean.FALSE.toString() : object.toString()); + attributable.getPlainAttr(schema).ifPresent(plainAttr -> { + plainAttr.getValues().clear(); + plainAttr.getValues().add(object == null ? Boolean.FALSE.toString() : object.toString()); + }); } - }); return this; diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxGridFieldPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxGridFieldPanel.java index fbf9ecf12a5..2d62d4c3470 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxGridFieldPanel.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxGridFieldPanel.java @@ -37,7 +37,7 @@ public class AjaxGridFieldPanel extends Panel { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 7589570522964677729L; public AjaxGridFieldPanel(final String id, final String name, final IModel> model) { super(id, model); @@ -45,13 +45,13 @@ public AjaxGridFieldPanel(final String id, final String name, final IModel( - "grid", - getColumns(), - new EditableListDataProvider<>(model.getObject().entrySet().stream(). - map(entry -> MutablePair.of(entry.getKey(), entry.getValue())). - collect(Collectors.toList())), 10) { + "grid", + getColumns(), + new EditableListDataProvider<>(model.getObject().entrySet().stream(). + map(entry -> MutablePair.of(entry.getKey(), entry.getValue())). + collect(Collectors.toList())), 10) { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = -1315456128897492459L; @Override protected boolean displayHeader() { diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxSpinnerFieldPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxNumberFieldPanel.java similarity index 50% rename from client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxSpinnerFieldPanel.java rename to client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxNumberFieldPanel.java index 838ad5b8ec5..e7c3fafa4fc 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxSpinnerFieldPanel.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxNumberFieldPanel.java @@ -19,55 +19,69 @@ package org.apache.syncope.client.ui.commons.markup.html.form; import com.googlecode.wicket.jquery.core.Options; -import com.googlecode.wicket.jquery.ui.JQueryUIBehavior; -import com.googlecode.wicket.jquery.ui.form.spinner.AjaxSpinner; -import com.googlecode.wicket.jquery.ui.form.spinner.SpinnerAdapter; -import com.googlecode.wicket.jquery.ui.form.spinner.SpinnerBehavior; +import com.googlecode.wicket.kendo.ui.form.NumberTextField; +import com.googlecode.wicket.kendo.ui.resource.KendoCultureResourceReference; import java.io.Serializable; import java.util.List; import java.util.Optional; -import org.apache.commons.lang3.StringUtils; +import java.util.function.Predicate; import org.apache.commons.lang3.math.NumberUtils; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior; +import org.apache.syncope.common.lib.Attr; import org.apache.syncope.common.lib.Attributable; import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.markup.head.IHeaderResponse; +import org.apache.wicket.markup.head.JavaScriptHeaderItem; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; -public final class AjaxSpinnerFieldPanel extends FieldPanel { +public final class AjaxNumberFieldPanel> extends FieldPanel { private static final long serialVersionUID = 6413819574530703577L; + @SuppressWarnings("unchecked") + public static > Class cast(final Class clazz) { + return (Class) clazz; + } + private final Class reference; private final IModel model; private final Options options; - private SpinnerBehavior behavior; + private final boolean enableOnChange; + + private final boolean convertValuesToString; - private AjaxSpinnerFieldPanel( + private AjaxNumberFieldPanel( final String id, final String name, final Class reference, final IModel model, final Options options, - final boolean enableOnChange) { + final boolean enableOnChange, + final boolean convertValuesToString) { super(id, name, model); - field = new AjaxSpinner<>("spinner", model, options, reference) { + this.reference = reference; + this.model = model; + this.options = options; + this.enableOnChange = enableOnChange; + this.convertValuesToString = convertValuesToString; + + field = new NumberTextField<>("numberTextField", model, reference, options) { - private static final long serialVersionUID = -3624755213720060594L; + private static final long serialVersionUID = -8837755342786762653L; @Override - public JQueryUIBehavior newWidgetBehavior(final String selector) { - behavior = new SpinnerBehavior(selector, new SpinnerAdapter()); - behavior.setOptions(options); - return behavior; + protected String getModelValue() { + T value = getModelObject(); + return value == null ? "" : value.toString().trim(); } }; @@ -84,15 +98,17 @@ protected void onUpdate(final AjaxRequestTarget target) { } add(field.setLabel(new ResourceModel(name, name)).setOutputMarkupId(true)); + } - this.name = name; - this.model = model; - this.reference = reference; - this.options = options; + @Override + public FieldPanel setReadOnly(final boolean readOnly) { + super.setReadOnly(readOnly); + NumberTextField.class.cast(field).setEnabled(!readOnly); + return this; } @Override - public AjaxSpinnerFieldPanel setNewModel(final List list) { + public AjaxNumberFieldPanel setNewModel(final List list) { setNewModel(new Model<>() { private static final long serialVersionUID = 527651414610325237L; @@ -101,20 +117,18 @@ public AjaxSpinnerFieldPanel setNewModel(final List list) { public T getObject() { T value = null; - if (list != null && !list.isEmpty() - && list.get(0) != null && StringUtils.isNotBlank(list.get(0).toString())) { - + if (list != null && !list.isEmpty() && list.get(0) != null && !list.get(0).toString().isEmpty()) { value = reference.equals(Integer.class) - ? reference.cast(NumberUtils.toInt(list.get(0).toString())) - : reference.equals(Long.class) - ? reference.cast(NumberUtils.toLong(list.get(0).toString())) - : reference.equals(Short.class) - ? reference.cast(NumberUtils.toShort(list.get(0).toString())) - : reference.equals(Float.class) - ? reference.cast(NumberUtils.toFloat(list.get(0).toString())) - : reference.equals(byte.class) - ? reference.cast(NumberUtils.toByte(list.get(0).toString())) - : reference.cast(NumberUtils.toDouble(list.get(0).toString())); + ? reference.cast(NumberUtils.toInt(list.get(0).toString())) + : reference.equals(Long.class) + ? reference.cast(NumberUtils.toLong(list.get(0).toString())) + : reference.equals(Short.class) + ? reference.cast(NumberUtils.toShort(list.get(0).toString())) + : reference.equals(Float.class) + ? reference.cast(NumberUtils.toFloat(list.get(0).toString())) + : reference.equals(byte.class) + ? reference.cast(NumberUtils.toByte(list.get(0).toString())) + : reference.cast(NumberUtils.toDouble(list.get(0).toString())); } return value; @@ -123,9 +137,7 @@ public T getObject() { @Override public void setObject(final T object) { list.clear(); - if (object != null) { - list.add(object.toString()); - } + Optional.ofNullable(object).ifPresent(v -> list.add(convertValuesToString ? v.toString() : v)); } }); @@ -134,7 +146,7 @@ public void setObject(final T object) { @SuppressWarnings("rawtypes") @Override - public AjaxSpinnerFieldPanel setNewModel(final ListItem item) { + public AjaxNumberFieldPanel setNewModel(final ListItem item) { field.setModel(new Model<>() { private static final long serialVersionUID = 6799404673615637845L; @@ -149,22 +161,31 @@ public T getObject() { if (obj instanceof String) { try { number = reference.equals(Integer.class) - ? reference.cast(Integer.valueOf((String) obj)) - : reference.equals(Long.class) - ? reference.cast(Long.valueOf((String) obj)) - : reference.equals(Short.class) - ? reference.cast(Short.valueOf((String) obj)) - : reference.equals(Float.class) - ? reference.cast(Float.valueOf((String) obj)) - : reference.equals(byte.class) - ? reference.cast(Byte.valueOf((String) obj)) - : reference.cast(Double.valueOf((String) obj)); + ? reference.cast(Integer.valueOf((String) obj)) + : reference.equals(Long.class) + ? reference.cast(Long.valueOf((String) obj)) + : reference.equals(Short.class) + ? reference.cast(Short.valueOf((String) obj)) + : reference.equals(Float.class) + ? reference.cast(Float.valueOf((String) obj)) + : reference.equals(byte.class) + ? reference.cast(Byte.valueOf((String) obj)) + : reference.cast(Double.valueOf((String) obj)); } catch (NumberFormatException e) { LOG.error("While attempting to parse {}", obj, e); } } else if (obj instanceof Number) { - // Don't parse anything - number = reference.cast(obj); + number = reference.equals(Integer.class) + ? reference.cast(((Number) obj).intValue()) + : reference.equals(Long.class) + ? reference.cast(((Number) obj).longValue()) + : reference.equals(Short.class) + ? reference.cast(((Number) obj).shortValue()) + : reference.equals(Float.class) + ? reference.cast(((Number) obj).floatValue()) + : reference.equals(byte.class) + ? reference.cast(((Number) obj).byteValue()) + : reference.cast(((Number) obj).doubleValue()); } } @@ -174,45 +195,44 @@ public T getObject() { @Override @SuppressWarnings("unchecked") public void setObject(final T object) { - item.setModelObject(Optional.ofNullable(object).map(Object::toString).orElse(null)); + item.setModelObject(Optional.ofNullable(object). + map(v -> convertValuesToString ? v.toString() : v). + orElse(null)); } }); return this; } - @SuppressWarnings({ "unchecked", "rawtypes" }) @Override - public FieldPanel setNewModel(final Attributable attributableTO, final String schema) { - field.setModel(new Model() { + public FieldPanel setNewModel(final Attributable attributable, final String schema) { + field.setModel(new Model<>() { private static final long serialVersionUID = -4214654722524358000L; @Override - public Serializable getObject() { - List values = attributableTO.getPlainAttr(schema).get().getValues(); - if (!values.isEmpty()) { - return reference.equals(Integer.class) - ? reference.cast(NumberUtils.toInt(values.get(0))) - : reference.equals(Long.class) - ? reference.cast(NumberUtils.toLong(values.get(0))) - : reference.equals(Short.class) - ? reference.cast(NumberUtils.toShort(values.get(0))) - : reference.equals(Float.class) - ? reference.cast(NumberUtils.toFloat(values.get(0))) - : reference.equals(byte.class) - ? reference.cast(NumberUtils.toByte(values.get(0))) - : reference.cast(NumberUtils.toDouble(values.get(0))); - } - return null; + public T getObject() { + return attributable.getPlainAttr(schema).map(Attr::getValues).filter(Predicate.not(List::isEmpty)). + map(values -> reference.equals(Integer.class) + ? reference.cast(NumberUtils.toInt(values.get(0))) + : reference.equals(Long.class) + ? reference.cast(NumberUtils.toLong(values.get(0))) + : reference.equals(Short.class) + ? reference.cast(NumberUtils.toShort(values.get(0))) + : reference.equals(Float.class) + ? reference.cast(NumberUtils.toFloat(values.get(0))) + : reference.equals(byte.class) + ? reference.cast(NumberUtils.toByte(values.get(0))) + : reference.cast(NumberUtils.toDouble(values.get(0)))). + orElse(null); } @Override - public void setObject(final Serializable object) { - attributableTO.getPlainAttr(schema).get().getValues().clear(); - if (object != null) { - attributableTO.getPlainAttr(schema).get().getValues().add(object.toString()); - } + public void setObject(final T object) { + attributable.getPlainAttr(schema).ifPresent(plainAttr -> { + plainAttr.getValues().clear(); + Optional.ofNullable(object).ifPresent(o -> plainAttr.getValues().add(o.toString())); + }); } }); @@ -220,8 +240,15 @@ public void setObject(final Serializable object) { } @Override - public AjaxSpinnerFieldPanel clone() { - AjaxSpinnerFieldPanel panel = new AjaxSpinnerFieldPanel<>(getId(), name, reference, model, options, false); + public void renderHead(final IHeaderResponse response) { + super.renderHead(response); + response.render(JavaScriptHeaderItem.forReference(new KendoCultureResourceReference(getLocale()))); + } + + @Override + public AjaxNumberFieldPanel clone() { + AjaxNumberFieldPanel panel = new AjaxNumberFieldPanel<>( + getId(), name, reference, model, options, enableOnChange, convertValuesToString); panel.setRequired(isRequired()); panel.setReadOnly(isReadOnly()); @@ -234,23 +261,14 @@ public AjaxSpinnerFieldPanel clone() { return panel; } - @Override - public FieldPanel setReadOnly(final boolean readOnly) { - super.setReadOnly(readOnly); - AjaxSpinner.class.cast(field).setEnabled(!readOnly); - options.set("disabled", readOnly); - if (behavior != null) { - behavior.setOptions(options); - } - return this; - } - - public static class Builder { + public static class Builder> { private final Options options = new Options(); private boolean enableOnChange = false; + private boolean convertValuesToString = true; + public Builder min(final T min) { options.set("min", min); return this; @@ -261,23 +279,58 @@ public Builder max(final T max) { return this; } + public Builder format(final String format) { + options.set("format", format); + return this; + } + public Builder step(final T step) { options.set("step", step); return this; } + public Builder options(final Options options) { + options.entries().forEach(e -> this.options.set(e.getKey(), e.getValue())); + return this; + } + public Builder enableOnChange() { enableOnChange = true; return this; } - public AjaxSpinnerFieldPanel build( + public Builder convertValuesToString(final boolean convertValuesToString) { + this.convertValuesToString = convertValuesToString; + return this; + } + + public AjaxNumberFieldPanel build( final String id, final String name, final Class reference, final IModel model) { - return new AjaxSpinnerFieldPanel<>(id, name, reference, model, options, enableOnChange); + if (options.entries().stream().noneMatch(e -> "decimals".equals(e.getKey()))) { + options.set("decimals", "10"); + } + + if (options.entries().stream().noneMatch(o -> "format".equalsIgnoreCase(o.getKey()))) { + if (reference.equals(Integer.class) || reference.equals(Long.class) || reference.equals(Short.class)) { + options.set("format", "'#'"); + } else { + options.set("format", "'#.##########'"); + } + } + if (options.entries().stream().noneMatch(o -> "step".equalsIgnoreCase(o.getKey()))) { + if (reference.equals(Integer.class) || reference.equals(Long.class) || reference.equals(Short.class)) { + options.set("step", "1"); + } else { + options.set("step", "0.000000001"); + } + } + + return new AjaxNumberFieldPanel<>( + id, name, reference, model, options, enableOnChange, convertValuesToString); } } } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.java index 3dbadf01ced..a18ec5b9665 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.java @@ -19,6 +19,7 @@ package org.apache.syncope.client.ui.commons.markup.html.form; import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.password.strength.PasswordStrengthBehavior; +import java.util.Optional; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior; import org.apache.wicket.ajax.AjaxRequestTarget; @@ -26,29 +27,32 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.ResourceModel; -public class AjaxPasswordFieldPanel extends FieldPanel { +public class AjaxPasswordFieldPanel extends TextFieldPanel { private static final long serialVersionUID = -5490115280336667460L; - public AjaxPasswordFieldPanel(final String id, final String name, final IModel model) { - this(id, name, model, true, null); - } - - public AjaxPasswordFieldPanel(final String id, final String name, final IModel model, + public AjaxPasswordFieldPanel( + final String id, + final String name, + final IModel model, final boolean enableOnChange) { + this(id, name, model, enableOnChange, null); } public AjaxPasswordFieldPanel( - final String id, final String name, final IModel model, final boolean enableOnChange, + final String id, + final String name, + final IModel model, + final boolean enableOnChange, final PasswordStrengthBehavior passwordStrengthBehavior) { + super(id, name, model); field = new PasswordTextField("passwordField", model); - if (passwordStrengthBehavior != null) { - field.add(passwordStrengthBehavior); - } + setHTMLInputNotAllowed(); add(field.setLabel(new ResourceModel(name, name)).setRequired(false).setOutputMarkupId(true)); + Optional.ofNullable(passwordStrengthBehavior).ifPresent(field::add); if (enableOnChange && !isReadOnly()) { field.add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { @@ -56,13 +60,18 @@ public AjaxPasswordFieldPanel( private static final long serialVersionUID = -1107858522700306810L; @Override - protected void onUpdate(final AjaxRequestTarget art) { + protected void onUpdate(final AjaxRequestTarget target) { // nothing to do } }); } } + public AjaxPasswordFieldPanel setResetPassword(final boolean resetPassword) { + ((PasswordTextField) field).setResetPassword(resetPassword); + return this; + } + @Override public FieldPanel addRequiredLabel() { if (!isRequired()) { diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxTextFieldPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxTextFieldPanel.java index 270f6fb84a7..0478abbf16c 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxTextFieldPanel.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/AjaxTextFieldPanel.java @@ -21,6 +21,7 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipConfig; import java.util.Iterator; import java.util.List; +import java.util.Optional; import java.util.regex.Pattern; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior; @@ -33,9 +34,9 @@ import org.apache.wicket.extensions.ajax.markup.html.autocomplete.IAutoCompleteRenderer; import org.apache.wicket.model.IModel; import org.apache.wicket.model.ResourceModel; -import org.apache.wicket.validation.IValidator; +import org.apache.wicket.util.convert.IConverter; -public class AjaxTextFieldPanel extends FieldPanel implements Cloneable { +public class AjaxTextFieldPanel extends TextFieldPanel implements Cloneable { private static final long serialVersionUID = 238940918106696068L; @@ -70,7 +71,9 @@ protected Iterator getChoices(final String input) { @Override protected AutoCompleteBehavior newAutoCompleteBehavior( - final IAutoCompleteRenderer renderer, final AutoCompleteSettings settings) { + final IAutoCompleteRenderer renderer, + final AutoCompleteSettings settings) { + return new IndicatorAutoCompleteBehavior<>(renderer, settings) { private static final long serialVersionUID = 1070808433195962931L; @@ -81,7 +84,16 @@ protected Iterator getChoices(final String input) { } }; } + + @SuppressWarnings("unchecked") + @Override + public IConverter getConverter(final Class type) { + return AjaxTextFieldPanel.this.getConverter(). + map(converter -> (IConverter) converter). + orElseGet(() -> super.getConverter(type)); + } }; + setHTMLInputNotAllowed(); add(field.setLabel(new ResourceModel(name, name)).setOutputMarkupId(true)); if (enableOnChange && !isReadOnly()) { @@ -97,16 +109,16 @@ protected void onUpdate(final AjaxRequestTarget target) { } } - public void addValidator(final IValidator validator) { - this.field.add(validator); - } - public void setChoices(final List choices) { if (choices != null) { this.choices = choices; } } + protected Optional> getConverter() { + return Optional.empty(); + } + public FieldPanel enableJexlHelp() { questionMarkJexlHelp.setVisible(true); return this; diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ConfirmBehavior.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/ConfirmBehavior.java similarity index 93% rename from client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ConfirmBehavior.java rename to client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/ConfirmBehavior.java index c4f0218a57b..0a59c422af7 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ConfirmBehavior.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/ConfirmBehavior.java @@ -16,14 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.client.console.wicket.markup.html.form; +package org.apache.syncope.client.ui.commons.markup.html.form; import static de.agilecoders.wicket.jquery.JQuery.$; import de.agilecoders.wicket.jquery.function.JavaScriptInlineFunction; import java.util.ArrayList; -import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.wicket.Component; +import org.apache.wicket.Session; import org.apache.wicket.behavior.Behavior; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.JavaScriptHeaderItem; @@ -63,7 +63,7 @@ public void renderHead(final Component component, final IHeaderResponse response + " className: 'btn-danger'" + " }" + "}," - + "locale: '" + SyncopeConsoleSession.get().getLocale().getLanguage() + "'," + + "locale: '" + Session.get().getLocale().getLanguage() + "'," + "callback: function(result) {" + " if (result == true) {" + " proceed = true;" diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/DateFieldPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/DateFieldPanel.java index 73e5cd96d72..694cea0ecb3 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/DateFieldPanel.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/DateFieldPanel.java @@ -24,7 +24,9 @@ import java.util.Date; import java.util.List; import java.util.Optional; +import java.util.function.Predicate; import org.apache.commons.lang3.time.FastDateFormat; +import org.apache.syncope.common.lib.Attr; import org.apache.syncope.common.lib.Attributable; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.JavaScriptHeaderItem; @@ -129,22 +131,23 @@ public FieldPanel setNewModel(final Attributable attributable, final Strin @Override public Date getObject() { - if (!attributable.getPlainAttr(schema).get().getValues().isEmpty()) { - try { - return fmt.parse(attributable.getPlainAttr(schema).get().getValues().get(0)); - } catch (ParseException ex) { - LOG.error("While parsing date", ex); - } - } - return null; + return attributable.getPlainAttr(schema).map(Attr::getValues).filter(Predicate.not(List::isEmpty)). + map(values -> { + try { + return fmt.parse(values.get(0)); + } catch (ParseException e) { + LOG.error("While parsing date", e); + return null; + } + }).orElse(null); } @Override public void setObject(final Date object) { - attributable.getPlainAttr(schema).get().getValues().clear(); - if (object != null) { - attributable.getPlainAttr(schema).get().getValues().add(fmt.format(object)); - } + attributable.getPlainAttr(schema).ifPresent(plainAttr -> { + plainAttr.getValues().clear(); + Optional.ofNullable(object).ifPresent(o -> plainAttr.getValues().add(fmt.format(object))); + }); } }); diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/EncryptedFieldPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/EncryptedFieldPanel.java index fa220fefb58..ba72ac7b36e 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/EncryptedFieldPanel.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/EncryptedFieldPanel.java @@ -25,7 +25,7 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.ResourceModel; -public class EncryptedFieldPanel extends FieldPanel implements Cloneable { +public class EncryptedFieldPanel extends TextFieldPanel implements Cloneable { private static final long serialVersionUID = 1882871043451691005L; @@ -34,7 +34,11 @@ public EncryptedFieldPanel(final String id, final String name, final IModel model, final boolean enableOnChange) { + final String id, + final String name, + final IModel model, + final boolean enableOnChange) { + super(id, name, model); field = new TextField<>("encryptedField", model) { @@ -43,9 +47,10 @@ public EncryptedFieldPanel( @Override protected String[] getInputTypes() { - return new String[]{"password"}; + return new String[] { "password" }; } }; + setHTMLInputNotAllowed(); if (enableOnChange && !isReadOnly()) { field.add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) { diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/FieldPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/FieldPanel.java index 59837203e3a..66bca800613 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/FieldPanel.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/FieldPanel.java @@ -24,8 +24,10 @@ import java.io.Serializable; import java.util.List; import java.util.Optional; +import java.util.function.Predicate; import org.apache.commons.lang3.SerializationUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.common.lib.Attr; import org.apache.syncope.common.lib.Attributable; import org.apache.wicket.AttributeModifier; import org.apache.wicket.PageReference; @@ -130,24 +132,24 @@ public FieldPanel setNewModel(final IModel model) { } @SuppressWarnings({ "rawtypes", "unchecked" }) - public FieldPanel setNewModel(final Attributable attributableTO, final String schema) { + public FieldPanel setNewModel(final Attributable attributable, final String schema) { field.setModel(new Model() { private static final long serialVersionUID = -4214654722524358000L; @Override public Serializable getObject() { - return (!attributableTO.getPlainAttr(schema).get().getValues().isEmpty()) - ? attributableTO.getPlainAttr(schema).get().getValues().get(0) - : null; + return attributable.getPlainAttr(schema).map(Attr::getValues).filter(Predicate.not(List::isEmpty)). + map(values -> values.get(0)). + orElse(null); } @Override public void setObject(final Serializable object) { - attributableTO.getPlainAttr(schema).get().getValues().clear(); - if (object != null) { - attributableTO.getPlainAttr(schema).get().getValues().add(object.toString()); - } + attributable.getPlainAttr(schema).ifPresent(plainAttr -> { + plainAttr.getValues().clear(); + Optional.ofNullable(object).ifPresent(o -> plainAttr.getValues().add(o.toString())); + }); } }); diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/IndicatingOnConfirmAjaxLink.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/IndicatingOnConfirmAjaxLink.java similarity index 89% rename from client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/IndicatingOnConfirmAjaxLink.java rename to client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/IndicatingOnConfirmAjaxLink.java index d9377e99c49..8df5ef4adf0 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/IndicatingOnConfirmAjaxLink.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/IndicatingOnConfirmAjaxLink.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.client.console.wicket.markup.html.form; +package org.apache.syncope.client.ui.commons.markup.html.form; import org.apache.syncope.client.ui.commons.Constants; import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink; @@ -30,10 +30,6 @@ public abstract class IndicatingOnConfirmAjaxLink extends IndicatingAjaxLink< private final boolean enabled; - public IndicatingOnConfirmAjaxLink(final String id, final boolean enabled) { - this(id, "confirmDelete", enabled); - } - public IndicatingOnConfirmAjaxLink(final String id, final String msg, final boolean enabled) { super(id); diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/SyncopePasswordStrengthConfig.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/SyncopePasswordStrengthConfig.java new file mode 100644 index 00000000000..7b4c72d3174 --- /dev/null +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/SyncopePasswordStrengthConfig.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.ui.commons.markup.html.form; + +import de.agilecoders.wicket.extensions.markup.html.bootstrap.form.password.strength.PasswordStrengthConfig; +import de.agilecoders.wicket.jquery.AbstractConfig; +import de.agilecoders.wicket.jquery.IKey; +import de.agilecoders.wicket.jquery.Key; + +public class SyncopePasswordStrengthConfig extends PasswordStrengthConfig { + + private static final long serialVersionUID = -5625052394514215251L; + + public enum KeyType { + common, + ui, + rules; + + } + + public SyncopePasswordStrengthConfig() { + super(); + + withProgressExtraCssClasses("pwstrengthProgress"). + withShowVerdictsInsideProgressBar(true). + withShowProgressBar(true); + } + + protected void put(final KeyType keyType, final IKey key, final T value) { + AbstractConfig ui = (AbstractConfig) all().get(keyType.name()); + ui.put(key, value); + } + + public PasswordStrengthConfig withProgressExtraCssClasses(final String progressExtraCssClasses) { + put(KeyType.ui, new Key<>("progressExtraCssClasses"), progressExtraCssClasses); + return this; + } +} diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel.java new file mode 100644 index 00000000000..abbc3f17db2 --- /dev/null +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.ui.commons.markup.html.form; + +import java.util.Optional; +import org.apache.wicket.model.IModel; +import org.apache.wicket.validation.IValidatable; +import org.apache.wicket.validation.IValidator; +import org.apache.wicket.validation.ValidationError; + +public abstract class TextFieldPanel extends FieldPanel { + + private static final long serialVersionUID = 1708195999215061362L; + + public TextFieldPanel(final String id, final String name, final IModel model) { + super(id, name, model); + } + + protected TextFieldPanel setHTMLInputNotAllowed() { + field.add(new IValidator() { + + private static final long serialVersionUID = -8386207349500954732L; + + @Override + public void validate(final IValidatable validatable) { + Optional.ofNullable(validatable.getValue()).filter(v -> v.indexOf('<') != -1).ifPresent(v -> { + ValidationError error = new ValidationError().addKey("htmlErrorMessage"); + error.setVariable("label", field.getLabel().getObject()); + validatable.error(error); + }); + } + }); + + return this; + } + + public void addValidator(final IValidator validator) { + this.field.add(validator); + } +} diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryCertPreviewer.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryCertPreviewer.java index 7e2c241fae9..6439f14f7be 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryCertPreviewer.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryCertPreviewer.java @@ -35,8 +35,8 @@ public class BinaryCertPreviewer extends BinaryPreviewer { private static final long serialVersionUID = -5843835939538055110L; - public BinaryCertPreviewer(final String id, final String mimeType) { - super(id, mimeType); + public BinaryCertPreviewer(final String mimeType) { + super(mimeType); } @Override diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryImagePreviewer.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryImagePreviewer.java index c720cf1f48c..15337f3d3c7 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryImagePreviewer.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryImagePreviewer.java @@ -30,23 +30,22 @@ public class BinaryImagePreviewer extends BinaryPreviewer { private static final long serialVersionUID = 3338812359368457349L; - private static final int IMG_SIZE = 300; + protected static final int IMG_SIZE = 300; - public BinaryImagePreviewer(final String id, final String mimeType) { - super(id, mimeType); + public BinaryImagePreviewer(final String mimeType) { + super(mimeType); } @Override public Component preview(final byte[] uploadedBytes) { - return this.addOrReplace( - new NonCachingImage("previewImage", new ThumbnailImageResource(new DynamicImageResource() { + return addOrReplace(new NonCachingImage("previewImage", new ThumbnailImageResource(new DynamicImageResource() { - private static final long serialVersionUID = 923201517955737928L; + private static final long serialVersionUID = 923201517955737928L; - @Override - protected byte[] getImageData(final IResource.Attributes attributes) { - return uploadedBytes; - } - }, IMG_SIZE))); + @Override + protected byte[] getImageData(final IResource.Attributes attributes) { + return uploadedBytes; + } + }, IMG_SIZE))); } } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryPDFPreviewer.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryPDFPreviewer.java index d41b0c5a858..1dc1b599d8d 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryPDFPreviewer.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryPDFPreviewer.java @@ -21,14 +21,11 @@ import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; import java.io.Serializable; import java.time.Instant; import org.apache.pdfbox.Loader; import org.apache.pdfbox.cos.COSObject; -import org.apache.pdfbox.io.MemoryUsageSetting; import org.apache.pdfbox.pdmodel.DefaultResourceCache; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.graphics.PDXObject; @@ -55,23 +52,21 @@ public class BinaryPDFPreviewer extends BinaryPreviewer { private transient BufferedImage firstPage; - public BinaryPDFPreviewer(final String id, final String mimeType) { - super(id, mimeType); + public BinaryPDFPreviewer(final String mimeType) { + super(mimeType); } @Override public Component preview(final byte[] uploadedBytes) { firstPage = null; - try (InputStream bais = new ByteArrayInputStream(uploadedBytes); - PDDocument document = Loader.loadPDF(bais, MemoryUsageSetting.setupTempFileOnly())) { - + try (PDDocument document = Loader.loadPDF(uploadedBytes)) { document.setResourceCache(new DefaultResourceCache() { @Override - public void put(final COSObject indirect, final PDXObject xobject) throws IOException { + public void put(final COSObject indirect, final PDXObject xobject) { + // no cache } - }); if (document.isEncrypted()) { LOG.info("Document is encrypted, no preview is possible"); @@ -96,15 +91,15 @@ public void put(final COSObject indirect, final PDXObject xobject) throws IOExce return this.addOrReplace(previewContainer); } - private static class ThumbnailImageResource extends DynamicImageResource implements Serializable { + protected static class ThumbnailImageResource extends DynamicImageResource implements Serializable { private static final long serialVersionUID = 923201517955737928L; - private final transient BufferedImage image; + protected final transient BufferedImage image; - private transient byte[] thumbnail; + protected transient byte[] thumbnail; - ThumbnailImageResource(final BufferedImage image) { + protected ThumbnailImageResource(final BufferedImage image) { this.image = image; } @@ -117,7 +112,7 @@ protected byte[] getImageData(final IResource.Attributes attributes) { return thumbnail; } - private BufferedImage getScaledImageInstance() { + protected BufferedImage getScaledImageInstance() { int originalWidth = image.getWidth(); int originalHeight = image.getHeight(); diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryPreviewer.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryPreviewer.java index 29f79f93955..43ccb6ff80e 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryPreviewer.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryPreviewer.java @@ -32,8 +32,8 @@ public abstract class BinaryPreviewer extends Panel { protected final String mimeType; - public BinaryPreviewer(final String id, final String mimeType) { - super(id); + public BinaryPreviewer(final String mimeType) { + super("previewer"); this.mimeType = mimeType; } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryTextPreviewer.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryTextPreviewer.java index c424bca98e7..dead868a632 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryTextPreviewer.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/BinaryTextPreviewer.java @@ -41,13 +41,12 @@ public class BinaryTextPreviewer extends BinaryPreviewer { private String previewerId; - public BinaryTextPreviewer(final String id, final String mimeType) { - super(id, mimeType); + public BinaryTextPreviewer(final String mimeType) { + super(mimeType); } @Override public Component preview(final byte[] uploadedBytes) { - Fragment fragment = new Fragment("preview", "noPreviewFragment", this); if (uploadedBytes.length > 0) { try { diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/DefaultPreviewer.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/DefaultPreviewer.java index bf7e13bd3b6..698e8f73204 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/DefaultPreviewer.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/preview/DefaultPreviewer.java @@ -26,8 +26,8 @@ public class DefaultPreviewer extends BinaryPreviewer { private static final long serialVersionUID = 3338812359368457349L; - public DefaultPreviewer(final String id, final String mimeType) { - super(id, mimeType); + public DefaultPreviewer(final String mimeType) { + super(mimeType); } @Override diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/panels/BaseSSOLoginFormPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/panels/BaseSSOLoginFormPanel.java index 9675eb7bab4..4e9117387f7 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/panels/BaseSSOLoginFormPanel.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/panels/BaseSSOLoginFormPanel.java @@ -24,7 +24,13 @@ public abstract class BaseSSOLoginFormPanel extends Panel { private static final long serialVersionUID = -2371733568360773586L; + protected boolean reauth; + public BaseSSOLoginFormPanel(final String id) { super(id); } + + public void setReauth(final boolean reauth) { + this.reauth = reauth; + } } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.java new file mode 100644 index 00000000000..134a03c73c1 --- /dev/null +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.java @@ -0,0 +1,229 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.ui.commons.panels; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; +import org.apache.commons.lang3.time.FastDateFormat; +import org.apache.syncope.client.ui.commons.MapChoiceRenderer; +import org.apache.syncope.client.ui.commons.markup.html.form.AbstractFieldPanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDateFieldPanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDateTimeFieldPanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxNumberFieldPanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPasswordFieldPanel; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; +import org.apache.syncope.common.lib.form.FormProperty; +import org.apache.syncope.common.lib.form.FormPropertyValue; +import org.apache.syncope.common.lib.form.SyncopeForm; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.markup.html.panel.Panel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.PropertyModel; +import org.apache.wicket.model.util.ListModel; +import org.apache.wicket.validation.validator.PatternValidator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SyncopeFormPanel extends Panel { + + private static final long serialVersionUID = -8847854414429745216L; + + protected static final Logger LOG = LoggerFactory.getLogger(SyncopeFormPanel.class); + + public SyncopeFormPanel(final String id, final F form) { + super(id); + + ListModel model = new ListModel<>(new ArrayList<>()); + model.getObject().addAll(form.getProperties()); + + ListView propView = new ListView<>("propView", model) { + + private static final long serialVersionUID = 9101744072914090143L; + + @Override + protected void populateItem(final ListItem item) { + FormProperty prop = item.getModelObject(); + + String label = StringUtils.isBlank(prop.getName()) ? prop.getId() : prop.getName(); + + AbstractFieldPanel field; + switch (prop.getType()) { + case Boolean: + field = new AjaxCheckBoxPanel("value", label, new PropertyModel(prop, "value") { + + private static final long serialVersionUID = -3743432456095828573L; + + @Override + public Boolean getObject() { + return BooleanUtils.toBoolean(prop.getValue()); + } + + @Override + public void setObject(final Boolean object) { + prop.setValue(BooleanUtils.toStringTrueFalse(object)); + } + }, false); + break; + + case Date: + FastDateFormat formatter = StringUtils.isBlank(prop.getDatePattern()) + ? FastDateFormat.getInstance() + : FastDateFormat.getInstance(prop.getDatePattern()); + + PropertyModel dateModel = new PropertyModel<>(prop, "value") { + + private static final long serialVersionUID = -3743432456095828573L; + + @Override + public Date getObject() { + try { + return StringUtils.isBlank(prop.getValue()) + ? null + : formatter.parse(prop.getValue()); + } catch (ParseException e) { + LOG.error("Unparsable date: {}", prop.getValue(), e); + return null; + } + } + + @Override + public void setObject(final Date object) { + Optional.ofNullable(object).ifPresent(date -> prop.setValue(formatter.format(date))); + } + }; + + if (StringUtils.containsIgnoreCase(prop.getDatePattern(), "H")) { + field = new AjaxDateTimeFieldPanel("value", label, dateModel, formatter); + } else { + field = new AjaxDateFieldPanel("value", label, dateModel, formatter); + } + break; + + case Enum: + field = new AjaxDropDownChoicePanel<>( + "value", label, new PropertyModel(prop, "value"), false). + setChoiceRenderer(new MapChoiceRenderer(prop.getEnumValues().stream(). + collect(Collectors.toMap( + FormPropertyValue::getKey, + FormPropertyValue::getValue)))). + setChoices(prop.getEnumValues().stream(). + map(FormPropertyValue::getKey).collect(Collectors.toList())); + break; + + case Dropdown: + if (prop.isDropdownFreeForm()) { + field = new AjaxTextFieldPanel("value", label, new PropertyModel<>(prop, "value"), false); + ((AjaxTextFieldPanel) field).setChoices(prop.getDropdownValues().stream(). + map(FormPropertyValue::getKey).collect(Collectors.toList())); + } else if (prop.isDropdownSingleSelection()) { + field = new AjaxDropDownChoicePanel<>( + "value", label, new PropertyModel(prop, "value"), false). + setChoiceRenderer(new MapChoiceRenderer(prop.getDropdownValues().stream(). + collect(Collectors.toMap( + FormPropertyValue::getKey, + FormPropertyValue::getValue)))). + setChoices(prop.getDropdownValues().stream(). + map(FormPropertyValue::getKey).collect(Collectors.toList())); + } else { + field = new AjaxPalettePanel.Builder().setName(label). + setRenderer(new MapChoiceRenderer(prop.getDropdownValues().stream(). + collect(Collectors.toMap( + FormPropertyValue::getKey, + FormPropertyValue::getValue)))).build( + "value", + new IModel>() { + + private static final long serialVersionUID = 1015030402166681242L; + + @Override + public List getObject() { + return Optional.ofNullable(prop.getValue()). + map(v -> List.of(v.split(";"))). + orElse(List.of()); + } + + @Override + public void setObject(final List object) { + prop.setValue(Optional.ofNullable(object). + map(v -> v.stream().collect(Collectors.joining(";"))). + orElse(null)); + } + }, new ListModel<>(prop.getDropdownValues().stream(). + map(FormPropertyValue::getKey).collect(Collectors.toList()))); + } + break; + + case Long: + field = new AjaxNumberFieldPanel.Builder().build( + "value", + label, + Long.class, + new PropertyModel<>(prop, "value") { + + private static final long serialVersionUID = -7688359318035249200L; + + @Override + public Long getObject() { + return StringUtils.isBlank(prop.getValue()) + ? null + : NumberUtils.toLong(prop.getValue()); + } + + @Override + public void setObject(final Long object) { + prop.setValue(String.valueOf(object)); + } + }); + break; + + case Password: + field = new AjaxPasswordFieldPanel("value", label, new PropertyModel<>(prop, "value"), false). + setResetPassword(false); + break; + + case String: + default: + field = new AjaxTextFieldPanel("value", label, new PropertyModel<>(prop, "value"), false); + Optional.ofNullable(prop.getStringRegEx()). + ifPresent(re -> ((AjaxTextFieldPanel) field).addValidator(new PatternValidator(re))); + break; + } + + field.setReadOnly(!prop.isWritable()); + if (prop.isRequired()) { + field.addRequiredLabel(); + } + + item.add(field); + } + }; + add(propView.setReuseItems(true)); + } +} diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/status/ConnObjectWrapper.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/status/ConnObjectWrapper.java index c5b8be70b35..3098b0fc270 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/status/ConnObjectWrapper.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/status/ConnObjectWrapper.java @@ -49,5 +49,4 @@ public String getResource() { public ConnObject getConnObjectTO() { return connObjectTO; } - } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/status/StatusUtils.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/status/StatusUtils.java index e6e73fab0d6..70d2930942e 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/status/StatusUtils.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/status/StatusUtils.java @@ -25,12 +25,12 @@ import org.apache.syncope.client.ui.commons.ConnIdSpecialName; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.panels.LabelPanel; -import org.apache.syncope.common.lib.Attr; import org.apache.syncope.common.lib.request.StatusR; import org.apache.syncope.common.lib.to.AnyTO; import org.apache.syncope.common.lib.to.ConnObject; import org.apache.syncope.common.lib.to.RealmTO; import org.apache.syncope.common.lib.types.ExecStatus; +import org.apache.syncope.common.lib.types.StatusRType; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.panel.Panel; @@ -42,18 +42,18 @@ public final class StatusUtils implements Serializable { public static StatusBean getStatusBean( final AnyTO anyTO, final String resource, - final ConnObject connObjectTO, + final ConnObject connObject, final boolean notUser) { StatusBean statusBean = new StatusBean(anyTO, resource); - if (connObjectTO != null) { - Boolean enabled = isEnabled(connObjectTO); + if (connObject != null) { + Boolean enabled = isEnabled(connObject); statusBean.setStatus(Optional.ofNullable(enabled).map(aBoolean -> aBoolean ? Status.ACTIVE : Status.SUSPENDED).orElseGet(() -> (notUser ? Status.ACTIVE : Status.UNDEFINED))); - statusBean.setConnObjectLink(getConnObjectLink(connObjectTO)); + statusBean.setConnObjectLink(getConnObjectLink(connObject)); } return statusBean; @@ -62,38 +62,37 @@ public static StatusBean getStatusBean( public static StatusBean getStatusBean( final RealmTO realmTO, final String resource, - final ConnObject connObjectTO) { + final ConnObject connObject) { StatusBean statusBean = new StatusBean(realmTO, resource); - if (connObjectTO != null) { - Boolean enabled = isEnabled(connObjectTO); + if (connObject != null) { + Boolean enabled = isEnabled(connObject); statusBean.setStatus(Optional.ofNullable(enabled) .filter(aBoolean -> !aBoolean).map(aBoolean -> Status.SUSPENDED).orElse(Status.ACTIVE)); - statusBean.setConnObjectLink(getConnObjectLink(connObjectTO)); + statusBean.setConnObjectLink(getConnObjectLink(connObject)); } return statusBean; } - public static Boolean isEnabled(final ConnObject objectTO) { - Optional status = objectTO.getAttr(ConnIdSpecialName.ENABLE); - return status.isPresent() && status.get().getValues() != null && !status.get().getValues().isEmpty() - ? Boolean.valueOf(status.get().getValues().get(0)) - : Boolean.FALSE; + public static Boolean isEnabled(final ConnObject connObject) { + return connObject.getAttr(ConnIdSpecialName.ENABLE). + filter(s -> !s.getValues().isEmpty()). + map(s -> Boolean.valueOf(s.getValues().get(0))). + orElse(Boolean.FALSE); } - private static String getConnObjectLink(final ConnObject objectTO) { - Optional name = Optional.ofNullable(objectTO).map(to -> to.getAttr(ConnIdSpecialName.NAME)).orElse(null); - return name != null && name.isPresent() && name.get().getValues() != null && !name.get().getValues().isEmpty() - ? name.get().getValues().get(0) - : null; + public static String getConnObjectLink(final ConnObject connObject) { + return connObject.getAttr(ConnIdSpecialName.NAME). + filter(s -> !s.getValues().isEmpty()). + map(s -> s.getValues().get(0)). + orElse(null); } - public static StatusR.Builder statusR(final Collection statuses) { - StatusR.Builder builder = new StatusR.Builder(); - builder.onSyncope(false); + public static StatusR statusR(final String key, final StatusRType type, final Collection statuses) { + StatusR.Builder builder = new StatusR.Builder(key, type).onSyncope(false); statuses.forEach(status -> { if (Constants.SYNCOPE.equalsIgnoreCase(status.getResource())) { builder.onSyncope(true); @@ -102,7 +101,7 @@ public static StatusR.Builder statusR(final Collection statuses) { } }); - return builder; + return builder.build(); } public static Panel getStatusImagePanel(final String componentId, final Status status) { @@ -207,7 +206,7 @@ public static Panel getWarningStatusPanel(final String componentId) { return new LabelPanel(componentId, getLabel("label", "warning icon", "Propagation failed", Constants.WARNING_ICON)); } - + public static Label getLabel(final String componentId, final String alt, final String title, final String clazz) { return new Label(componentId, StringUtils.EMPTY) { diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AbstractWizardMgtPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AbstractWizardMgtPanel.java index 7ed5447020e..4444f498522 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AbstractWizardMgtPanel.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AbstractWizardMgtPanel.java @@ -31,5 +31,4 @@ public abstract class AbstractWizardMgtPanel extends Pan public AbstractWizardMgtPanel(final String id) { super(id); } - } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizard.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizard.java index 5011e9d412b..c4d95375ae8 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizard.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/AjaxWizard.java @@ -281,7 +281,7 @@ public abstract static class NewItemEvent { private final T item; - private IModel resourceModel; + private IModel titleModel; private final AjaxRequestTarget target; @@ -309,12 +309,12 @@ public NewItemEvent forceModalPanel(final WizardModalPanel modalPanel) { return this; } - public IModel getResourceModel() { - return resourceModel; + public IModel getTitleModel() { + return titleModel; } - public NewItemEvent setResourceModel(final IModel resourceModel) { - this.resourceModel = resourceModel; + public NewItemEvent setTitleModel(final IModel titleModel) { + this.titleModel = titleModel; return this; } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AbstractGroupsModel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AbstractGroupsModel.java index 66d799f4c7e..7264856b087 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AbstractGroupsModel.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AbstractGroupsModel.java @@ -31,38 +31,30 @@ public abstract class AbstractGroupsModel extends ListModel { protected List memberships; - protected String realm; + /** + * Retrieve the first MAX_GROUP_LIST_CARDINALITY assignable. + */ + protected abstract void reloadObject(); @Override public List getObject() { - reload(); + if (groups == null) { + reloadObject(); + } return groups; } /** - * Retrieve the first MAX_GROUP_LIST_CARDINALITY assignable. + * Retrieve group memberships. */ - protected abstract void reloadObject(); + protected abstract void reloadMemberships(); public List getMemberships() { - reload(); + if (memberships == null) { + reloadMemberships(); + } return memberships; } - /** - * Retrieve group memberships. - */ - protected abstract void reloadMemberships(); - public abstract List getDynMemberships(); - - /** - * Retrieve dyn group memberships. - */ - protected abstract void reloadDynMemberships(); - - /** - * Reload data if the realm changes (see SYNCOPE-1135). - */ - protected abstract void reload(); } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AbstractResources.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AbstractResources.java index 47c265f335d..0d141dd2ee9 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AbstractResources.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AbstractResources.java @@ -34,10 +34,12 @@ public abstract class AbstractResources extends WizardStep implements ICondition private static final long serialVersionUID = 552437609667518888L; + protected final AnyTO anyTO; + protected final ListModel available; public AbstractResources(final AnyWrapper modelObject) { - final T entityTO = modelObject.getInnerObject(); + anyTO = modelObject.getInnerObject(); if (modelObject instanceof UserWrapper && UserWrapper.class.cast(modelObject).getPreviousUserTO() != null @@ -52,21 +54,20 @@ public AbstractResources(final AnyWrapper modelObject) { this.setOutputMarkupId(true); this.available = new ListModel<>(List.of()); - add(new AjaxPalettePanel.Builder().build("resources", - new PropertyModel<>(entityTO, "resources") { + add(new AjaxPalettePanel.Builder().build("resources", new PropertyModel<>(anyTO, "resources") { - private static final long serialVersionUID = 3799387950428254072L; + private static final long serialVersionUID = 3799387950428254072L; - @Override - public List getObject() { - return new ArrayList<>(entityTO.getResources()); - } + @Override + public List getObject() { + return new ArrayList<>(anyTO.getResources()); + } - @Override - public void setObject(final List object) { - entityTO.getResources().clear(); - entityTO.getResources().addAll(object); - } - }, available).hideLabel().setOutputMarkupId(true)); + @Override + public void setObject(final List object) { + anyTO.getResources().clear(); + anyTO.getResources().addAll(object); + } + }, available).hideLabel().setOutputMarkupId(true)); } } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AnyWrapper.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AnyWrapper.java index 482b4975e12..6fec895f0a4 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AnyWrapper.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/AnyWrapper.java @@ -21,7 +21,7 @@ import java.io.Serializable; import org.apache.syncope.common.lib.to.AnyTO; -public class AnyWrapper implements Serializable { +public abstract class AnyWrapper implements Serializable { private static final long serialVersionUID = 8058288034211558375L; diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/EntityWrapper.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/EntityWrapper.java index 67640498445..95bcd6523b0 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/EntityWrapper.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/EntityWrapper.java @@ -18,9 +18,12 @@ */ package org.apache.syncope.client.ui.commons.wizards.any; +import java.io.Serializable; import org.apache.syncope.common.lib.to.EntityTO; -public class EntityWrapper { +public class EntityWrapper implements Serializable { + + private static final long serialVersionUID = 1L; protected final T entityTO; @@ -31,5 +34,4 @@ public EntityWrapper(final T entityTO) { public T getInnerObject() { return entityTO; } - } diff --git a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/PasswordPanel.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/PasswordPanel.java index 09fecc67f97..214c64ff921 100644 --- a/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/PasswordPanel.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/wizards/any/PasswordPanel.java @@ -57,7 +57,7 @@ public PasswordPanel( add(form); AjaxPasswordFieldPanel confirmPasswordField = new AjaxPasswordFieldPanel( - "confirmPassword", "confirmPassword", new Model<>(), false, null); + "confirmPassword", "confirmPassword", Model.of(), false); ((PasswordTextField) confirmPasswordField.getField()).setResetPassword(false); form.add(confirmPasswordField.setPlaceholder("confirmPassword").setMarkupId("confirmPassword")); diff --git a/client/idrepo/common-ui/src/main/resources/META-INF/resources/ui-commons/css/syncopeUI.scss b/client/idrepo/common-ui/src/main/resources/META-INF/resources/ui-commons/css/syncopeUI.scss index e0bf1f48a52..edc3ccd5adb 100644 --- a/client/idrepo/common-ui/src/main/resources/META-INF/resources/ui-commons/css/syncopeUI.scss +++ b/client/idrepo/common-ui/src/main/resources/META-INF/resources/ui-commons/css/syncopeUI.scss @@ -19,12 +19,10 @@ @import 'utils'; - pre { @include white_space_pre_wrap; } - #veil { display: none; position: fixed; @@ -66,22 +64,18 @@ pre { border-radius: 0.5em; @include animation(spinner 2000ms infinite linear); - @include shadow(rgba(0, 0, 0, 0.75) 1.5em 0 0 0, - rgba(0, 0, 0, 0.75) 1.1em 1.1em 0 0, - rgba(0, 0, 0, 0.75) 0 1.5em 0 0, - rgba(0, 0, 0, 0.75) -1.1em 1.1em 0 0, - rgba(0, 0, 0, 0.5) -1.5em 0 0 0, - rgba(0, 0, 0, 0.5) -1.1em -1.1em 0 0, - rgba(0, 0, 0, 0.75) 0 -1.5em 0 0, + @include shadow(rgba(0, 0, 0, 0.75) 1.5em 0 0 0, + rgba(0, 0, 0, 0.75) 1.1em 1.1em 0 0, + rgba(0, 0, 0, 0.75) 0 1.5em 0 0, + rgba(0, 0, 0, 0.75) -1.1em 1.1em 0 0, + rgba(0, 0, 0, 0.5) -1.5em 0 0 0, + rgba(0, 0, 0, 0.5) -1.1em -1.1em 0 0, + rgba(0, 0, 0, 0.75) 0 -1.5em 0 0, rgba(0, 0, 0, 0.75) 1.1em -1.1em 0 0); } } } - - - - /* General ============================================================================= */ @@ -114,8 +108,8 @@ pre { } .realm-header { + width: 100%; clear: both; - display: block; display: inline-table; margin: 0 0 10px; line-height: 25px; @@ -130,8 +124,7 @@ pre { } .realm-choice { - right: 0px; - position: absolute; + float: right; } .realm-header .dropdown-menu li a { @@ -320,7 +313,6 @@ a.help { } } - .wizard-buttons { padding: 10px 0px 5px 0px; position: absolute; @@ -374,7 +366,7 @@ span.overridable div.checkbox { } } -#outer.modal-lg, +#outer.modal-lg, #utilityModal.modal-lg { max-width: 1200px; width: 97%; @@ -416,7 +408,11 @@ td.checkGroupColumn { color: #fff!important; } - +.pwstrengthProgress { + position: absolute; + bottom: 0px; + width: 100%; +} /* Style for Information panel ============================================================================= */ @@ -461,7 +457,6 @@ td.checkGroupColumn { margin-left: 155px; } - #ownership div.toggle { width: 110px !important; } @@ -513,9 +508,6 @@ td.checkGroupColumn { padding-left: 15px; } - - - /* Startat ============================================================================= */ @@ -541,10 +533,6 @@ td.checkGroupColumn { } } - - - - /* Notifications ============================================================================= */ /*Temporany fix diagonal stacking*/ @@ -599,11 +587,6 @@ td.checkGroupColumn { } } - - - - - /* Actions ============================================================================= */ @@ -666,12 +649,6 @@ div.listview-actions a { margin: 0px; } - - - - - - /* Datatable ============================================================================= */ @@ -778,6 +755,12 @@ div.panel-collapse.collapse.show span.ui-spinner.ui-corner-all.ui-widget.ui-widg top: 5px !important; } +.k-datepicker input { + width: 0px !important; +} +.k-timepicker input { + width: 0px !important; +} /* Parameters Details ============================================================================= */ @@ -786,8 +769,6 @@ div#parametersForm { min-height: 220px; } - - li.todoitem a { cursor: default; } @@ -843,11 +824,6 @@ div#userFilter { width: 20px; } - - - - - /* Alert widget onside menu ============================================================================= */ @@ -898,10 +874,6 @@ div#userFilter { } } - - - - /* Transformers toggle panel ============================================================================= */ @@ -965,9 +937,6 @@ div#userFilter { clear: both; } - - - /* Events ============================================================================= */ @@ -1006,9 +975,6 @@ div#userFilter { min-width: 585px; } - - - /* Others ============================================================================= */ .form-check { @@ -1072,8 +1038,8 @@ th ul.menu { padding: 0; } -#inline-actions ul.menu, -#tablehandling ul.menu, +#inline-actions ul.menu, +#tablehandling ul.menu, .listview-actions ul.menu { list-style-type: none; margin: 0; @@ -1088,7 +1054,7 @@ th ul.menu li { } #inline-actions ul.menu li, -#tablehandling ul.menu li, +#tablehandling ul.menu li, .listview-actions ul.menu li { display: inline-block; } @@ -1098,8 +1064,8 @@ th ul.menu li a { display: inline-block !important; } -#inline-actions ul.menu li a, -.listview-actions ul.menu li a, +#inline-actions ul.menu li a, +.listview-actions ul.menu li a, #tablehandling ul.menu li a { margin-left: 5px; display: inline-block !important; @@ -1115,7 +1081,7 @@ ul.menu { } } -#inline-actions ul.menu i, +#inline-actions ul.menu i, #tablehandling ul.menu i { width: auto !important; } @@ -1131,7 +1097,7 @@ div#tablehandling ul.menu li a { } .realm-choice #realm-choice-field { - width: 200px; + width: 400px; padding-right: 20px; } @@ -1164,9 +1130,6 @@ h3.card-title { @include shadow(0px 0px 20px 1px rgba(0,0,0,0.75)); } - - - /* Utility classes ============================================================================= */ @@ -1238,3 +1201,12 @@ pre { float: right; margin-right:12px; } + +@media screen and (max-width: 500px) { + .realm-choice #realm-choice-field{ + width: 100%; + } + .realm-choice { + float: none; + } +} diff --git a/client/idrepo/common-ui/src/main/resources/MIMETypes.json b/client/idrepo/common-ui/src/main/resources/MIMETypes.json index f49a5a1150a..e7e36820f0c 100644 --- a/client/idrepo/common-ui/src/main/resources/MIMETypes.json +++ b/client/idrepo/common-ui/src/main/resources/MIMETypes.json @@ -139,7 +139,8 @@ "name": "application/oda" }, { - "name": "application/pdf" + "name": "application/pdf", + "extension": "pdf" }, { "name": "application/pkcs10" @@ -1025,6 +1026,10 @@ "name": "text/javascript", "extension": "js" }, + { + "name": "text/csv", + "extension": "csv" + }, { "name": "text/mcf" }, diff --git a/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxSpinnerFieldPanel.html b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxNumberFieldPanel.html similarity index 95% rename from client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxSpinnerFieldPanel.html rename to client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxNumberFieldPanel.html index 3587e3f9971..aecb9b4268e 100644 --- a/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxSpinnerFieldPanel.html +++ b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxNumberFieldPanel.html @@ -23,6 +23,6 @@ - + diff --git a/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.html b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.html index 30329ae9176..4de436c3446 100644 --- a/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.html +++ b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/AjaxPasswordFieldPanel.html @@ -22,6 +22,22 @@ - +
+ + + + +
- \ No newline at end of file + diff --git a/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/EncryptedFieldPanel_fr_CA.properties b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/EncryptedFieldPanel_fr_CA.properties new file mode 100644 index 00000000000..193287d6031 --- /dev/null +++ b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/EncryptedFieldPanel_fr_CA.properties @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +confirmMessage=This will remove the current value. Continue? diff --git a/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel.properties b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel.properties new file mode 100644 index 00000000000..812929d9247 --- /dev/null +++ b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel.properties @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +htmlErrorMessage=HTML input not allowed for '${label}' diff --git a/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_fr_CA.properties b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_fr_CA.properties new file mode 100644 index 00000000000..812929d9247 --- /dev/null +++ b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_fr_CA.properties @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +htmlErrorMessage=HTML input not allowed for '${label}' diff --git a/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_it.properties b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_it.properties new file mode 100644 index 00000000000..722f9084855 --- /dev/null +++ b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_it.properties @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +htmlErrorMessage=Input HTML non consentito per '${label}' diff --git a/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_ja.properties b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_ja.properties new file mode 100644 index 00000000000..812929d9247 --- /dev/null +++ b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_ja.properties @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +htmlErrorMessage=HTML input not allowed for '${label}' diff --git a/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_pt_BR.properties b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_pt_BR.properties new file mode 100644 index 00000000000..812929d9247 --- /dev/null +++ b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_pt_BR.properties @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +htmlErrorMessage=HTML input not allowed for '${label}' diff --git a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/reports/ReportletWizardBuilder$Profile_ru.properties b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_ru.properties similarity index 60% rename from client/idrepo/console/src/main/resources/org/apache/syncope/client/console/reports/ReportletWizardBuilder$Profile_ru.properties rename to client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_ru.properties index 015497366d8..1ffe19264e3 100644 --- a/client/idrepo/console/src/main/resources/org/apache/syncope/client/console/reports/ReportletWizardBuilder$Profile_ru.properties +++ b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/markup/html/form/TextFieldPanel_ru.properties @@ -15,5 +15,5 @@ # specific language governing permissions and limitations # under the License. # -reportlet=Reportlet -configuration=\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f +# field.DateTimeFieldPanel$DateTimeFormValidator=\u00d0\u009f\u00d0\u00be\u00d0\u00bb\u00d0\u00b5 '${label0}' \u00d0\u00b4\u00d0\u00be\u00d0\u00bb\u00d0\u00b6\u00d0\u00bd\u00d0\u00be \u00d0\u00b1\u00d1\u008b\u00d1\u0082\u00d1\u008c \u00d0\u00b7\u00d0\u00b0\u00d0\u00bf\u00d0\u00be\u00d0\u00bb\u00d0\u00bd\u00d0\u00b5\u00d0\u00bd\u00d0\u00be \u00d0\u00bf\u00d0\u00be\u00d0\u00bb\u00d0\u00bd\u00d0\u00be\u00d1\u0081\u00d1\u0082\u00d1\u008c\u00d1\u008e +htmlErrorMessage=HTML input not allowed for '${label}' diff --git a/CONTRIBUTING.md b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.html similarity index 74% rename from CONTRIBUTING.md rename to client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.html index c527cceca5f..6271a58363d 100644 --- a/CONTRIBUTING.md +++ b/client/idrepo/common-ui/src/main/resources/org/apache/syncope/client/ui/commons/panels/SyncopeFormPanel.html @@ -16,7 +16,12 @@ specific language governing permissions and limitations under the License. --> -**Apache Syncope** is an Open Source system for managing digital identities in enterprise environments, -implemented in Java EE technology and released under Apache 2.0 license. + + +
+ [value] +
-Would you like to contribute? Visit https://syncope.apache.org/contributing.html + +
+ diff --git a/client/idrepo/console/NOTICE b/client/idrepo/console/NOTICE index bde93187899..a9a10ab5afa 100644 --- a/client/idrepo/console/NOTICE +++ b/client/idrepo/console/NOTICE @@ -1,5 +1,5 @@ Apache Syncope -Copyright 2012-2022 The Apache Software Foundation +Copyright 2012-2023 The Apache Software Foundation This product includes software developed by: The Apache Software Foundation (http://www.apache.org/). diff --git a/client/idrepo/console/pom.xml b/client/idrepo/console/pom.xml index 05a638f5250..fafe1a670c5 100644 --- a/client/idrepo/console/pom.xml +++ b/client/idrepo/console/pom.xml @@ -24,7 +24,7 @@ under the License. org.apache.syncope.client syncope-client-idrepo - 3.0.1-SNAPSHOT + 3.0.17-SNAPSHOT Apache Syncope Client IdRepo Console @@ -72,6 +72,15 @@ under the License. ${project.version}
+ + org.bouncycastle + bcpkix-jdk15on + + + org.bouncycastle + bcprov-jdk15on + + com.nimbusds nimbus-jose-jwt @@ -102,8 +111,8 @@ under the License. jsplumb - org.webjars.bower - chart.js + org.webjars + chartjs org.webjars @@ -199,9 +208,9 @@ under the License. org.apache.maven.plugins maven-surefire-plugin - + true - + @@ -274,13 +283,39 @@ under the License. debug + true true - clean package spring-boot:run + clean package + + org.apache.maven.plugins + maven-resources-plugin + + + copy-fit-classes + generate-sources + + copy-resources + + + ${project.build.outputDirectory}/org/apache/syncope/fit/core/reference + + + ${basedir}/../../../fit/core-reference/target/classes/org/apache/syncope/fit/core/reference + + SampleReportConf.class + + + + + + + + org.springframework.boot spring-boot-maven-plugin @@ -288,6 +323,7 @@ under the License. -Djavax.net.ssl.trustStore=${basedir}/../../../fit/wa-reference/src/test/resources/keystore.jks -Djavax.net.ssl.trustStorePassword=password -Dwicket.core.settings.general.configuration-type=development + -Dwicket.ioc.useByteBuddy=true -XX:HotswapAgent=fatjar -Xdebug -Xrunjdwp:transport=dt_socket,address=8003,server=y,suspend=n @@ -295,6 +331,14 @@ under the License. debug
+ + + package + + run + + + @@ -349,6 +393,7 @@ under the License. syncope-ext-scimv2-client-console ${project.version} + org.apache.syncope.ext.oidcc4ui syncope-ext-oidcc4ui-client-console diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/ConsoleContext.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/ConsoleContext.java deleted file mode 100644 index 6c6d741876a..00000000000 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/ConsoleContext.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.syncope.client.console; - -import org.apache.syncope.client.console.commons.AnyDirectoryPanelAdditionalActionLinksProvider; -import org.apache.syncope.client.console.commons.AnyDirectoryPanelAdditionalActionsProvider; -import org.apache.syncope.client.console.commons.AnyWizardBuilderAdditionalSteps; -import org.apache.syncope.client.console.commons.ExternalResourceProvider; -import org.apache.syncope.client.console.commons.IdRepoAnyDirectoryPanelAdditionalActionLinksProvider; -import org.apache.syncope.client.console.commons.IdRepoAnyDirectoryPanelAdditionalActionsProvider; -import org.apache.syncope.client.console.commons.IdRepoAnyWizardBuilderAdditionalSteps; -import org.apache.syncope.client.console.commons.IdRepoExternalResourceProvider; -import org.apache.syncope.client.console.commons.IdRepoImplementationInfoProvider; -import org.apache.syncope.client.console.commons.IdRepoPolicyTabProvider; -import org.apache.syncope.client.console.commons.IdRepoRealmPolicyProvider; -import org.apache.syncope.client.console.commons.IdRepoStatusProvider; -import org.apache.syncope.client.console.commons.IdRepoVirSchemaDetailsPanelProvider; -import org.apache.syncope.client.console.commons.ImplementationInfoProvider; -import org.apache.syncope.client.console.commons.PolicyTabProvider; -import org.apache.syncope.client.console.commons.PreviewUtils; -import org.apache.syncope.client.console.commons.RealmPolicyProvider; -import org.apache.syncope.client.console.commons.StatusProvider; -import org.apache.syncope.client.console.commons.VirSchemaDetailsPanelProvider; -import org.apache.syncope.client.console.init.ClassPathScanImplementationContributor; -import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup; -import org.apache.syncope.client.ui.commons.MIMETypesLoader; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration(proxyBeanMethods = false) -public class ConsoleContext { - - @ConditionalOnMissingBean - @Bean - public ClassPathScanImplementationLookup classPathScanImplementationLookup( - final ApplicationContext ctx, final ConsoleProperties props) { - - ClassPathScanImplementationLookup lookup = new ClassPathScanImplementationLookup( - ctx.getBeansOfType(ClassPathScanImplementationContributor.class).values(), props); - lookup.load(); - return lookup; - } - - @ConditionalOnMissingBean - @Bean - public MIMETypesLoader mimeTypesLoader() { - MIMETypesLoader mimeTypesLoader = new MIMETypesLoader(); - mimeTypesLoader.load(); - return mimeTypesLoader; - } - - @ConditionalOnMissingBean - @Bean - public PreviewUtils previewUtils() { - return new PreviewUtils(); - } - - @ConditionalOnMissingBean - @Bean - public ExternalResourceProvider resourceProvider() { - return new IdRepoExternalResourceProvider(); - } - - @ConditionalOnMissingBean - @Bean - public AnyDirectoryPanelAdditionalActionsProvider anyDirectoryPanelAdditionalActionsProvider() { - return new IdRepoAnyDirectoryPanelAdditionalActionsProvider(); - } - - @ConditionalOnMissingBean - @Bean - public AnyDirectoryPanelAdditionalActionLinksProvider anyDirectoryPanelAdditionalActionLinksProvider() { - return new IdRepoAnyDirectoryPanelAdditionalActionLinksProvider(); - } - - @ConditionalOnMissingBean - @Bean - public AnyWizardBuilderAdditionalSteps anyWizardBuilderAdditionalSteps() { - return new IdRepoAnyWizardBuilderAdditionalSteps(); - } - - @ConditionalOnMissingBean - @Bean - public StatusProvider statusProvider() { - return new IdRepoStatusProvider(); - } - - @ConditionalOnMissingBean - @Bean - public VirSchemaDetailsPanelProvider virSchemaDetailsPanelProvider() { - return new IdRepoVirSchemaDetailsPanelProvider(); - } - - @ConditionalOnMissingBean - @Bean - public ImplementationInfoProvider implementationInfoProvider() { - return new IdRepoImplementationInfoProvider(); - } - - @ConditionalOnMissingBean - @Bean - public RealmPolicyProvider realmPolicyProvider() { - return new IdRepoRealmPolicyProvider(); - } - - @Bean - public PolicyTabProvider idRepoPolicyTabProvider() { - return new IdRepoPolicyTabProvider(); - } -} diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/ConsoleProperties.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/ConsoleProperties.java index 30764ebf2fd..15d86880e81 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/ConsoleProperties.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/ConsoleProperties.java @@ -18,6 +18,7 @@ */ package org.apache.syncope.client.console; +import java.io.Serializable; import java.util.HashMap; import java.util.Map; import org.apache.syncope.client.console.pages.BasePage; @@ -28,7 +29,11 @@ @ConfigurationProperties("console") public class ConsoleProperties extends CommonUIProperties { - public static class Topology { + private static final long serialVersionUID = -6444470724127309370L; + + public static class Topology implements Serializable { + + private static final long serialVersionUID = -4530238696048859905L; private int corePoolSize = 10; @@ -61,32 +66,16 @@ public void setQueueCapacity(final int queueCapacity) { } } - private String adminUser = "admin"; - - private String reconciliationReportKey; - private final Map> page = new HashMap<>(); private String defaultAnyPanelClass = AnyPanel.class.getName(); - private final Topology topology = new Topology(); - - @Override - public String getAdminUser() { - return adminUser; - } - - @Override - public void setAdminUser(final String adminUser) { - this.adminUser = adminUser; - } + private int realmsFullTreeThreshold = 20; - public String getReconciliationReportKey() { - return reconciliationReportKey; - } + private final Topology topology = new Topology(); - public void setReconciliationReportKey(final String reconciliationReportKey) { - this.reconciliationReportKey = reconciliationReportKey; + public Map> getPage() { + return page; } public String getDefaultAnyPanelClass() { @@ -97,8 +86,12 @@ public void setDefaultAnyPanelClass(final String defaultAnyPanelClass) { this.defaultAnyPanelClass = defaultAnyPanelClass; } - public Map> getPage() { - return page; + public int getRealmsFullTreeThreshold() { + return realmsFullTreeThreshold; + } + + public void setRealmsFullTreeThreshold(final int realmsFullTreeThreshold) { + this.realmsFullTreeThreshold = realmsFullTreeThreshold; } public Topology getTopology() { diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/IdRepoConsoleContext.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/IdRepoConsoleContext.java new file mode 100644 index 00000000000..94576912ea7 --- /dev/null +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/IdRepoConsoleContext.java @@ -0,0 +1,315 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.console; + +import java.util.List; +import org.apache.syncope.client.console.commons.AccessPolicyConfProvider; +import org.apache.syncope.client.console.commons.AnyDirectoryPanelAdditionalActionLinksProvider; +import org.apache.syncope.client.console.commons.AnyDirectoryPanelAdditionalActionsProvider; +import org.apache.syncope.client.console.commons.AnyWizardBuilderAdditionalSteps; +import org.apache.syncope.client.console.commons.ExternalResourceProvider; +import org.apache.syncope.client.console.commons.IdRepoAccessPolicyConfProvider; +import org.apache.syncope.client.console.commons.IdRepoAnyDirectoryPanelAdditionalActionLinksProvider; +import org.apache.syncope.client.console.commons.IdRepoAnyDirectoryPanelAdditionalActionsProvider; +import org.apache.syncope.client.console.commons.IdRepoAnyWizardBuilderAdditionalSteps; +import org.apache.syncope.client.console.commons.IdRepoExternalResourceProvider; +import org.apache.syncope.client.console.commons.IdRepoImplementationInfoProvider; +import org.apache.syncope.client.console.commons.IdRepoPolicyTabProvider; +import org.apache.syncope.client.console.commons.IdRepoRealmPolicyProvider; +import org.apache.syncope.client.console.commons.IdRepoStatusProvider; +import org.apache.syncope.client.console.commons.IdRepoVirSchemaDetailsPanelProvider; +import org.apache.syncope.client.console.commons.ImplementationInfoProvider; +import org.apache.syncope.client.console.commons.PolicyTabProvider; +import org.apache.syncope.client.console.commons.PreviewUtils; +import org.apache.syncope.client.console.commons.RealmPolicyProvider; +import org.apache.syncope.client.console.commons.StatusProvider; +import org.apache.syncope.client.console.commons.VirSchemaDetailsPanelProvider; +import org.apache.syncope.client.console.init.ClassPathScanImplementationContributor; +import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup; +import org.apache.syncope.client.console.rest.AccessTokenRestClient; +import org.apache.syncope.client.console.rest.AnyObjectRestClient; +import org.apache.syncope.client.console.rest.AnyTypeClassRestClient; +import org.apache.syncope.client.console.rest.AnyTypeRestClient; +import org.apache.syncope.client.console.rest.ApplicationRestClient; +import org.apache.syncope.client.console.rest.AuditRestClient; +import org.apache.syncope.client.console.rest.CommandRestClient; +import org.apache.syncope.client.console.rest.DelegationRestClient; +import org.apache.syncope.client.console.rest.DynRealmRestClient; +import org.apache.syncope.client.console.rest.FIQLQueryRestClient; +import org.apache.syncope.client.console.rest.GroupRestClient; +import org.apache.syncope.client.console.rest.ImplementationRestClient; +import org.apache.syncope.client.console.rest.LoggerConf; +import org.apache.syncope.client.console.rest.NotificationRestClient; +import org.apache.syncope.client.console.rest.PolicyRestClient; +import org.apache.syncope.client.console.rest.RealmRestClient; +import org.apache.syncope.client.console.rest.RelationshipTypeRestClient; +import org.apache.syncope.client.console.rest.ReportRestClient; +import org.apache.syncope.client.console.rest.RoleRestClient; +import org.apache.syncope.client.console.rest.SchemaRestClient; +import org.apache.syncope.client.console.rest.SecurityQuestionRestClient; +import org.apache.syncope.client.console.rest.SyncopeRestClient; +import org.apache.syncope.client.console.rest.TaskRestClient; +import org.apache.syncope.client.console.rest.UserRestClient; +import org.apache.syncope.client.console.rest.UserSelfRestClient; +import org.apache.syncope.client.ui.commons.MIMETypesLoader; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +public class IdRepoConsoleContext { + + @ConditionalOnMissingBean + @Bean + public ClassPathScanImplementationLookup classPathScanImplementationLookup( + final ConsoleProperties props, + final List classPathScanImplementationContributors) { + + ClassPathScanImplementationLookup lookup = + new ClassPathScanImplementationLookup(classPathScanImplementationContributors, props); + lookup.load(); + return lookup; + } + + @ConditionalOnMissingBean + @Bean + public MIMETypesLoader mimeTypesLoader() { + MIMETypesLoader mimeTypesLoader = new MIMETypesLoader(); + mimeTypesLoader.load(); + return mimeTypesLoader; + } + + @ConditionalOnMissingBean + @Bean + public PreviewUtils previewUtils(final ClassPathScanImplementationLookup lookup) { + return new PreviewUtils(lookup); + } + + @ConditionalOnMissingBean + @Bean + public ExternalResourceProvider resourceProvider() { + return new IdRepoExternalResourceProvider(); + } + + @ConditionalOnMissingBean + @Bean + public AnyDirectoryPanelAdditionalActionsProvider anyDirectoryPanelAdditionalActionsProvider() { + return new IdRepoAnyDirectoryPanelAdditionalActionsProvider(); + } + + @ConditionalOnMissingBean + @Bean + public AnyDirectoryPanelAdditionalActionLinksProvider anyDirectoryPanelAdditionalActionLinksProvider() { + return new IdRepoAnyDirectoryPanelAdditionalActionLinksProvider(); + } + + @ConditionalOnMissingBean + @Bean + public AnyWizardBuilderAdditionalSteps anyWizardBuilderAdditionalSteps() { + return new IdRepoAnyWizardBuilderAdditionalSteps(); + } + + @ConditionalOnMissingBean + @Bean + public StatusProvider statusProvider() { + return new IdRepoStatusProvider(); + } + + @ConditionalOnMissingBean + @Bean + public VirSchemaDetailsPanelProvider virSchemaDetailsPanelProvider() { + return new IdRepoVirSchemaDetailsPanelProvider(); + } + + @ConditionalOnMissingBean + @Bean + public ImplementationInfoProvider implementationInfoProvider( + final ClassPathScanImplementationLookup lookup, + final ImplementationRestClient implementationRestClient) { + + return new IdRepoImplementationInfoProvider(lookup, implementationRestClient); + } + + @ConditionalOnMissingBean + @Bean + public RealmPolicyProvider realmPolicyProvider(final PolicyRestClient policyRestClient) { + return new IdRepoRealmPolicyProvider(policyRestClient); + } + + @Bean + public PolicyTabProvider idRepoPolicyTabProvider(final PolicyRestClient policyRestClient) { + return new IdRepoPolicyTabProvider(policyRestClient); + } + + @ConditionalOnMissingBean + @Bean + public AccessPolicyConfProvider accessPolicyConfProvider() { + return new IdRepoAccessPolicyConfProvider(); + } + + @ConditionalOnMissingBean + @Bean + public AccessTokenRestClient accessTokenRestClient() { + return new AccessTokenRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public AnyObjectRestClient anyObjectRestClient() { + return new AnyObjectRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public AnyTypeClassRestClient anyTypeClassRestClient() { + return new AnyTypeClassRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public AnyTypeRestClient anyTypeRestClient() { + return new AnyTypeRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public ApplicationRestClient applicationRestClient() { + return new ApplicationRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public AuditRestClient auditRestClient() { + return new AuditRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public CommandRestClient commandRestClient() { + return new CommandRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public DelegationRestClient delegationRestClient() { + return new DelegationRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public DynRealmRestClient dynRealmRestClient() { + return new DynRealmRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public FIQLQueryRestClient fiqlQueryRestClient() { + return new FIQLQueryRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public GroupRestClient groupRestClient() { + return new GroupRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public ImplementationRestClient implementationRestClient() { + return new ImplementationRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public LoggerConf loggerConf() { + return new LoggerConf(); + } + + @ConditionalOnMissingBean + @Bean + public NotificationRestClient notificationRestClient() { + return new NotificationRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public PolicyRestClient policyRestClient() { + return new PolicyRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public RealmRestClient realmRestClient() { + return new RealmRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public RelationshipTypeRestClient relationshipTypeRestClient() { + return new RelationshipTypeRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public ReportRestClient reportRestClient() { + return new ReportRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public RoleRestClient roleRestClient() { + return new RoleRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public SchemaRestClient schemaRestClient() { + return new SchemaRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public SecurityQuestionRestClient securityQuestionRestClient() { + return new SecurityQuestionRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public SyncopeRestClient syncopeRestClient() { + return new SyncopeRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public TaskRestClient taskRestClient() { + return new TaskRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public UserRestClient userRestClient() { + return new UserRestClient(); + } + + @ConditionalOnMissingBean + @Bean + public UserSelfRestClient userSelfRestClient() { + return new UserSelfRestClient(); + } +} diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SecurityConfig.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SecurityConfig.java index f33629d7320..f54a0494e67 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SecurityConfig.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SecurityConfig.java @@ -20,32 +20,40 @@ import org.apache.syncope.common.lib.types.IdRepoEntitlement; import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.util.matcher.NegatedRequestMatcher; @EnableWebSecurity @Configuration(proxyBeanMethods = false) public class SecurityConfig { + @ConditionalOnMissingBean @Bean - public SecurityFilterChain filterChain(final HttpSecurity http) throws Exception { - http.csrf().disable(). - authorizeRequests(). - requestMatchers(EndpointRequest.toAnyEndpoint()). - authenticated(). - and(). - httpBasic(); + public SecurityFilterChain actuatorFilterChain(final HttpSecurity http) throws Exception { + EndpointRequest.EndpointRequestMatcher actuatorEndpoints = EndpointRequest.toAnyEndpoint(); + http.authorizeHttpRequests(customizer -> customizer. + requestMatchers(new NegatedRequestMatcher(actuatorEndpoints)).permitAll(). + requestMatchers(actuatorEndpoints).authenticated()); + + http.httpBasic(Customizer.withDefaults()); + http.csrf(AbstractHttpConfigurer::disable); + return http.build(); } + @ConditionalOnMissingBean @Bean - public InMemoryUserDetailsManager userDetailsService(final ConsoleProperties props) { + public InMemoryUserDetailsManager actuatorUserDetailsService(final ConsoleProperties props) { UserDetails user = User.withUsername(props.getAnonymousUser()). password("{noop}" + props.getAnonymousKey()). roles(IdRepoEntitlement.ANONYMOUS). diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleApplication.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleApplication.java index d3ee8b5cf0b..ff65011667b 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleApplication.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleApplication.java @@ -19,34 +19,34 @@ package org.apache.syncope.client.console; import com.giffing.wicket.spring.boot.starter.web.config.WicketWebInitializerAutoConfig.WebSocketWicketWebInitializerAutoConfiguration; +import java.util.List; import java.util.Map; -import org.apache.syncope.client.console.actuate.SyncopeConsoleInfoContributor; +import org.apache.syncope.client.console.commons.AccessPolicyConfProvider; import org.apache.syncope.client.console.commons.AnyDirectoryPanelAdditionalActionLinksProvider; import org.apache.syncope.client.console.commons.AnyDirectoryPanelAdditionalActionsProvider; import org.apache.syncope.client.console.commons.AnyWizardBuilderAdditionalSteps; import org.apache.syncope.client.console.commons.ExternalResourceProvider; import org.apache.syncope.client.console.commons.ImplementationInfoProvider; +import org.apache.syncope.client.console.commons.PolicyTabProvider; import org.apache.syncope.client.console.commons.StatusProvider; import org.apache.syncope.client.console.commons.VirSchemaDetailsPanelProvider; import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup; +import org.apache.syncope.client.console.wizards.any.UserFormFinalizer; import org.apache.syncope.client.ui.commons.actuate.SyncopeCoreHealthIndicator; import org.apache.syncope.common.keymaster.client.api.ServiceOps; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStart; import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStop; +import org.apache.wicket.request.resource.IResource; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; -import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; -import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; -@SpringBootApplication(exclude = { - ErrorMvcAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class }, proxyBeanMethods = false) +@SpringBootApplication(proxyBeanMethods = false) @EnableConfigurationProperties(ConsoleProperties.class) public class SyncopeConsoleApplication extends SpringBootServletInitializer { @@ -77,7 +77,10 @@ public SyncopeWebApplication syncopeWebApplication( final StatusProvider statusProvider, final VirSchemaDetailsPanelProvider virSchemaDetailsPanelProvider, final ImplementationInfoProvider implementationInfoProvider, - final ApplicationContext ctx) { + final AccessPolicyConfProvider accessPolicyConfProvider, + final List policyTabProviders, + final List userFormFinalizers, + final List resources) { return new SyncopeWebApplication( props, @@ -88,7 +91,11 @@ public SyncopeWebApplication syncopeWebApplication( anyDirectoryPanelAdditionalActionLinksProvider, anyWizardBuilderAdditionalSteps, statusProvider, virSchemaDetailsPanelProvider, - implementationInfoProvider, ctx); + implementationInfoProvider, + accessPolicyConfProvider, + policyTabProviders, + userFormFinalizers, + resources); } @ConditionalOnMissingBean @@ -103,17 +110,15 @@ public SyncopeCoreHealthIndicator syncopeCoreHealthIndicator( props.isUseGZIPCompression()); } - @ConditionalOnMissingBean - @Bean - public SyncopeConsoleInfoContributor syncopeConsoleInfoContributor() { - return new SyncopeConsoleInfoContributor(); - } - + @ConditionalOnProperty( + prefix = "keymaster", name = "enableAutoRegistration", havingValue = "true", matchIfMissing = true) @Bean public KeymasterStart keymasterStart() { return new KeymasterStart(NetworkService.Type.CONSOLE); } + @ConditionalOnProperty( + prefix = "keymaster", name = "enableAutoRegistration", havingValue = "true", matchIfMissing = true) @Bean public KeymasterStop keymasterStop() { return new KeymasterStop(NetworkService.Type.CONSOLE); diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java index e0f1c3ecc3a..4e39ad4f1f8 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java @@ -43,6 +43,7 @@ import org.apache.commons.lang3.tuple.Triple; import org.apache.cxf.jaxrs.client.WebClient; import org.apache.syncope.client.console.commons.RealmsUtils; +import org.apache.syncope.client.lib.SyncopeAnonymousClient; import org.apache.syncope.client.lib.SyncopeClient; import org.apache.syncope.client.lib.SyncopeClientFactoryBean; import org.apache.syncope.client.lib.batch.BatchRequest; @@ -63,6 +64,7 @@ import org.slf4j.LoggerFactory; import org.springframework.core.task.TaskRejectedException; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; +import org.springframework.util.CollectionUtils; public class SyncopeConsoleSession extends AuthenticatedWebSession implements BaseSession { @@ -93,15 +95,11 @@ public String fallback() { protected static final Logger LOG = LoggerFactory.getLogger(SyncopeConsoleSession.class); - protected final SyncopeClientFactoryBean clientFactory; - - protected final SyncopeClient anonymousClient; - - protected final Pair gitAndBuildInfo; - - protected final PlatformInfo platformInfo; + public static SyncopeConsoleSession get() { + return (SyncopeConsoleSession) Session.get(); + } - protected final SystemInfo systemInfo; + protected final SyncopeClientFactoryBean clientFactory; protected final Map, Object> services = Collections.synchronizedMap(new HashMap<>()); @@ -111,6 +109,14 @@ public String fallback() { protected SyncopeClient client; + protected SyncopeAnonymousClient anonymousClient; + + protected Pair gitAndBuildInfo; + + protected PlatformInfo platformInfo; + + protected SystemInfo systemInfo; + protected UserTO selfTO; protected Map> auth; @@ -121,19 +127,10 @@ public String fallback() { protected Roles roles; - public static SyncopeConsoleSession get() { - return (SyncopeConsoleSession) Session.get(); - } - public SyncopeConsoleSession(final Request request) { super(request); clientFactory = SyncopeWebApplication.get().newClientFactory(); - anonymousClient = SyncopeWebApplication.get().newAnonymousClient(); - - gitAndBuildInfo = anonymousClient.gitAndBuildInfo(); - platformInfo = anonymousClient.platform(); - systemInfo = anonymousClient.system(); executor = SyncopeWebApplication.get().newThreadPoolTaskExecutor(); } @@ -165,7 +162,7 @@ public void onException(final Exception e) { message = getApplication().getResourceSettings().getLocalizer(). getString(message, null, null, null, null, message); - error(message); + error(message.replace("\n", "
")); } public MediaType getMediaType() { @@ -257,6 +254,11 @@ public boolean authenticate(final String jwt) { } public void cleanup() { + anonymousClient = null; + gitAndBuildInfo = null; + platformInfo = null; + systemInfo = null; + client = null; auth = null; delegations = null; @@ -286,8 +288,8 @@ public List getAuthRealms() { } public List getSearchableRealms() { - Set roots = auth.get(IdRepoEntitlement.REALM_LIST); - return roots.isEmpty() + Set roots = auth.get(IdRepoEntitlement.REALM_SEARCH); + return CollectionUtils.isEmpty(roots) ? List.of() : roots.stream().sorted().collect(Collectors.toList()); } @@ -367,6 +369,11 @@ public void setDelegatedBy(final String delegatedBy) { public void refreshAuth(final String username) { try { + anonymousClient = SyncopeWebApplication.get().newAnonymousClient(getDomain()); + gitAndBuildInfo = anonymousClient.gitAndBuildInfo(); + platformInfo = anonymousClient.platform(); + systemInfo = anonymousClient.system(); + Triple>, List, UserTO> self = client.self(); auth = self.getLeft(); delegations = self.getMiddle(); @@ -382,8 +389,9 @@ public void refreshAuth(final String username) { } @Override - public SyncopeClient getAnonymousClient() { - return anonymousClient; + public SyncopeAnonymousClient getAnonymousClient() { + return Optional.ofNullable(anonymousClient). + orElseGet(() -> SyncopeWebApplication.get().newAnonymousClient(getDomain())); } @Override diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java index 23dfe3178af..2a9f8011faf 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java @@ -23,15 +23,18 @@ import de.agilecoders.wicket.core.settings.BootstrapSettings; import de.agilecoders.wicket.core.settings.IBootstrapSettings; import de.agilecoders.wicket.core.settings.SingleThemeProvider; -import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; +import org.apache.syncope.client.console.annotations.UserFormFinalize; +import org.apache.syncope.client.console.commons.AccessPolicyConfProvider; import org.apache.syncope.client.console.commons.AnyDirectoryPanelAdditionalActionLinksProvider; import org.apache.syncope.client.console.commons.AnyDirectoryPanelAdditionalActionsProvider; import org.apache.syncope.client.console.commons.AnyWizardBuilderAdditionalSteps; import org.apache.syncope.client.console.commons.ExternalResourceProvider; import org.apache.syncope.client.console.commons.ImplementationInfoProvider; import org.apache.syncope.client.console.commons.PolicyTabProvider; +import org.apache.syncope.client.console.commons.RealmsUtils; import org.apache.syncope.client.console.commons.StatusProvider; import org.apache.syncope.client.console.commons.VirSchemaDetailsPanelProvider; import org.apache.syncope.client.console.init.ClassPathScanImplementationLookup; @@ -39,9 +42,9 @@ import org.apache.syncope.client.console.pages.Dashboard; import org.apache.syncope.client.console.pages.Login; import org.apache.syncope.client.console.pages.MustChangePassword; +import org.apache.syncope.client.console.rest.RealmRestClient; import org.apache.syncope.client.console.wizards.any.UserFormFinalizer; -import org.apache.syncope.client.lib.AnonymousAuthenticationHandler; -import org.apache.syncope.client.lib.SyncopeClient; +import org.apache.syncope.client.lib.SyncopeAnonymousClient; import org.apache.syncope.client.lib.SyncopeClientFactoryBean; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.SyncopeUIRequestCycleListener; @@ -50,6 +53,7 @@ import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; import org.apache.syncope.common.keymaster.client.api.ServiceOps; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; +import org.apache.syncope.common.rest.api.beans.RealmQuery; import org.apache.wicket.Page; import org.apache.wicket.authroles.authentication.AbstractAuthenticatedWebSession; import org.apache.wicket.authroles.authentication.AuthenticatedWebSession; @@ -64,14 +68,12 @@ import org.apache.wicket.request.cycle.RequestCycle; import org.apache.wicket.request.http.WebResponse; import org.apache.wicket.request.mapper.parameter.PageParameters; -import org.apache.wicket.request.resource.AbstractResource; import org.apache.wicket.request.resource.IResource; import org.apache.wicket.request.resource.ResourceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.context.ApplicationContext; +import org.springframework.aop.support.AopUtils; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -import org.springframework.util.ClassUtils; public class SyncopeWebApplication extends WicketBootSecuredWebApplication { @@ -101,7 +103,13 @@ public static SyncopeWebApplication get() { protected final ImplementationInfoProvider implementationInfoProvider; - protected final ApplicationContext ctx; + protected final AccessPolicyConfProvider accessPolicyConfProvider; + + protected final List policyTabProviders; + + protected final List userFormFinalizers; + + protected final List resources; public SyncopeWebApplication( final ConsoleProperties props, @@ -114,7 +122,10 @@ public SyncopeWebApplication( final StatusProvider statusProvider, final VirSchemaDetailsPanelProvider virSchemaDetailsPanelProvider, final ImplementationInfoProvider implementationInfoProvider, - final ApplicationContext ctx) { + final AccessPolicyConfProvider accessPolicyConfProvider, + final List policyTabProviders, + final List userFormFinalizers, + final List resources) { this.props = props; this.lookup = lookup; @@ -126,35 +137,14 @@ public SyncopeWebApplication( this.statusProvider = statusProvider; this.virSchemaDetailsPanelProvider = virSchemaDetailsPanelProvider; this.implementationInfoProvider = implementationInfoProvider; - this.ctx = ctx; + this.accessPolicyConfProvider = accessPolicyConfProvider; + this.policyTabProviders = policyTabProviders; + this.userFormFinalizers = userFormFinalizers; + this.resources = resources; } - @Override - protected void init() { - super.init(); - - // Application settings - IBootstrapSettings settings = new BootstrapSettings(); - - // set theme provider - settings.setThemeProvider(new SingleThemeProvider(new AdminLTE())); - - // install application settings - Bootstrap.install(this, settings); - - getResourceSettings().setUseMinifiedResources(true); - getResourceSettings().setUseDefaultOnMissingResource(true); - getResourceSettings().setThrowExceptionOnMissingResource(false); - - getSecuritySettings().setAuthorizationStrategy(new MetaDataRoleAuthorizationStrategy(this)); - - lookup.getIdRepoPageClasses(). - forEach(cls -> MetaDataRoleAuthorizationStrategy.authorize(cls, Constants.ROLE_AUTHENTICATED)); - - getMarkupSettings().setStripWicketTags(true); - getMarkupSettings().setCompressWhitespace(true); - - getRequestCycleListeners().add(new SyncopeUIRequestCycleListener() { + protected SyncopeUIRequestCycleListener buildSyncopeUIRequestCycleListener() { + return new SyncopeUIRequestCycleListener() { @Override protected boolean isSignedIn() { @@ -170,8 +160,10 @@ protected void invalidateSession() { protected IRequestablePage getErrorPage(final PageParameters errorParameters) { return new Login(errorParameters); } - }); + }; + } + protected void initSecurity() { if (props.isxForward()) { XForwardedRequestWrapperFactory.Config config = new XForwardedRequestWrapperFactory.Config(); config.setProtocolHeader(props.getxForwardProtocolHeader()); @@ -187,6 +179,8 @@ protected IRequestablePage getErrorPage(final PageParameters errorParameters) { getRequestCycleListeners().add(new WebSocketAwareResourceIsolationRequestCycleListener()); } + getCspSettings().blocking().unsafeInline(); + getRequestCycleListeners().add(new IRequestCycleListener() { @Override @@ -197,27 +191,56 @@ public void onEndRequest(final RequestCycle cycle) { } } }); - getCspSettings().blocking().unsafeInline(); + } + + @Override + protected void init() { + super.init(); + + // Application settings + IBootstrapSettings settings = new BootstrapSettings(); + + // set theme provider + settings.setThemeProvider(new SingleThemeProvider(new AdminLTE())); + + // install application settings + Bootstrap.install(this, settings); + + getResourceSettings().setUseMinifiedResources(true); + getResourceSettings().setUseDefaultOnMissingResource(true); + getResourceSettings().setThrowExceptionOnMissingResource(false); + + getSecuritySettings().setAuthorizationStrategy(new MetaDataRoleAuthorizationStrategy(this)); + + lookup.getIdRepoPageClasses(). + forEach(cls -> MetaDataRoleAuthorizationStrategy.authorize(cls, Constants.ROLE_AUTHENTICATED)); + + getMarkupSettings().setStripWicketTags(true); + getMarkupSettings().setCompressWhitespace(true); + + getRequestCycleListeners().add(buildSyncopeUIRequestCycleListener()); + + initSecurity(); mountPage("/login", getSignInPageClass()); - for (Class resource : lookup.getClasses(AbstractResource.class)) { - Resource annotation = resource.getAnnotation(Resource.class); - try { - AbstractResource instance = resource.getDeclaredConstructor().newInstance(); + for (IResource resource : resources) { + Class resourceClass = AopUtils.getTargetClass(resource); + Resource annotation = resourceClass.getAnnotation(Resource.class); + if (annotation == null) { + LOG.error("No @Resource annotation found, ignoring {}", resourceClass.getName()); + } else { + LOG.debug("Mounting {} under {}", resourceClass.getName(), annotation.path()); - LOG.debug("Mounting {} under {}", resource.getName(), annotation.path()); mountResource(annotation.path(), new ResourceReference(annotation.key()) { - protected static final long serialVersionUID = -128426276529456602L; + private static final long serialVersionUID = -128426276529456602L; @Override public IResource getResource() { - return instance; + return resource; } }); - } catch (Exception e) { - LOG.error("Could not instantiate {}", resource.getName(), e); } } @@ -263,9 +286,10 @@ public ThreadPoolTaskExecutor newThreadPoolTaskExecutor() { return executor; } - public SyncopeClient newAnonymousClient() { - return newClientFactory().create( - new AnonymousAuthenticationHandler(props.getAnonymousUser(), props.getAnonymousKey())); + public SyncopeAnonymousClient newAnonymousClient(final String domain) { + return newClientFactory(). + setDomain(domain). + createAnonymous(props.getAnonymousUser(), props.getAnonymousKey()); } public SyncopeClientFactoryBean newClientFactory() { @@ -290,10 +314,6 @@ public String getAnonymousKey() { return props.getAnonymousKey(); } - public String getReconciliationReportKey() { - return props.getReconciliationReportKey(); - } - public long getMaxWaitTimeInSeconds() { return props.getMaxWaitTimeOnApplyChanges(); } @@ -302,6 +322,17 @@ public int getMaxUploadFileSizeMB() { return props.getMaxUploadFileSizeMB(); } + public boolean fullRealmsTree(final RealmRestClient restClient) { + if (props.getRealmsFullTreeThreshold() <= 0) { + return false; + } + + RealmQuery query = RealmsUtils.buildBaseQuery(); + query.setPage(1); + query.setSize(0); + return restClient.search(query).getTotalCount() < props.getRealmsFullTreeThreshold(); + } + public ExternalResourceProvider getResourceProvider() { return resourceProvider; } @@ -331,22 +362,23 @@ public ImplementationInfoProvider getImplementationInfoProvider() { } public Collection getPolicyTabProviders() { - return ctx.getBeansOfType(PolicyTabProvider.class).values(); + return policyTabProviders; } public List getFormFinalizers(final AjaxWizard.Mode mode) { - List finalizers = new ArrayList<>(); - - lookup.getUserFormFinalizerClasses(mode).forEach(finalizer -> { - if (finalizer != null) { - try { - finalizers.add(ClassUtils.getConstructorIfAvailable(finalizer).newInstance()); - } catch (Exception e) { - LOG.error("Could not instantiate {}", finalizer, e); - } + return userFormFinalizers.stream().filter(uff -> { + Class clazz = AopUtils.getTargetClass(uff); + UserFormFinalize annotation = clazz.getAnnotation(UserFormFinalize.class); + if (annotation == null) { + LOG.error("No @UserFormFinalize annotation found, ignoring {}", clazz.getName()); + return false; } - }); - return finalizers; + return annotation.mode() == mode; + }).collect(Collectors.toList()); + } + + public AccessPolicyConfProvider getAccessPolicyConfProvider() { + return accessPolicyConfProvider; } } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDetails.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDetails.java index cf538151ace..e9c05898cf8 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDetails.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryDetails.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.StreamReadFeature; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.json.JsonMapper; @@ -66,34 +67,14 @@ public abstract class AuditHistoryDetails extends Panel private static final long serialVersionUID = -7400543686272100483L; - private static final Logger LOG = LoggerFactory.getLogger(AuditHistoryDetails.class); + protected static final Logger LOG = LoggerFactory.getLogger(AuditHistoryDetails.class); - private static final List EVENTS = List.of("create", "update", "matchingrule_update", - "unmatchingrule_assign", "unmatchingrule_provision"); + public static final List DEFAULT_EVENTS = List.of( + "create", "update", "matchingrule_update", "unmatchingrule_assign", "unmatchingrule_provision"); - private static final SortParam REST_SORT = new SortParam<>("event_date", false); + protected static final SortParam REST_SORT = new SortParam<>("event_date", false); - private EntityTO currentEntity; - - private AuditElements.EventCategoryType type; - - private String category; - - private Class reference; - - private List auditEntries = new ArrayList<>(); - - private AuditEntry latestAuditEntry; - - private AuditEntry after; - - private AjaxDropDownChoicePanel beforeVersionsPanel; - - private AjaxDropDownChoicePanel afterVersionsPanel; - - private final AjaxLink restore; - - private static class SortingNodeFactory extends JsonNodeFactory { + protected static class SortingNodeFactory extends JsonNodeFactory { private static final long serialVersionUID = 1870252010670L; @@ -103,7 +84,7 @@ public ObjectNode objectNode() { } } - private static class SortedSetJsonSerializer extends StdSerializer> { + protected static class SortedSetJsonSerializer extends StdSerializer> { private static final long serialVersionUID = 3849059774309L; @@ -148,30 +129,59 @@ public void serialize( } @SuppressWarnings("unchecked") - private static Class cast(final Class aClass) { + protected static Class cast(final Class aClass) { return (Class) aClass; } - private static final ObjectMapper MAPPER = JsonMapper.builder(). + protected static final ObjectMapper MAPPER = JsonMapper.builder(). nodeFactory(new SortingNodeFactory()).build(). registerModule(new SimpleModule().addSerializer(new SortedSetJsonSerializer(cast(Set.class)))). registerModule(new JavaTimeModule()); + protected EntityTO currentEntity; + + protected AuditElements.EventCategoryType type; + + protected String category; + + protected final List events; + + protected Class reference; + + protected final List auditEntries = new ArrayList<>(); + + protected AuditEntry latestAuditEntry; + + protected AuditEntry after; + + protected AjaxDropDownChoicePanel beforeVersionsPanel; + + protected AjaxDropDownChoicePanel afterVersionsPanel; + + protected final AjaxLink restore; + + protected final AuditRestClient restClient; + @SuppressWarnings("unchecked") public AuditHistoryDetails( final String id, final EntityTO currentEntity, final AuditElements.EventCategoryType type, final String category, - final String auditRestoreEntitlement) { + final List events, + final String auditRestoreEntitlement, + final AuditRestClient restClient) { super(id); - this.setOutputMarkupId(true); - this.reference = (Class) currentEntity.getClass(); this.currentEntity = currentEntity; this.type = type; this.category = category; + this.events = events; + this.reference = (Class) currentEntity.getClass(); + this.restClient = restClient; + + setOutputMarkupId(true); IChoiceRenderer choiceRenderer = new IChoiceRenderer<>() { @@ -212,8 +222,8 @@ protected void onEvent(final AjaxRequestTarget target) { AuditEntry afterEntry = afterVersionsPanel.getModelObject() == null ? after : buildAfterAuditEntry(beforeEntry); - AuditHistoryDetails.this.addOrReplace(new JsonDiffPanel(toJSON(beforeEntry, reference), - toJSON(afterEntry, reference))); + AuditHistoryDetails.this.addOrReplace( + new JsonDiffPanel(toJSON(beforeEntry, reference), toJSON(afterEntry, reference))); // change after audit entries in order to match only the ones newer than the current after one afterVersionsPanel.setChoices(auditEntries.stream(). filter(ae -> ae.getDate().isAfter(beforeEntry.getDate()) @@ -225,8 +235,7 @@ protected void onEvent(final AjaxRequestTarget target) { } }); afterVersionsPanel = - new AjaxDropDownChoicePanel<>("afterVersions", getString("afterVersions"), new Model<>(), - true); + new AjaxDropDownChoicePanel<>("afterVersions", getString("afterVersions"), new Model<>(), true); afterVersionsPanel.setChoiceRenderer(choiceRenderer); afterVersionsPanel.add(new IndicatorAjaxEventBehavior(Constants.ON_CHANGE) { @@ -278,20 +287,20 @@ public void onClick(final AjaxRequestTarget target) { protected void initDiff() { // audit fetch size is fixed, for the moment... - this.auditEntries.clear(); - this.auditEntries.addAll(new AuditRestClient().search( + auditEntries.clear(); + auditEntries.addAll(restClient.search( currentEntity.getKey(), 1, 50, type, category, - EVENTS, + events, AuditElements.Result.SUCCESS, REST_SORT)); // the default selected is the newest one, if any - this.latestAuditEntry = auditEntries.isEmpty() ? null : auditEntries.get(0); - this.after = latestAuditEntry == null ? null : buildAfterAuditEntry(latestAuditEntry); + latestAuditEntry = auditEntries.isEmpty() ? null : auditEntries.get(0); + after = latestAuditEntry == null ? null : buildAfterAuditEntry(latestAuditEntry); // add default diff panel addOrReplace(new JsonDiffPanel(toJSON(latestAuditEntry, reference), toJSON(after, reference))); @@ -306,7 +315,7 @@ protected void initDiff() { restore.setEnabled(!auditEntries.isEmpty()); } - private AuditEntry buildAfterAuditEntry(final AuditEntry input) { + protected AuditEntry buildAfterAuditEntry(final AuditEntry input) { AuditEntry output = new AuditEntry(); output.setWho(input.getWho()); output.setDate(input.getDate()); @@ -316,16 +325,23 @@ private AuditEntry buildAfterAuditEntry(final AuditEntry input) { return output; } - private Model toJSON(final AuditEntry auditEntry, final Class reference) { + protected Model toJSON(final AuditEntry auditEntry, final Class reference) { + if (auditEntry == null) { + return Model.of(); + } + try { - if (auditEntry == null) { - return Model.of(); + String content; + if (auditEntry.getBefore() == null) { + JsonNode output = MAPPER.readTree(auditEntry.getOutput()); + if (output.has("entity")) { + content = output.get("entity").toPrettyString(); + } else { + content = output.toPrettyString(); + } + } else { + content = auditEntry.getBefore(); } - String content = auditEntry.getBefore() == null - ? MAPPER.readTree(auditEntry.getOutput()).get("entity") == null - ? MAPPER.readTree(auditEntry.getOutput()).toPrettyString() - : MAPPER.readTree(auditEntry.getOutput()).get("entity").toPrettyString() - : auditEntry.getBefore(); T entity = MAPPER.reader(). with(StreamReadFeature.STRICT_DUPLICATE_DETECTION). @@ -339,7 +355,7 @@ private Model toJSON(final AuditEntry auditEntry, final Class referen return Model.of(MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(entity)); } catch (Exception e) { LOG.error("While (de)serializing entity {}", auditEntry, e); - throw new WicketRuntimeException(e); + return Model.of(); } } } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryModal.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryModal.java index 5f6c1813154..724df480138 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryModal.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/audit/AuditHistoryModal.java @@ -18,6 +18,7 @@ */ package org.apache.syncope.client.console.audit; +import org.apache.syncope.client.console.rest.AuditRestClient; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; import org.apache.syncope.client.ui.commons.panels.ModalPanel; import org.apache.syncope.common.lib.to.EntityTO; @@ -33,7 +34,8 @@ public AuditHistoryModal( final AuditElements.EventCategoryType type, final String category, final T entity, - final String auditRestoreEntitlement) { + final String auditRestoreEntitlement, + final AuditRestClient restClient) { super(BaseModal.CONTENT_ID); @@ -42,7 +44,9 @@ public AuditHistoryModal( entity, type, category, - auditRestoreEntitlement) { + AuditHistoryDetails.DEFAULT_EVENTS, + auditRestoreEntitlement, + restClient) { private static final long serialVersionUID = -5311898419151367494L; diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/batch/BatchContent.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/batch/BatchContent.java index 4ed8488a237..21c8a0bd803 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/batch/BatchContent.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/batch/BatchContent.java @@ -241,9 +241,7 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { items.forEach(item -> { UserTO user = (UserTO) item; - StatusR req = new StatusR.Builder(). - key(user.getKey()). - type(StatusRType.SUSPEND). + StatusR req = new StatusR.Builder(user.getKey(), StatusRType.SUSPEND). onSyncope(true). resources(user.getResources()). build(); @@ -256,9 +254,7 @@ public void onClick(final AjaxRequestTarget target, final Serializable ignore) { items.forEach(item -> { UserTO user = (UserTO) item; - StatusR req = new StatusR.Builder(). - key(user.getKey()). - type(StatusRType.REACTIVATE). + StatusR req = new StatusR.Builder(user.getKey(), StatusRType.REACTIVATE). onSyncope(true). resources(user.getResources()). build(); diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/BaseDataSet.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/BaseDataSet.java index f4cbba866db..842fe1d1747 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/BaseDataSet.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/BaseDataSet.java @@ -29,11 +29,9 @@ public abstract class BaseDataSet implements Serializable { private static final long serialVersionUID = 1581171902504828797L; - /** The fill color. */ - private String fillColor = "rgba(220,220,220,0.5)"; + private String backgroundColor = "rgba(220,220,220,0.5)"; - /** The stroke color. */ - private String strokeColor = "rgba(220,220,220,1)"; + private String borderColor = "rgba(220,220,220,1)"; /** The data. */ private final List data; @@ -47,43 +45,21 @@ public BaseDataSet(final List data) { this.data = data; } - /** - * Gets the fill color. - * - * @return the fill color - */ - public String getFillColor() { - return fillColor; + public String getBackgroundColor() { + return backgroundColor; } - /** - * Sets the fill color. - * - * @param fillColor the fill color - * @return the abstract base data set - */ - public BaseDataSet setFillColor(final String fillColor) { - this.fillColor = fillColor; + public BaseDataSet setBackgroundColor(final String backgroundColor) { + this.backgroundColor = backgroundColor; return this; } - /** - * Gets the stroke color. - * - * @return the stroke color - */ - public String getStrokeColor() { - return strokeColor; + public String getBorderColor() { + return borderColor; } - /** - * Sets the stroke color. - * - * @param strokeColor the stroke color - * @return the abstract base data set - */ - public BaseDataSet setStrokeColor(final String strokeColor) { - this.strokeColor = strokeColor; + public BaseDataSet setBorderColor(final String borderColor) { + this.borderColor = borderColor; return this; } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/ChartJSBehavior.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/ChartJSBehavior.java index 5ca88cbaae8..f2674bf9eef 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/ChartJSBehavior.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/ChartJSBehavior.java @@ -39,11 +39,9 @@ protected void respond(final AjaxRequestTarget target) { public void renderHead(final Component component, final IHeaderResponse response) { super.renderHead(component, response); - response.render(OnDomReadyHeaderItem.forScript( - "WicketCharts['" + component.getMarkupId() + "']=buildChart('" + component.getMarkupId() + "');")); - if (component.getParent() instanceof ChartJSPanel) { - response.render(OnDomReadyHeaderItem.forScript(((ChartJSPanel) component.getParent()).generateChart())); + response.render(OnDomReadyHeaderItem.forScript( + ((ChartJSPanel) component.getParent()).generateChart(component.getMarkupId()))); } } } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/ChartJSPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/ChartJSPanel.java index eba2768c08e..d7be3a41375 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/ChartJSPanel.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/ChartJSPanel.java @@ -62,7 +62,7 @@ public Chart getChart() { return model.getObject(); } - public String generateChart() { + public String generateChart(final String markupId) { String dataString = null; String optionString = null; try { @@ -75,7 +75,12 @@ public String generateChart() { LOG.error("Unexpected error during JSON serialization", e); } - return "var " + container.getMarkupId() + " = WicketCharts['" + container.getMarkupId() + "']." - + model.getObject().getClass().getSimpleName() + '(' + dataString + ", " + optionString + ");"; + return "WicketCharts['" + markupId + "'] = new Chart(" + + "getChartCtx('" + markupId + "')," + + "{" + + "type: '" + model.getObject().getClass().getSimpleName().toLowerCase() + "'," + + "data: " + dataString + "," + + "options:" + optionString + + "})"; } } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/ChartOptions.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/ChartOptions.java index e463209916c..19e702c542f 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/ChartOptions.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/ChartOptions.java @@ -28,63 +28,60 @@ public abstract class ChartOptions implements Serializable { private static final long serialVersionUID = 2401861279216541412L; - /** The animation. */ - private Boolean animation; + public static class Axis implements Serializable { - /** The animation steps. */ - private Integer animationSteps; + private static final long serialVersionUID = 1L; - /** The animation easing. */ - private String animationEasing; + private Boolean display; - /** The on animation complete. */ - private String onAnimationComplete; - - @JsonRawValue - private String customTooltips; + public Boolean getDisplay() { + return display; + } - private Boolean showScale; - - /** The scale override. */ - private Boolean scaleOverride; + public void setDisplay(final Boolean display) { + this.display = display; + } + } - // ** The next three are required if scaleOverride is true ** - /** The scale steps. */ - private Integer scaleSteps; + public static class Scales implements Serializable { - /** The scale step width. */ - private Integer scaleStepWidth; + private static final long serialVersionUID = 1L; - /** The scale start value. */ - private Integer scaleStartValue; + private Axis x; - /** The scale line color. */ - private String scaleLineColor; + private Axis y; - /** The scale line width. */ - private Integer scaleLineWidth; + public Axis getX() { + return x; + } - /** The scale show labels. */ - private Boolean scaleShowLabels; + public void setX(final Axis x) { + this.x = x; + } - /** The scale label. */ - private String scaleLabel; + public Axis getY() { + return y; + } - /** The scale font family. */ - private String scaleFontFamily; + public void setY(final Axis y) { + this.y = y; + } + } - /** The scale font size. */ - private Integer scaleFontSize; + /** The animation. */ + private Boolean animation; - /** The scale font style. */ - private String scaleFontStyle; + /** The animation steps. */ + private Integer animationSteps; - /** The scale font color. */ - private String scaleFontColor; + /** The animation easing. */ + private String animationEasing; - private Boolean scaleIntegersOnly; + /** The on animation complete. */ + private String onAnimationComplete; - private Boolean scaleBeginAtZero; + @JsonRawValue + private String customTooltips; private Boolean responsive; @@ -126,6 +123,8 @@ public abstract class ChartOptions implements Serializable { private String multiTooltipTemplate; + private Scales scales; + @JsonRawValue private String onAnimationProgress; @@ -209,249 +208,6 @@ public void setOnAnimationComplete(final String onAnimationComplete) { this.onAnimationComplete = onAnimationComplete; } - /** - * Gets the scale override. - * - * @return the scale override - */ - public Boolean getScaleOverride() { - return scaleOverride; - } - - /** - * Sets the scale override. - * - * @param scaleOverride decides if you want to override with a hard coded scale - */ - public void setScaleOverride(final Boolean scaleOverride) { - this.scaleOverride = scaleOverride; - } - - /** - * Gets the scale steps. - * - * @return the scale steps - */ - public Integer getScaleSteps() { - return scaleSteps; - } - - /** - * Sets the scale steps. - * - * @param scaleSteps the number of steps in a hard coded scale (required if scaleOverride == true, default is null). - */ - public void setScaleSteps(final Integer scaleSteps) { - this.scaleSteps = scaleSteps; - } - - /** - * Gets the scale step width. - * - * @return the scale step width - */ - public Integer getScaleStepWidth() { - return scaleStepWidth; - } - - /** - * Sets the scale step width. - * - * @param scaleStepWidth the value jump in the hard coded scale (required if scaleOverride == true, default is - * null). - */ - public void setScaleStepWidth(final Integer scaleStepWidth) { - this.scaleStepWidth = scaleStepWidth; - } - - /** - * Gets the scale start value. - * - * @return the scale start value - */ - public Integer getScaleStartValue() { - return scaleStartValue; - } - - /** - * Sets the scale start value. - * - * @param scaleStartValue the scale starting value (required if scaleOverride == true, default is null). - */ - public void setScaleStartValue(final Integer scaleStartValue) { - this.scaleStartValue = scaleStartValue; - } - - /** - * Gets the scale line color. - * - * @return the scale line color - */ - public String getScaleLineColor() { - return scaleLineColor; - } - - /** - * Sets the scale line color. - * - * @param scaleLineColor - * color of the scale line - */ - public void setScaleLineColor(final String scaleLineColor) { - this.scaleLineColor = scaleLineColor; - } - - /** - * Gets the scale line width. - * - * @return the scale line width - */ - public Integer getScaleLineWidth() { - return scaleLineWidth; - } - - /** - * Sets the scale line width. - * - * @param scaleLineWidth the pixel width of the scale line - */ - public void setScaleLineWidth(final Integer scaleLineWidth) { - this.scaleLineWidth = scaleLineWidth; - } - - /** - * Gets the scale show labels. - * - * @return the scale show labels - */ - public Boolean getScaleShowLabels() { - return scaleShowLabels; - } - - /** - * Sets the scale show labels. - * - * @param scaleShowLabels decides whether to show labels on the scale - */ - public void setScaleShowLabels(final Boolean scaleShowLabels) { - this.scaleShowLabels = scaleShowLabels; - } - - /** - * Gets the scale label. - * - * @return the scale label - */ - public String getScaleLabel() { - return scaleLabel; - } - - /** - * Sets the scale label. - * - * @param scaleLabel an interpolated js string that can access value. - */ - public void setScaleLabel(final String scaleLabel) { - this.scaleLabel = scaleLabel; - } - - /** - * Gets the scale font family. - * - * @return the scale font family - */ - public String getScaleFontFamily() { - return scaleFontFamily; - } - - /** - * Sets the scale font family. - * - * @param scaleFontFamily scale label font declaration for the scale label (default is - * "'Arial'"). - */ - public void setScaleFontFamily(final String scaleFontFamily) { - this.scaleFontFamily = scaleFontFamily; - } - - /** - * Gets the scale font size. - * - * @return the scale font size - */ - public Integer getScaleFontSize() { - return scaleFontSize; - } - - /** - * Sets the scale font size. - * - * @param scaleFontSize the scale label font size in pixels - */ - public void setScaleFontSize(final Integer scaleFontSize) { - this.scaleFontSize = scaleFontSize; - } - - /** - * Gets the scale font style. - * - * @return the scale font style - */ - public String getScaleFontStyle() { - return scaleFontStyle; - } - - /** - * Sets the scale font style. - * - * @param scaleFontStyle the scale label font weight style (default is "normal"). - */ - public void setScaleFontStyle(final String scaleFontStyle) { - this.scaleFontStyle = scaleFontStyle; - } - - /** - * Gets the scale font color. - * - * @return the scale font color - */ - public String getScaleFontColor() { - return scaleFontColor; - } - - /** - * Sets the scale font color. - * - * @param scaleFontColor the scale label font color (default is "#666"). - */ - public void setScaleFontColor(final String scaleFontColor) { - this.scaleFontColor = scaleFontColor; - } - - public Boolean getShowScale() { - return showScale; - } - - public void setShowScale(final Boolean showScale) { - this.showScale = showScale; - } - - public Boolean getScaleIntegersOnly() { - return scaleIntegersOnly; - } - - public void setScaleIntegersOnly(final Boolean scaleIntegersOnly) { - this.scaleIntegersOnly = scaleIntegersOnly; - } - - public Boolean getScaleBeginAtZero() { - return scaleBeginAtZero; - } - - public void setScaleBeginAtZero(final Boolean scaleBeginAtZero) { - this.scaleBeginAtZero = scaleBeginAtZero; - } - public Boolean getResponsive() { return responsive; } @@ -637,4 +393,12 @@ public boolean isResponsive() { public void setResponsive(final boolean responsive) { this.responsive = responsive; } + + public Scales getScales() { + return scales; + } + + public void setScales(final Scales scales) { + this.scales = scales; + } } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/Doughnut.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/Doughnut.java index 6121093cc08..f2c2fa207a2 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/Doughnut.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/Doughnut.java @@ -19,15 +19,13 @@ package org.apache.syncope.client.console.chartjs; import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; /** * Provides a simple implementation of chart.js doughnut chart. * * @see
chart.js docs */ -public class Doughnut extends SimpleChart implements Serializable { +public class Doughnut extends SimpleChart implements Serializable { private static final long serialVersionUID = -6898362145345731457L; @@ -38,12 +36,4 @@ public DoughnutChartOptions getOptions() { } return options; } - - @Override - public List getData() { - if (data == null) { - data = new ArrayList<>(); - } - return data; - } } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/DoughnutAndPieChartData.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/DoughnutAndPieChartData.java new file mode 100644 index 00000000000..c61fa27825d --- /dev/null +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/DoughnutAndPieChartData.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.console.chartjs; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class DoughnutAndPieChartData implements Serializable { + + private static final long serialVersionUID = 1L; + + public static class DataSet implements Serializable { + + private static final long serialVersionUID = 1L; + + private final List data = new ArrayList<>(); + + private final List backgroundColor = new ArrayList<>(); + + public List getData() { + return data; + } + + public List getBackgroundColor() { + return backgroundColor; + } + } + + private final List datasets = new ArrayList<>(); + + private final List labels = new ArrayList<>(); + + public List getDatasets() { + return datasets; + } + + public List getLabels() { + return labels; + } +} diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/DoughnutChartData.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/DoughnutChartData.java deleted file mode 100644 index 5403785ae82..00000000000 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/DoughnutChartData.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.syncope.client.console.chartjs; - -/** - * Provides chart data used by doughnut charts. - */ -public class DoughnutChartData extends SimpleColorValueChartData { - - private static final long serialVersionUID = -5122104387810776812L; - - private String label; - - /** - * Instantiates a new doughnut chart data. - * - * @param value the value - * @param color the color - */ - public DoughnutChartData(final Integer value, final String color) { - super(value, color); - } - - public DoughnutChartData(final Number value, final String color, final String label) { - super(value, color); - this.label = label; - } - - public String getLabel() { - return label; - } - - public void setLabel(final String label) { - this.label = label; - } -} diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/DoughnutChartOptions.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/DoughnutChartOptions.java index b72dafbe711..b8facd6a4a8 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/DoughnutChartOptions.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/DoughnutChartOptions.java @@ -45,5 +45,4 @@ public Integer getPercentageInnerCutout() { public void setPercentageInnerCutout(final Integer percentageInnerCutout) { this.percentageInnerCutout = percentageInnerCutout; } - } diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/LineChartOptions.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/LineChartOptions.java index 1aa824696ac..51060356a6f 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/LineChartOptions.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/chartjs/LineChartOptions.java @@ -29,8 +29,6 @@ public class LineChartOptions extends ChartOptions { private Boolean scaleShowVerticalLines = true; - private Double bezierCurveTension = 0.4; - private Integer pointHitDetectionRadius = 20; private String legendTemplate = " + + + + + +