mirror of
https://github.com/bmlong137/keycloak-group-password-policy.git
synced 2025-05-29 06:54:42 +00:00
Merge pull request #8 from bmlong137/develop
Version compatibility and improved functionality by @bmlong137
This commit is contained in:
commit
dffb643b19
11
.gitignore
vendored
11
.gitignore
vendored
@ -1 +1,12 @@
|
||||
# Maven
|
||||
target
|
||||
pom.xml.versionsBackup
|
||||
|
||||
# Eclipse
|
||||
.project
|
||||
.classpath
|
||||
.settings
|
||||
|
||||
# VS Code
|
||||
.factorypath
|
||||
.vscode
|
||||
|
33
README.md
33
README.md
@ -11,10 +11,30 @@ The extension can be installed just like any keycloak extension. Either copy it
|
||||
`keycloak/standalone/deployments` folder, or load it via the jboss command line tool.
|
||||
|
||||
## Usage
|
||||
To use the plugin you create a new password policy entry on the realm's password policy sub-page
|
||||
with the `Group Policy` type, then enter a group attribute name as the configuration.
|
||||
On a password change request, the extension will then check all the user's groups for this
|
||||
attribute name and parse the corresponding attribute value as a serialized password policy.
|
||||
There are multiple steps you will want to take to use this plugin. First, you need to determine
|
||||
what password policies you will want for all users and for each group of users. Once you have
|
||||
that, you will need to come up with an ID where you will specify group password policies. For
|
||||
the purposes of this documentation we will use the ID `passwordPolicy`.
|
||||
|
||||
Go to the realm's password policy page. In the latest versions of Keycloak, this can be found
|
||||
by navigating to the "Authentication" menu item in the vertical menu on the left side of the
|
||||
realm's user interface. You will then need to navigate to the "Password Policy" tab along the
|
||||
menu of tabs on the top of the page.
|
||||
|
||||
This interface provides you the OOTB ability to specify password policies for **all** users.
|
||||
This is still true with the plugin installed. You will now have an additional option: **Group
|
||||
Policy**. To use the plugin, you must add that password policy. The "Policy Value" should be
|
||||
set to the ID we came up with earlier: `passwordPolicy`.
|
||||
|
||||
If you intend to use group-specific password expiration (`forceExpiredPasswordChange`), you will
|
||||
need to perform an additional step in the configuration. In the same "Authentication" section,
|
||||
navigate to the "Required Actions" tab along the menu of tabs on the top of the page. Use the
|
||||
"Register" button to add the "Group-based Expired Password" action. Move it up in the order to
|
||||
after the "Update Password" action.
|
||||
|
||||
At this point, you will need to add an attribute (with key `passwordPolicy`) to each group you
|
||||
want to have additional password policies. The format of that text is defined by Keycloak
|
||||
documentation and covered in the section below.
|
||||
|
||||
### Password policy format
|
||||
All policies are represented by a short string immediately followed by parenthesis, optionally
|
||||
@ -36,7 +56,8 @@ The [policies provided with KeyCloak](https://www.keycloak.org/docs/6.0/server_a
|
||||
| `regexPattern(string)` | regular expression | ✓ |
|
||||
| `notUsername()` | | ✓ |
|
||||
| `passwordBlacklist(string)` | file name | - |
|
||||
| `passwordHistory(int)` | number of last used passwords to disallow | - |
|
||||
| `passwordHistory(int)` | number of last used passwords to disallow | ✓ |
|
||||
| `forceExpiredPasswordChange(string)` | number of days to expire password after | ✓ |
|
||||
|
||||
On the realm model the password policy attribute is also used for other purposes.
|
||||
There are some registered "policies", that do not actually implement a policy that
|
||||
@ -46,11 +67,9 @@ If these currently work is completely untested.
|
||||
|
||||
| Identifier | Description | Tested |
|
||||
| ------------- |:------------------------------------ | ------ |
|
||||
| `forceExpiredPasswordChange(int)` | number of days to expire password after | - |
|
||||
| `hashAlgorithm(string)` | hash algorithm to use when hashing the password | - |
|
||||
| `hashIterations(int)` | number of hash iterations | - |
|
||||
|
||||
|
||||
## Implementation
|
||||
To minimize code duplication the extension uses as much of the built-in KeyCloak code
|
||||
as possible. The parsing and instantiation of the policy provider classes is used as-is.
|
||||
|
357
pom.xml
357
pom.xml
@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.github.jpicht.keycloak.policy</groupId>
|
||||
<artifactId>keycloak-group-password-policy</artifactId>
|
||||
<version>0.1-SNAPSHOT</version>
|
||||
<version>0.2-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
@ -13,8 +13,8 @@
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||
|
||||
<keycloak.version>6.0.1</keycloak.version>
|
||||
<auto-service.version>1.0-rc5</auto-service.version>
|
||||
<keycloak.version>${keycloak.majorVersion}.0.0</keycloak.version>
|
||||
<auto-service.version>1.0</auto-service.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@ -33,6 +33,11 @@
|
||||
<artifactId>jboss-logging</artifactId>
|
||||
<version>3.4.0.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-services</artifactId>
|
||||
<version>${keycloak.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-core</artifactId>
|
||||
@ -45,23 +50,6 @@
|
||||
<scope>provided</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak.testsuite</groupId>
|
||||
<artifactId>integration-arquillian-tests-base</artifactId>
|
||||
<version>6.0.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-test-helper</artifactId>
|
||||
<version>6.0.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-services</artifactId>
|
||||
<version>6.0.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<pluginManagement>
|
||||
@ -71,7 +59,336 @@
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<configuration>
|
||||
<classifier>keycloak-v${keycloak.majorVersion}</classifier>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<!-- This is required in order for the classloader of this JAR to access the specified library at runtime -->
|
||||
<Dependencies>org.keycloak.keycloak-services</Dependencies>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>keycloak-v6</id>
|
||||
<properties>
|
||||
<keycloak.majorVersion>6</keycloak.majorVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source-keycloak-v6</id>
|
||||
<goals><goal>add-source</goal></goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${basedir}/src/keycloak-v6-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v6-v11/java</source>
|
||||
<source>${basedir}/src/keycloak-v6/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>keycloak-v7</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<properties>
|
||||
<keycloak.majorVersion>7</keycloak.majorVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source-keycloak-v7</id>
|
||||
<goals><goal>add-source</goal></goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${basedir}/src/keycloak-v6-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v6-v11/java</source>
|
||||
<source>${basedir}/src/keycloak-v6/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>keycloak-v8</id>
|
||||
<properties>
|
||||
<keycloak.majorVersion>8</keycloak.majorVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source-keycloak-v8</id>
|
||||
<goals><goal>add-source</goal></goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${basedir}/src/keycloak-v6-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v8-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v6-v11/java</source>
|
||||
<source>${basedir}/src/keycloak-v8/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>keycloak-v9</id>
|
||||
<properties>
|
||||
<keycloak.majorVersion>9</keycloak.majorVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source-keycloak-v9</id>
|
||||
<goals><goal>add-source</goal></goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${basedir}/src/keycloak-v6-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v8-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v9-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v6-v11/java</source>
|
||||
<source>${basedir}/src/keycloak-v9/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>keycloak-v10</id>
|
||||
<properties>
|
||||
<keycloak.majorVersion>10</keycloak.majorVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source-keycloak-v10</id>
|
||||
<goals><goal>add-source</goal></goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${basedir}/src/keycloak-v6-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v8-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v9-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v10-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v6-v11/java</source>
|
||||
<source>${basedir}/src/keycloak-v10/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>keycloak-v11</id>
|
||||
<properties>
|
||||
<keycloak.majorVersion>11</keycloak.majorVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source-keycloak-v11</id>
|
||||
<goals><goal>add-source</goal></goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${basedir}/src/keycloak-v6-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v8-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v9-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v10-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v11-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v6-v11/java</source>
|
||||
<source>${basedir}/src/keycloak-v11/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>keycloak-v12</id>
|
||||
<properties>
|
||||
<keycloak.majorVersion>12</keycloak.majorVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source-keycloak-v12</id>
|
||||
<goals><goal>add-source</goal></goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${basedir}/src/keycloak-v6-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v8-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v9-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v10-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v11-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v12-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v12/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>keycloak-v13</id>
|
||||
<properties>
|
||||
<keycloak.majorVersion>13</keycloak.majorVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source-keycloak-v13</id>
|
||||
<goals><goal>add-source</goal></goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${basedir}/src/keycloak-v6-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v8-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v9-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v10-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v11-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v12-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v13-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v13/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>keycloak-v14</id>
|
||||
<properties>
|
||||
<keycloak.majorVersion>14</keycloak.majorVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source-keycloak-v14</id>
|
||||
<goals><goal>add-source</goal></goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${basedir}/src/keycloak-v6-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v8-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v9-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v10-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v11-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v12-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v13-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v14-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v14/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>keycloak-v15</id>
|
||||
<properties>
|
||||
<keycloak.majorVersion>15</keycloak.majorVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source-keycloak-v15</id>
|
||||
<goals><goal>add-source</goal></goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>${basedir}/src/keycloak-v6-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v8-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v9-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v10-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v11-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v12-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v13-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v14-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v15-common/java</source>
|
||||
<source>${basedir}/src/keycloak-v15/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
public abstract class FakeRealmV10 extends FakeRealmV9 {
|
||||
|
||||
@Override
|
||||
public int getClientSessionIdleTimeout() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientSessionIdleTimeout(int seconds) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getClientSessionMaxLifespan() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientSessionMaxLifespan(int seconds) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2019 Julian Picht
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
|
||||
public class FakeRealm extends FakeRealmV10 {
|
||||
|
||||
private PasswordPolicy passwordPolicy;
|
||||
|
||||
@Override
|
||||
public PasswordPolicy getPasswordPolicy() {
|
||||
return passwordPolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPasswordPolicy(PasswordPolicy policy) {
|
||||
passwordPolicy = policy;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
public abstract class FakeRealmV11 extends FakeRealmV10 {
|
||||
|
||||
@Override
|
||||
public int getClientOfflineSessionIdleTimeout() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientOfflineSessionIdleTimeout(int seconds) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getClientOfflineSessionMaxLifespan() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientOfflineSessionMaxLifespan(int seconds) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2019 Julian Picht
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
|
||||
public class FakeRealm extends FakeRealmV11 {
|
||||
|
||||
private PasswordPolicy passwordPolicy;
|
||||
|
||||
@Override
|
||||
public PasswordPolicy getPasswordPolicy() {
|
||||
return passwordPolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPasswordPolicy(PasswordPolicy policy) {
|
||||
passwordPolicy = policy;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.keycloak.component.ComponentModel;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.AuthenticationFlowModel;
|
||||
import org.keycloak.models.AuthenticatorConfigModel;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientScopeModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderModel;
|
||||
import org.keycloak.models.RequiredActionProviderModel;
|
||||
import org.keycloak.models.RequiredCredentialModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
|
||||
public abstract class FakeRealmV12 extends FakeRealmV11 {
|
||||
|
||||
@Override
|
||||
public Stream<RequiredCredentialModel> getRequiredCredentialsStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<GroupModel> getDefaultGroupsStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ClientModel> getClientsStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ClientModel> getClientsStream(Integer firstResult, Integer maxResults) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ClientModel> getAlwaysDisplayInConsoleClientsStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ClientModel> searchClientByClientIdStream(String clientId, Integer firstResult, Integer maxResults) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<AuthenticationFlowModel> getAuthenticationFlowsStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<AuthenticationExecutionModel> getAuthenticationExecutionsStream(String flowId) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<AuthenticatorConfigModel> getAuthenticatorConfigsStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<RequiredActionProviderModel> getRequiredActionProvidersStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<IdentityProviderModel> getIdentityProvidersStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<IdentityProviderMapperModel> getIdentityProviderMappersStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<IdentityProviderMapperModel> getIdentityProviderMappersByAliasStream(String brokerAlias) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComponentModel> getComponentsStream(String parentId, String providerType) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComponentModel> getComponentsStream(String parentId) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ComponentModel> getComponentsStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> getEventsListenersStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> getEnabledEventTypesStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> getSupportedLocalesStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<GroupModel> getGroupsStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<GroupModel> getTopLevelGroupsStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<GroupModel> getTopLevelGroupsStream(Integer first, Integer max) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<GroupModel> searchForGroupByNameStream(String search, Integer first, Integer max) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ClientScopeModel> getClientScopesStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void patchRealmLocalizationTexts(String locale, Map<String, String> localizationTexts) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeRealmLocalizationTexts(String locale) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Map<String, String>> getRealmLocalizationTexts() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getRealmLocalizationTextsByLocale(String locale) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ClientScopeModel> getDefaultClientScopesStream(boolean defaultScope) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<RoleModel> getRolesStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<RoleModel> getRolesStream(Integer firstResult, Integer maxResults) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<RoleModel> searchForRolesStream(String search, Integer first, Integer max) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> getDefaultRolesStream() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2019 Julian Picht
|
||||
* Copyright 2021 Brian Long
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
||||
public class GroupPasswordPolicyFinder {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(GroupPasswordPolicyFinder.class);
|
||||
|
||||
public List<String> findPolicies(RealmModel realm, UserModel user) {
|
||||
// First get the name of the attribute
|
||||
String groupAttribute = realm.getPasswordPolicy().getPolicyConfig(GroupPasswordPolicyProviderFactory.ID);
|
||||
logger.debugf("groupAttribute: %s", groupAttribute);
|
||||
logger.debugf("user: %s", user.getUsername());
|
||||
|
||||
LinkedList<String> policyDefinitions = new LinkedList<>();
|
||||
|
||||
// Iterate groups and collect policy strings
|
||||
user.getGroupsStream().forEach(new Consumer<GroupModel>() {
|
||||
@Override
|
||||
public void accept(GroupModel group) {
|
||||
logger.debugf("group: %s", group.getName());
|
||||
group.getAttributeStream(groupAttribute).forEach(new Consumer<String>() {
|
||||
@Override
|
||||
public void accept(String policyString) {
|
||||
logger.infof("adding group password policy: %s", policyString);
|
||||
policyDefinitions.add(policyString);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return policyDefinitions;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2019 Julian Picht
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
|
||||
public class FakeRealm extends FakeRealmV12 {
|
||||
|
||||
private PasswordPolicy passwordPolicy;
|
||||
|
||||
@Override
|
||||
public PasswordPolicy getPasswordPolicy() {
|
||||
return passwordPolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPasswordPolicy(PasswordPolicy policy) {
|
||||
passwordPolicy = policy;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.keycloak.models.CibaConfig;
|
||||
import org.keycloak.models.ClientInitialAccessModel;
|
||||
import org.keycloak.models.OAuth2DeviceConfig;
|
||||
import org.keycloak.models.RoleModel;
|
||||
|
||||
public abstract class FakeRealmV13 extends FakeRealmV12 {
|
||||
|
||||
@Override
|
||||
public OAuth2DeviceConfig getOAuth2DeviceConfig() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CibaConfig getCibaPolicy() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleModel getDefaultRole() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultRole(RoleModel role) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientInitialAccessModel createClientInitialAccessModel(int expiration, int count) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientInitialAccessModel getClientInitialAccessModel(String id) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeClientInitialAccessModel(String id) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<ClientInitialAccessModel> getClientInitialAccesses() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decreaseRemainingCount(ClientInitialAccessModel clientInitialAccess) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2019 Julian Picht
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
|
||||
public class FakeRealm extends FakeRealmV13 {
|
||||
|
||||
private PasswordPolicy passwordPolicy;
|
||||
|
||||
@Override
|
||||
public PasswordPolicy getPasswordPolicy() {
|
||||
return passwordPolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPasswordPolicy(PasswordPolicy policy) {
|
||||
passwordPolicy = policy;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
|
||||
public abstract class FakeRealmV14 extends FakeRealmV13 {
|
||||
|
||||
@Override
|
||||
public Stream<ClientModel> searchClientByAttributes(Map<String, String> attributes, Integer firstResult, Integer maxResults) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2019 Julian Picht
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
|
||||
public class FakeRealm extends FakeRealmV14 {
|
||||
|
||||
private PasswordPolicy passwordPolicy;
|
||||
|
||||
@Override
|
||||
public PasswordPolicy getPasswordPolicy() {
|
||||
return passwordPolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPasswordPolicy(PasswordPolicy policy) {
|
||||
passwordPolicy = policy;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import org.keycloak.models.ParConfig;
|
||||
|
||||
public class FakeRealmV15 extends FakeRealmV14 {
|
||||
|
||||
@Override
|
||||
public ParConfig getParPolicy() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2019 Julian Picht
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
|
||||
public class FakeRealm extends FakeRealmV15 {
|
||||
|
||||
private PasswordPolicy passwordPolicy;
|
||||
|
||||
@Override
|
||||
public PasswordPolicy getPasswordPolicy() {
|
||||
return passwordPolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPasswordPolicy(PasswordPolicy policy) {
|
||||
passwordPolicy = policy;
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright 2019 Julian Picht
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -36,8 +37,8 @@ import org.keycloak.models.RequiredActionProviderModel;
|
||||
import org.keycloak.models.RequiredCredentialModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
|
||||
public class FakeRealm implements RealmModel {
|
||||
|
||||
public abstract class FakeRealmV6 implements RealmModel {
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
@ -508,15 +509,14 @@ public class FakeRealm implements RealmModel {
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
private PasswordPolicy passwordPolicy;
|
||||
@Override
|
||||
public PasswordPolicy getPasswordPolicy() {
|
||||
return passwordPolicy;
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPasswordPolicy(PasswordPolicy policy) {
|
||||
passwordPolicy = policy;
|
||||
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||
}
|
||||
|
||||
@Override
|
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2019 Julian Picht
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
||||
public class GroupPasswordPolicyFinder {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(GroupPasswordPolicyFinder.class);
|
||||
|
||||
protected List<String> findPolicies(RealmModel realm, UserModel user) {
|
||||
// First get the name of the attribute
|
||||
String groupAttribute = realm.getPasswordPolicy().getPolicyConfig(GroupPasswordPolicyProviderFactory.ID);
|
||||
logger.debugf("groupAttribute: %s", groupAttribute);
|
||||
logger.debugf("user: %s", user.getUsername());
|
||||
|
||||
LinkedList<String> policyDefinitions = new LinkedList<>();
|
||||
|
||||
// Iterate groups and collect policy strings
|
||||
for (GroupModel group : user.getGroups()) {
|
||||
logger.debugf("group: %s", group.getName());
|
||||
for (String policyString : group.getAttribute(groupAttribute)) {
|
||||
logger.infof("adding group password policy: %s", policyString);
|
||||
policyDefinitions.add(policyString);
|
||||
}
|
||||
}
|
||||
|
||||
return policyDefinitions;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2019 Julian Picht
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
|
||||
public class FakeRealm extends FakeRealmV6 {
|
||||
|
||||
private PasswordPolicy passwordPolicy;
|
||||
|
||||
@Override
|
||||
public PasswordPolicy getPasswordPolicy() {
|
||||
return passwordPolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPasswordPolicy(PasswordPolicy policy) {
|
||||
passwordPolicy = policy;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.WebAuthnPolicy;
|
||||
|
||||
public abstract class FakeRealmV8 extends FakeRealmV6 {
|
||||
|
||||
@Override
|
||||
public WebAuthnPolicy getWebAuthnPolicy() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWebAuthnPolicy(WebAuthnPolicy policy) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationExecutionModel getAuthenticationExecutionByFlowId(String flowId) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2019 Julian Picht
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
|
||||
public class FakeRealm extends FakeRealmV8 {
|
||||
|
||||
private PasswordPolicy passwordPolicy;
|
||||
|
||||
@Override
|
||||
public PasswordPolicy getPasswordPolicy() {
|
||||
return passwordPolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPasswordPolicy(PasswordPolicy policy) {
|
||||
passwordPolicy = policy;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import org.keycloak.models.RoleModel;
|
||||
import org.keycloak.models.WebAuthnPolicy;
|
||||
|
||||
public abstract class FakeRealmV9 extends FakeRealmV8 {
|
||||
|
||||
@Override
|
||||
public WebAuthnPolicy getWebAuthnPolicyPasswordless() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWebAuthnPolicyPasswordless(WebAuthnPolicy policy) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClientModel> getClients(Integer firstResult, Integer maxResults) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getClientsCount() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClientModel> getAlwaysDisplayInConsoleClients() {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ClientModel> searchClientByClientId(String clientId, Integer firstResult, Integer maxResults) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupModel createGroup(String id, String name, GroupModel toParent) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> getRoles(Integer firstResult, Integer maxResults) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<RoleModel> searchForRoles(String search, Integer first, Integer max) {
|
||||
throw new UnsupportedOperationException("Not supported yet.");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2019 Julian Picht
|
||||
* Copyright 2021 Brian Long (brian@inteligr8.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
|
||||
public class FakeRealm extends FakeRealmV9 {
|
||||
|
||||
private PasswordPolicy passwordPolicy;
|
||||
|
||||
@Override
|
||||
public PasswordPolicy getPasswordPolicy() {
|
||||
return passwordPolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPasswordPolicy(PasswordPolicy policy) {
|
||||
passwordPolicy = policy;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2021 Brian Long
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config.Scope;
|
||||
import org.keycloak.authentication.RequiredActionFactory;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
|
||||
/**
|
||||
* @author brian@inteligr8.com
|
||||
*/
|
||||
@AutoService(RequiredActionFactory.class)
|
||||
public class GroupExpiredPasswordRequiredActionFactory implements RequiredActionFactory {
|
||||
|
||||
private final Logger logger = Logger.getLogger(GroupExpiredPasswordRequiredActionFactory.class);
|
||||
|
||||
private static final String ID = "groupExpirePassswordAction";
|
||||
private static final String DISPLAY = "Group-based Expired Password";
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequiredActionProvider create(KeycloakSession session) {
|
||||
this.logger.trace("create()");
|
||||
return new GroupExpiredPasswordRequiredActionProvider(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Scope config) {
|
||||
this.logger.trace("init()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayText() {
|
||||
return DISPLAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.logger.trace("close()");
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2021 Brian Long
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
||||
/**
|
||||
* @author brian@inteligr8.com
|
||||
*/
|
||||
public class GroupExpiredPasswordRequiredActionProvider extends RequiredActionMultiplexer {
|
||||
|
||||
private final Logger logger = Logger.getLogger(RequiredActionMultiplexer.class);
|
||||
private final GroupPasswordPolicyFinder finder = new GroupPasswordPolicyFinder();
|
||||
private final KeycloakSession session;
|
||||
|
||||
public GroupExpiredPasswordRequiredActionProvider(KeycloakSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int findDaysToExpire(RealmModel realm, UserModel user) {
|
||||
if (this.logger.isTraceEnabled())
|
||||
this.logger.tracef("findDaysToExpire(%s, %s)", realm == null ? null : realm.getName(), user == null ? null : user.getId());
|
||||
|
||||
List<String> policyStrs = this.finder.findPolicies(realm, user);
|
||||
if (policyStrs == null || policyStrs.isEmpty())
|
||||
return -1;
|
||||
this.logger.debugf("found policies: [%s]", policyStrs.toString());
|
||||
|
||||
Integer minDaysToExpire = null;
|
||||
|
||||
for (String policyStr : policyStrs) {
|
||||
this.logger.tracef("inspecting policy: %s", policyStr);
|
||||
|
||||
PasswordPolicy policy = PasswordPolicy.parse(this.session, policyStr);
|
||||
int daysToExpire = policy.getDaysToExpirePassword();
|
||||
if (daysToExpire < 0)
|
||||
// policy does not have an expiration characteristic; so ignoring ...
|
||||
continue;
|
||||
|
||||
this.logger.debugf("found password expiration policy: %d days", daysToExpire);
|
||||
|
||||
if (minDaysToExpire == null) {
|
||||
// days to expire was set
|
||||
minDaysToExpire = daysToExpire;
|
||||
} else {
|
||||
// days to expire was set; we want the most restrictive
|
||||
minDaysToExpire = Math.min(minDaysToExpire, daysToExpire);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.debugf("determined password expiration policy: %d days", minDaysToExpire);
|
||||
return minDaysToExpire == null ? -1 : minDaysToExpire;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright 2019 Julian Picht
|
||||
* Copyright 2021 Brian Long
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -16,41 +17,24 @@
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.GroupModel;
|
||||
import java.util.List;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.policy.PasswordPolicyConfigException;
|
||||
|
||||
public class GroupPasswordPolicyProvider extends PolicyProviderMultiplexer {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(GroupPasswordPolicyProvider.class);
|
||||
|
||||
private GroupPasswordPolicyFinder finder = new GroupPasswordPolicyFinder();
|
||||
|
||||
public GroupPasswordPolicyProvider(KeycloakSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LinkedList<String> findPolicies(RealmModel realm, UserModel user) {
|
||||
// First get the name of the attribute
|
||||
String groupAttribute = realm.getPasswordPolicy().getPolicyConfig(GroupPasswordPolicyProviderFactory.ID);
|
||||
logger.debugf("groupAttribute %s", groupAttribute);
|
||||
logger.debugf("user %s", user.getUsername());
|
||||
|
||||
LinkedList<String> policyDefinitions = new LinkedList<>();
|
||||
|
||||
// Iterate groups and collect policy strings
|
||||
for (GroupModel group : user.getGroups()) {
|
||||
logger.debugf("group %s", group.getName());
|
||||
for (String policyString : group.getAttribute(groupAttribute)) {
|
||||
logger.infof("adding group password policy: %s", policyString);
|
||||
policyDefinitions.add(policyString);
|
||||
}
|
||||
}
|
||||
|
||||
return policyDefinitions;
|
||||
protected List<String> findPolicies(RealmModel realm, UserModel user) {
|
||||
return this.finder.findPolicies(realm, user);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -64,4 +48,5 @@ public class GroupPasswordPolicyProvider extends PolicyProviderMultiplexer {
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,6 +17,8 @@
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
@ -25,6 +27,8 @@ import org.keycloak.policy.PasswordPolicyProviderFactory;
|
||||
|
||||
@AutoService(PasswordPolicyProviderFactory.class)
|
||||
public class GroupPasswordPolicyProviderFactory implements PasswordPolicyProviderFactory {
|
||||
|
||||
private final Logger logger = Logger.getLogger(GroupPasswordPolicyProviderFactory.class);
|
||||
|
||||
static final String ID = "groupPasswordPolicy";
|
||||
|
||||
@ -40,6 +44,7 @@ public class GroupPasswordPolicyProviderFactory implements PasswordPolicyProvide
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
this.logger.trace("init()");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -68,5 +73,6 @@ public class GroupPasswordPolicyProviderFactory implements PasswordPolicyProvide
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.logger.trace("close()");
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.PasswordPolicy;
|
||||
import org.keycloak.models.RealmModel;
|
||||
@ -38,7 +39,7 @@ abstract public class PolicyProviderMultiplexer implements PasswordPolicyProvide
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
abstract protected LinkedList<String> findPolicies(RealmModel realm, UserModel user);
|
||||
protected abstract List<String> findPolicies(RealmModel realm, UserModel user);
|
||||
|
||||
@Override
|
||||
public PolicyError validate(String username, String password) {
|
||||
@ -65,7 +66,6 @@ abstract public class PolicyProviderMultiplexer implements PasswordPolicyProvide
|
||||
|
||||
// use org.keycloak.models.PasswordPolicy to parse the policy string
|
||||
protected PasswordPolicy parsePolicy(String policy) {
|
||||
LinkedList<PasswordPolicyProvider> list = new LinkedList<>();
|
||||
PasswordPolicy parsedPolicy = PasswordPolicy.parse(session, policy);
|
||||
return parsedPolicy;
|
||||
}
|
||||
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2021 Brian Long
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.github.jpicht.keycloak.policy;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.authentication.InitiatedActionSupport;
|
||||
import org.keycloak.authentication.RequiredActionContext;
|
||||
import org.keycloak.authentication.RequiredActionProvider;
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.credential.CredentialModel;
|
||||
import org.keycloak.credential.CredentialProvider;
|
||||
import org.keycloak.credential.PasswordCredentialProvider;
|
||||
import org.keycloak.credential.PasswordCredentialProviderFactory;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
|
||||
/**
|
||||
* @author brian@inteligr8.com
|
||||
*/
|
||||
abstract class RequiredActionMultiplexer implements RequiredActionProvider {
|
||||
|
||||
private final Logger logger = Logger.getLogger(RequiredActionMultiplexer.class);
|
||||
|
||||
protected abstract int findDaysToExpire(RealmModel realm, UserModel user);
|
||||
|
||||
@Override
|
||||
public InitiatedActionSupport initiatedActionSupport() {
|
||||
return InitiatedActionSupport.SUPPORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a re-implementation of what is found in the default
|
||||
* implementation in Keycloak. It just makes days-to-expire abstract so it
|
||||
* can be implemented any number of ways.
|
||||
*
|
||||
* https://github.com/keycloak/keycloak/blob/af3b573d196af882dfb25cdccb98361746e85481/services/src/main/java/org/keycloak/authentication/requiredactions/UpdatePassword.java#L67
|
||||
*/
|
||||
@Override
|
||||
public void evaluateTriggers(RequiredActionContext context) {
|
||||
this.logger.tracef("evaluateTriggers(%s)", context.getUser() != null ? context.getUser().getUsername() : null);
|
||||
|
||||
int daysToExpirePassword = this.findDaysToExpire(context.getRealm(), context.getUser());
|
||||
if (daysToExpirePassword > -1) {
|
||||
this.logger.debugf("Found password expiration: %d days", daysToExpirePassword);
|
||||
|
||||
PasswordCredentialProvider passwordProvider = (PasswordCredentialProvider)context.getSession()
|
||||
.getProvider(CredentialProvider.class, PasswordCredentialProviderFactory.PROVIDER_ID);
|
||||
CredentialModel password = passwordProvider.getPassword(context.getRealm(), context.getUser());
|
||||
if (password != null) {
|
||||
this.logger.tracef("Found password credentials; created: %d ms", password.getCreatedDate());
|
||||
|
||||
if(password.getCreatedDate() == null) {
|
||||
context.getUser().addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
|
||||
this.logger.debug("User is required to update password");
|
||||
} else {
|
||||
long timeElapsed = Time.currentTimeMillis() - password.getCreatedDate();
|
||||
long timeToExpire = TimeUnit.DAYS.toMillis(daysToExpirePassword);
|
||||
|
||||
if(timeElapsed > timeToExpire) {
|
||||
context.getUser().addRequiredAction(UserModel.RequiredAction.UPDATE_PASSWORD);
|
||||
this.logger.debug("User is required to update password");
|
||||
} else {
|
||||
this.logger.tracef("Password credentials expire in %d ms", timeToExpire);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requiredActionChallenge(RequiredActionContext context) {
|
||||
this.logger.tracef("requiredActionChallenge(%s)", context.getUser() != null ? context.getUser().getUsername() : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processAction(RequiredActionContext context) {
|
||||
this.logger.tracef("processAction(%s)", context.getUser() != null ? context.getUser().getUsername() : null);
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user