diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index ea7a82bcfd..341d1323ad 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -14,7 +14,7 @@ jobs: with: fetch-depth: 0 - name: Setup Node - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3 + uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7 # v3 with: node-version: lts/* - name: Install dependencies diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index e5be0d54fb..060bc18ac2 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -12,7 +12,7 @@ jobs: uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 - name: "set up JDK ${{ matrix.java }}" - uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3 + uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3 with: distribution: 'zulu' java-version: ${{ matrix.java }} diff --git a/.github/workflows/semantic-release.yml b/.github/workflows/semantic-release.yml index 0b4412634a..8fc593c880 100644 --- a/.github/workflows/semantic-release.yml +++ b/.github/workflows/semantic-release.yml @@ -14,13 +14,13 @@ jobs: - name: Checkout uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3 - name: Setup Node.js - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3 + uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7 # v3 with: node-version: "lts/*" - name: Install dependencies run: npm ci - name: "Set up JDK" - uses: actions/setup-java@cd89f46ac9d01407894225f350157564c9c7cee2 # v3 + uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3 with: distribution: 'zulu' java-version: 17 diff --git a/package-lock.json b/package-lock.json index e576068f46..ccf449cf11 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,9 @@ "name": "perun", "version": "0.0.0-development", "devDependencies": { - "@commitlint/cli": "17.7.2", - "@commitlint/config-conventional": "17.7.0", - "@commitlint/cz-commitlint": "17.7.2", + "@commitlint/cli": "17.8.1", + "@commitlint/config-conventional": "17.8.1", + "@commitlint/cz-commitlint": "17.8.1", "@semantic-release/changelog": "6.0.3", "@semantic-release/exec": "6.0.3", "@semantic-release/git": "10.0.1", @@ -192,16 +192,16 @@ } }, "node_modules/@commitlint/cli": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.7.2.tgz", - "integrity": "sha512-t3N7TZq7lOeqTOyEgfGcaltHqEJf7YDlPg75MldeVPPyz14jZq/+mbGF9tueDLFX8R6RwdymrN6D+U5XwZ8Iwg==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-17.8.1.tgz", + "integrity": "sha512-ay+WbzQesE0Rv4EQKfNbSMiJJ12KdKTDzIt0tcK4k11FdsWmtwP0Kp1NWMOUswfIWo6Eb7p7Ln721Nx9FLNBjg==", "dev": true, "dependencies": { - "@commitlint/format": "^17.4.4", - "@commitlint/lint": "^17.7.0", - "@commitlint/load": "^17.7.2", - "@commitlint/read": "^17.5.1", - "@commitlint/types": "^17.4.4", + "@commitlint/format": "^17.8.1", + "@commitlint/lint": "^17.8.1", + "@commitlint/load": "^17.8.1", + "@commitlint/read": "^17.8.1", + "@commitlint/types": "^17.8.1", "execa": "^5.0.0", "lodash.isfunction": "^3.0.9", "resolve-from": "5.0.0", @@ -216,9 +216,9 @@ } }, "node_modules/@commitlint/config-conventional": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-17.7.0.tgz", - "integrity": "sha512-iicqh2o6et+9kWaqsQiEYZzfLbtoWv9uZl8kbI8EGfnc0HeGafQBF7AJ0ylN9D/2kj6txltsdyQs8+2fTMwWEw==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-17.8.1.tgz", + "integrity": "sha512-NxCOHx1kgneig3VLauWJcDWS40DVjg7nKOpBEEK9E5fjJpQqLCilcnKkIIjdBH98kEO1q3NpE5NSrZ2kl/QGJg==", "dev": true, "dependencies": { "conventional-changelog-conventionalcommits": "^6.1.0" @@ -228,12 +228,12 @@ } }, "node_modules/@commitlint/config-validator": { - "version": "17.6.7", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-17.6.7.tgz", - "integrity": "sha512-vJSncmnzwMvpr3lIcm0I8YVVDJTzyjy7NZAeXbTXy+MPUdAr9pKyyg7Tx/ebOQ9kqzE6O9WT6jg2164br5UdsQ==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-17.8.1.tgz", + "integrity": "sha512-UUgUC+sNiiMwkyiuIFR7JG2cfd9t/7MV8VB4TZ+q02ZFkHoduUS4tJGsCBWvBOGD9Btev6IecPMvlWUfJorkEA==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", + "@commitlint/types": "^17.8.1", "ajv": "^8.11.0" }, "engines": { @@ -241,14 +241,14 @@ } }, "node_modules/@commitlint/cz-commitlint": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/@commitlint/cz-commitlint/-/cz-commitlint-17.7.2.tgz", - "integrity": "sha512-E5j4D8t4o4pGOoE56JOtkTCEXhZJguv8prX+XmdxTF4gYphSjDEb+EQ1xWfv98hxOdgvFJNQfLA/JbPjkfh7DA==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/cz-commitlint/-/cz-commitlint-17.8.1.tgz", + "integrity": "sha512-7/13k+NxxqwYnrrb52g70qrXs5NQS7r/qV9GAwcoE/8LLWoziV38nsgELajFu6sNgai9X8d8IX5UyiB1M1zGjg==", "dev": true, "dependencies": { - "@commitlint/ensure": "^17.6.7", - "@commitlint/load": "^17.7.2", - "@commitlint/types": "^17.4.4", + "@commitlint/ensure": "^17.8.1", + "@commitlint/load": "^17.8.1", + "@commitlint/types": "^17.8.1", "chalk": "^4.1.0", "lodash.isplainobject": "^4.0.6", "word-wrap": "^1.2.5" @@ -262,12 +262,12 @@ } }, "node_modules/@commitlint/ensure": { - "version": "17.6.7", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-17.6.7.tgz", - "integrity": "sha512-mfDJOd1/O/eIb/h4qwXzUxkmskXDL9vNPnZ4AKYKiZALz4vHzwMxBSYtyL2mUIDeU9DRSpEUins8SeKtFkYHSw==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-17.8.1.tgz", + "integrity": "sha512-xjafwKxid8s1K23NFpL8JNo6JnY/ysetKo8kegVM7c8vs+kWLP8VrQq+NbhgVlmCojhEDbzQKp4eRXSjVOGsow==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", + "@commitlint/types": "^17.8.1", "lodash.camelcase": "^4.3.0", "lodash.kebabcase": "^4.1.1", "lodash.snakecase": "^4.1.1", @@ -279,21 +279,21 @@ } }, "node_modules/@commitlint/execute-rule": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-17.4.0.tgz", - "integrity": "sha512-LIgYXuCSO5Gvtc0t9bebAMSwd68ewzmqLypqI2Kke1rqOqqDbMpYcYfoPfFlv9eyLIh4jocHWwCK5FS7z9icUA==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-17.8.1.tgz", + "integrity": "sha512-JHVupQeSdNI6xzA9SqMF+p/JjrHTcrJdI02PwesQIDCIGUrv04hicJgCcws5nzaoZbROapPs0s6zeVHoxpMwFQ==", "dev": true, "engines": { "node": ">=v14" } }, "node_modules/@commitlint/format": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-17.4.4.tgz", - "integrity": "sha512-+IS7vpC4Gd/x+uyQPTAt3hXs5NxnkqAZ3aqrHd5Bx/R9skyCAWusNlNbw3InDbAK6j166D9asQM8fnmYIa+CXQ==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-17.8.1.tgz", + "integrity": "sha512-f3oMTyZ84M9ht7fb93wbCKmWxO5/kKSbwuYvS867duVomoOsgrgljkGGIztmT/srZnaiGbaK8+Wf8Ik2tSr5eg==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", + "@commitlint/types": "^17.8.1", "chalk": "^4.1.0" }, "engines": { @@ -301,12 +301,12 @@ } }, "node_modules/@commitlint/is-ignored": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.7.0.tgz", - "integrity": "sha512-043rA7m45tyEfW7Zv2vZHF++176MLHH9h70fnPoYlB1slKBeKl8BwNIlnPg4xBdRBVNPaCqvXxWswx2GR4c9Hw==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-17.8.1.tgz", + "integrity": "sha512-UshMi4Ltb4ZlNn4F7WtSEugFDZmctzFpmbqvpyxD3la510J+PLcnyhf9chs7EryaRFJMdAKwsEKfNK0jL/QM4g==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", + "@commitlint/types": "^17.8.1", "semver": "7.5.4" }, "engines": { @@ -314,30 +314,30 @@ } }, "node_modules/@commitlint/lint": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-17.7.0.tgz", - "integrity": "sha512-TCQihm7/uszA5z1Ux1vw+Nf3yHTgicus/+9HiUQk+kRSQawByxZNESeQoX9ujfVd3r4Sa+3fn0JQAguG4xvvbA==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-17.8.1.tgz", + "integrity": "sha512-aQUlwIR1/VMv2D4GXSk7PfL5hIaFSfy6hSHV94O8Y27T5q+DlDEgd/cZ4KmVI+MWKzFfCTiTuWqjfRSfdRllCA==", "dev": true, "dependencies": { - "@commitlint/is-ignored": "^17.7.0", - "@commitlint/parse": "^17.7.0", - "@commitlint/rules": "^17.7.0", - "@commitlint/types": "^17.4.4" + "@commitlint/is-ignored": "^17.8.1", + "@commitlint/parse": "^17.8.1", + "@commitlint/rules": "^17.8.1", + "@commitlint/types": "^17.8.1" }, "engines": { "node": ">=v14" } }, "node_modules/@commitlint/load": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-17.7.2.tgz", - "integrity": "sha512-XA7WTnsjHZ4YH6ZYsrnxgLdXzriwMMq+utZUET6spbOEEIPBCDLdOQXS26P+v3TTO4hUHOEhzUquaBv3jbBixw==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-17.8.1.tgz", + "integrity": "sha512-iF4CL7KDFstP1kpVUkT8K2Wl17h2yx9VaR1ztTc8vzByWWcbO/WaKwxsnCOqow9tVAlzPfo1ywk9m2oJ9ucMqA==", "dev": true, "dependencies": { - "@commitlint/config-validator": "^17.6.7", - "@commitlint/execute-rule": "^17.4.0", - "@commitlint/resolve-extends": "^17.6.7", - "@commitlint/types": "^17.4.4", + "@commitlint/config-validator": "^17.8.1", + "@commitlint/execute-rule": "^17.8.1", + "@commitlint/resolve-extends": "^17.8.1", + "@commitlint/types": "^17.8.1", "@types/node": "20.5.1", "chalk": "^4.1.0", "cosmiconfig": "^8.0.0", @@ -347,28 +347,28 @@ "lodash.uniq": "^4.5.0", "resolve-from": "^5.0.0", "ts-node": "^10.8.1", - "typescript": "^4.6.4 || ^5.0.0" + "typescript": "^4.6.4 || ^5.2.2" }, "engines": { "node": ">=v14" } }, "node_modules/@commitlint/message": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-17.4.2.tgz", - "integrity": "sha512-3XMNbzB+3bhKA1hSAWPCQA3lNxR4zaeQAQcHj0Hx5sVdO6ryXtgUBGGv+1ZCLMgAPRixuc6en+iNAzZ4NzAa8Q==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-17.8.1.tgz", + "integrity": "sha512-6bYL1GUQsD6bLhTH3QQty8pVFoETfFQlMn2Nzmz3AOLqRVfNNtXBaSY0dhZ0dM6A2MEq4+2d7L/2LP8TjqGRkA==", "dev": true, "engines": { "node": ">=v14" } }, "node_modules/@commitlint/parse": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-17.7.0.tgz", - "integrity": "sha512-dIvFNUMCUHqq5Abv80mIEjLVfw8QNuA4DS7OWip4pcK/3h5wggmjVnlwGCDvDChkw2TjK1K6O+tAEV78oxjxag==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-17.8.1.tgz", + "integrity": "sha512-/wLUickTo0rNpQgWwLPavTm7WbwkZoBy3X8PpkUmlSmQJyWQTj0m6bDjiykMaDt41qcUbfeFfaCvXfiR4EGnfw==", "dev": true, "dependencies": { - "@commitlint/types": "^17.4.4", + "@commitlint/types": "^17.8.1", "conventional-changelog-angular": "^6.0.0", "conventional-commits-parser": "^4.0.0" }, @@ -377,13 +377,13 @@ } }, "node_modules/@commitlint/read": { - "version": "17.5.1", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-17.5.1.tgz", - "integrity": "sha512-7IhfvEvB//p9aYW09YVclHbdf1u7g7QhxeYW9ZHSO8Huzp8Rz7m05aCO1mFG7G8M+7yfFnXB5xOmG18brqQIBg==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-17.8.1.tgz", + "integrity": "sha512-Fd55Oaz9irzBESPCdMd8vWWgxsW3OWR99wOntBDHgf9h7Y6OOHjWEdS9Xzen1GFndqgyoaFplQS5y7KZe0kO2w==", "dev": true, "dependencies": { - "@commitlint/top-level": "^17.4.0", - "@commitlint/types": "^17.4.4", + "@commitlint/top-level": "^17.8.1", + "@commitlint/types": "^17.8.1", "fs-extra": "^11.0.0", "git-raw-commits": "^2.0.11", "minimist": "^1.2.6" @@ -393,13 +393,13 @@ } }, "node_modules/@commitlint/resolve-extends": { - "version": "17.6.7", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-17.6.7.tgz", - "integrity": "sha512-PfeoAwLHtbOaC9bGn/FADN156CqkFz6ZKiVDMjuC2N5N0740Ke56rKU7Wxdwya8R8xzLK9vZzHgNbuGhaOVKIg==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-17.8.1.tgz", + "integrity": "sha512-W/ryRoQ0TSVXqJrx5SGkaYuAaE/BUontL1j1HsKckvM6e5ZaG0M9126zcwL6peKSuIetJi7E87PRQF8O86EW0Q==", "dev": true, "dependencies": { - "@commitlint/config-validator": "^17.6.7", - "@commitlint/types": "^17.4.4", + "@commitlint/config-validator": "^17.8.1", + "@commitlint/types": "^17.8.1", "import-fresh": "^3.0.0", "lodash.mergewith": "^4.6.2", "resolve-from": "^5.0.0", @@ -410,15 +410,15 @@ } }, "node_modules/@commitlint/rules": { - "version": "17.7.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-17.7.0.tgz", - "integrity": "sha512-J3qTh0+ilUE5folSaoK91ByOb8XeQjiGcdIdiB/8UT1/Rd1itKo0ju/eQVGyFzgTMYt8HrDJnGTmNWwcMR1rmA==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-17.8.1.tgz", + "integrity": "sha512-2b7OdVbN7MTAt9U0vKOYKCDsOvESVXxQmrvuVUZ0rGFMCrCPJWWP1GJ7f0lAypbDAhaGb8zqtdOr47192LBrIA==", "dev": true, "dependencies": { - "@commitlint/ensure": "^17.6.7", - "@commitlint/message": "^17.4.2", - "@commitlint/to-lines": "^17.4.0", - "@commitlint/types": "^17.4.4", + "@commitlint/ensure": "^17.8.1", + "@commitlint/message": "^17.8.1", + "@commitlint/to-lines": "^17.8.1", + "@commitlint/types": "^17.8.1", "execa": "^5.0.0" }, "engines": { @@ -426,18 +426,18 @@ } }, "node_modules/@commitlint/to-lines": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-17.4.0.tgz", - "integrity": "sha512-LcIy/6ZZolsfwDUWfN1mJ+co09soSuNASfKEU5sCmgFCvX5iHwRYLiIuoqXzOVDYOy7E7IcHilr/KS0e5T+0Hg==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-17.8.1.tgz", + "integrity": "sha512-LE0jb8CuR/mj6xJyrIk8VLz03OEzXFgLdivBytoooKO5xLt5yalc8Ma5guTWobw998sbR3ogDd+2jed03CFmJA==", "dev": true, "engines": { "node": ">=v14" } }, "node_modules/@commitlint/top-level": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-17.4.0.tgz", - "integrity": "sha512-/1loE/g+dTTQgHnjoCy0AexKAEFyHsR2zRB4NWrZ6lZSMIxAhBJnmCqwao7b4H8888PsfoTBCLBYIw8vGnej8g==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-17.8.1.tgz", + "integrity": "sha512-l6+Z6rrNf5p333SHfEte6r+WkOxGlWK4bLuZKbtf/2TXRN+qhrvn1XE63VhD8Oe9oIHQ7F7W1nG2k/TJFhx2yA==", "dev": true, "dependencies": { "find-up": "^5.0.0" @@ -447,9 +447,9 @@ } }, "node_modules/@commitlint/types": { - "version": "17.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-17.4.4.tgz", - "integrity": "sha512-amRN8tRLYOsxRr6mTnGGGvB5EmW/4DDjLMgiwK3CCVEmN6Sr/6xePGEpWaspKkckILuUORCwe6VfDBw6uj4axQ==", + "version": "17.8.1", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-17.8.1.tgz", + "integrity": "sha512-PXDQXkAmiMEG162Bqdh9ChML/GJZo6vU+7F03ALKDK8zYc6SuAr47LjG7hGYRqUOz+WK0dU7bQ0xzuqFMdxzeQ==", "dev": true, "dependencies": { "chalk": "^4.1.0" diff --git a/package.json b/package.json index 3f1895efb2..a8f8091517 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,9 @@ "name": "perun", "version": "0.0.0-development", "devDependencies": { - "@commitlint/cli": "17.7.2", - "@commitlint/config-conventional": "17.7.0", - "@commitlint/cz-commitlint": "17.7.2", + "@commitlint/cli": "17.8.1", + "@commitlint/config-conventional": "17.8.1", + "@commitlint/cz-commitlint": "17.8.1", "@semantic-release/changelog": "6.0.3", "@semantic-release/exec": "6.0.3", "@semantic-release/git": "10.0.1", diff --git a/perun-base/src/main/java/cz/metacentrum/perun/core/api/CoreConfig.java b/perun-base/src/main/java/cz/metacentrum/perun/core/api/CoreConfig.java index eeebb5c51f..8d34c90f32 100644 --- a/perun-base/src/main/java/cz/metacentrum/perun/core/api/CoreConfig.java +++ b/perun-base/src/main/java/cz/metacentrum/perun/core/api/CoreConfig.java @@ -59,6 +59,7 @@ public void initBeansUtils() { private String instanceId; private String instanceName; private String mailchangeBackupFrom; + private String mailchangeReplyTo; private String mailchangeSecretKey; private String nativeLanguage; private String passwordManagerProgram; @@ -325,6 +326,15 @@ public void setMailchangeBackupFrom(String mailchangeBackupFrom) { this.mailchangeBackupFrom = mailchangeBackupFrom; } + public String getMailchangeReplyTo() { + return mailchangeReplyTo; + } + + public void setMailchangeReplyTo(String mailchangeReplyTo) { + this.mailchangeReplyTo = mailchangeReplyTo; + } + + public String getMailchangeSecretKey() { return mailchangeSecretKey; } diff --git a/perun-base/src/main/java/cz/metacentrum/perun/core/api/GroupsPageQuery.java b/perun-base/src/main/java/cz/metacentrum/perun/core/api/GroupsPageQuery.java index 5b0e58e018..5aee48827e 100644 --- a/perun-base/src/main/java/cz/metacentrum/perun/core/api/GroupsPageQuery.java +++ b/perun-base/src/main/java/cz/metacentrum/perun/core/api/GroupsPageQuery.java @@ -1,5 +1,7 @@ package cz.metacentrum.perun.core.api; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; /** @@ -14,6 +16,8 @@ public class GroupsPageQuery { private GroupsOrderColumn sortColumn; private String searchString = ""; private Integer memberId; + private List roles = new ArrayList<>(); + private List types = new ArrayList<>(); public GroupsPageQuery() {} @@ -37,6 +41,31 @@ public GroupsPageQuery(int pageSize, int offset, SortingOrder order, GroupsOrder this.memberId = memberId; } + public GroupsPageQuery(int pageSize, int offset, SortingOrder order, GroupsOrderColumn sortColumn, String searchString, Integer memberId, List roles, List types) { + this(pageSize, offset, order, sortColumn, searchString, memberId); + this.roles = roles; + this.types = types; + } + + public GroupsPageQuery(int pageSize, int offset, SortingOrder order, GroupsOrderColumn sortColumn, String searchString, List roles, List types) { + this(pageSize, offset, order, sortColumn, searchString); + this.roles = roles; + this.types = types; + } + + public GroupsPageQuery(int pageSize, int offset, SortingOrder order, GroupsOrderColumn sortColumn, List roles, List types) { + this(pageSize, offset, order, sortColumn); + this.roles = roles; + this.types = types; + } + + public GroupsPageQuery(int pageSize, int offset, SortingOrder order, GroupsOrderColumn sortColumn, Integer memberId, List roles, List types) { + this(pageSize, offset, order, sortColumn); + this.memberId = memberId; + this.roles = roles; + this.types = types; + } + public int getPageSize() { return pageSize; } @@ -83,6 +112,22 @@ public void setMemberId(Integer memberId) { this.memberId = memberId; } + public List getRoles() { + return roles; + } + + public void setRoles(List roles) { + this.roles = roles; + } + + public List getTypes() { + return types; + } + + public void setTypes(List types) { + this.types = types; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -95,6 +140,8 @@ public boolean equals(Object o) { if (getOrder() != that.getOrder()) return false; if (getSortColumn() != that.getSortColumn()) return false; if (!Objects.equals(getMemberId(), that.getMemberId())) return false; + if (getRoles() != that.getRoles()) return false; + if (getTypes() != that.getTypes()) return false; return getSearchString().equals(that.getSearchString()); } @@ -106,6 +153,8 @@ public int hashCode() { result = 31 * result + (getSortColumn() != null ? getSortColumn().hashCode() : 0); result = 31 * result + (getSearchString() != null ? getSearchString().hashCode() : 0); result = 31 * result + (getMemberId() != null ? getMemberId().hashCode() : 0); + result = 31 * result + (getRoles() != null ? getRoles().hashCode() : 0); + result = 31 * result + (getTypes() != null ? getTypes().hashCode() : 0); return result; } } diff --git a/perun-base/src/main/java/cz/metacentrum/perun/core/api/RoleAssignmentType.java b/perun-base/src/main/java/cz/metacentrum/perun/core/api/RoleAssignmentType.java new file mode 100644 index 0000000000..5c17e2ce8e --- /dev/null +++ b/perun-base/src/main/java/cz/metacentrum/perun/core/api/RoleAssignmentType.java @@ -0,0 +1,6 @@ +package cz.metacentrum.perun.core.api; + +public enum RoleAssignmentType { + DIRECT, + INDIRECT +} diff --git a/perun-base/src/main/java/cz/metacentrum/perun/core/api/exceptions/SSHKeyNotValidException.java b/perun-base/src/main/java/cz/metacentrum/perun/core/api/exceptions/SSHKeyNotValidException.java new file mode 100644 index 0000000000..7bfdbb0119 --- /dev/null +++ b/perun-base/src/main/java/cz/metacentrum/perun/core/api/exceptions/SSHKeyNotValidException.java @@ -0,0 +1,34 @@ +package cz.metacentrum.perun.core.api.exceptions; + +/** + * Validation of SSH key failed for some reason + * + * @author David Flor + */ +public class SSHKeyNotValidException extends PerunException { + + /** + * Simple constructor with a message + * @param message message with details about the cause + */ + public SSHKeyNotValidException(String message) { + super(message); + } + + /** + * Constructor with a message and Throwable object + * @param message message with details about the cause + * @param cause Throwable that caused throwing of this exception + */ + public SSHKeyNotValidException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructor with a Throwable object + * @param cause Throwable that caused throwing of this exception + */ + public SSHKeyNotValidException(Throwable cause) { + super(cause); + } +} diff --git a/perun-base/src/main/resources/perun-base.xml b/perun-base/src/main/resources/perun-base.xml index f17a957a55..344d6867fc 100644 --- a/perun-base/src/main/resources/perun-base.xml +++ b/perun-base/src/main/resources/perun-base.xml @@ -32,6 +32,7 @@ + @@ -134,6 +135,7 @@ + 6 jda3ufK92DKs2335af 2Akd14k3o9s1d2G5 diff --git a/perun-base/src/main/resources/perun-roles.yml b/perun-base/src/main/resources/perun-roles.yml index 2f2dab0ee0..20c6eb3714 100644 --- a/perun-base/src/main/resources/perun-roles.yml +++ b/perun-base/src/main/resources/perun-roles.yml @@ -2265,6 +2265,21 @@ perun_policies: include_policies: - default_policy + getAllRichGroupsWithAttributesByNames_Vo_List_List_List_policy: + policy_roles: + - RESOURCEADMIN: Vo + - RESOURCEOBSERVER: Vo + - GROUPADMIN: Vo + - GROUPOBSERVER: Vo + - GROUPMEMBERSHIPMANAGER: Vo + - PERUNOBSERVER: + - VOOBSERVER: Vo + - VOADMIN: Vo + - TOPGROUPCREATOR: Vo + - TRUSTEDFACILITYADMIN: Vo + include_policies: + - default_policy + getMemberRichGroupsWithAttributesByNames_Member_List_policy: policy_roles: - GROUPADMIN: Vo @@ -2287,6 +2302,28 @@ perun_policies: include_policies: - default_policy + getMemberRichGroupsWithAttributesByNames_Member_List_List_List_policy: + policy_roles: + - GROUPADMIN: Vo + - GROUPOBSERVER: Vo + - GROUPMEMBERSHIPMANAGER: Vo + - PERUNOBSERVER: + - VOOBSERVER: Vo + - VOADMIN: Vo + include_policies: + - default_policy + + filter-getMemberRichGroupsWithAttributesByNames_Member_List_List_List_policy: + policy_roles: + - GROUPADMIN: Group + - GROUPOBSERVER: Group + - GROUPMEMBERSHIPMANAGER: Group + - PERUNOBSERVER: + - VOOBSERVER: Vo + - VOADMIN: Vo + include_policies: + - default_policy + getAllRichGroupsWithAttributesByNames_Vo_List_policy: policy_roles: - RESOURCEADMIN: Vo @@ -2316,6 +2353,20 @@ perun_policies: include_policies: - default_policy + filter-getAllRichGroupsWithAttributesByNames_Vo_List_List_List_policy: + policy_roles: + - RESOURCEADMIN: Vo + - RESOURCEOBSERVER: Vo + - GROUPADMIN: Group + - GROUPOBSERVER: Group + - GROUPMEMBERSHIPMANAGER: Group + - PERUNOBSERVER: + - VOOBSERVER: Vo + - VOADMIN: Vo + - TRUSTEDFACILITYADMIN: Vo + include_policies: + - default_policy + getRichSubGroupsWithAttributesByNames_Group_List_policy: policy_roles: - RESOURCEADMIN: Vo @@ -2372,6 +2423,34 @@ perun_policies: include_policies: - default_policy + getAllRichSubGroupsWithAttributesByNames_Group_List_List_List_policy: + policy_roles: + - RESOURCEADMIN: Vo + - RESOURCEOBSERVER: Vo + - GROUPADMIN: Group + - GROUPOBSERVER: Group + - GROUPMEMBERSHIPMANAGER: Group + - PERUNOBSERVER: + - VOOBSERVER: Vo + - VOADMIN: Vo + - TRUSTEDFACILITYADMIN: Vo + include_policies: + - default_policy + + filter-getAllRichSubGroupsWithAttributesByNames_Group_List_List_List_policy: + policy_roles: + - RESOURCEADMIN: Vo + - RESOURCEOBSERVER: Vo + - GROUPADMIN: Group + - GROUPOBSERVER: Group + - GROUPMEMBERSHIPMANAGER: Group + - PERUNOBSERVER: + - VOOBSERVER: Vo + - VOADMIN: Vo + - TRUSTEDFACILITYADMIN: Vo + include_policies: + - default_policy + getRichGroupByIdWithAttributesByNames_int_List_policy: policy_roles: - RESOURCEADMIN: Vo @@ -7775,8 +7854,6 @@ perun_policies: group-verifyApplication_int_policy: policy_roles: - VOADMIN: Vo - - GROUPADMIN: Group - - GROUPMEMBERSHIPMANAGER: Group include_policies: - default_policy mfa_rules: diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/api/GroupsManager.java b/perun-core/src/main/java/cz/metacentrum/perun/core/api/GroupsManager.java index 14a73a2a7e..72ec399341 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/api/GroupsManager.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/api/GroupsManager.java @@ -1231,8 +1231,29 @@ public interface GroupsManager { * @throws MemberNotExistsException * @throws PrivilegeException */ + @Deprecated List getMemberRichGroupsWithAttributesByNames(PerunSession sess, Member member, List attrNames) throws MemberNotExistsException, PrivilegeException; + /** + * Return all RichGroups for specified member, containing selected attributes filtered by role and its type. + * "members" group is not included. + * + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @param sess internal session + * @param member the member to get the rich groups for + * @param attrNames list of selected attributes from supported namespaces + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return list of rich groups with selected attributes + * @throws InternalErrorException + * @throws MemberNotExistsException + * @throws PrivilegeException + */ + List getMemberRichGroupsWithAttributesByNames(PerunSession sess, Member member, List attrNames, List roles, List types) throws MemberNotExistsException, PrivilegeException; + /** * Return all RichGroups containing selected attributes * @@ -1243,8 +1264,23 @@ public interface GroupsManager { * @throws InternalErrorException * @throws VoNotExistsException */ + @Deprecated List getAllRichGroupsWithAttributesByNames(PerunSession sess, Vo vo, List attrNames) throws VoNotExistsException, PrivilegeException; + /** + * Return all RichGroups containing selected attributes filtered by role and its type + * + * @param sess perun session + * @param vo vo + * @param attrNames if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List of RichGroups + * @throws InternalErrorException + * @throws VoNotExistsException + */ + List getAllRichGroupsWithAttributesByNames(PerunSession sess, Vo vo, List attrNames, List roles, List types) throws VoNotExistsException, PrivilegeException; + /** * Return RichSubGroups in parentGroup (only 1 level subgroups) containing selected attributes * @@ -1267,8 +1303,23 @@ public interface GroupsManager { * @throws InternalErrorException * @throws GroupNotExistsException */ + @Deprecated List getAllRichSubGroupsWithAttributesByNames(PerunSession sess, Group parentGroup, List attrNames) throws GroupNotExistsException, PrivilegeException; + /** + * Return all RichSubGroups in parentGroup (all levels sub groups) containing selected attributes filtered by role and its type, + * + * @param sess perun session + * @param parentGroup parent group + * @param attrNames if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List of RichGroups + * @throws InternalErrorException + * @throws GroupNotExistsException + */ + List getAllRichSubGroupsWithAttributesByNames(PerunSession sess, Group parentGroup, List attrNames, List roles, List types) throws GroupNotExistsException, PrivilegeException; + /** * Return RichGroup selected by id containing selected attributes * diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/api/ServicesManager.java b/perun-core/src/main/java/cz/metacentrum/perun/core/api/ServicesManager.java index a7b164f434..552526363b 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/api/ServicesManager.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/api/ServicesManager.java @@ -89,7 +89,7 @@ public interface ServicesManager { * @param richDestinations the list of rich destinations * */ - void blockServicesOnDestinations(PerunSession perunSession, List richDestinations) throws PrivilegeException, DestinationNotExistsException, ServiceAlreadyBannedException, FacilityNotExistsException; + void blockServicesOnDestinations(PerunSession perunSession, List richDestinations) throws PrivilegeException, DestinationNotExistsException, FacilityNotExistsException; /** * Block all services currently assigned on this facility. diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/api/UsersManager.java b/perun-core/src/main/java/cz/metacentrum/perun/core/api/UsersManager.java index f0d0cc81ef..d3d48d5e7f 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/api/UsersManager.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/api/UsersManager.java @@ -25,6 +25,7 @@ import cz.metacentrum.perun.core.api.exceptions.RelationExistsException; import cz.metacentrum.perun.core.api.exceptions.RelationNotExistsException; import cz.metacentrum.perun.core.api.exceptions.ResourceNotExistsException; +import cz.metacentrum.perun.core.api.exceptions.SSHKeyNotValidException; import cz.metacentrum.perun.core.api.exceptions.ServiceNotExistsException; import cz.metacentrum.perun.core.api.exceptions.SpecificUserAlreadyRemovedException; import cz.metacentrum.perun.core.api.exceptions.SpecificUserExpectedException; @@ -1337,6 +1338,15 @@ List findRichUsersWithoutSpecificVoWithAttributes(PerunSession sess, V */ String validatePreferredEmailChange(PerunSession sess, User user, String token) throws PrivilegeException, UserNotExistsException, WrongAttributeAssignmentException, AttributeNotExistsException, WrongReferenceAttributeValueException, WrongAttributeValueException; + /** + * Validate ssh public key, throws exception if validation fails + * + * @param sess sess + * @param sshKey ssh public key to verify + * @throws SSHKeyNotValidException when validation fails + */ + void validateSSHKey(PerunSession sess, String sshKey) throws SSHKeyNotValidException; + /** * Return list of email addresses of user, which are * awaiting validation and are inside time window diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/bl/GroupsManagerBl.java b/perun-core/src/main/java/cz/metacentrum/perun/core/bl/GroupsManagerBl.java index 086743dbb9..875ee5733a 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/bl/GroupsManagerBl.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/bl/GroupsManagerBl.java @@ -17,6 +17,7 @@ import cz.metacentrum.perun.core.api.RichGroup; import cz.metacentrum.perun.core.api.RichMember; import cz.metacentrum.perun.core.api.RichUser; +import cz.metacentrum.perun.core.api.RoleAssignmentType; import cz.metacentrum.perun.core.api.Status; import cz.metacentrum.perun.core.api.User; import cz.metacentrum.perun.core.api.Vo; @@ -523,7 +524,7 @@ public interface GroupsManagerBl { * * Do not return expired members of the group. * - * @param sess perun session + * @param perunSession perun session * @param group to get members from * @return list of active (valid) members * @throws InternalErrorException @@ -548,7 +549,7 @@ public interface GroupsManagerBl { * * Do not return active members of the group. * - * @param sess perun session + * @param perunSession perun session * @param group to get members from * @return list of inactive (expired) members * @throws InternalErrorException @@ -1576,8 +1577,27 @@ public interface GroupsManagerBl { * @return list of rich groups with selected attributes * @throws InternalErrorException */ + @Deprecated List getMemberRichGroupsWithAttributesByNames(PerunSession sess, Member member, List attrNames); + /** + * Return all RichGroups for specified member, containing selected attributes filtered by role and its type. + * "members" group is not included. + * + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @param sess internal session + * @param member the member to get the rich groups for + * @param attrNames list of selected attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return list of rich groups with selected attributes + * @throws InternalErrorException + */ + List getMemberRichGroupsWithAttributesByNames(PerunSession sess, Member member, List attrNames, List roles, List types); + /** * Returns all RichGroups containing selected attributes * @@ -1587,8 +1607,22 @@ public interface GroupsManagerBl { * @return List of RichGroups * @throws InternalErrorException */ + @Deprecated List getAllRichGroupsWithAttributesByNames(PerunSession sess, Vo vo, List attrNames); + /** + * Returns all RichGroups containing selected attributes filtered by role and its type + * + * @param sess perun session + * @param vo vo + * @param attrNames if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List of RichGroups + * @throws InternalErrorException + */ + List getAllRichGroupsWithAttributesByNames(PerunSession sess, Vo vo, List attrNames, List roles, List types); + /** * Returns RichSubGroups from parentGroup containing selected attributes (only 1 level subgroups) * @@ -1609,8 +1643,22 @@ public interface GroupsManagerBl { * @return List of RichGroups * @throws InternalErrorException */ + @Deprecated List getAllRichSubGroupsWithAttributesByNames(PerunSession sess, Group parentGroup, List attrNames); + /** + * Returns all RichSubGroups from parentGroup containing selected attributes filtered by role and its type (all levels subgroups) + * + * @param sess + * @param parentGroup + * @param attrNames if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List of RichGroups + * @throws InternalErrorException + */ + List getAllRichSubGroupsWithAttributesByNames(PerunSession sess, Group parentGroup, List attrNames, List roles, List types); + /** * Returns RichGroup selected by id containing selected attributes * @@ -1992,7 +2040,7 @@ public interface GroupsManagerBl { * Get list of groups where the given group is given the admin role. * * @param perunSession - * @param Group with the admin role. + * @param group with the admin role. * @return List of administered groups. * @throws InternalErrorException */ @@ -2002,7 +2050,7 @@ public interface GroupsManagerBl { * Get list of VOs where the given group is given the admin role. * * @param perunSession - * @param Group with the admin role. + * @param group with the admin role. * @return List of administered VOs. * @throws InternalErrorException */ @@ -2012,7 +2060,7 @@ public interface GroupsManagerBl { * Get list of facilities where the given group is given the admin role. * * @param perunSession - * @param Group with the admin role. + * @param group with the admin role. * @return List of administered facilities. * @throws InternalErrorException */ diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/bl/UsersManagerBl.java b/perun-core/src/main/java/cz/metacentrum/perun/core/bl/UsersManagerBl.java index 971340c80c..4c031367af 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/bl/UsersManagerBl.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/bl/UsersManagerBl.java @@ -45,6 +45,7 @@ import cz.metacentrum.perun.core.api.exceptions.PasswordStrengthFailedException; import cz.metacentrum.perun.core.api.exceptions.RelationExistsException; import cz.metacentrum.perun.core.api.exceptions.RelationNotExistsException; +import cz.metacentrum.perun.core.api.exceptions.SSHKeyNotValidException; import cz.metacentrum.perun.core.api.exceptions.SpecificUserAlreadyRemovedException; import cz.metacentrum.perun.core.api.exceptions.SpecificUserOwnerAlreadyRemovedException; import cz.metacentrum.perun.core.api.exceptions.UserAlreadyRemovedException; @@ -1519,6 +1520,15 @@ void deletePassword(PerunSession sess, User user, String loginNamespace) */ String validatePreferredEmailChange(PerunSession sess, User user, String token) throws WrongAttributeValueException, WrongAttributeAssignmentException, AttributeNotExistsException, WrongReferenceAttributeValueException; + /** + * Validate ssh public key, throws exception if validation fails + * + * @param sess sess + * @param sshKey ssh public key to verify + * @throws SSHKeyNotValidException when validation fails + */ + void validateSSHKey(PerunSession sess, String sshKey) throws SSHKeyNotValidException; + /** * Return list of email addresses of user, which are * awaiting validation and are inside time window diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/blImpl/AuthzResolverBlImpl.java b/perun-core/src/main/java/cz/metacentrum/perun/core/blImpl/AuthzResolverBlImpl.java index 800aa89501..6a1d96c70d 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/blImpl/AuthzResolverBlImpl.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/blImpl/AuthzResolverBlImpl.java @@ -33,6 +33,7 @@ import cz.metacentrum.perun.core.api.RichResource; import cz.metacentrum.perun.core.api.RichUser; import cz.metacentrum.perun.core.api.Role; +import cz.metacentrum.perun.core.api.RoleAssignmentType; import cz.metacentrum.perun.core.api.RoleManagementRules; import cz.metacentrum.perun.core.api.RoleObject; import cz.metacentrum.perun.core.api.SecurityTeam; @@ -2953,6 +2954,20 @@ public static List getResourcesWhereUserIsInRoles(PerunSession sess, U return new ArrayList<>(authzResolverImpl.getResourcesWhereUserIsInRoles(user, roles)); } + /** + * Check if the given group passes the user's roles filter. + * + * @param sess session + * @param user user + * @param group group + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return list of groups + */ + public static boolean groupMatchesUserRolesFilter(PerunSession sess, User user, Group group, List roles, List types) { + return authzResolverImpl.groupMatchesUserRolesFilter(sess, user, group, roles, types); + } + /** * Get all Groups where the given user has set one of the given roles * or the given user is a member of an authorized group with such roles. diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/blImpl/GroupsManagerBlImpl.java b/perun-core/src/main/java/cz/metacentrum/perun/core/blImpl/GroupsManagerBlImpl.java index bd588f5fe5..f22b8be0a4 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/blImpl/GroupsManagerBlImpl.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/blImpl/GroupsManagerBlImpl.java @@ -50,6 +50,7 @@ import cz.metacentrum.perun.core.api.RichUser; import cz.metacentrum.perun.core.api.RichUserExtSource; import cz.metacentrum.perun.core.api.Role; +import cz.metacentrum.perun.core.api.RoleAssignmentType; import cz.metacentrum.perun.core.api.SecurityTeam; import cz.metacentrum.perun.core.api.Status; import cz.metacentrum.perun.core.api.User; @@ -1960,7 +1961,7 @@ public List synchronizeGroup(PerunSession sess, Group group) throws Attr long startTime = System.nanoTime(); getPerunBl().getAuditer().log(sess,new GroupSyncStarted(group)); - log.debug("Group synchronization for {} has been started.", group); + log.info("Group synchronization for {} has been started.", group); //Initialization of group extSource source = getGroupExtSourceForSynchronization(sess, group); @@ -1986,25 +1987,28 @@ public List synchronizeGroup(PerunSession sess, Group group) throws Attr List actualGroupMembers = getPerunBl().getGroupsManagerBl().getGroupDirectRichMembers(sess, group); if(lightweightSynchronization) { + log.debug("Group synchronization {}: categorize members for lightweight sync", group); categorizeMembersForLightweightSynchronization(sess, group, source, membersSource, actualGroupMembers, candidatesToAdd, membersToRemove, skippedMembers); } else { //Get subjects from extSource List> subjects = getSubjectsFromExtSource(sess, source, group); //Convert subjects to candidates List candidates = convertSubjectsToCandidates(sess, subjects, membersSource, source, actualGroupMembers, skippedMembers); - + log.debug("Group synchronization {}: categorize members for standard sync", group); categorizeMembersForSynchronization(sess, actualGroupMembers, candidates, candidatesToAdd, membersToUpdate, membersToRemove); } // Remove members from group who are not present in synchronized ExtSource boolean isAuthoritative = isAuthoritative(sess, group); Collections.sort(membersToRemove); + log.debug("Group synchronization {}: removing {} members", group, membersToRemove.size()); for (RichMember memberToRemove : membersToRemove) { removeFormerMemberWhileSynchronization(sess, group, memberToRemove, isAuthoritative); } List attrDefs = new ArrayList<>(); //Update members already presented in group + log.debug("Group synchronization {}: updating {} members", group, membersToUpdate.size()); for (Candidate candidate : membersToUpdate.keySet()) { RichMember memberToUpdate = membersToUpdate.get(candidate); //Load attrDefinitions just once for first candidate @@ -2016,6 +2020,7 @@ public List synchronizeGroup(PerunSession sess, Group group) throws Attr //Add not presented candidates to group Collections.sort(candidatesToAdd); + log.debug("Group synchronization {}: adding {} members", group, candidatesToAdd.size()); for (Candidate candidateToAdd : candidatesToAdd) { addMissingMemberWhileSynchronization(sess, group, candidateToAdd, overwriteUserAttributesList, mergeMemberAttributesList, skippedMembers); } @@ -3042,18 +3047,51 @@ public List getRichGroupsWithAttributesAssignedToResource(PerunSessio } @Override + @Deprecated public List getAllRichGroupsWithAttributesByNames(PerunSession sess, Vo vo, List attrNames) { return convertGroupsToRichGroupsWithAttributes(sess, this.getAllGroups(sess, vo), attrNames); } @Override + public List getAllRichGroupsWithAttributesByNames(PerunSession sess, Vo vo, List attrNames, List roles, List types) { + List groups = this.getAllGroups(sess, vo); + if ((!roles.isEmpty() || !types.isEmpty()) && sess.getPerunPrincipal().getUser() != null) { + groups.removeIf(group -> !AuthzResolverBlImpl.groupMatchesUserRolesFilter(sess, sess.getPerunPrincipal().getUser(), group, roles, types)); + } + return convertGroupsToRichGroupsWithAttributes(sess, groups, attrNames); + } + + @Override + @Deprecated public List getMemberRichGroupsWithAttributesByNames(PerunSession sess, Member member, List attrNames) { List memberGroups = this.getMemberGroups(sess, member); + return convertGroupsToMemberRichGroups(sess, member, memberGroups, attrNames); + } + + @Override + public List getMemberRichGroupsWithAttributesByNames(PerunSession sess, Member member, List attrNames, List roles, List types) { + List memberGroups = this.getMemberGroups(sess, member); + if ((!roles.isEmpty() || !types.isEmpty()) && sess.getPerunPrincipal().getUser() != null) { + memberGroups.removeIf(group -> !AuthzResolverBlImpl.groupMatchesUserRolesFilter(sess, sess.getPerunPrincipal().getUser(), group, roles, types)); + } + return convertGroupsToMemberRichGroups(sess, member, memberGroups, attrNames); + } + + /** + * Converts the list of Groups to RichGroup, adding group and member-group attributes. + * + * @param sess session + * @param member member + * @param groups list of groups + * @param attrNames list of attribute names + * @return list of rich groups + */ + private List convertGroupsToMemberRichGroups(PerunSession sess, Member member, List groups, List attrNames) { List richGroups = new ArrayList<>(); if(attrNames == null) { //if attrNames is null, it means all possible group and member-group attributes - for(Group group: memberGroups) { + for(Group group: groups) { List allGroupAndMemberGroupAttributes = new ArrayList<>(); allGroupAndMemberGroupAttributes.addAll(this.getPerunBl().getAttributesManagerBl().getAttributes(sess, group)); try { @@ -3065,7 +3103,7 @@ public List getMemberRichGroupsWithAttributesByNames(PerunSession ses } } else { //if attrNames is not null, it means only selected group and member-group attributes - for (Group group : memberGroups) { + for (Group group : groups) { List selectedGroupAndMemberGroupAttributes = new ArrayList<>(); selectedGroupAndMemberGroupAttributes.addAll(this.getPerunBl().getAttributesManagerBl().getAttributes(sess, group, attrNames)); try { @@ -3076,7 +3114,6 @@ public List getMemberRichGroupsWithAttributesByNames(PerunSession ses richGroups.add(new RichGroup(group, selectedGroupAndMemberGroupAttributes)); } } - return richGroups; } @@ -3086,10 +3123,20 @@ public List getRichSubGroupsWithAttributesByNames(PerunSession sess, } @Override + @Deprecated public List getAllRichSubGroupsWithAttributesByNames(PerunSession sess, Group parentGroup, List attrNames) { return convertGroupsToRichGroupsWithAttributes(sess, this.getAllSubGroups(sess, parentGroup), attrNames); } + @Override + public List getAllRichSubGroupsWithAttributesByNames(PerunSession sess, Group parentGroup, List attrNames, List roles, List types) { + List subGroups = this.getAllSubGroups(sess, parentGroup); + if ((!roles.isEmpty() || !types.isEmpty()) && sess.getPerunPrincipal().getUser() != null) { + subGroups.removeIf(group -> !AuthzResolverBlImpl.groupMatchesUserRolesFilter(sess, sess.getPerunPrincipal().getUser(), group, roles, types)); + } + return convertGroupsToRichGroupsWithAttributes(sess, subGroups, attrNames); + } + @Override public RichGroup getRichGroupByIdWithAttributesByNames(PerunSession sess, int groupId, List attrNames)throws GroupNotExistsException{ return convertGroupToRichGroupWithAttributesByName(sess, this.getGroupById(sess, groupId), attrNames); @@ -3716,7 +3763,7 @@ private List convertSubjectsToCandidates(PerunSession sess, List overwriteUserAttributesList, List mergeMemberAttributesList, List attrDefs) { - //If member does not exists in this moment (somebody removed him before updating process), skip him and log it + //If member does not exist at this moment (somebody removed him before updating process), skip him and log it try { getPerunBl().getMembersManagerBl().checkMemberExists(sess, memberToUpdate); } catch (MemberNotExistsException ex) { diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/blImpl/UsersManagerBlImpl.java b/perun-core/src/main/java/cz/metacentrum/perun/core/blImpl/UsersManagerBlImpl.java index dc09f8bfdd..17e2fd9eb4 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/blImpl/UsersManagerBlImpl.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/blImpl/UsersManagerBlImpl.java @@ -70,6 +70,7 @@ import cz.metacentrum.perun.core.api.exceptions.PasswordStrengthFailedException; import cz.metacentrum.perun.core.api.exceptions.RelationExistsException; import cz.metacentrum.perun.core.api.exceptions.RelationNotExistsException; +import cz.metacentrum.perun.core.api.exceptions.SSHKeyNotValidException; import cz.metacentrum.perun.core.api.exceptions.SpecificUserAlreadyRemovedException; import cz.metacentrum.perun.core.api.exceptions.SpecificUserOwnerAlreadyRemovedException; import cz.metacentrum.perun.core.api.exceptions.UserAlreadyRemovedException; @@ -92,6 +93,7 @@ import cz.metacentrum.perun.core.bl.PerunBl; import cz.metacentrum.perun.core.bl.UsersManagerBl; import cz.metacentrum.perun.core.impl.PerunSessionImpl; +import cz.metacentrum.perun.core.impl.SSHValidator; import cz.metacentrum.perun.core.impl.Utils; import cz.metacentrum.perun.core.impl.modules.pwdmgr.GenericPasswordManagerModule; import cz.metacentrum.perun.core.implApi.UsersManagerImplApi; @@ -1910,6 +1912,11 @@ public String validatePreferredEmailChange(PerunSession sess, User user, String return email; } + @Override + public void validateSSHKey(PerunSession sess, String sshKey) throws SSHKeyNotValidException { + Utils.validateSSHPublicKey(sshKey); + } + @Override public List getPendingPreferredEmailChanges(PerunSession sess, User user) throws WrongAttributeAssignmentException, AttributeNotExistsException { diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/entry/GroupsManagerEntry.java b/perun-core/src/main/java/cz/metacentrum/perun/core/entry/GroupsManagerEntry.java index 87c6de6b39..ef36094cfe 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/entry/GroupsManagerEntry.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/entry/GroupsManagerEntry.java @@ -17,6 +17,7 @@ import cz.metacentrum.perun.core.api.RichMember; import cz.metacentrum.perun.core.api.RichUser; import cz.metacentrum.perun.core.api.Role; +import cz.metacentrum.perun.core.api.RoleAssignmentType; import cz.metacentrum.perun.core.api.Status; import cz.metacentrum.perun.core.api.User; import cz.metacentrum.perun.core.api.Vo; @@ -940,6 +941,12 @@ public Paginated getGroupsPage(PerunSession sess, Vo vo, GroupsPageQu perunBl.getMembersManagerBl().checkMemberExists(sess, member); } + for (String role : query.getRoles()) { + if (!AuthzResolver.roleExists(role)) { + throw new InternalErrorException("Role: "+ role +" does not exists."); + } + } + // Authorization if (member != null) { if (!AuthzResolver.authorizedInternal(sess, "member-getGroupsPage_Vo_GroupsPageQuery_List_policy", member)) { @@ -1373,6 +1380,7 @@ public List getRichGroupsAssignedToResourceWithAttributesByNames(Peru return getGroupsManagerBl().filterOnlyAllowedAttributes(sess, richGroups, member, resource, true); } + @Deprecated public List getMemberRichGroupsWithAttributesByNames(PerunSession sess, Member member, List attrNames) throws MemberNotExistsException, PrivilegeException { Utils.checkPerunSession(sess); this.getPerunBl().getMembersManagerBl().checkMemberExists(sess, member); @@ -1390,6 +1398,29 @@ public List getMemberRichGroupsWithAttributesByNames(PerunSession ses } @Override + public List getMemberRichGroupsWithAttributesByNames(PerunSession sess, Member member, List attrNames, List roles, List types) throws MemberNotExistsException, PrivilegeException { + Utils.checkPerunSession(sess); + this.getPerunBl().getMembersManagerBl().checkMemberExists(sess, member); + + for (String role : roles) { + if (!AuthzResolver.roleExists(role)) { + throw new InternalErrorException("Role: "+ role +" does not exists."); + } + } + + // Authorization + if (!AuthzResolver.authorizedInternal(sess, "getMemberRichGroupsWithAttributesByNames_Member_List_List_List_policy", member)) { + throw new PrivilegeException(sess, "getMemberRichGroupsWithAttributesByNames"); + } + + List richGroups = getGroupsManagerBl().getMemberRichGroupsWithAttributesByNames(sess, member, attrNames, roles, types); + richGroups.removeIf(richGroup -> !AuthzResolver.authorizedInternal(sess, "filter-getMemberRichGroupsWithAttributesByNames_Member_List_List_List_policy", Arrays.asList(member, richGroup))); + + return getGroupsManagerBl().filterOnlyAllowedAttributes(sess, richGroups, member, null, true); + } + + @Override + @Deprecated public List getAllRichGroupsWithAttributesByNames(PerunSession sess, Vo vo, List attrNames) throws VoNotExistsException, PrivilegeException { Utils.checkPerunSession(sess); this.getPerunBl().getVosManagerBl().checkVoExists(sess, vo); @@ -1406,6 +1437,28 @@ public List getAllRichGroupsWithAttributesByNames(PerunSession sess, return getGroupsManagerBl().filterOnlyAllowedAttributes(sess, richGroups, null, true); } + @Override + public List getAllRichGroupsWithAttributesByNames(PerunSession sess, Vo vo, List attrNames, List roles, List types) throws VoNotExistsException, PrivilegeException { + Utils.checkPerunSession(sess); + this.getPerunBl().getVosManagerBl().checkVoExists(sess, vo); + + for (String role : roles) { + if (!AuthzResolver.roleExists(role)) { + throw new InternalErrorException("Role: "+ role +" does not exists."); + } + } + + // Authorization + if (!AuthzResolver.authorizedInternal(sess, "getAllRichGroupsWithAttributesByNames_Vo_List_List_List_policy", vo)) { + throw new PrivilegeException(sess, "getAllRichGroupsWithAttributesByNames"); + } + + List richGroups = getGroupsManagerBl().getAllRichGroupsWithAttributesByNames(sess, vo, attrNames, roles, types); + richGroups.removeIf(richGroup -> !AuthzResolver.authorizedInternal(sess, "filter-getAllRichGroupsWithAttributesByNames_Vo_List_List_List_policy", richGroup)); + + return getGroupsManagerBl().filterOnlyAllowedAttributes(sess, richGroups, null, true); + } + @Override public List getRichSubGroupsWithAttributesByNames(PerunSession sess, Group parentGroup, List attrNames) throws GroupNotExistsException, PrivilegeException { Utils.checkPerunSession(sess); @@ -1423,6 +1476,7 @@ public List getRichSubGroupsWithAttributesByNames(PerunSession sess, } @Override + @Deprecated public List getAllRichSubGroupsWithAttributesByNames(PerunSession sess, Group parentGroup, List attrNames) throws GroupNotExistsException, PrivilegeException { Utils.checkPerunSession(sess); this.getGroupsManagerBl().checkGroupExists(sess, parentGroup); @@ -1438,6 +1492,28 @@ public List getAllRichSubGroupsWithAttributesByNames(PerunSession ses return getGroupsManagerBl().filterOnlyAllowedAttributes(sess, richGroups, null, true); } + @Override + public List getAllRichSubGroupsWithAttributesByNames(PerunSession sess, Group parentGroup, List attrNames, List roles, List types) throws GroupNotExistsException, PrivilegeException { + Utils.checkPerunSession(sess); + this.getGroupsManagerBl().checkGroupExists(sess, parentGroup); + + for (String role : roles) { + if (!AuthzResolver.roleExists(role)) { + throw new InternalErrorException("Role: "+ role +" does not exists."); + } + } + + // Authorization + if (!AuthzResolver.authorizedInternal(sess, "getAllRichSubGroupsWithAttributesByNames_Group_List_List_List_policy", parentGroup)) { + throw new PrivilegeException(sess, "getAllRichSubGroupsWithAttributesByNames"); + } + + List richGroups = getGroupsManagerBl().getAllRichSubGroupsWithAttributesByNames(sess, parentGroup, attrNames, roles, types); + richGroups.removeIf(richGroup -> !AuthzResolver.authorizedInternal(sess, "filter-getAllRichSubGroupsWithAttributesByNames_Group_List_List_List_policy", richGroup)); + + return getGroupsManagerBl().filterOnlyAllowedAttributes(sess, richGroups, null, true); + } + @Override public RichGroup getRichGroupByIdWithAttributesByNames(PerunSession sess, int groupId, List attrNames) throws GroupNotExistsException, PrivilegeException { Utils.checkPerunSession(sess); diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/entry/ServicesManagerEntry.java b/perun-core/src/main/java/cz/metacentrum/perun/core/entry/ServicesManagerEntry.java index 92a270654f..8d51fe7384 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/entry/ServicesManagerEntry.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/entry/ServicesManagerEntry.java @@ -98,9 +98,12 @@ public void blockServiceOnDestination(PerunSession sess, Service service, int de } @Override - public void blockServicesOnDestinations(PerunSession sess, List richDestinations) throws PrivilegeException, DestinationNotExistsException, ServiceAlreadyBannedException, FacilityNotExistsException { + public void blockServicesOnDestinations(PerunSession sess, List richDestinations) throws PrivilegeException, DestinationNotExistsException, FacilityNotExistsException { for (RichDestination richDestination : richDestinations) { - blockServiceOnDestination(sess, richDestination.getService(), richDestination.getId()); + try { + blockServiceOnDestination(sess, richDestination.getService(), richDestination.getId()); + } catch (ServiceAlreadyBannedException ignored) { + } } } diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/entry/UsersManagerEntry.java b/perun-core/src/main/java/cz/metacentrum/perun/core/entry/UsersManagerEntry.java index 15e9293b1a..091933dd97 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/entry/UsersManagerEntry.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/entry/UsersManagerEntry.java @@ -58,6 +58,7 @@ import cz.metacentrum.perun.core.api.exceptions.RelationExistsException; import cz.metacentrum.perun.core.api.exceptions.RelationNotExistsException; import cz.metacentrum.perun.core.api.exceptions.ResourceNotExistsException; +import cz.metacentrum.perun.core.api.exceptions.SSHKeyNotValidException; import cz.metacentrum.perun.core.api.exceptions.ServiceNotExistsException; import cz.metacentrum.perun.core.api.exceptions.SpecificUserAlreadyRemovedException; import cz.metacentrum.perun.core.api.exceptions.SpecificUserExpectedException; @@ -1560,6 +1561,13 @@ public String validatePreferredEmailChange(PerunSession sess, User user, String return getPerunBl().getUsersManagerBl().validatePreferredEmailChange(sess, user, token); } + @Override + public void validateSSHKey(PerunSession sess, String sshKey) throws SSHKeyNotValidException { + Utils.checkPerunSession(sess); + + getPerunBl().getUsersManagerBl().validateSSHKey(sess, sshKey); + } + @Override public List getPendingPreferredEmailChanges(PerunSession sess, User user) throws PrivilegeException, UserNotExistsException, WrongAttributeAssignmentException, AttributeNotExistsException { diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/impl/AttributesManagerImpl.java b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/AttributesManagerImpl.java index 6e7075dc09..6521823c2d 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/impl/AttributesManagerImpl.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/AttributesManagerImpl.java @@ -4331,7 +4331,7 @@ private String attributeNameToModuleName(String attributeName) { * * @param attribute attribute for which you get the module * @return instance group attribute module - * null if the module doesn't exists + * null if the module doesn't exist */ private GroupAttributesModuleImplApi getGroupAttributeModule(PerunSession sess, AttributeDefinition attribute) { Object attributeModule = getAttributesModule(sess, attribute); @@ -4340,7 +4340,7 @@ private GroupAttributesModuleImplApi getGroupAttributeModule(PerunSession sess, if (attributeModule instanceof GroupAttributesModuleImplApi) { return (GroupAttributesModuleImplApi) attributeModule; } else { - throw new WrongModuleTypeException("Required attribute module isn't FacilityAttributesModule"); + throw new WrongModuleTypeException("Required attribute module isn't GroupAttributesModule"); } } @@ -4349,7 +4349,7 @@ private GroupAttributesModuleImplApi getGroupAttributeModule(PerunSession sess, * * @param attribute attribute for which you get the module * @return instance host attribute module - * null if the module doesn't exists + * null if the module doesn't exist */ private HostAttributesModuleImplApi getHostAttributeModule(PerunSession sess, AttributeDefinition attribute) { Object attributeModule = getAttributesModule(sess, attribute); @@ -4367,7 +4367,7 @@ private HostAttributesModuleImplApi getHostAttributeModule(PerunSession sess, At * * @param attribute attribute for which you get the module * @return instance vo attribute module - * null if the module doesn't exists + * null if the module doesn't exist */ private VoAttributesModuleImplApi getVoAttributeModule(PerunSession sess, AttributeDefinition attribute) { Object attributeModule = getAttributesModule(sess, attribute); @@ -4376,7 +4376,7 @@ private VoAttributesModuleImplApi getVoAttributeModule(PerunSession sess, Attrib if (attributeModule instanceof VoAttributesModuleImplApi) { return (VoAttributesModuleImplApi) attributeModule; } else { - throw new WrongModuleTypeException("Required attribute module isn't FacilityAttributesModule"); + throw new WrongModuleTypeException("Required attribute module isn't VoAttributesModule"); } } @@ -4385,7 +4385,7 @@ private VoAttributesModuleImplApi getVoAttributeModule(PerunSession sess, Attrib * * @param attribute attribute for which you get the module * @return instance resource member attribute module - * null if the module doesn't exists + * null if the module doesn't exist */ private MemberResourceAttributesModuleImplApi getResourceMemberAttributeModule(PerunSession sess, AttributeDefinition attribute) { Object attributeModule = getAttributesModule(sess, attribute); @@ -4394,7 +4394,7 @@ private MemberResourceAttributesModuleImplApi getResourceMemberAttributeModule(P if (attributeModule instanceof MemberResourceAttributesModuleImplApi) { return (MemberResourceAttributesModuleImplApi) attributeModule; } else { - throw new WrongModuleTypeException("Required attribute module isn't FacilityAttributesModule"); + throw new WrongModuleTypeException("Required attribute module isn't ResourceMemberAttributesModule"); } } @@ -4403,7 +4403,7 @@ private MemberResourceAttributesModuleImplApi getResourceMemberAttributeModule(P * * @param attribute attribute for which you get the module * @return instance member group attribute module - * null if the module doesn't exists + * null if the module doesn't exist */ private MemberGroupAttributesModuleImplApi getMemberGroupAttributeModule(PerunSession sess, AttributeDefinition attribute) { Object attributeModule = getAttributesModule(sess, attribute); @@ -4421,7 +4421,7 @@ private MemberGroupAttributesModuleImplApi getMemberGroupAttributeModule(PerunSe * * @param attribute attribute for which you get the module * @return instance facility attribute module - * null if the module doesn't exists + * null if the module doesn't exist */ private FacilityAttributesModuleImplApi getFacilityAttributeModule(PerunSession sess, AttributeDefinition attribute) { Object attributeModule = getAttributesModule(sess, attribute); @@ -4691,7 +4691,7 @@ MemberGroupVirtualAttributesModuleImplApi getMemberGroupVirtualAttributeModule(P * Get UserExtSource attribute module for the attribute. * * @param attribute attribute for which you get the module - * @return instance UserExtSource attribute module, null if the module doesn't exists + * @return instance UserExtSource attribute module, null if the module doesn't exist */ private UserExtSourceVirtualAttributesModuleImplApi getUserExtSourceVirtualAttributeModule(PerunSession sess, AttributeDefinition attribute) { Object attributeModule = getAttributesModule(sess, attribute); @@ -4747,7 +4747,7 @@ public Object getAttributesModule(PerunSession sess, AttributeDefinition attribu //if specific module not exists or attribute has no parameter, find the common one moduleName = attributeNameToModuleName(attribute.getNamespace() + ":" + attribute.getBaseFriendlyName()); Object attributeModule = attributesModulesMap.get(moduleName); - if (attributeModule == null) log.debug("Attribute module not found. Module name={}", moduleName); + if (attributeModule == null) log.trace("Attribute module not found. Module name={}", moduleName); return attributeModule; } diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/impl/AuthzResolverImpl.java b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/AuthzResolverImpl.java index 667e5d924c..81d2889a60 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/impl/AuthzResolverImpl.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/AuthzResolverImpl.java @@ -8,11 +8,11 @@ import cz.metacentrum.perun.core.api.Member; import cz.metacentrum.perun.core.api.MemberGroupStatus; import cz.metacentrum.perun.core.api.Pair; -import cz.metacentrum.perun.core.api.Perun; import cz.metacentrum.perun.core.api.PerunPolicy; import cz.metacentrum.perun.core.api.PerunSession; import cz.metacentrum.perun.core.api.Resource; import cz.metacentrum.perun.core.api.Role; +import cz.metacentrum.perun.core.api.RoleAssignmentType; import cz.metacentrum.perun.core.api.RoleManagementRules; import cz.metacentrum.perun.core.api.SecurityTeam; import cz.metacentrum.perun.core.api.Service; @@ -1133,6 +1133,28 @@ public Set getGroupsWhereUserIsInRoles(User user, List roles) { } } + @Override + public boolean groupMatchesUserRolesFilter(PerunSession sess, User user, Group group, List roles, List types) { + MapSqlParameterSource parameters = prepareParametersToGetObjectsByUserRoles(user, roles); + parameters.addValue("groupId", group.getId()); + + boolean includeIndirectRoles = types.contains(RoleAssignmentType.INDIRECT) || types.isEmpty(); + boolean includeDirectRoles = types.contains(RoleAssignmentType.DIRECT) || types.isEmpty(); + + try { + List directRelations = namedParameterJdbcTemplate.query("select " + groupMappingSelectQuery + " from authz join groups on authz.group_id=groups.id " + + " where groups.id=:groupId and authz.user_id=:uid" + (!roles.isEmpty() ? " and (authz.role_id in (select id from roles where name in (:roles)))" : ""), parameters, GROUP_MAPPER); + + List indirectRelations = namedParameterJdbcTemplate.query("select " + groupMappingSelectQuery + " from authz join groups on authz.group_id=groups.id " + + " left outer join groups_members on groups_members.group_id=authz.authorized_group_id left outer join members on members.id=groups_members.member_id " + + " where groups.id=:groupId and members.user_id=:uid" + (!roles.isEmpty() ? " and (authz.role_id in (select id from roles where name in (:roles)))" : ""), parameters, GROUP_MAPPER); + + return (includeDirectRoles && !directRelations.isEmpty()) || (includeIndirectRoles && !indirectRelations.isEmpty()); + } catch (RuntimeException ex) { + throw new InternalErrorException(ex); + } + } + @Override public Set getMembersWhereUserIsInRoles(User user, List roles) { MapSqlParameterSource parameters = prepareParametersToGetObjectsByUserRoles(user, roles); diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/impl/GroupsManagerImpl.java b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/GroupsManagerImpl.java index cbb68a81c6..f98d4c1e82 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/impl/GroupsManagerImpl.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/GroupsManagerImpl.java @@ -18,6 +18,7 @@ import cz.metacentrum.perun.core.api.Paginated; import cz.metacentrum.perun.core.api.PerunSession; import cz.metacentrum.perun.core.api.Resource; +import cz.metacentrum.perun.core.api.RoleAssignmentType; import cz.metacentrum.perun.core.api.SecurityTeam; import cz.metacentrum.perun.core.api.Status; import cz.metacentrum.perun.core.api.User; @@ -680,6 +681,9 @@ private String getSQLSelectForGroupsPage(GroupsPageQuery query) { public Paginated getGroupsPage(PerunSession sess, Vo vo, GroupsPageQuery query) { MapSqlParameterSource namedParams = new MapSqlParameterSource(); + boolean includeIndirectRoles = query.getTypes().contains(RoleAssignmentType.INDIRECT) || query.getTypes().isEmpty(); + boolean includeDirectRoles = query.getTypes().contains(RoleAssignmentType.DIRECT) || query.getTypes().isEmpty(); + List authorizedGroupsIds = getGroupsIds(sess, vo); authorizedGroupsIds.removeIf(groupId -> !AuthzResolverBlImpl.isAuthorizedForGroup(sess, "filter-getGroupsPage_Vo_GroupsPageQuery_List_policy", groupId, vo.getId())); @@ -688,24 +692,42 @@ public Paginated getGroupsPage(PerunSession sess, Vo vo, GroupsPageQuery namedParams.addValue("groupsIds", authorizedGroupsIds); namedParams.addValue("offset", query.getOffset()); namedParams.addValue("limit", query.getPageSize()); + namedParams.addValue("uid", sess.getPerunPrincipal().getUser() != null ? sess.getPerunPrincipal().getUser().getId() : null); + namedParams.addValue("roles", query.getRoles().stream().map(String::toLowerCase).toList()); if (query.getMemberId() != null) namedParams.addValue("memberId", query.getMemberId()); String selectQuery = getSQLSelectForGroupsPage(query); String searchQuery = getSQLWhereForGroupsPage(query, namedParams); - Paginated groups = namedParameterJdbcTemplate.query( - selectQuery + - " WHERE groups.vo_id=(:voId)" + - " AND groups.id IN (:groupsIds)" + + if ((query.getRoles().isEmpty() && query.getTypes().isEmpty()) || sess.getPerunPrincipal().getUser() == null ) { + return namedParameterJdbcTemplate.query( + selectQuery + + " WHERE groups.vo_id=(:voId)" + + " AND groups.id IN (:groupsIds)" + + searchQuery + + " ORDER BY " + query.getSortColumn().getSqlOrderBy(query) + + " OFFSET (:offset)" + + " LIMIT (:limit);", + namedParams, + getPaginatedGroupsExtractor(query)); + } + return namedParameterJdbcTemplate.query( + "SELECT DISTINCT " + groupMappingSelectQuery + + ", count(*) OVER() AS total_count " + + "FROM authz JOIN " + + (query.getMemberId() == null ? " groups ON authz.group_id=groups.id " : + "(SELECT * FROM groups WHERE groups.name!='members' OR groups.parent_group_id IS NOT NULL) AS groups ON authz.group_id=groups.id JOIN " + + "(SELECT * FROM groups_members WHERE member_id = (:memberId)) AS g_m ON groups.id = g_m.group_id ") + + (includeIndirectRoles ? " LEFT OUTER JOIN groups_members ON groups_members.group_id=authz.authorized_group_id LEFT OUTER JOIN members ON members.id=groups_members.member_id " : "") + + "WHERE groups.vo_id=(:voId) AND groups.id IN (:groupsIds) AND (" + + (includeDirectRoles ? "authz.user_id=:uid " : "false ") + (includeIndirectRoles ? "or members.user_id=:uid) ": ") ") + + (!query.getRoles().isEmpty() ? " AND (authz.role_id IN (SELECT id FROM roles WHERE name IN (:roles))) " : "") + searchQuery + " ORDER BY " + query.getSortColumn().getSqlOrderBy(query) + " OFFSET (:offset)" + " LIMIT (:limit);", - namedParams, - getPaginatedGroupsExtractor(query)); - - return groups; + namedParams, getPaginatedGroupsExtractor(query)); } @Override diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/impl/SSHValidator.java b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/SSHValidator.java new file mode 100644 index 0000000000..08fe9b393a --- /dev/null +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/SSHValidator.java @@ -0,0 +1,337 @@ +package cz.metacentrum.perun.core.impl; + +import com.google.api.client.util.Base64; +import cz.metacentrum.perun.core.api.exceptions.InternalErrorException; +import cz.metacentrum.perun.core.api.exceptions.SSHKeyNotValidException; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.math.BigInteger; +import java.nio.file.Files; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.spec.DSAPublicKeySpec; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.InvalidParameterSpecException; +import java.security.spec.RSAPublicKeySpec; +import java.util.Arrays; +import java.util.List; + +/** + * Validates SSH keys using predefined rules and the `ssh-keygen` tool as a final check + * + * @author David Flor + */ +public class SSHValidator { + + private static final Logger log = LoggerFactory.getLogger(SSHValidator.class); + + private static final String SSH_RSA = "ssh-rsa"; + private static final String SSH_DSS = "ssh-dss"; + private static final String ECDSA_SHA2_NISTP256 = "ecdsa-sha2-nistp256"; + private static final String ECDSA_SHA2_NISTP384 = "ecdsa-sha2-nistp384"; + private static final String ECDSA_SHA2_NISTP521 = "ecdsa-sha2-nistp521"; + private static final String SSH_ED25519 = "ssh-ed25519"; + private static final String SSH_ED25519_CERT = "ssh-ed25519-cert-v01@openssh.com"; + private static final String SK_SSH_ED25519 = "sk-ssh-ed25519@openssh.com"; + private static final String SK_SSH_ED25519_CERT = "sk-ssh-ed25519-cert-v01@openssh.com"; + private static final String SK_ECDSA_SHA2_NISTP256 = "sk-ecdsa-sha2-nistp256@openssh.com"; + private static final String SSH_RSA_CERT = "ssh-rsa-cert-v01@openssh.com"; + private static final String SSH_DSS_CERT = "ssh-dss-cert-v01@openssh.com"; + private static final String ECDSA_SHA2_NISTP256_CERT = "ecdsa-sha2-nistp256-cert-v01@openssh.com"; + private static final String ECDSA_SHA2_NISTP384_CERT = "ecdsa-sha2-nistp384-cert-v01@openssh.com"; + private static final String ECDSA_SHA2_NISTP521_CERT = "ecdsa-sha2-nistp521-cert-v01@openssh.com"; + private static final String SK_ECDSA_SHA2_NISTP256_CERT = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"; + + private static final List ALLOWED_SSH_TYPES = List.of( + SSH_RSA, + SSH_DSS, + ECDSA_SHA2_NISTP256, + ECDSA_SHA2_NISTP384, + ECDSA_SHA2_NISTP521, + SSH_ED25519, + SSH_ED25519_CERT, + SK_SSH_ED25519, + SK_SSH_ED25519_CERT, + SK_ECDSA_SHA2_NISTP256, + SSH_RSA_CERT, + SSH_DSS_CERT, + ECDSA_SHA2_NISTP256_CERT, + ECDSA_SHA2_NISTP384_CERT, + ECDSA_SHA2_NISTP521_CERT, + SK_ECDSA_SHA2_NISTP256_CERT); + + // for now without cert variant + private static final List RSA_SSH_TYPES = List.of( + SSH_RSA); + + // for now without cert variant + private static final List ECDSA_SSH_TYPES = List.of( + ECDSA_SHA2_NISTP256, + ECDSA_SHA2_NISTP384, + ECDSA_SHA2_NISTP521, + SK_ECDSA_SHA2_NISTP256); + + // for now without cert variant + private static final List DSA_SSH_TYPES = List.of( + SSH_DSS); + + + /** + * Checks whether is the SSH key in the correct format. + * + * @param sshKey SSH key to be checked + * @throws SSHKeyNotValidException that is thrown whenever SSH key is not in correct format + */ + public static void validateSSH(String sshKey) throws SSHKeyNotValidException { + if (sshKey == null || sshKey.isEmpty()) { + throw new SSHKeyNotValidException("SSH key has to cannot be empty or null"); + } + try { + sshKey = removeSSHKeyCommandPrefix(sshKey); + int[] pos = {0}; + byte[] sshBase64KeyBytes; + + String[] sshKeyParts = sshKey.split(" "); + if (sshKeyParts.length < 2) { + throw new SSHKeyNotValidException("SSH public key has to consists at least from the key type and the Base64 encoded public key."); + } + + String sshKeyType = sshKeyParts[0]; + if (!ALLOWED_SSH_TYPES.contains(sshKeyType)) { + throw new SSHKeyNotValidException("The " + sshKeyType + " key type is not allowed. Allowed types are: " + ALLOWED_SSH_TYPES + "."); + } + + try { + sshBase64KeyBytes = Base64.decodeBase64(sshKeyParts[1]); + } catch (Exception exception) { + throw new SSHKeyNotValidException("Provided Base64 encoded public key is not valid."); + } + + String sshBase64KeyType = decodeType(sshBase64KeyBytes, pos); + if (!sshBase64KeyType.equals(sshKeyType)) { + throw new SSHKeyNotValidException("SSH types are not same. Type defined before the Base64 is: " + sshKeyType + " and type inside the Base64 is: " + sshBase64KeyType + "."); + } + + try { + if (RSA_SSH_TYPES.contains(sshKeyType)) { + decodeRSA(sshBase64KeyBytes, pos); + } else if (DSA_SSH_TYPES.contains(sshKeyType)) { + decodeDSA(sshBase64KeyBytes, pos); + } else if (ECDSA_SSH_TYPES.contains(sshKeyType)) { + decodeEcdsa(sshBase64KeyBytes, pos); + } + } catch (Exception ex) { + throw new SSHKeyNotValidException("Provided Base64 encoded public key is not valid."); + } + } catch (Exception e) { + throw new SSHKeyNotValidException("Invalid SSH key format: " + e.getMessage()); + } + // check one more time with ssh-keygen for edge cases + runSshKeygen(sshKey); + } + + /** + * Validates ssh public key using the ssh-keygen tool + * + * @param sshKey ssh public key to verify + * @throws SSHKeyNotValidException when validation fails + */ + private static void runSshKeygen(String sshKey) throws SSHKeyNotValidException { + File tempSSH = null; + try { + tempSSH = File.createTempFile("perunSSHAttr", ".txt"); + + try (BufferedWriter bw = new BufferedWriter(new FileWriter(tempSSH))) { + bw.write(sshKey); + } + ProcessBuilder pb = new ProcessBuilder("ssh-keygen", "-l", "-f", tempSSH.getAbsolutePath()); + Process process = pb.start(); + + // String result = new String(process.getInputStream().readAllBytes()); + String error = new String(process.getErrorStream().readAllBytes()); + + int returnCode = process.waitFor(); + if (returnCode != 0) { + log.error("SSH validation error: " + error + " for key: " + sshKey + " with error code: " + returnCode); + if (returnCode == 255) { + throw new SSHKeyNotValidException("Provided SSH key is not valid"); + } + throw new SSHKeyNotValidException("SSH validation failed with: " + error); + } + } catch (IOException | InterruptedException ex) { + throw new InternalErrorException("File error while verifying ssh key"); + } finally { + try { + if (tempSSH != null) Files.deleteIfExists(tempSSH.toPath()); + } catch (IOException ex) { + log.error("Failed to remove file: " + tempSSH.getAbsolutePath() + " after verifying ssh key"); + throw new InternalErrorException("Couldn't delete files after verifying ssh key"); + } + } + } + + /** + * Removes any potential command prefix before the ssh key + * + * @param sshKey raw ssh key value from the attribute + * @return SSH key without the command prefix + */ + private static String removeSSHKeyCommandPrefix(String sshKey) { + // entries in authorized_keys are of this format (from man page): + // "Public keys consist of the following space-separated fields: options, keytype, base64-encoded key, comment. + // The options field is optional." + + // split on spaces outside of quotes + String[] sshKeyParts = sshKey.split(" (?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"); + + // check whether key has options, cut them if so + if (!ALLOWED_SSH_TYPES.contains(sshKeyParts[0])) { + String[] keyPartsWithoutPrefix = Arrays.copyOfRange(sshKeyParts, 1, sshKeyParts.length); + return String.join(" ", keyPartsWithoutPrefix); + } + return sshKey; + + } + + /** + * Checks whether is the key in the correct ecdsa format. + * + * @param bytes Data of SSH key encoded in Base64 + * @param pos Position in the 'bytes' + * @throws NoSuchAlgorithmException Should never occur since hardcoded value is used + * @throws InvalidKeySpecException Thrown if the used algorithm does not match the EC specification + */ + private static void decodeEcdsa(byte[] bytes, int[] pos) throws NoSuchAlgorithmException, InvalidKeySpecException { + // Based on RFC 5656, section 3.1 (https://tools.ietf.org/html/rfc5656#section-3.1) + String identifier = decodeType(bytes, pos); + BigInteger publicKey = decodeBigInt(bytes, pos); + ECPoint ecPoint = getECPoint(publicKey, identifier); + ECParameterSpec ecParameterSpec = getECParameterSpec(identifier); + ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecParameterSpec); + KeyFactory.getInstance("EC").generatePublic(spec); + } + + /** + * Checks whether is the key in the correct dsa format. + * + * @param bytes Data of SSH key encoded in Base64 + * @param pos Position in the 'bytes' + * @throws NoSuchAlgorithmException Should never occur since hardcoded value is used + * @throws InvalidKeySpecException Thrown if the used algorithm does not match the DSA specification + */ + private static void decodeDSA(byte[] bytes, int[] pos) throws NoSuchAlgorithmException, InvalidKeySpecException { + BigInteger p = decodeBigInt(bytes, pos); + BigInteger q = decodeBigInt(bytes, pos); + BigInteger g = decodeBigInt(bytes, pos); + BigInteger y = decodeBigInt(bytes, pos); + DSAPublicKeySpec spec = new DSAPublicKeySpec(y, p, q, g); + KeyFactory.getInstance("DSA").generatePublic(spec); + } + + /** + * Checks whether is the key in the correct rsa format. + * + * @param bytes Data of SSH key encoded in Base64 + * @param pos Position in the 'bytes' + * @throws NoSuchAlgorithmException Should never occur since hardcoded value is used + * @throws InvalidKeySpecException Thrown if the used algorithm does not match the RSA specification + */ + private static void decodeRSA(byte[] bytes, int[] pos) throws NoSuchAlgorithmException, InvalidKeySpecException { + BigInteger exponent = decodeBigInt(bytes, pos); + BigInteger modulus = decodeBigInt(bytes, pos); + RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent); + KeyFactory.getInstance("RSA").generatePublic(spec); + } + + /** + * Provides means to get from a parsed Q value to the X and Y point values. + * that can be used to create and ECPoint compatible with ECPublicKeySpec. + * + * @param q According to RFC 5656: + * "Q is the public key encoded from an elliptic curve point into an octet string" + * @param identifier According to RFC 5656: + * "The string [identifier] is the identifier of the elliptic curve domain parameters." + * @return An ECPoint suitable for creating a JCE ECPublicKeySpec. + */ + private static ECPoint getECPoint(BigInteger q, String identifier) { + String name = identifier.replace("nist", "sec") + "r1"; + ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name); + org.bouncycastle.math.ec.ECPoint point = ecSpec.getCurve().decodePoint(q.toByteArray()); + BigInteger x = point.getAffineXCoord().toBigInteger(); + BigInteger y = point.getAffineYCoord().toBigInteger(); + return new ECPoint(x, y); + } + + /** + * Gets the curve parameters for the given key type identifier. + * + * @param identifier According to RFC 5656: + * "The string [identifier] is the identifier of the elliptic curve domain parameters." + * @return An ECParameterSpec suitable for creating a JCE ECPublicKeySpec. + */ + private static ECParameterSpec getECParameterSpec(String identifier) { + try { + // http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269#SupportedCurves(ECDSAandECGOST)-NIST(aliasesforSECcurves) + String name = identifier.replace("nist", "sec") + "r1"; + AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC"); + parameters.init(new ECGenParameterSpec(name)); + return parameters.getParameterSpec(ECParameterSpec.class); + } catch (InvalidParameterSpecException | NoSuchAlgorithmException e) { + throw new IllegalArgumentException("Unable to parse curve parameters: ", e); + } + } + + /** + * Decodes type of SSh key encoded in provided data + * + * @param bytes Data of SSH key encoded in Base64 + * @param pos Position in the 'bytes' + * @return Type of SSH key + */ + private static String decodeType(byte[] bytes, int[] pos) { + int len = decodeInt(bytes, pos); + String type = new String(bytes, pos[0], len); + pos[0] += len; + return type; + } + + /** + * Decodes integer part encoded in provided data. Usually used when validating concrete SSH algorithm. + * + * @param bytes Data of SSH key encoded in Base64 + * @param pos Position in the 'bytes' + * @return Integer part of SSH key + */ + private static int decodeInt(byte[] bytes, int[] pos) { + return ((bytes[pos[0]++] & 0xFF) << 24) | ((bytes[pos[0]++] & 0xFF) << 16) + | ((bytes[pos[0]++] & 0xFF) << 8) | (bytes[pos[0]++] & 0xFF); + } + + /** + * Decodes big integer part encoded in provided data. Usually used when validating concrete SSH algorithm. + * + * @param bytes Data of SSH key encoded in Base64 + * @param pos Position in the 'bytes' + * @return Big integer part of SSH key + */ + private static BigInteger decodeBigInt(byte[] bytes, int[] pos) { + int len = decodeInt(bytes, pos); + byte[] bigIntBytes = new byte[len]; + System.arraycopy(bytes, pos[0], bigIntBytes, 0, len); + pos[0] += len; + return new BigInteger(bigIntBytes); + } + +} diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/impl/Utils.java b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/Utils.java index 9f6e74576f..2ca0a6bfee 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/impl/Utils.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/Utils.java @@ -29,6 +29,7 @@ import cz.metacentrum.perun.core.api.exceptions.ParseUserNameException; import cz.metacentrum.perun.core.api.exceptions.ParserException; import cz.metacentrum.perun.core.api.exceptions.PrivilegeException; +import cz.metacentrum.perun.core.api.exceptions.SSHKeyNotValidException; import cz.metacentrum.perun.core.api.exceptions.SpaceNotAllowedException; import cz.metacentrum.perun.core.api.exceptions.SpecialCharsNotAllowedException; import cz.metacentrum.perun.core.api.exceptions.UserNotExistsException; @@ -37,6 +38,7 @@ import cz.metacentrum.perun.core.bl.PerunBl; import cz.metacentrum.perun.core.blImpl.ModulesUtilsBlImpl; import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jdbc.core.JdbcTemplate; @@ -216,7 +218,7 @@ public static List extractAdditionalUserExtSources(PerunSessi // Entry contains extSourceName|extSourceType|extLogin;uesAttribute=value1,value2[|LoA] String[] userExtSourceRaw = subjectFromExtSource.get(attrName).split("\\|"); - log.debug("Processing additionalUserExtSource {}", subjectFromExtSource.get(attrName)); + log.trace("Processing additionalUserExtSource {}", subjectFromExtSource.get(attrName)); // Check if the array has at least 3 parts, this is protection against outOfBoundException if(userExtSourceRaw.length < 3) { @@ -1274,7 +1276,7 @@ public static void sendAccountActivationConfirmationEmail(User user, String emai String defaultSubject = "["+instanceName+"] Account activation in namespace: "+namespace; String defaultText = "Dear "+user.getDisplayName()+",\n\nyour account in namespace \""+namespace+"\" was successfully activated."+ "\n\nThis message is automatically sent to all your email addresses registered in "+instanceName+" in order to prevent malicious account activation without your knowledge.\n\n" + - "If you didn't request / perform account activation, please notify your administrators and support at "+BeansUtils.getCoreConfig().getMailchangeBackupFrom()+" to resolve this security issue.\n\n" + + "If you didn't request / perform account activation, please notify your administrators and support at "+(StringUtils.isNotEmpty(BeansUtils.getCoreConfig().getMailchangeReplyTo())? BeansUtils.getCoreConfig().getMailchangeReplyTo() : BeansUtils.getCoreConfig().getMailchangeBackupFrom())+" to resolve this security issue.\n\n" + "Message is automatically generated." + "\n----------------------------------------------------------------" + "\nPerun - Identity & Access Management System"; @@ -1310,7 +1312,7 @@ public static void sendPasswordResetConfirmationEmail(User user, String email, S String defaultSubject = "["+instanceName+"] Password reset in namespace: "+namespace; String defaultText = "Dear "+user.getDisplayName()+",\n\nyour password in namespace \""+namespace+"\" was successfully reset."+ "\n\nThis message is automatically sent to all your email addresses registered in "+instanceName+" in order to prevent malicious password reset without your knowledge.\n\n" + - "If you didn't request / perform password reset, please notify your administrators and support at "+BeansUtils.getCoreConfig().getMailchangeBackupFrom()+" to resolve this security issue.\n\n" + + "If you didn't request / perform password reset, please notify your administrators and support at "+ (StringUtils.isNotEmpty(BeansUtils.getCoreConfig().getMailchangeReplyTo()) ? BeansUtils.getCoreConfig().getMailchangeReplyTo() : BeansUtils.getCoreConfig().getMailchangeBackupFrom())+" to resolve this security issue.\n\n" + "Message is automatically generated." + "\n----------------------------------------------------------------" + "\nPerun - Identity & Access Management System"; @@ -1407,6 +1409,9 @@ private static void sendEmail(String subjectOfEmail, String bodyOfEmail, String SimpleMailMessage message = new SimpleMailMessage(); message.setTo(email); message.setFrom(BeansUtils.getCoreConfig().getMailchangeBackupFrom()); + if (StringUtils.isNotEmpty(BeansUtils.getCoreConfig().getMailchangeReplyTo())) { + message.setReplyTo(BeansUtils.getCoreConfig().getMailchangeReplyTo()); + } // set subject and body message.setSubject(subjectOfEmail); @@ -1979,6 +1984,10 @@ public static void validateFullGroupName(String name) { } } + public static void validateSSHPublicKey(String sshKey) throws SSHKeyNotValidException { + SSHValidator.validateSSH(sshKey); + } + /** * Validates group name. diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/impl/modules/attributes/urn_perun_user_attribute_def_def_sshPublicKey.java b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/modules/attributes/urn_perun_user_attribute_def_def_sshPublicKey.java index 61ba9b5688..cac5cf2a9c 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/impl/modules/attributes/urn_perun_user_attribute_def_def_sshPublicKey.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/modules/attributes/urn_perun_user_attribute_def_def_sshPublicKey.java @@ -1,31 +1,16 @@ package cz.metacentrum.perun.core.impl.modules.attributes; -import com.google.api.client.util.Base64; import cz.metacentrum.perun.core.api.Attribute; import cz.metacentrum.perun.core.api.AttributeDefinition; import cz.metacentrum.perun.core.api.AttributesManager; import cz.metacentrum.perun.core.api.User; import cz.metacentrum.perun.core.api.exceptions.WrongAttributeValueException; import cz.metacentrum.perun.core.impl.PerunSessionImpl; +import cz.metacentrum.perun.core.impl.Utils; import cz.metacentrum.perun.core.implApi.modules.attributes.UserAttributesModuleAbstract; import cz.metacentrum.perun.core.implApi.modules.attributes.UserAttributesModuleImplApi; -import org.bouncycastle.jce.ECNamedCurveTable; -import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; -import java.math.BigInteger; -import java.security.AlgorithmParameters; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.spec.DSAPublicKeySpec; -import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; -import java.security.spec.RSAPublicKeySpec; -import java.security.spec.ECPublicKeySpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.InvalidParameterSpecException; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** @@ -33,56 +18,6 @@ */ public class urn_perun_user_attribute_def_def_sshPublicKey extends UserAttributesModuleAbstract implements UserAttributesModuleImplApi { - private static final String SSH_RSA = "ssh-rsa"; - private static final String SSH_DSS = "ssh-dss"; - private static final String ECDSA_SHA2_NISTP256 = "ecdsa-sha2-nistp256"; - private static final String ECDSA_SHA2_NISTP384 = "ecdsa-sha2-nistp384"; - private static final String ECDSA_SHA2_NISTP521 = "ecdsa-sha2-nistp521"; - private static final String SSH_ED25519 = "ssh-ed25519"; - private static final String SSH_ED25519_CERT = "ssh-ed25519-cert-v01@openssh.com"; - private static final String SK_SSH_ED25519 = "sk-ssh-ed25519@openssh.com"; - private static final String SK_SSH_ED25519_CERT = "sk-ssh-ed25519-cert-v01@openssh.com"; - private static final String SK_ECDSA_SHA2_NISTP256 = "sk-ecdsa-sha2-nistp256@openssh.com"; - private static final String SSH_RSA_CERT = "ssh-rsa-cert-v01@openssh.com"; - private static final String SSH_DSS_CERT = "ssh-dss-cert-v01@openssh.com"; - private static final String ECDSA_SHA2_NISTP256_CERT = "ecdsa-sha2-nistp256-cert-v01@openssh.com"; - private static final String ECDSA_SHA2_NISTP384_CERT = "ecdsa-sha2-nistp384-cert-v01@openssh.com"; - private static final String ECDSA_SHA2_NISTP521_CERT = "ecdsa-sha2-nistp521-cert-v01@openssh.com"; - private static final String SK_ECDSA_SHA2_NISTP256_CERT = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"; - - private static final List ALLOWED_SSH_TYPES = List.of( - SSH_RSA, - SSH_DSS, - ECDSA_SHA2_NISTP256, - ECDSA_SHA2_NISTP384, - ECDSA_SHA2_NISTP521, - SSH_ED25519, - SSH_ED25519_CERT, - SK_SSH_ED25519, - SK_SSH_ED25519_CERT, - SK_ECDSA_SHA2_NISTP256, - SSH_RSA_CERT, - SSH_DSS_CERT, - ECDSA_SHA2_NISTP256_CERT, - ECDSA_SHA2_NISTP384_CERT, - ECDSA_SHA2_NISTP521_CERT, - SK_ECDSA_SHA2_NISTP256_CERT); - - // for now without cert variant - private static final List RSA_SSH_TYPES = List.of( - SSH_RSA); - - // for now without cert variant - private static final List ECDSA_SSH_TYPES = List.of( - ECDSA_SHA2_NISTP256, - ECDSA_SHA2_NISTP384, - ECDSA_SHA2_NISTP521, - SK_ECDSA_SHA2_NISTP256); - - // for now without cert variant - private static final List DSA_SSH_TYPES = List.of( - SSH_DSS); - @Override public void checkAttributeSyntax(PerunSessionImpl perunSession, User user, Attribute attribute) throws WrongAttributeValueException { //Null in value is ok here @@ -95,8 +30,7 @@ public void checkAttributeSyntax(PerunSessionImpl perunSession, User user, Attri if (sshKey.contains("\n")) throw new WrongAttributeValueException(attribute, user, "One of keys in attribute contains new line character. New line character is not allowed here."); try { - sshKey = removeSSHKeyCommandPrefix(sshKey); - validateSSH(sshKey); + Utils.validateSSHPublicKey(sshKey); } catch (Exception e) { throw new WrongAttributeValueException(attribute, user, "Invalid SSH key format: " + e.getMessage()); } @@ -104,202 +38,6 @@ public void checkAttributeSyntax(PerunSessionImpl perunSession, User user, Attri } } - /** - * Removes any potential command prefix before the ssh key - * - * @param sshKey raw ssh key value from the attribute - * @return SSH key without the command prefix - */ - private String removeSSHKeyCommandPrefix(String sshKey) { - // entries in authorized_keys are of this format (from man page): - // "Public keys consist of the following space-separated fields: options, keytype, base64-encoded key, comment. - // The options field is optional." - - // split on spaces outside of quotes - String[] sshKeyParts = sshKey.split(" (?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)"); - - // check whether key has options, cut them if so - if (!ALLOWED_SSH_TYPES.contains(sshKeyParts[0])) { - String[] keyPartsWithoutPrefix = Arrays.copyOfRange(sshKeyParts, 1, sshKeyParts.length); - return String.join(" ", keyPartsWithoutPrefix); - } - return sshKey; - - } - - /** - * Checks whether is the SSH key in the correct format. - * - * @param sshKey SSH key to be checked - * @throws Exception that is thrown whenever SSH key is not in correct format - */ - private void validateSSH(String sshKey) throws Exception { - int[] pos = {0}; - byte[] sshBase64KeyBytes; - - String[] sshKeyParts = sshKey.split(" "); - if (sshKeyParts.length < 2) { - throw new IllegalArgumentException("SSH public key has to consists at least from the key type and the Base64 encoded public key."); - } - - String sshKeyType = sshKeyParts[0]; - if (!ALLOWED_SSH_TYPES.contains(sshKeyType)) { - throw new IllegalArgumentException("The " + sshKeyType + " key type is not allowed. Allowed types are: " + ALLOWED_SSH_TYPES + "."); - } - - try { - sshBase64KeyBytes = Base64.decodeBase64(sshKeyParts[1]); - } catch (Exception exception) { - throw new IllegalArgumentException("Provided Base64 encoded public key is not valid."); - } - - String sshBase64KeyType = decodeType(sshBase64KeyBytes, pos); - if (!sshBase64KeyType.equals(sshKeyType)) { - throw new IllegalArgumentException("SSH types are not same. Type defined before the Base64 is: " + sshKeyType + " and type inside the Base64 is: " + sshBase64KeyType + "."); - } - - try { - if (RSA_SSH_TYPES.contains(sshKeyType)) { - decodeRSA(sshBase64KeyBytes, pos); - } else if (DSA_SSH_TYPES.contains(sshKeyType)) { - decodeDSA(sshBase64KeyBytes, pos); - } else if (ECDSA_SSH_TYPES.contains(sshKeyType)) { - decodeEcdsa(sshBase64KeyBytes, pos); - } - } catch (Exception ex) { - throw new IllegalArgumentException("Provided Base64 encoded public key is not valid."); - } - - } - - /** - * Checks whether is the key in the correct ecdsa format. - * - * @param bytes Data of SSH key encoded in Base64 - * @param pos Position in the 'bytes' - * @throws NoSuchAlgorithmException Should never occur since hardcoded value is used - * @throws InvalidKeySpecException Thrown if the used algorithm does not match the EC specification - */ - private void decodeEcdsa(byte[] bytes, int[] pos) throws NoSuchAlgorithmException, InvalidKeySpecException { - // Based on RFC 5656, section 3.1 (https://tools.ietf.org/html/rfc5656#section-3.1) - String identifier = decodeType(bytes, pos); - BigInteger publicKey = decodeBigInt(bytes, pos); - ECPoint ecPoint = getECPoint(publicKey, identifier); - ECParameterSpec ecParameterSpec = getECParameterSpec(identifier); - ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecParameterSpec); - KeyFactory.getInstance("EC").generatePublic(spec); - } - - /** - * Checks whether is the key in the correct dsa format. - * - * @param bytes Data of SSH key encoded in Base64 - * @param pos Position in the 'bytes' - * @throws NoSuchAlgorithmException Should never occur since hardcoded value is used - * @throws InvalidKeySpecException Thrown if the used algorithm does not match the DSA specification - */ - private void decodeDSA(byte[] bytes, int[] pos) throws NoSuchAlgorithmException, InvalidKeySpecException { - BigInteger p = decodeBigInt(bytes, pos); - BigInteger q = decodeBigInt(bytes, pos); - BigInteger g = decodeBigInt(bytes, pos); - BigInteger y = decodeBigInt(bytes, pos); - DSAPublicKeySpec spec = new DSAPublicKeySpec(y, p, q, g); - KeyFactory.getInstance("DSA").generatePublic(spec); - } - - /** - * Checks whether is the key in the correct rsa format. - * - * @param bytes Data of SSH key encoded in Base64 - * @param pos Position in the 'bytes' - * @throws NoSuchAlgorithmException Should never occur since hardcoded value is used - * @throws InvalidKeySpecException Thrown if the used algorithm does not match the RSA specification - */ - private void decodeRSA(byte[] bytes, int[] pos) throws NoSuchAlgorithmException, InvalidKeySpecException { - BigInteger exponent = decodeBigInt(bytes, pos); - BigInteger modulus = decodeBigInt(bytes, pos); - RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent); - KeyFactory.getInstance("RSA").generatePublic(spec); - } - - /** - * Provides means to get from a parsed Q value to the X and Y point values. - * that can be used to create and ECPoint compatible with ECPublicKeySpec. - * - * @param q According to RFC 5656: - * "Q is the public key encoded from an elliptic curve point into an octet string" - * @param identifier According to RFC 5656: - * "The string [identifier] is the identifier of the elliptic curve domain parameters." - * @return An ECPoint suitable for creating a JCE ECPublicKeySpec. - */ - private ECPoint getECPoint(BigInteger q, String identifier) { - String name = identifier.replace("nist", "sec") + "r1"; - ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name); - org.bouncycastle.math.ec.ECPoint point = ecSpec.getCurve().decodePoint(q.toByteArray()); - BigInteger x = point.getAffineXCoord().toBigInteger(); - BigInteger y = point.getAffineYCoord().toBigInteger(); - return new ECPoint(x, y); - } - - /** - * Gets the curve parameters for the given key type identifier. - * - * @param identifier According to RFC 5656: - * "The string [identifier] is the identifier of the elliptic curve domain parameters." - * @return An ECParameterSpec suitable for creating a JCE ECPublicKeySpec. - */ - private ECParameterSpec getECParameterSpec(String identifier) { - try { - // http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269#SupportedCurves(ECDSAandECGOST)-NIST(aliasesforSECcurves) - String name = identifier.replace("nist", "sec") + "r1"; - AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC"); - parameters.init(new ECGenParameterSpec(name)); - return parameters.getParameterSpec(ECParameterSpec.class); - } catch (InvalidParameterSpecException | NoSuchAlgorithmException e) { - throw new IllegalArgumentException("Unable to parse curve parameters: ", e); - } - } - - /** - * Decodes type of SSh key encoded in provided data - * - * @param bytes Data of SSH key encoded in Base64 - * @param pos Position in the 'bytes' - * @return Type of SSH key - */ - private String decodeType(byte[] bytes, int[] pos) { - int len = decodeInt(bytes, pos); - String type = new String(bytes, pos[0], len); - pos[0] += len; - return type; - } - - /** - * Decodes integer part encoded in provided data. Usually used when validating concrete SSH algorithm. - * - * @param bytes Data of SSH key encoded in Base64 - * @param pos Position in the 'bytes' - * @return Integer part of SSH key - */ - private int decodeInt(byte[] bytes, int[] pos) { - return ((bytes[pos[0]++] & 0xFF) << 24) | ((bytes[pos[0]++] & 0xFF) << 16) - | ((bytes[pos[0]++] & 0xFF) << 8) | (bytes[pos[0]++] & 0xFF); - } - - /** - * Decodes big integer part encoded in provided data. Usually used when validating concrete SSH algorithm. - * - * @param bytes Data of SSH key encoded in Base64 - * @param pos Position in the 'bytes' - * @return Big integer part of SSH key - */ - private BigInteger decodeBigInt(byte[] bytes, int[] pos) { - int len = decodeInt(bytes, pos); - byte[] bigIntBytes = new byte[len]; - System.arraycopy(bytes, pos[0], bigIntBytes, 0, len); - pos[0] += len; - return new BigInteger(bigIntBytes); - } @Override public AttributeDefinition getAttributeDefinition() { diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/impl/modules/attributes/urn_perun_user_facility_attribute_def_virt_enabledO365MailForward.java b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/modules/attributes/urn_perun_user_facility_attribute_def_virt_enabledO365MailForward.java index d32e76c3eb..a3b379e432 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/impl/modules/attributes/urn_perun_user_facility_attribute_def_virt_enabledO365MailForward.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/impl/modules/attributes/urn_perun_user_facility_attribute_def_virt_enabledO365MailForward.java @@ -22,8 +22,8 @@ */ public class urn_perun_user_facility_attribute_def_virt_enabledO365MailForward extends UserFacilityVirtualAttributesModuleAbstract implements UserFacilityVirtualAttributesModuleImplApi { - private final static String A_U_F_DISABLE0365MAILFORWARD = AttributesManager.NS_USER_FACILITY_ATTR_VIRT + ":disableO365MailForward"; - private final static String A_U_F_O365MAILFORWARD = AttributesManager.NS_USER_FACILITY_ATTR_VIRT + ":o365MailForward"; + private final static String A_U_F_DISABLE0365MAILFORWARD = AttributesManager.NS_USER_FACILITY_ATTR_DEF + ":disableO365MailForward"; + private final static String A_U_F_O365MAILFORWARD = AttributesManager.NS_USER_FACILITY_ATTR_DEF + ":o365MailForward"; @Override public Attribute getAttributeValue(PerunSessionImpl sess, User user, Facility facility, AttributeDefinition attributeDefinition) { diff --git a/perun-core/src/main/java/cz/metacentrum/perun/core/implApi/AuthzResolverImplApi.java b/perun-core/src/main/java/cz/metacentrum/perun/core/implApi/AuthzResolverImplApi.java index 679f4cbf49..a1edc52ba3 100644 --- a/perun-core/src/main/java/cz/metacentrum/perun/core/implApi/AuthzResolverImplApi.java +++ b/perun-core/src/main/java/cz/metacentrum/perun/core/implApi/AuthzResolverImplApi.java @@ -3,9 +3,9 @@ import cz.metacentrum.perun.core.api.Facility; import cz.metacentrum.perun.core.api.Group; import cz.metacentrum.perun.core.api.Member; -import cz.metacentrum.perun.core.api.PerunPolicy; import cz.metacentrum.perun.core.api.PerunSession; import cz.metacentrum.perun.core.api.Resource; +import cz.metacentrum.perun.core.api.RoleAssignmentType; import cz.metacentrum.perun.core.api.SecurityTeam; import cz.metacentrum.perun.core.api.Service; import cz.metacentrum.perun.core.api.User; @@ -632,6 +632,18 @@ public interface AuthzResolverImplApi { */ Set getGroupsWhereUserIsInRoles(User user, List roles); + /** + * Check if the given group passes the user's roles filter. + * + * @param sess session + * @param user user + * @param group group + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return list of groups + */ + boolean groupMatchesUserRolesFilter(PerunSession sess, User user, Group group, List roles, List types); + /** * Get all Members where the given user has set one of the given roles * or the given user is a member of an authorized group with such roles. diff --git a/perun-core/src/test/java/cz/metacentrum/perun/core/api/AuthzResolverIntegrationTest.java b/perun-core/src/test/java/cz/metacentrum/perun/core/api/AuthzResolverIntegrationTest.java index ae519a8beb..b3cd3484a0 100644 --- a/perun-core/src/test/java/cz/metacentrum/perun/core/api/AuthzResolverIntegrationTest.java +++ b/perun-core/src/test/java/cz/metacentrum/perun/core/api/AuthzResolverIntegrationTest.java @@ -1504,6 +1504,45 @@ public void getGroupsWhereUserIsInRoles() throws Exception { assertTrue(result.contains(testGroup2)); } + @Test + public void groupMatchesUserRolesFilter() throws Exception { + System.out.println(CLASS_NAME + "groupMatchesUserRolesFilter"); + + final Vo testVo = perun.getVosManager().createVo(sess, new Vo(0,"testvo1","testvo1")); + final Group testGroup = perun.getGroupsManager().createGroup(sess, testVo, new Group("testGroup", "testg")); + final Group testGroup2 = perun.getGroupsManager().createGroup(sess, testVo, new Group("testGroup2", "testg2")); + final Group testGroup4 = perun.getGroupsManager().createGroup(sess, testVo, new Group("testGroup4", "testg4")); + + final Member testMember = createSomeMember(testVo); + final User testUser = perun.getUsersManagerBl().getUserByMember(sess, testMember); + perun.getGroupsManager().addMember(sess, testGroup, testMember); + + AuthzResolver.setRole(sess, testUser, testGroup2, Role.GROUPADMIN); + AuthzResolver.setRole(sess, testGroup, testGroup4, Role.GROUPOBSERVER); + + sess.getPerunPrincipal().setUser(testUser); + + List directRoles = perun.getGroupsManager().getAllGroups(sess, testVo); + directRoles.removeIf(group -> !AuthzResolverBlImpl.groupMatchesUserRolesFilter(sess, testUser, group, List.of(Role.GROUPADMIN), List.of(RoleAssignmentType.DIRECT))); + assertEquals(1, directRoles.size()); + assertTrue(directRoles.contains(testGroup2)); + + List indirectRoles = perun.getGroupsManager().getAllGroups(sess, testVo); + indirectRoles.removeIf(group -> !AuthzResolverBlImpl.groupMatchesUserRolesFilter(sess, testUser, group, List.of(Role.GROUPOBSERVER), List.of(RoleAssignmentType.INDIRECT))); + assertEquals(1, indirectRoles.size()); + assertTrue(indirectRoles.contains(testGroup4)); + + List allIndirectGroups = perun.getGroupsManager().getAllGroups(sess, testVo); + allIndirectGroups.removeIf(group -> !AuthzResolverBlImpl.groupMatchesUserRolesFilter(sess, testUser, group, new ArrayList<>(), List.of(RoleAssignmentType.INDIRECT))); + assertEquals(1, allIndirectGroups.size()); + assertTrue(allIndirectGroups.contains(testGroup4)); + + List allGroupAdmins = perun.getGroupsManager().getAllGroups(sess, testVo); + allGroupAdmins.removeIf(group -> !AuthzResolverBlImpl.groupMatchesUserRolesFilter(sess, testUser, group, List.of(Role.GROUPADMIN), new ArrayList<>())); + assertEquals(1, allGroupAdmins.size()); + assertTrue(allGroupAdmins.contains(testGroup2)); + } + @Test public void getGroupsWherePrincipalIsInRoles() throws Exception { System.out.println(CLASS_NAME + "getGroupsWherePrincipalIsInRoles"); diff --git a/perun-core/src/test/java/cz/metacentrum/perun/core/entry/GroupsManagerEntryIntegrationTest.java b/perun-core/src/test/java/cz/metacentrum/perun/core/entry/GroupsManagerEntryIntegrationTest.java index e82883c5cf..b57006a394 100644 --- a/perun-core/src/test/java/cz/metacentrum/perun/core/entry/GroupsManagerEntryIntegrationTest.java +++ b/perun-core/src/test/java/cz/metacentrum/perun/core/entry/GroupsManagerEntryIntegrationTest.java @@ -4,6 +4,7 @@ import cz.metacentrum.perun.core.api.Attribute; import cz.metacentrum.perun.core.api.AttributeDefinition; import cz.metacentrum.perun.core.api.AttributesManager; +import cz.metacentrum.perun.core.api.AuthzResolver; import cz.metacentrum.perun.core.api.BeansUtils; import cz.metacentrum.perun.core.api.Candidate; import cz.metacentrum.perun.core.api.ExtSource; @@ -23,6 +24,8 @@ import cz.metacentrum.perun.core.api.Resource; import cz.metacentrum.perun.core.api.RichGroup; import cz.metacentrum.perun.core.api.RichMember; +import cz.metacentrum.perun.core.api.Role; +import cz.metacentrum.perun.core.api.RoleAssignmentType; import cz.metacentrum.perun.core.api.SortingOrder; import cz.metacentrum.perun.core.api.Status; import cz.metacentrum.perun.core.api.User; @@ -6586,6 +6589,213 @@ public void getGroupsWhereUserIsActiveMemberInactiveInGroup() throws Exception { assertFalse(result.contains(group6)); //expired member } + @Test + public void getAllRichSubGroupsFilteredByRole() throws Exception { + System.out.println(CLASS_NAME + "getAllRichSubGroupsFilteredByRole"); + + vo = setUpVo(); + perun.getGroupsManager().createGroup(sess, vo, group); + perun.getGroupsManager().createGroup(sess, vo, group2); + perun.getGroupsManager().createGroup(sess, group2, group3); + perun.getGroupsManager().createGroup(sess, group2, group4); + perun.getGroupsManager().createGroup(sess, group2, group5); + + Member member = setUpMember(vo); + User user = perun.getUsersManagerBl().getUserByMember(sess, member); + perun.getGroupsManager().addMember(sess, group, member); + + AuthzResolver.setRole(sess, user, group3, Role.GROUPADMIN); + AuthzResolver.setRole(sess, group, group4, Role.GROUPOBSERVER); + + sess.getPerunPrincipal().setUser(user); + + List directRoles = groupsManager.getAllRichSubGroupsWithAttributesByNames(sess, group2, new ArrayList<>(), List.of(Role.GROUPADMIN), List.of(RoleAssignmentType.DIRECT)); + assertEquals(1, directRoles.size()); + assertEquals(group3.getId(), directRoles.get(0).getId()); + + List indirectRoles = groupsManager.getAllRichSubGroupsWithAttributesByNames(sess, group2, new ArrayList<>(), List.of(Role.GROUPOBSERVER), List.of(RoleAssignmentType.INDIRECT)); + assertEquals(1, indirectRoles.size()); + assertEquals(group4.getId(), indirectRoles.get(0).getId()); + + List allIndirectGroups = groupsManager.getAllRichSubGroupsWithAttributesByNames(sess, group2, new ArrayList<>(), new ArrayList<>(), List.of(RoleAssignmentType.INDIRECT)); + assertEquals(1, allIndirectGroups.size()); + assertEquals(group4.getId(), allIndirectGroups.get(0).getId()); + + List allGroupAdmins = groupsManager.getAllRichSubGroupsWithAttributesByNames(sess, group2, new ArrayList<>(), List.of(Role.GROUPADMIN), new ArrayList<>()); + assertEquals(1, allGroupAdmins.size()); + assertEquals(group3.getId(), allGroupAdmins.get(0).getId()); + } + + @Test + public void getAllRichGroupsFilteredByRole() throws Exception { + System.out.println(CLASS_NAME + "getAllRichGroupsFilteredByRole"); + + vo = setUpVo(); + perun.getGroupsManager().createGroup(sess, vo, group); + perun.getGroupsManager().createGroup(sess, vo, group2); + perun.getGroupsManager().createGroup(sess, vo, group3); + perun.getGroupsManager().createGroup(sess, vo, group4); + + Member member = setUpMember(vo); + User user = perun.getUsersManagerBl().getUserByMember(sess, member); + perun.getGroupsManager().addMember(sess, group, member); + + AuthzResolver.setRole(sess, user, group2, Role.GROUPADMIN); + AuthzResolver.setRole(sess, group, group3, Role.GROUPOBSERVER); + + sess.getPerunPrincipal().setUser(user); + + List directRoles = groupsManager.getAllRichGroupsWithAttributesByNames(sess, vo, new ArrayList<>(), List.of(Role.GROUPADMIN), List.of(RoleAssignmentType.DIRECT)); + assertEquals(1, directRoles.size()); + assertEquals(group2.getId(), directRoles.get(0).getId()); + + List indirectRoles = groupsManager.getAllRichGroupsWithAttributesByNames(sess, vo, new ArrayList<>(), List.of(Role.GROUPOBSERVER), List.of(RoleAssignmentType.INDIRECT)); + assertEquals(1, indirectRoles.size()); + assertEquals(group3.getId(), indirectRoles.get(0).getId()); + + List allIndirectGroups = groupsManager.getAllRichGroupsWithAttributesByNames(sess, vo, new ArrayList<>(), new ArrayList<>(), List.of(RoleAssignmentType.INDIRECT)); + assertEquals(1, allIndirectGroups.size()); + assertEquals(group3.getId(), allIndirectGroups.get(0).getId()); + + List allGroupAdmins = groupsManager.getAllRichGroupsWithAttributesByNames(sess, vo, new ArrayList<>(), List.of(Role.GROUPADMIN), new ArrayList<>()); + assertEquals(1, allGroupAdmins.size()); + assertEquals(group2.getId(), allGroupAdmins.get(0).getId()); + } + + @Test + public void getMemberRichGroupsFilteredByRole() throws Exception { + System.out.println(CLASS_NAME + "getMemberRichGroupsFilteredByRole"); + + vo = setUpVo(); + perun.getGroupsManager().createGroup(sess, vo, group); + perun.getGroupsManager().createGroup(sess, vo, group2); + perun.getGroupsManager().createGroup(sess, vo, group3); + perun.getGroupsManager().createGroup(sess, vo, group4); + + Member member = setUpMember(vo); + User user = perun.getUsersManagerBl().getUserByMember(sess, member); + perun.getGroupsManager().addMember(sess, group, member); + + AuthzResolver.setRole(sess, user, group2, Role.GROUPADMIN); + AuthzResolver.setRole(sess, group, group3, Role.GROUPOBSERVER); + + Member testMember = setUpMember(vo); + perun.getGroupsManager().addMember(sess, group2, testMember); + perun.getGroupsManager().addMember(sess, group3, testMember); + + sess.getPerunPrincipal().setUser(user); + + List directRoles = groupsManager.getMemberRichGroupsWithAttributesByNames(sess, testMember, new ArrayList<>(), List.of(Role.GROUPADMIN), List.of(RoleAssignmentType.DIRECT)); + assertEquals(1, directRoles.size()); + assertEquals(group2.getId(), directRoles.get(0).getId()); + + List indirectRoles = groupsManager.getMemberRichGroupsWithAttributesByNames(sess, testMember, new ArrayList<>(), List.of(Role.GROUPOBSERVER), List.of(RoleAssignmentType.INDIRECT)); + assertEquals(1, indirectRoles.size()); + assertEquals(group3.getId(), indirectRoles.get(0).getId()); + + List allIndirectGroups = groupsManager.getMemberRichGroupsWithAttributesByNames(sess, testMember, new ArrayList<>(), new ArrayList<>(), List.of(RoleAssignmentType.INDIRECT)); + assertEquals(1, allIndirectGroups.size()); + assertEquals(group3.getId(), allIndirectGroups.get(0).getId()); + + List allGroupAdmins = groupsManager.getMemberRichGroupsWithAttributesByNames(sess, testMember, new ArrayList<>(), List.of(Role.GROUPADMIN), new ArrayList<>()); + assertEquals(1, allGroupAdmins.size()); + assertEquals(group2.getId(), allGroupAdmins.get(0).getId()); + } + + @Test + public void getGroupsPageByRoles() throws Exception { + System.out.println(CLASS_NAME + "getGroupsPageByRoles"); + + vo = setUpVo(); + perun.getGroupsManager().createGroup(sess, vo, group); + perun.getGroupsManager().createGroup(sess, vo, group2); + perun.getGroupsManager().createGroup(sess, vo, group3); + + Member member = setUpMember(vo); + User user = perun.getUsersManagerBl().getUserByMember(sess, member); + perun.getGroupsManager().addMember(sess, group, member); + + AuthzResolver.setRole(sess, user, group2, Role.GROUPADMIN); + AuthzResolver.setRole(sess, group, group3, Role.GROUPOBSERVER); + + sess.getPerunPrincipal().setUser(user); + + GroupsPageQuery query1 = new GroupsPageQuery(10, 0, SortingOrder.ASCENDING, GroupsOrderColumn.ID, List.of(Role.GROUPADMIN), List.of(RoleAssignmentType.DIRECT)); + Paginated directRoles = groupsManager.getGroupsPage(sess, vo, query1, List.of()); + assertNotNull(directRoles); + assertEquals(1, directRoles.getData().size()); + assertEquals(group2.getId(), directRoles.getData().get(0).getId()); + + GroupsPageQuery query2 = new GroupsPageQuery(10, 0, SortingOrder.ASCENDING, GroupsOrderColumn.ID, List.of(Role.GROUPOBSERVER), List.of(RoleAssignmentType.INDIRECT)); + Paginated indirectRoles = groupsManager.getGroupsPage(sess, vo, query2, List.of()); + assertNotNull(indirectRoles); + assertEquals(1, indirectRoles.getData().size()); + assertEquals(group3.getId(), indirectRoles.getData().get(0).getId()); + + GroupsPageQuery query3 = new GroupsPageQuery(10, 0, SortingOrder.ASCENDING, GroupsOrderColumn.ID, new ArrayList<>(), List.of(RoleAssignmentType.INDIRECT)); + Paginated allIndirectGroups = groupsManager.getGroupsPage(sess, vo, query3, List.of()); + assertNotNull(allIndirectGroups); + assertEquals(1, allIndirectGroups.getData().size()); + assertEquals(group3.getId(), allIndirectGroups.getData().get(0).getId()); + + GroupsPageQuery query4 = new GroupsPageQuery(10, 0, SortingOrder.ASCENDING, GroupsOrderColumn.ID, List.of(Role.GROUPADMIN), new ArrayList<>()); + Paginated allGroupAdmins = groupsManager.getGroupsPage(sess, vo, query4, List.of()); + assertNotNull(allGroupAdmins); + assertEquals(1, allGroupAdmins.getData().size()); + assertEquals(group2.getId(), allGroupAdmins.getData().get(0).getId()); + } + + @Test + public void getGroupsPageByRolesWithMemberId() throws Exception { + System.out.println(CLASS_NAME + "getGroupsPageByRoles"); + + vo = setUpVo(); + perun.getGroupsManager().createGroup(sess, vo, group); + perun.getGroupsManager().createGroup(sess, vo, group2); + perun.getGroupsManager().createGroup(sess, vo, group21); + perun.getGroupsManager().createGroup(sess, vo, group3); + perun.getGroupsManager().createGroup(sess, vo, group4); + + Member testMember = setUpMember(vo); + perun.getGroupsManager().addMember(sess, group2, testMember); + perun.getGroupsManager().addMember(sess, group3, testMember); + + Member member = setUpMember(vo); + User user = perun.getUsersManagerBl().getUserByMember(sess, member); + perun.getGroupsManager().addMember(sess, group, member); + + AuthzResolver.setRole(sess, user, group2, Role.GROUPADMIN); + AuthzResolver.setRole(sess, user, group21, Role.GROUPADMIN); + AuthzResolver.setRole(sess, group, group3, Role.GROUPOBSERVER); + AuthzResolver.setRole(sess, group, group4, Role.GROUPOBSERVER); + + sess.getPerunPrincipal().setUser(user); + + GroupsPageQuery query1 = new GroupsPageQuery(10, 0, SortingOrder.ASCENDING, GroupsOrderColumn.ID, testMember.getId(), List.of(Role.GROUPADMIN), List.of(RoleAssignmentType.DIRECT)); + Paginated directRoles = groupsManager.getGroupsPage(sess, vo, query1, List.of()); + assertNotNull(directRoles); + assertEquals(1, directRoles.getData().size()); + assertEquals(group2.getId(), directRoles.getData().get(0).getId()); + + GroupsPageQuery query2 = new GroupsPageQuery(10, 0, SortingOrder.ASCENDING, GroupsOrderColumn.ID, testMember.getId(), List.of(Role.GROUPOBSERVER), List.of(RoleAssignmentType.INDIRECT)); + Paginated indirectRoles = groupsManager.getGroupsPage(sess, vo, query2, List.of()); + assertNotNull(indirectRoles); + assertEquals(1, indirectRoles.getData().size()); + assertEquals(group3.getId(), indirectRoles.getData().get(0).getId()); + + GroupsPageQuery query3 = new GroupsPageQuery(10, 0, SortingOrder.ASCENDING, GroupsOrderColumn.ID, testMember.getId(), new ArrayList<>(), List.of(RoleAssignmentType.INDIRECT)); + Paginated allIndirectGroups = groupsManager.getGroupsPage(sess, vo, query3, List.of()); + assertNotNull(allIndirectGroups); + assertEquals(1, allIndirectGroups.getData().size()); + assertEquals(group3.getId(), allIndirectGroups.getData().get(0).getId()); + + GroupsPageQuery query4 = new GroupsPageQuery(10, 0, SortingOrder.ASCENDING, GroupsOrderColumn.ID, testMember.getId(), List.of(Role.GROUPADMIN), new ArrayList<>()); + Paginated allGroupAdmins = groupsManager.getGroupsPage(sess, vo, query4, List.of()); + assertNotNull(allGroupAdmins); + assertEquals(1, allGroupAdmins.getData().size()); + assertEquals(group2.getId(), allGroupAdmins.getData().get(0).getId()); + } + // PRIVATE METHODS ------------------------------------------------------------- private Vo setUpVo() throws Exception { diff --git a/perun-core/src/test/java/cz/metacentrum/perun/core/entry/ServicesManagerEntryIntegrationTest.java b/perun-core/src/test/java/cz/metacentrum/perun/core/entry/ServicesManagerEntryIntegrationTest.java index 2ff13ff890..a029eae5d1 100644 --- a/perun-core/src/test/java/cz/metacentrum/perun/core/entry/ServicesManagerEntryIntegrationTest.java +++ b/perun-core/src/test/java/cz/metacentrum/perun/core/entry/ServicesManagerEntryIntegrationTest.java @@ -1192,6 +1192,31 @@ public void blockAndUnblockServiceOnDestinations() throws Exception { assertFalse("Service should NOT be blocked on the richDestination3", perun.getServicesManager().isServiceBlockedOnDestination(sess, service2, destination3.getId())); } + @Test + public void blockServiceOnDestinationsAndIgnoreAlreadyBlocked() throws Exception { + System.out.println(CLASS_NAME + "blockServiceOnDestinationsAndIgnoreAlreadyBlocked"); + + facility = setUpFacility(); + service = setUpService(); + List destinations = setUpDestinations(); + + Destination destination1 = perun.getServicesManager().addDestination(sess, service, facility, destinations.get(0)); + RichDestination richDestination1 = new RichDestination(destination1, facility, service); + Destination destination2 = perun.getServicesManager().addDestination(sess, service, facility, destinations.get(1)); + RichDestination richDestination2 = new RichDestination(destination2, facility, service); + + List serviceDestinations = perun.getServicesManagerBl().getAllRichDestinations(sess, facility); + assertTrue(serviceDestinations.contains(richDestination1)); + assertTrue( serviceDestinations.contains(richDestination2)); + + perun.getServicesManager().blockServiceOnDestination(sess, service, richDestination1.getId()); + assertTrue(perun.getServicesManager().isServiceBlockedOnDestination(sess, service, richDestination1.getId())); + + List destinationsToBlock = Arrays.asList(richDestination1, richDestination2); + perun.getServicesManager().blockServicesOnDestinations(sess, destinationsToBlock); + assertTrue(perun.getServicesManager().isServiceBlockedOnDestination(sess, service, richDestination2.getId())); + } + @Test public void blockAndUnblockServicesOnFacility() throws Exception { System.out.println(CLASS_NAME + "blockAndUnblockServicesOnFacility"); diff --git a/perun-core/src/test/java/cz/metacentrum/perun/core/impl/UtilsIntegrationTest.java b/perun-core/src/test/java/cz/metacentrum/perun/core/impl/UtilsIntegrationTest.java index 8a10922a93..5dd18fbf05 100644 --- a/perun-core/src/test/java/cz/metacentrum/perun/core/impl/UtilsIntegrationTest.java +++ b/perun-core/src/test/java/cz/metacentrum/perun/core/impl/UtilsIntegrationTest.java @@ -15,6 +15,7 @@ import cz.metacentrum.perun.core.api.Vo; import cz.metacentrum.perun.core.api.exceptions.IllegalArgumentException; import cz.metacentrum.perun.core.api.exceptions.InternalErrorException; +import cz.metacentrum.perun.core.api.exceptions.SSHKeyNotValidException; import org.junit.Before; import org.junit.Test; @@ -661,6 +662,24 @@ public void checkHostnameInvalid() throws Exception { Utils.checkHostname(host); } + @Test + public void validateSSHPublicKey() { + System.out.println("Utils.validateSShKeyInvalid"); + String invalid1 = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCYZTcdI8iZFJ2c63iN0kMhpcEGuE054DCJh8gCBhyOKQn6LH3wBX/U6RERh+1UmWkblEnQM3B2vEnSGRgNfG7KQgi2xSMHlb4KO1wNB6mOwNV4a+rX115ncWxHwR+7UZPYEmafXX5WZWzT3mzvHWRLZvw87uD7FLWqFGAbEwdvinHIB4tLvCcnLSc+O9xmdZVMKbiuCIO/odhqmfUM4RD7htaBL/ZSFZn5fen5wo9xhTd2Z7fTOALPbRkG5uIWMo7TiiLNWlo9f1sao1zNmNxZrUpgbL7mUJwWz1Wor8hlOCIbjHYySFK8vz6ziqbOHh2/8DVEqAh/dEJMhVhY9rHUDjbfjOrCMswF9NWRO4Gmsn9ARHRwXN2Gq3bu6cJ6L7h5YuBH93+QtZZhYm34JfNNsZnCsaz4g0aTUwD4UtZ7kxqMMf0xE7ndc7y4wCI7+kHn/nPamtSCFT8Pgg8WfDF22S4ouZcRVS9eU1O8a/fn0dpL77wmY8rvCDyzX3VhUAHfp9YHYPB1rVRN/9tLR2wpwHHhDz758750bin/tkp7QHCJ+27vqLU3RX/ZTFjUeNX2HeHpfQEy5jyptSZgfmbnmljqOfVpDgyQ2Wvc+prN6iTjDmsaTZrY0AIQq9EUVYFLFXhqo2x3tYcC7bmlFfRE8Dl5klpfniRNOWLnMdvXcw"; + String invalid2 = "ssh-rsa 2048 10:e7:0a:ff:be:c3:c9:fb:2b:06:f3:07:ac:68:43:02"; + String validECDSA = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGgt1/rkRvQJp92tP8uxLJfy340lJGSSxsPp3+W1JdMbk+S2qIPwM5o/oblTjGhVRzKcas4pLrBz7L/Mxn6D6qw= martin@martin-ThinkPad-T480"; + String validED25519 = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJhGU1cLG0UldPhYxbEjKcZmFSZsGznmAYvra2QPls7a martin@martin-ThinkPad-T480"; + String validRSA = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC7FPq20sXf+83P/mvfEBntaGUkVJu36X2gLIi5TioYPSqGVIPV+ztnhNUuJHQZ3HYRDhGw/5c32mIYKQvsAB0T/WT6hgs9zVHU1s5ieJSduxx9DqbEkHaZUirmukd8uF97QJm6Ve/cvS3YUb3yxWXcRiJX5jy1aRazoJgm/Vocgz/1PHInq46IQUN6I62ge7u5YrpSxym6Ehw8ZGCr7QyIyg5TdNVbK4flkf6LM/uKh0JuODfm+/R/3TjzbR/7oDzfkQR4TZE3sCHXpSEwaHbb4SM6if1di2PKefhlx9m7w0oMwaE6Epoq/US1FHxR0up+PQYqqwE+/fi9C88byT1Kjz7xpC3IV0bOdeP6nDcLDYsKssgotqU0YIrBCTes/an1efe1jrYZQvr54XvKNFWUnJsMJLosT2ZCWkNCyyrnL9V+KEJ07Qb4NAXfgcrVakP/6647FAXCgyY8Len9c/0aTn7SVd1aC3aTGRvLtvPNPzhbDJGKzjPs90So0GZ+q7s= martin@martin-ThinkPad-T480"; + + assertThatExceptionOfType(SSHKeyNotValidException.class).isThrownBy(() -> Utils.validateSSHPublicKey(invalid1)); + + assertThatExceptionOfType(SSHKeyNotValidException.class).isThrownBy(() -> Utils.validateSSHPublicKey(invalid2)); + + assertThatNoException().isThrownBy(() -> Utils.validateSSHPublicKey(validECDSA)); + assertThatNoException().isThrownBy(() -> Utils.validateSSHPublicKey(validED25519)); + assertThatNoException().isThrownBy(() -> Utils.validateSSHPublicKey(validRSA)); + } + private Vo setUpVo() throws Exception { Vo newVo = new Vo(0, "UserManagerTestVo", "UMTestVo"); diff --git a/perun-core/src/test/java/cz/metacentrum/perun/core/impl/modules/attributes/urn_perun_user_facility_attribute_def_virt_enabledO365MailForwardTest.java b/perun-core/src/test/java/cz/metacentrum/perun/core/impl/modules/attributes/urn_perun_user_facility_attribute_def_virt_enabledO365MailForwardTest.java index 3efbf91b9c..63b77466bf 100644 --- a/perun-core/src/test/java/cz/metacentrum/perun/core/impl/modules/attributes/urn_perun_user_facility_attribute_def_virt_enabledO365MailForwardTest.java +++ b/perun-core/src/test/java/cz/metacentrum/perun/core/impl/modules/attributes/urn_perun_user_facility_attribute_def_virt_enabledO365MailForwardTest.java @@ -46,13 +46,13 @@ public void setUp() throws Exception { disabledMailFwdAttr.setValue(true); o365MailAttr.setValue(exampleMail); - when(session.getPerunBl().getAttributesManagerBl().getAttribute(any(PerunSessionImpl.class), any(Facility.class), any(User.class), eq(AttributesManager.NS_USER_FACILITY_ATTR_VIRT + ":o365MailForward"))).thenReturn(o365MailAttr); + when(session.getPerunBl().getAttributesManagerBl().getAttribute(any(PerunSessionImpl.class), any(Facility.class), any(User.class), eq(AttributesManager.NS_USER_FACILITY_ATTR_DEF + ":o365MailForward"))).thenReturn(o365MailAttr); } @Test public void getAttributeValueWithEnabledFwdTest() throws Exception { System.out.println("urn_perun_user_facility_attribute_def_virt_enabledO365MailForward.GetAttributeValue()"); - when(session.getPerunBl().getAttributesManagerBl().getAttribute(any(PerunSessionImpl.class), any(Facility.class), any(User.class), eq(AttributesManager.NS_USER_FACILITY_ATTR_VIRT + ":disableO365MailForward"))).thenReturn(enabledMailFwdAttr); + when(session.getPerunBl().getAttributesManagerBl().getAttribute(any(PerunSessionImpl.class), any(Facility.class), any(User.class), eq(AttributesManager.NS_USER_FACILITY_ATTR_DEF + ":disableO365MailForward"))).thenReturn(enabledMailFwdAttr); Attribute testAttr = classInstance.getAttributeValue(session, user, facility, session.getPerunBl().getAttributesManagerBl().getAttributeDefinition(session, AttributesManager.NS_USER_FACILITY_ATTR_VIRT + "enabledO365MailForward")); assertEquals(exampleMail, testAttr.getValue()); @@ -61,7 +61,7 @@ public void getAttributeValueWithEnabledFwdTest() throws Exception { @Test public void getAttributeValueWithDisabledFwdTest() throws Exception { System.out.println("urn_perun_user_facility_attribute_def_virt_enabledO365MailForward.GetAttributeValue()"); - when(session.getPerunBl().getAttributesManagerBl().getAttribute(any(PerunSessionImpl.class), any(Facility.class), any(User.class), eq(AttributesManager.NS_USER_FACILITY_ATTR_VIRT + ":disableO365MailForward"))).thenReturn(disabledMailFwdAttr); + when(session.getPerunBl().getAttributesManagerBl().getAttribute(any(PerunSessionImpl.class), any(Facility.class), any(User.class), eq(AttributesManager.NS_USER_FACILITY_ATTR_DEF + ":disableO365MailForward"))).thenReturn(disabledMailFwdAttr); Attribute testAttr = classInstance.getAttributeValue(session, user, facility, session.getPerunBl().getAttributesManagerBl().getAttributeDefinition(session, AttributesManager.NS_USER_FACILITY_ATTR_VIRT + "enabledO365MailForward")); assertEquals("", testAttr.getValue()); diff --git a/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/jms/EngineMessageConsumer.java b/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/jms/EngineMessageConsumer.java index 98f66d9a53..a078cf67c5 100644 --- a/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/jms/EngineMessageConsumer.java +++ b/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/jms/EngineMessageConsumer.java @@ -106,7 +106,7 @@ public void run() { while (!shouldStop()) { producer = producerFactory.getProducer(); - + // Step 11. Deliver output and try to receive the message TextMessage messageReceived = null; try { @@ -114,11 +114,11 @@ public void run() { producer.deliverOutputMessages(); } - log.debug("Gonna call messageConsumer.receive(timeout)..."); + log.trace("Gonna call messageConsumer.receive(timeout)..."); messageReceived = (TextMessage) messageConsumer.receive(timeout); if (messageReceived != null) { - if (log.isDebugEnabled()) { - log.debug("System message received [" + messageReceived.getText() + "]"); + if (log.isTraceEnabled()) { + log.trace("System message received [" + messageReceived.getText() + "]"); } try { engineMessageProcessor.processEngineMessage(messageReceived.getText()); @@ -129,8 +129,8 @@ public void run() { } messageReceived.acknowledge(); } else { - if (log.isDebugEnabled()) { - log.debug("No message available..."); + if (log.isTraceEnabled()) { + log.trace("No message available..."); } } } catch (JMSException e) { diff --git a/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/jms/EngineMessageProcessor.java b/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/jms/EngineMessageProcessor.java index 74bbc80759..5e888bc671 100644 --- a/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/jms/EngineMessageProcessor.java +++ b/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/jms/EngineMessageProcessor.java @@ -140,7 +140,7 @@ public void startProcessingSystemMessages() { if(outputMessages == null) { outputMessages = new LinkedBlockingDeque(); } - + connection = null; try { if(restartHornetQServer) { @@ -148,7 +148,7 @@ public void startProcessingSystemMessages() { perunHornetQServer.stopServer(); perunHornetQServer.startServer(); } - + // Step 2. Instantiate the TransportConfiguration object which // contains the knowledge of what transport to use, // The server port etc. @@ -289,12 +289,12 @@ protected void processEngineMessage(String message) throws PerunHornetQServerExc // process expected messages EngineMessageProducer engineMessageProducer; - + if (clientMessageSplitter[0].equalsIgnoreCase("register")) { // Do we have this queue already? engineMessageProducer = engineMessageProducerFactory.getProducer(); - + if (engineMessageProducer != null) { // ...and close all tasks that could have been running there schedulingPool.closeTasksForEngine(); diff --git a/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/jms/EngineMessageProducer.java b/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/jms/EngineMessageProducer.java index 2dca5f1a90..0ce2e361aa 100644 --- a/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/jms/EngineMessageProducer.java +++ b/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/jms/EngineMessageProducer.java @@ -83,19 +83,19 @@ public void sendMessage(String text) { /** * Try to deliver all pending messages. - * @throws JMSException - * + * @throws JMSException + * */ public void deliverOutputMessages() throws JMSException { while(!outputMessages.isEmpty()) { TextMessage message = outputMessages.poll(); producer.send(message); if (log.isDebugEnabled()) { - log.debug("Sent message (queue:" + queueName + "): " + message.getText()); + log.debug("Sent message (queue name:" + queueName + "): " + message.getText()); } } } - + /** * Get name of the queue for engine. * @@ -105,14 +105,13 @@ public String getQueueName() { return queueName; } - /** + /** * Shutdown before destroying the producer. - * */ public void shutdown() { try { producer.close(); - // session is not not ours to close + // session is not ours to close // session.close(); } catch (JMSException e) { log.error(e.toString(), e); diff --git a/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/processing/EventProcessor.java b/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/processing/EventProcessor.java index 1bb2d779b6..18875242d6 100644 --- a/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/processing/EventProcessor.java +++ b/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/processing/EventProcessor.java @@ -134,17 +134,17 @@ public void run() { try { Event event = eventQueue.take(); createTaskFromEvent(event); - log.debug("Remaining events in a Queue = {}", eventQueue.size()); + log.trace("Remaining events in a Queue = {}", eventQueue.size()); } catch (Exception e) { log.error(e.getMessage(), e); } } - log.debug("EventProcessor has stopped."); + log.warn("EventProcessor has stopped."); } /** * Creates Task from Event data. Tries to resolve Service and Facility pairs from Event. - * Events for non existing entities are discarded. + * Events for non-existing entities are discarded. * * @param event Event to parse * @throws ServiceNotExistsException When Service from Event doesn't exists anymore @@ -160,12 +160,20 @@ private void createTaskFromEvent(Event event) throws ServiceNotExistsException, Facility facility = map.getKey(); for (Service service : map.getValue()) { if (!service.isEnabled()) { - log.debug("Service not enabled: {}.", service); + if (log.isDebugEnabled()) { + log.debug("Service disabled: {}.", service); + } else { + log.info("Service disabled: {}.", service.getId() + " / " + service.getName()); + } continue; } if (((PerunBl) perun).getServicesManagerBl().isServiceBlockedOnFacility(service, facility)) { - log.debug("Service blocked on Facility: {} , {}.", service, facility); + if (log.isDebugEnabled()) { + log.debug("Service blocked on Facility: {} , {}.", service, facility); + } else { + log.info("Service blocked on Facility: {} , {}.", service.getId() + " / " + service.getName(), facility.getId() + " / " + facility.getName()); + } continue; } @@ -198,7 +206,12 @@ private void createTaskFromEvent(Event event) throws ServiceNotExistsException, if (destinations.isEmpty()) { // All service destinations were blocked -> Task is denied to be sent to engine just like // when service is blocked globally in Perun or on facility as a whole. - log.debug("{} blocked on all destinations on {}.", service, facility); + + if (log.isDebugEnabled()) { + log.debug("{} blocked on all destinations on {}.", service, facility); + } else { + log.info("Service: {} blocked on all destinations on Facility: {}.", service.getId() + " / " + service.getName(), facility.getId() + " / " + facility.getName()); + } continue; } } @@ -227,7 +240,7 @@ private void createTaskFromEvent(Event event) throws ServiceNotExistsException, task.setSourceUpdated(true); if (isForced) task.setPropagationForced(true); task.setRecurrence(0); - log.debug("[{}] Task is already in pool. Re-setting source updated and forced flags, {}.", task.getId(), task); + log.info("[{}] Task is already in pool. Re-setting source updated and forced flags, {}.", task.getId(), task); } else { // no such task yet, create one task = new Task(); @@ -241,7 +254,7 @@ private void createTaskFromEvent(Event event) throws ServiceNotExistsException, task.setPropagationForced(isForced); try { schedulingPool.addToPool(task); - log.debug("[{}] New Task added to pool. {}.", task.getId(), task); + log.info("[{}] New Task added to pool. {}.", task.getId(), task); } catch (TaskStoreException e) { log.error("[{}] Could not add Task to pool. Task {} will be lost: {}", task.getId(), task, e); } diff --git a/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/processing/impl/EventServiceResolverImpl.java b/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/processing/impl/EventServiceResolverImpl.java index a36833b7a2..15ac6b4326 100644 --- a/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/processing/impl/EventServiceResolverImpl.java +++ b/perun-dispatcher/src/main/java/cz/metacentrum/perun/dispatcher/processing/impl/EventServiceResolverImpl.java @@ -85,15 +85,15 @@ public void setPerun(Perun perun) { @Override public Map> resolveEvent(AuditEvent event) throws InvalidEventMessageException, ServiceNotExistsException, PrivilegeException { - log.info("Event - I am going to process event: {}", event); - Map> result = new HashMap>(); if (event instanceof EngineIgnoreEvent) { - log.info("Event ignored {} facilities will be returned", result.size()); + log.debug("Event {} ignored 0 facilities will be returned", event.getName()); return result; } + log.info("Event - I am going to process event: {}", event); + // GET All Beans (only PerunBeans) from message List listOfBeans = new ArrayList(); listOfBeans = AuditParser.parseLog(event.getMessage()); @@ -282,7 +282,7 @@ public Map> resolveEvent(AuditEvent event) throws Invalid } } - log.info("{} facilities will be returned", result.size()); + log.debug("{} facilities will be returned", result.size()); return result; } diff --git a/perun-engine/src/main/java/cz/metacentrum/perun/engine/scheduling/impl/GenWorkerImpl.java b/perun-engine/src/main/java/cz/metacentrum/perun/engine/scheduling/impl/GenWorkerImpl.java index 05721e5342..2dbbcb750c 100644 --- a/perun-engine/src/main/java/cz/metacentrum/perun/engine/scheduling/impl/GenWorkerImpl.java +++ b/perun-engine/src/main/java/cz/metacentrum/perun/engine/scheduling/impl/GenWorkerImpl.java @@ -46,8 +46,13 @@ public Task call() throws TaskExecutionException { log.info("[{}] Executing GEN worker for Task with Service ID: {} and Facility ID: {}.", getTask().getId(), getTask().getServiceId(), getTask().getFacilityId()); - - ProcessBuilder pb = new ProcessBuilder(service.getScript(), "-c", "-f", String.valueOf(getTask().getFacilityId())); + ProcessBuilder pb; + if (service.getScript().equals("./" + service.getName())) { + pb = new ProcessBuilder(service.getScript(), "-c", "-f", String.valueOf(getTask().getFacilityId())); + } else { + // if calling some generic script, also pass name of the service to avoid gen folder collision + pb = new ProcessBuilder(service.getScript(), "-c", "-f", String.valueOf(getTask().getFacilityId()), "-s", service.getName()); + } try { diff --git a/perun-engine/src/main/java/cz/metacentrum/perun/engine/scheduling/impl/SendWorkerImpl.java b/perun-engine/src/main/java/cz/metacentrum/perun/engine/scheduling/impl/SendWorkerImpl.java index d5bd55e8a1..fac5fac2a1 100644 --- a/perun-engine/src/main/java/cz/metacentrum/perun/engine/scheduling/impl/SendWorkerImpl.java +++ b/perun-engine/src/main/java/cz/metacentrum/perun/engine/scheduling/impl/SendWorkerImpl.java @@ -69,14 +69,24 @@ public SendTask call() throws TaskExecutionException { log.info("[{}] Executing SEND worker for Task with Service ID: {} and Facility ID: {} and Destination: {}", sendTask.getTask().getId(), sendTask.getTask().getServiceId(), sendTask.getTask().getFacilityId(), sendTask.getDestination().getDestination()); - - ProcessBuilder pb = new ProcessBuilder( + ProcessBuilder pb; + if (service.getScript().equals("./" + service.getName())) { + pb = new ProcessBuilder( service.getScript(), task.getFacility().getName(), sendTask.getDestination().getDestination(), sendTask.getDestination().getType() - ); - + ); + } else { + // if calling some generic script, also pass name of the service to allow correct gen folder selection + pb = new ProcessBuilder( + service.getScript(), + task.getFacility().getName(), + sendTask.getDestination().getDestination(), + sendTask.getDestination().getType(), + service.getName() + ); + } try { // start the script and wait for results diff --git a/perun-notification/src/main/java/cz/metacentrum/perun/notif/dao/jdbc/PerunNotifAuditMessageDaoImpl.java b/perun-notification/src/main/java/cz/metacentrum/perun/notif/dao/jdbc/PerunNotifAuditMessageDaoImpl.java index d24047581b..089e110faf 100644 --- a/perun-notification/src/main/java/cz/metacentrum/perun/notif/dao/jdbc/PerunNotifAuditMessageDaoImpl.java +++ b/perun-notification/src/main/java/cz/metacentrum/perun/notif/dao/jdbc/PerunNotifAuditMessageDaoImpl.java @@ -1,6 +1,5 @@ package cz.metacentrum.perun.notif.dao.jdbc; -import cz.metacentrum.perun.core.api.exceptions.InternalErrorException; import cz.metacentrum.perun.core.impl.Utils; import cz.metacentrum.perun.notif.dao.PerunNotifAuditMessageDao; import cz.metacentrum.perun.notif.entities.PerunNotifAuditMessage; @@ -29,7 +28,7 @@ public PerunNotifAuditMessage save(String message) { int newPerunNotifAuditMessageId = Utils.getNewId(this.getJdbcTemplate(), "pn_audit_message_id_seq"); this.getJdbcTemplate().update("INSERT INTO pn_audit_message(id, message) values (?,?)", newPerunNotifAuditMessageId, message); - logger.debug("PerunNotifAuditMessage saved to db: id = {} message = {}", newPerunNotifAuditMessageId, message); + logger.trace("PerunNotifAuditMessage saved to db: id = {} message = {}", newPerunNotifAuditMessageId, message); return new PerunNotifAuditMessage(newPerunNotifAuditMessageId, message); } @@ -37,14 +36,14 @@ public void remove(long id) { logger.debug("Removing perunNotifAuditMessage with id = {}", id); this.getJdbcTemplate().update("delete from pn_audit_message where id=?", id); - logger.debug("PerunNotifAuditMessage with id: {} removed.", id); + logger.trace("PerunNotifAuditMessage with id: {} removed.", id); } public List getAll() { logger.debug("Listing all perunNotifAuditMessages."); List result = this.getJdbcTemplate().query("SELECT * FROM pn_audit_message", PerunNotifAuditMessage.PERUN_NOTIF_MESSAGE); - logger.debug("Result of list of PerunNotifAuditMessage: {}", result); + logger.trace("Result of list of PerunNotifAuditMessage: {}", result); return result; } } diff --git a/perun-notification/src/main/java/cz/metacentrum/perun/notif/managers/SchedulingManagerImpl.java b/perun-notification/src/main/java/cz/metacentrum/perun/notif/managers/SchedulingManagerImpl.java index 4a69b09264..f4ddf53e03 100644 --- a/perun-notification/src/main/java/cz/metacentrum/perun/notif/managers/SchedulingManagerImpl.java +++ b/perun-notification/src/main/java/cz/metacentrum/perun/notif/managers/SchedulingManagerImpl.java @@ -133,7 +133,7 @@ public void processPerunAuditMessages() { private void processPerunNotifAuditMessage(PerunNotifAuditMessage perunAuditMessage, PerunSession session) throws Exception { try { - logger.debug("Getting regexIds, matching received message with id: " + perunAuditMessage.getId()); + logger.trace("Getting regexIds, matching received message with id: " + perunAuditMessage.getId()); Set regexIds = perunNotifRegexManager.getIdsOfRegexesMatchingMessage(perunAuditMessage); logger.debug("Received regexIds for message with id: " + perunAuditMessage.getId() + "; regexIds = " + regexIds + "; now getting templateIds."); if (regexIds == null || regexIds.isEmpty()) { diff --git a/perun-openapi/openapi.yml b/perun-openapi/openapi.yml index 62828f5942..fff0c1fd87 100644 --- a/perun-openapi/openapi.yml +++ b/perun-openapi/openapi.yml @@ -876,12 +876,21 @@ components: sortColumn: { $ref: '#/components/schemas/GroupsOrderColumn' } memberId: { type: integer } searchString: { type: string } + roles: { type: array, items: { $ref: '#/components/schemas/GroupAdminRoles' } } + types: { type: array, items: { $ref: '#/components/schemas/RoleAssignmentType' } } required: - pageSize - offset - order - sortColumn + RoleAssignmentType: + type: string + description: 'type of role assignment' + enum: + - DIRECT + - INDIRECT + ConsentStatus: type: string description: 'statuses of consents' @@ -949,6 +958,14 @@ components: - "TOPGROUPCREATOR" - "VOADMIN" + GroupAdminRoles: + type: string + description: 'admin roles for a group' + enum: + - "GROUPOBSERVER" + - "GROUPMEMBERSHIPMANAGER" + - "GROUPADMIN" + VoMemberStatuses: type: string description: 'statuses of a member in a Vo' @@ -13205,6 +13222,8 @@ paths: parameters: - $ref: '#/components/parameters/voId' - $ref: '#/components/parameters/attrNames' + - { name: "roles[]", schema: { type: array, items: { $ref: '#/components/schemas/GroupAdminRoles' } }, in: query, description: "list of roles: GROUPADMIN, GROUPOBSERVER, GROUPMEMBERSHIPMANAGER" } + - { name: "types[]", schema: { type: array, items: { $ref: '#/components/schemas/RoleAssignmentType' } }, in: query, description: "list of role types: DIRECT, INDIRECT" } responses: '200': $ref: '#/components/responses/ListOfRichGroupsResponse' @@ -13220,6 +13239,8 @@ paths: parameters: - $ref: '#/components/parameters/groupId' - $ref: '#/components/parameters/attrNamesOptional' + - { name: "roles[]", schema: { type: array, items: { $ref: '#/components/schemas/GroupAdminRoles' } }, in: query, description: "list of roles: GROUPADMIN, GROUPOBSERVER, GROUPMEMBERSHIPMANAGER" } + - { name: "types[]", schema: { type: array, items: { $ref: '#/components/schemas/RoleAssignmentType' } }, in: query, description: "list of role types: DIRECT, INDIRECT" } responses: '200': $ref: '#/components/responses/ListOfRichGroupsResponse' @@ -13667,6 +13688,8 @@ paths: parameters: - $ref: '#/components/parameters/memberId' - $ref: '#/components/parameters/attrNames' + - { name: "roles[]", schema: { type: array, items: { $ref: '#/components/schemas/GroupAdminRoles' } }, in: query, description: "list of roles: GROUPADMIN, GROUPOBSERVER, GROUPMEMBERSHIPMANAGER" } + - { name: "types[]", schema: { type: array, items: { $ref: '#/components/schemas/RoleAssignmentType' } }, in: query, description: "list of role types: DIRECT, INDIRECT" } responses: '200': $ref: '#/components/responses/ListOfRichGroupsResponse' diff --git a/perun-openapi/pom.xml b/perun-openapi/pom.xml index 4c678d0622..ff1181738c 100644 --- a/perun-openapi/pom.xml +++ b/perun-openapi/pom.xml @@ -100,7 +100,7 @@ io.swagger swagger-annotations - 1.6.11 + 1.6.12 org.openapitools diff --git a/perun-registrar-lib/src/main/java/cz/metacentrum/perun/registrar/impl/MailManagerImpl.java b/perun-registrar-lib/src/main/java/cz/metacentrum/perun/registrar/impl/MailManagerImpl.java index 188536f02e..37121bc849 100644 --- a/perun-registrar-lib/src/main/java/cz/metacentrum/perun/registrar/impl/MailManagerImpl.java +++ b/perun-registrar-lib/src/main/java/cz/metacentrum/perun/registrar/impl/MailManagerImpl.java @@ -14,6 +14,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Properties; import java.util.Set; import java.util.regex.Matcher; @@ -1096,6 +1097,11 @@ private void setFromMailAddress(MimeMessage message, Application app) { String replyToMail = fromMail; String replyToName = fromName; + if (!Objects.equals(getPropertyFromConfiguration("replyTo"), EMPTY_STRING)) { + replyToMail = getPropertyFromConfiguration("replyTo"); + replyToName = getPropertyFromConfiguration("replyToName"); + } + // get proper value from attribute try { Attribute attrSenderName = getMailFromVoAndGroupAttrs(app, URN_VO_FROM_NAME_EMAIL, URN_GROUP_FROM_NAME_EMAIL); diff --git a/perun-registrar-lib/src/main/java/cz/metacentrum/perun/registrar/impl/RegistrarManagerImpl.java b/perun-registrar-lib/src/main/java/cz/metacentrum/perun/registrar/impl/RegistrarManagerImpl.java index 80554c5651..0eac0a551c 100644 --- a/perun-registrar-lib/src/main/java/cz/metacentrum/perun/registrar/impl/RegistrarManagerImpl.java +++ b/perun-registrar-lib/src/main/java/cz/metacentrum/perun/registrar/impl/RegistrarManagerImpl.java @@ -1745,11 +1745,10 @@ public Application rejectApplication(PerunSession sess, int appId, String reason } @Override - @Transactional(rollbackFor = Exception.class) public void rejectApplications(PerunSession sess, List applicationIds, String reason) throws PerunException { Collections.sort(applicationIds, Collections.reverseOrder()); for (Integer id : applicationIds) { - rejectApplication(sess, id, reason); + registrarManager.rejectApplication(sess, id, reason); } } @@ -1851,7 +1850,6 @@ public Application approveApplication(PerunSession sess, int appId) throws Perun } @Override - @Transactional(rollbackFor = Exception.class) public void approveApplications(PerunSession sess, List applicationIds) throws PerunException { Collections.sort(applicationIds); for (Integer id : applicationIds) { @@ -1955,8 +1953,9 @@ private void submitEmbeddedGroupApplications(PerunSession sess, List grou groupApplication.setExtSourceType(app.getExtSourceType()); groupApplication.setCreatedBy("Automatically generated"); - submitApplication(sess, groupApplication, new ArrayList<>()); + submitApplication(registrarSession, groupApplication, new ArrayList<>()); } catch (Exception e) { + log.error("Error submitting embedded application {}", e); failedGroups.put(group.getId(), e.getMessage()); } } @@ -3056,7 +3055,7 @@ public List getFormItemsWithPrefilledValu // If the item has no options for the user to offer (bcs user is already member in all possible options, // remove it from the form completely if (StringUtils.isBlank(item.getFormItem().getI18n().get(ApplicationFormItem.EN).getOptions())) { - it.remove(); + itemsIt.remove(); } } @@ -3312,8 +3311,11 @@ private void checkDuplicateRegistrationAttempt(PerunSession sess, AppType appTyp // pass not member and have only approved or rejected apps } } - // if false, throws exception with reason for GUI - membersManager.canBeMemberWithReason(sess, vo, user, String.valueOf(extSourceLoa)); + // check for embedded applications was already done in original app, this would always fail because of registrar session + if (!AppType.EMBEDDED.equals(appType)) { + // if false, throws exception with reason for GUI + membersManager.canBeMemberWithReason(sess, vo, user, String.valueOf(extSourceLoa)); + } } // if extension, user != null !! if (AppType.EXTENSION.equals(appType)) { diff --git a/perun-registrar-lib/src/main/java/cz/metacentrum/perun/registrar/modules/BBMRIResources.java b/perun-registrar-lib/src/main/java/cz/metacentrum/perun/registrar/modules/BBMRIResources.java index 72322d3e1c..cd266cd373 100644 --- a/perun-registrar-lib/src/main/java/cz/metacentrum/perun/registrar/modules/BBMRIResources.java +++ b/perun-registrar-lib/src/main/java/cz/metacentrum/perun/registrar/modules/BBMRIResources.java @@ -52,7 +52,7 @@ */ public class BBMRIResources extends DefaultRegistrarModule { - private final static Logger log = LoggerFactory.getLogger(BBMRIResources.class); + private static final Logger log = LoggerFactory.getLogger(BBMRIResources.class); // field names private static final String RESOURCE_IDS = "resourceIds"; @@ -70,7 +70,6 @@ public class BBMRIResources extends DefaultRegistrarModule { * @param session who approves the application * @param app application * @return unchanged application - * @throws PerunException in case of internal error in Perun */ @Override public Application approveApplication(PerunSession session, Application app) @@ -157,8 +156,8 @@ public void canBeApproved(PerunSession session, Application app) throws PerunExc * @return Map of String to Group, where key is the ID of the resource and Group is the representation */ private Map getPerunResourceIdToGroupMap(PerunSession session, Application app, PerunBl perun) - throws PrivilegeException, RegistrarException, VoNotExistsException, WrongAttributeAssignmentException, - AttributeNotExistsException, GroupNotExistsException + throws PrivilegeException, RegistrarException, WrongAttributeAssignmentException, + AttributeNotExistsException { // get root group for resources hierarchy Group resourceOriginGroup = getResourceOriginGroup(session, app, perun); @@ -189,13 +188,13 @@ private String getResourceIdAttributeName(PerunSession session, Application app, * @return resource IDs set */ private Group getResourceOriginGroup(PerunSession session, Application app, PerunBl perun) - throws PrivilegeException, RegistrarException, VoNotExistsException + throws PrivilegeException, RegistrarException { try { - if (perun.getAttributesManagerBl() + Boolean resourceOriginEnabled = perun.getAttributesManagerBl() .getAttribute(session, app.getGroup(), RESOURCE_ORIGIN_ENABLED_ATTR_NAME) - .valueAsBoolean() - ) { + .valueAsBoolean(); + if (resourceOriginEnabled != null && resourceOriginEnabled) { try { String resourceOriginGroupName = getResourceOriginGroupNameFromApplication(session, app); return perun.getGroupsManagerBl().getGroupByName(session, app.getVo(), resourceOriginGroupName); @@ -290,7 +289,7 @@ private Map getResourceIDsToGroupsMap(PerunSession session, { Map resourceIDsToGroupMap = new HashMap<>(); - List resourceGroups = perun.getGroupsManagerBl().getSubGroups(session, resourceOriginGroup); + List resourceGroups = perun.getGroupsManagerBl().getAllSubGroups(session, resourceOriginGroup); if (resourceGroups == null || resourceGroups.isEmpty()) { log.debug("No resource groups found, returning empty map."); return resourceIDsToGroupMap; diff --git a/perun-rpc/pom.xml b/perun-rpc/pom.xml index 968719b5fc..d49588eae6 100644 --- a/perun-rpc/pom.xml +++ b/perun-rpc/pom.xml @@ -34,7 +34,7 @@ org.codehaus.cargo cargo-maven3-plugin - 1.10.9 + 1.10.10 tomcat9x diff --git a/perun-rpc/src/main/java/cz/metacentrum/perun/rpc/methods/GroupsManagerMethod.java b/perun-rpc/src/main/java/cz/metacentrum/perun/rpc/methods/GroupsManagerMethod.java index 4f65b5d160..9531e7a0da 100644 --- a/perun-rpc/src/main/java/cz/metacentrum/perun/rpc/methods/GroupsManagerMethod.java +++ b/perun-rpc/src/main/java/cz/metacentrum/perun/rpc/methods/GroupsManagerMethod.java @@ -14,6 +14,7 @@ import cz.metacentrum.perun.core.api.RichGroup; import cz.metacentrum.perun.core.api.RichMember; import cz.metacentrum.perun.core.api.RichUser; +import cz.metacentrum.perun.core.api.RoleAssignmentType; import cz.metacentrum.perun.core.api.Status; import cz.metacentrum.perun.core.api.User; import cz.metacentrum.perun.core.api.Vo; @@ -1533,129 +1534,696 @@ public List call(ApiCaller ac, Deserializer parms) throws PerunException{ } }, + + /*# + * Returns sub-list of all RichGroups, each containing selected attributes, starting at fromIndex (included) + * and ending at the size of the original list. + * + * Example: [1,2,3,4], fromIndex=1 => [2,3,4] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param fromIndex int begin index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role, each containing selected attributes, starting at fromIndex (included) + * and ending at the size of the original list. + * + * Example: [1,2,3,4], fromIndex=1 => [2,3,4] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param fromIndex int begin index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role assignment type, each containing selected attributes, starting at fromIndex (included) + * and ending at the size of the original list. + * + * Example: [1,2,3,4], fromIndex=1 => [2,3,4] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param fromIndex int begin index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role and its assignment type, each containing selected attributes, starting at fromIndex (included) + * and ending at the size of the original list. + * + * Example: [1,2,3,4], fromIndex=1 => [2,3,4] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param fromIndex int begin index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of all RichGroups, each containing all attributes, starting at fromIndex (included) + * and ending at the size of the original list. + * + * Example: [1,2,3,4], fromIndex=1 => [2,3,4] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param fromIndex int begin index of returned subList, included + * @return List RichGroups containing all attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role, each containing all attributes, starting at fromIndex (included) + * and ending at the size of the original list. + * + * Example: [1,2,3,4], fromIndex=1 => [2,3,4] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param fromIndex int begin index of returned subList, included + * @return List RichGroups containing all attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role assignment type, each containing all attributes, starting at fromIndex (included) + * and ending at the size of the original list. + * + * Example: [1,2,3,4], fromIndex=1 => [2,3,4] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @param fromIndex int begin index of returned subList, included + * @return List RichGroups containing all attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role and its assignment type, each containing all attributes, starting at fromIndex (included) + * and ending at the size of the original list. + * + * Example: [1,2,3,4], fromIndex=1 => [2,3,4] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @param fromIndex int begin index of returned subList, included + * @return List RichGroups containing all attributes + */ + /*# + * Returns sub-list of all RichGroups, each containing selected attributes, starting at first index of the original + * list (included) and ending at the toIndex (included). + * + * Example: [1,2,3,4], toIndex=2 => [1,2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param toIndex int end index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role, each containing selected attributes, starting at first index of the original + * list (included) and ending at the toIndex (included). + * + * Example: [1,2,3,4], toIndex=2 => [1,2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param toIndex int end index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role assignment type, each containing selected attributes, starting at first index of the original + * list (included) and ending at the toIndex (included). + * + * Example: [1,2,3,4], toIndex=2 => [1,2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param toIndex int end index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role and its assignment type, each containing selected attributes, starting at first index of the original + * list (included) and ending at the toIndex (included). + * + * Example: [1,2,3,4], toIndex=2 => [1,2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param toIndex int end index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of all RichGroups, each containing all attributes, starting at first index of the original + * list (included) and ending at the toIndex (included). + * + * Example: [1,2,3,4], toIndex=2 => [1,2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param toIndex int end index of returned subList, included + * @return List RichGroups containing all attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role, each containing all attributes, starting at first index of the original + * list (included) and ending at the toIndex (included). + * + * Example: [1,2,3,4], toIndex=2 => [1,2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param toIndex int end index of returned subList, included + * @return List RichGroups containing all attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role assignment type, each containing all attributes, starting at first index of the original + * list (included) and ending at the toIndex (included). + * + * Example: [1,2,3,4], toIndex=2 => [1,2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @param toIndex int end index of returned subList, included + * @return List RichGroups containing all attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role and its assignment type, each containing all attributes, starting at first index of the original + * list (included) and ending at the toIndex (included). + * + * Example: [1,2,3,4], toIndex=2 => [1,2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @param toIndex int end index of returned subList, included + * @return List RichGroups containing all attributes + */ + /*# + * Returns sub-list of all RichGroups, each containing selected attributes, starting at fromIndex (included) + * and ending at the toIndex (included). + * + * Example: [1,2,3,4], fromIndex=1, toIndex=2 => [2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param fromIndex int begin index of returned subList, included + * @param toIndex int end index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role, each containing selected attributes, starting at fromIndex (included) + * and ending at the toIndex (included). + * + * Example: [1,2,3,4], fromIndex=1, toIndex=2 => [2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param fromIndex int begin index of returned subList, included + * @param toIndex int end index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role assignment type, each containing selected attributes, starting at fromIndex (included) + * and ending at the toIndex (included). + * + * Example: [1,2,3,4], fromIndex=1, toIndex=2 => [2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param fromIndex int begin index of returned subList, included + * @param toIndex int end index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role and its assignment type, each containing selected attributes, starting at fromIndex (included) + * and ending at the toIndex (included). + * + * Example: [1,2,3,4], fromIndex=1, toIndex=2 => [2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param fromIndex int begin index of returned subList, included + * @param toIndex int end index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of all RichGroups, each containing all attributes, starting at fromIndex (included) + * and ending at the toIndex (included). + * + * Example: [1,2,3,4], fromIndex=1, toIndex=2 => [2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param fromIndex int begin index of returned subList, included + * @param toIndex int end index of returned subList, included + * @return List RichGroups containing all attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role, each containing all attributes, starting at fromIndex (included) + * and ending at the toIndex (included). + * + * Example: [1,2,3,4], fromIndex=1, toIndex=2 => [2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param fromIndex int begin index of returned subList, included + * @param toIndex int end index of returned subList, included + * @return List RichGroups containing all attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role assignment type, each containing all attributes, starting at fromIndex (included) + * and ending at the toIndex (included). + * + * Example: [1,2,3,4], fromIndex=1, toIndex=2 => [2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @param fromIndex int begin index of returned subList, included + * @param toIndex int end index of returned subList, included + * @return List RichGroups containing all attributes + */ + /*# + * Returns sub-list of all RichGroups filtered by user's role and its assignment type, each containing all attributes, starting at fromIndex (included) + * and ending at the toIndex (included). + * + * Example: [1,2,3,4], fromIndex=1, toIndex=2 => [2,3] + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @param fromIndex int begin index of returned subList, included + * @param toIndex int end index of returned subList, included + * @return List RichGroups containing all attributes + */ + /*# + * Returns full list of all RichGroups containing selected attributes. + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @return List RichGroups containing selected attributes + */ + /*# + * Returns full list of all RichGroups filtered by user's role, containing selected attributes. + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns full list of all RichGroups filtered by user's role assignment type, containing selected attributes. + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns full list of all RichGroups filtered by user's role and its assignment type, containing selected attributes. + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns full list of all RichGroups containing all attributes. + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @return List RichGroups containing all attributes + */ + /*# + * Returns full list of all RichGroups filtered by user's role, containing all attributes. + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param roles list of selected roles (if empty, then return groups by all roles) + * @return List RichGroups containing all attributes + */ + /*# + * Returns full list of all RichGroups filtered by user's role assignment type, containing all attributes. + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing all attributes + */ + /*# + * Returns full list of all RichGroups filtered by user's role and its assignment type, containing all attributes. + * + * @throw VoNotExistsException When Vo doesn't exist + * + * @param vo int id of vo + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing all attributes + */ + getAllRichGroupsWithAttributesByNames { + + @Override + public List call(ApiCaller ac, Deserializer parms) throws PerunException { + List listOfRichGroups = ac.getGroupsManager().getAllRichGroupsWithAttributesByNames( + ac.getSession(), ac.getVoById(parms.readInt("vo")), + parms.contains("attrNames") ? parms.readList("attrNames", String.class) : null, + parms.contains("roles") ? parms.readList("roles", String.class) : new ArrayList<>(), + parms.contains("types") ? parms.readList("types", String.class).stream().map(RoleAssignmentType::valueOf).toList() : new ArrayList<>()); + + if(listOfRichGroups == null) listOfRichGroups = new ArrayList<>(); + + if (parms.contains("fromIndex") && parms.contains("toIndex")) { + return ac.getSublist(listOfRichGroups, parms.readInt("fromIndex"), parms.readInt("toIndex")); + } else if (parms.contains("fromIndex")) { + int toIndex = listOfRichGroups.size(); + return ac.getSublist(listOfRichGroups, parms.readInt("fromIndex"), toIndex); + } else if (parms.contains("toIndex")) { + return ac.getSublist(listOfRichGroups, 0, parms.readInt("toIndex")); + } else { + return listOfRichGroups; + } + } + }, + + /*# + * Returns sub-list of member's RichGroups, each containing selected attributes, starting at fromIndex (included) + * and ending at the size of the original list. + * + * Example: [1,2,3,4], fromIndex=1 => [2,3,4] + * + * "members" group is not included! + * + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @throw MemberNotExistsException When the member doesn't exist + * + * @param member int id of member + * @param fromIndex int begin index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @return List RichGroups containing selected attributes + */ /*# - * Returns sub-list of all RichGroups, each containing selected attributes, starting at fromIndex (included) + * Returns sub-list of member's RichGroups filtered by user's role, each containing selected attributes, starting at fromIndex (included) * and ending at the size of the original list. * * Example: [1,2,3,4], fromIndex=1 => [2,3,4] * - * @throw VoNotExistsException When Vo doesn't exist + * "members" group is not included! * - * @param vo int id of vo + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @throw MemberNotExistsException When the member doesn't exist + * + * @param member int id of member * @param fromIndex int begin index of returned subList, included * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) * @return List RichGroups containing selected attributes */ /*# - * Returns sub-list of all RichGroups, each containing all attributes, starting at fromIndex (included) + * Returns sub-list of member's RichGroups filtered by user's role assignment type, each containing selected attributes, starting at fromIndex (included) * and ending at the size of the original list. * * Example: [1,2,3,4], fromIndex=1 => [2,3,4] * - * @throw VoNotExistsException When Vo doesn't exist * - * @param vo int id of vo + * "members" group is not included! + * + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @throw MemberNotExistsException When the member doesn't exist + * + * @param member int id of member * @param fromIndex int begin index of returned subList, included - * @return List RichGroups containing all attributes + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes */ /*# - * Returns sub-list of all RichGroups, each containing selected attributes, starting at first index of the original + * Returns sub-list of member's RichGroups filtered by user's role and its assignment type, each containing selected attributes, starting at fromIndex (included) + * and ending at the size of the original list. + * + * Example: [1,2,3,4], fromIndex=1 => [2,3,4] + * + * "members" group is not included! + * + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @throw MemberNotExistsException When the member doesn't exist + * + * @param member int id of member + * @param fromIndex int begin index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of member's RichGroups, each containing selected attributes, starting at first index of the original * list (included) and ending at the toIndex (included). * * Example: [1,2,3,4], toIndex=2 => [1,2,3] * - * @throw VoNotExistsException When Vo doesn't exist * - * @param vo int id of vo + * "members" group is not included! + * + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @throw MemberNotExistsException When the member doesn't exist + * + * @param member int id of member * @param toIndex int end index of returned subList, included * @param attrNames List if attrNames is null method will return RichGroups containing all attributes * @return List RichGroups containing selected attributes */ /*# - * Returns sub-list of all RichGroups, each containing all attributes, starting at first index of the original + * Returns sub-list of member's RichGroups filtered by user's role, each containing selected attributes, starting at first index of the original * list (included) and ending at the toIndex (included). * * Example: [1,2,3,4], toIndex=2 => [1,2,3] * - * @throw VoNotExistsException When Vo doesn't exist * - * @param vo int id of vo + * "members" group is not included! + * + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @throw MemberNotExistsException When the member doesn't exist + * + * @param member int id of member * @param toIndex int end index of returned subList, included - * @return List RichGroups containing all attributes + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @return List RichGroups containing selected attributes */ /*# - * Returns sub-list of all RichGroups, each containing selected attributes, starting at fromIndex (included) + * Returns sub-list of member's RichGroups filtered by user's role assignment type, each containing selected attributes, starting at first index of the original + * list (included) and ending at the toIndex (included). + * + * Example: [1,2,3,4], toIndex=2 => [1,2,3] + * + * + * "members" group is not included! + * + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @throw MemberNotExistsException When the member doesn't exist + * + * @param member int id of member + * @param toIndex int end index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of member's RichGroups filtered by user's role and its assignment type, each containing selected attributes, starting at first index of the original + * list (included) and ending at the toIndex (included). + * + * Example: [1,2,3,4], toIndex=2 => [1,2,3] + * + * + * "members" group is not included! + * + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @throw MemberNotExistsException When the member doesn't exist + * + * @param member int id of member + * @param toIndex int end index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns sub-list of member's RichGroups, each containing selected attributes, starting at fromIndex (included) * and ending at the toIndex (included). * * Example: [1,2,3,4], fromIndex=1, toIndex=2 => [2,3] * - * @throw VoNotExistsException When Vo doesn't exist * - * @param vo int id of vo + * "members" group is not included! + * + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @throw MemberNotExistsException When the member doesn't exist + * + * @param member int id of member * @param fromIndex int begin index of returned subList, included * @param toIndex int end index of returned subList, included * @param attrNames List if attrNames is null method will return RichGroups containing all attributes * @return List RichGroups containing selected attributes */ /*# - * Returns sub-list of all RichGroups, each containing all attributes, starting at fromIndex (included) + * Returns sub-list of member's RichGroups filtered by user's role, each containing selected attributes, starting at fromIndex (included) * and ending at the toIndex (included). * * Example: [1,2,3,4], fromIndex=1, toIndex=2 => [2,3] * - * @throw VoNotExistsException When Vo doesn't exist * - * @param vo int id of vo + * "members" group is not included! + * + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @throw MemberNotExistsException When the member doesn't exist + * + * @param member int id of member * @param fromIndex int begin index of returned subList, included * @param toIndex int end index of returned subList, included - * @return List RichGroups containing all attributes + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @return List RichGroups containing selected attributes */ /*# - * Returns full list of all RichGroups containing selected attributes. + * Returns sub-list of member's RichGroups filtered by user's role assignment type, each containing selected attributes, starting at fromIndex (included) + * and ending at the toIndex (included). * - * @throw VoNotExistsException When Vo doesn't exist + * Example: [1,2,3,4], fromIndex=1, toIndex=2 => [2,3] * - * @param vo int id of vo + * + * "members" group is not included! + * + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @throw MemberNotExistsException When the member doesn't exist + * + * @param member int id of member + * @param fromIndex int begin index of returned subList, included + * @param toIndex int end index of returned subList, included * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param types list of selected types of roles (if empty, then return by roles of all types) * @return List RichGroups containing selected attributes */ /*# - * Returns full list of all RichGroups containing all attributes. + * Returns sub-list of member's RichGroups filtered by user's role and its assignment type, each containing selected attributes, starting at fromIndex (included) + * and ending at the toIndex (included). * - * @throw VoNotExistsException When Vo doesn't exist + * Example: [1,2,3,4], fromIndex=1, toIndex=2 => [2,3] * - * @param vo int id of vo - * @return List RichGroups containing all attributes + * + * "members" group is not included! + * + * Supported are attributes from these namespaces: + * - group + * - member-group + * + * @throw MemberNotExistsException When the member doesn't exist + * + * @param member int id of member + * @param fromIndex int begin index of returned subList, included + * @param toIndex int end index of returned subList, included + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes */ - getAllRichGroupsWithAttributesByNames { - - @Override - public List call(ApiCaller ac, Deserializer parms) throws PerunException { - - List listOfRichGroups = ac.getGroupsManager().getAllRichGroupsWithAttributesByNames(ac.getSession(), - ac.getVoById(parms.readInt("vo")), - parms.contains("attrNames") ? parms.readList("attrNames", String.class) : null); - - if(listOfRichGroups == null) listOfRichGroups = new ArrayList<>(); - - if (parms.contains("fromIndex") && parms.contains("toIndex")) { - return ac.getSublist(listOfRichGroups, parms.readInt("fromIndex"), parms.readInt("toIndex")); - } else if (parms.contains("fromIndex")) { - int toIndex = listOfRichGroups.size(); - return ac.getSublist(listOfRichGroups, parms.readInt("fromIndex"), toIndex); - } else if (parms.contains("toIndex")) { - return ac.getSublist(listOfRichGroups, 0, parms.readInt("toIndex")); - } else { - return listOfRichGroups; - } - } - }, - /*# - * Returns sub-list of member's RichGroups, each containing selected attributes, starting at fromIndex (included) - * and ending at the size of the original list. + * Returns full list of member's RichGroups containing selected attributes. * - * Example: [1,2,3,4], fromIndex=1 => [2,3,4] * * "members" group is not included! * @@ -1666,15 +2234,12 @@ public List call(ApiCaller ac, Deserializer parms) throws PerunExcept * @throw MemberNotExistsException When the member doesn't exist * * @param member int id of member - * @param fromIndex int begin index of returned subList, included * @param attrNames List if attrNames is null method will return RichGroups containing all attributes * @return List RichGroups containing selected attributes */ /*# - * Returns sub-list of member's RichGroups, each containing selected attributes, starting at first index of the original - * list (included) and ending at the toIndex (included). + * Returns full list of member's RichGroups filtered by user's role, containing selected attributes. * - * Example: [1,2,3,4], toIndex=2 => [1,2,3] * * "members" group is not included! * @@ -1685,15 +2250,13 @@ public List call(ApiCaller ac, Deserializer parms) throws PerunExcept * @throw MemberNotExistsException When the member doesn't exist * * @param member int id of member - * @param toIndex int end index of returned subList, included * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) * @return List RichGroups containing selected attributes */ /*# - * Returns sub-list of member's RichGroups, each containing selected attributes, starting at fromIndex (included) - * and ending at the toIndex (included). + * Returns full list of member's RichGroups filtered by user's role assignment type, containing selected attributes. * - * Example: [1,2,3,4], fromIndex=1, toIndex=2 => [2,3] * * "members" group is not included! * @@ -1704,13 +2267,13 @@ public List call(ApiCaller ac, Deserializer parms) throws PerunExcept * @throw MemberNotExistsException When the member doesn't exist * * @param member int id of member - * @param fromIndex int begin index of returned subList, included - * @param toIndex int end index of returned subList, included * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param types list of selected types of roles (if empty, then return by roles of all types) * @return List RichGroups containing selected attributes */ /*# - * Returns full list of member's RichGroups containing selected attributes. + * Returns full list of member's RichGroups filtered by user's role and its assignment type, containing selected attributes. + * * * "members" group is not included! * @@ -1722,16 +2285,19 @@ public List call(ApiCaller ac, Deserializer parms) throws PerunExcept * * @param member int id of member * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) * @return List RichGroups containing selected attributes */ getMemberRichGroupsWithAttributesByNames { @Override public List call(ApiCaller ac, Deserializer parms) throws PerunException { - List listOfRichGroups = ac.getGroupsManager().getMemberRichGroupsWithAttributesByNames(ac.getSession(), - ac.getMemberById(parms.readInt("member")), - parms.readList("attrNames", String.class)); + ac.getMemberById(parms.readInt("member")), + parms.readList("attrNames", String.class), + parms.contains("roles") ? parms.readList("roles", String.class) : new ArrayList<>(), + parms.contains("types") ? parms.readList("types", String.class).stream().map(RoleAssignmentType::valueOf).toList() : new ArrayList<>()); if(listOfRichGroups == null) listOfRichGroups = new ArrayList<>(); @@ -1777,14 +2343,46 @@ public List call(ApiCaller ac, Deserializer parms) throws PerunExcept * @param attrNames List if attrNames is null method will return RichGroups containing all attributes * @return List RichGroups containing selected attributes */ + /*# + * Returns all AllRichSubGroups from parent group filtered by user's role, containing selected attributes (all level subgroups). + * + * @throw GroupNotExistsException When the group doesn't exist + * + * @param group int id of group + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns all AllRichSubGroups from parent group filtered by user's role assignment type, containing selected attributes (all level subgroups). + * + * @throw GroupNotExistsException When the group doesn't exist + * + * @param group int id of group + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes + */ + /*# + * Returns all AllRichSubGroups from parent group filtered by user's role and its assignment type, containing selected attributes (all level subgroups). + * + * @throw GroupNotExistsException When the group doesn't exist + * + * @param group int id of group + * @param attrNames List if attrNames is null method will return RichGroups containing all attributes + * @param roles list of selected roles (if empty, then return groups by all roles) + * @param types list of selected types of roles (if empty, then return by roles of all types) + * @return List RichGroups containing selected attributes + */ getAllRichSubGroupsWithAttributesByNames { @Override public List call(ApiCaller ac, Deserializer parms) throws PerunException { - return ac.getGroupsManager().getAllRichSubGroupsWithAttributesByNames(ac.getSession(), - ac.getGroupById(parms.readInt("group")), - parms.readList("attrNames", String.class)); + ac.getGroupById(parms.readInt("group")), + parms.readList("attrNames", String.class), + parms.contains("roles") ? parms.readList("roles", String.class) : new ArrayList<>(), + parms.contains("types") ? parms.readList("types", String.class).stream().map(RoleAssignmentType::valueOf).toList() : new ArrayList<>()); } }, diff --git a/perun-rpc/src/main/java/cz/metacentrum/perun/rpc/methods/UsersManagerMethod.java b/perun-rpc/src/main/java/cz/metacentrum/perun/rpc/methods/UsersManagerMethod.java index 783af8f9e2..f654febe2c 100644 --- a/perun-rpc/src/main/java/cz/metacentrum/perun/rpc/methods/UsersManagerMethod.java +++ b/perun-rpc/src/main/java/cz/metacentrum/perun/rpc/methods/UsersManagerMethod.java @@ -1641,6 +1641,23 @@ public String call(ApiCaller ac, Deserializer parms) throws PerunException { } }, + /*# + * Validate ssh public key, throws exception if validation fails + * + * + * @param sshKey String public ssh key to validate + * + * @throw SSHKeyNotValidException when validation fails + */ + validateSSHKey { + @Override + public Void call(ApiCaller ac, Deserializer parms) throws PerunException { + parms.stateChangingCheck(); + ac.getUsersManager().validateSSHKey(ac.getSession(), parms.readString("sshKey")); + return null; + } + }, + /*# * Return list of email addresses of user, which are * awaiting validation and are inside time window diff --git a/perun-web-gui/src/main/java/cz/metacentrum/perun/webgui/model/Candidate.java b/perun-web-gui/src/main/java/cz/metacentrum/perun/webgui/model/Candidate.java index 5abc30393b..6f2d2832c0 100644 --- a/perun-web-gui/src/main/java/cz/metacentrum/perun/webgui/model/Candidate.java +++ b/perun-web-gui/src/main/java/cz/metacentrum/perun/webgui/model/Candidate.java @@ -93,7 +93,7 @@ public final native String getTitleBefore() /*-{ * @return title after name of candidate */ public final native String getTitleAfter() /*-{ - return this.TitleAfter; + return this.titleAfter; }-*/; /** @@ -218,4 +218,4 @@ public final boolean equals(Candidate o) { return o.getId().equals(this.getId()); } -} \ No newline at end of file +} diff --git a/pom.xml b/pom.xml index 2788a30746..39d86d6af4 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ org.springframework.boot spring-boot-starter-parent - 2.7.16 + 2.7.17 @@ -62,20 +62,20 @@ default - 1.5.0 + 1.6.0 1.10.0 3.3.3 2.1.4 1.6 0.5.11 9.3.1 - directory_v1-rev20230822-2.0.0 + directory_v1-rev20231005-2.0.0 2.2.21.Final 3.2.10.Final 1.1.0.GA 1.0 1.0 - 20230618 + 20231013 0.3.0 0.9.11 1.19.1