426ead23fff2ca4e5e4cd23851f5f41858f29dc8
configuration/buildAndUpdateProduct.sh
| ... | ... | @@ -766,7 +766,7 @@ if [[ "$@" == "build" ]] || [[ "$@" == "all" ]]; then |
| 766 | 766 | JAVA_HOME="${JAVA8_HOME}" `dirname $0`/install-gwt "${PROJECT_HOME}" |
| 767 | 767 | else |
| 768 | 768 | echo "Downloading and installing forked GWT version..." |
| 769 | - `dirname $0`/install-gwt-from-fork-releases https://github.com/SAP/gwt-forward-serialization-rpc https://github.com/SAP/gwt-maven-plugin-forward-serialization-rpc 2.12.2 . |
|
| 769 | + `dirname $0`/install-gwt-from-fork-releases https://github.com/SAP/gwt-forward-serialization-rpc https://github.com/SAP/gwt-maven-plugin-forward-serialization-rpc 2.12.3 . |
|
| 770 | 770 | fi |
| 771 | 771 | fi |
| 772 | 772 | echo "Using following command: mvn $extra -DargLine=\"$APP_PARAMETERS\" -fae -s $MAVEN_SETTINGS $clean install" |
configuration/gwt-poms/gwt-2.12.2.pom
| ... | ... | @@ -1,251 +0,0 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | -<project xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
| 4 | - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
|
| 5 | - <parent> |
|
| 6 | - <groupId>org.sonatype.oss</groupId> |
|
| 7 | - <artifactId>oss-parent</artifactId> |
|
| 8 | - <version>4</version> |
|
| 9 | - </parent> |
|
| 10 | - <modelVersion>4.0.0</modelVersion> |
|
| 11 | - <groupId>org.gwtproject</groupId> |
|
| 12 | - <artifactId>gwt</artifactId> |
|
| 13 | - <packaging>pom</packaging> |
|
| 14 | - <name>GWT</name> |
|
| 15 | - <url>http://www.gwtproject.org/</url> |
|
| 16 | - <version>2.12.2</version> |
|
| 17 | - <licenses> |
|
| 18 | - <license> |
|
| 19 | - <name>GWT Terms</name> |
|
| 20 | - <url>http://www.gwtproject.org/terms.html</url> |
|
| 21 | - </license> |
|
| 22 | - </licenses> |
|
| 23 | - <properties> |
|
| 24 | - <jetty.version>9.4.44.v20210927</jetty.version> |
|
| 25 | - <asm.version>9.2</asm.version> |
|
| 26 | - </properties> |
|
| 27 | - <dependencyManagement> |
|
| 28 | - <dependencies> |
|
| 29 | - <dependency> |
|
| 30 | - <groupId>com.google.gwt</groupId> |
|
| 31 | - <artifactId>gwt-user</artifactId> |
|
| 32 | - <version>${project.version}</version> |
|
| 33 | - </dependency> |
|
| 34 | - <dependency> |
|
| 35 | - <groupId>org.gwtproject</groupId> |
|
| 36 | - <artifactId>gwt-user</artifactId> |
|
| 37 | - <version>${project.version}</version> |
|
| 38 | - </dependency> |
|
| 39 | - <dependency> |
|
| 40 | - <groupId>com.google.gwt</groupId> |
|
| 41 | - <artifactId>gwt-dev</artifactId> |
|
| 42 | - <version>${project.version}</version> |
|
| 43 | - </dependency> |
|
| 44 | - <dependency> |
|
| 45 | - <groupId>org.gwtproject</groupId> |
|
| 46 | - <artifactId>gwt-dev</artifactId> |
|
| 47 | - <version>${project.version}</version> |
|
| 48 | - </dependency> |
|
| 49 | - <dependency> |
|
| 50 | - <groupId>com.google.gwt</groupId> |
|
| 51 | - <artifactId>gwt-codeserver</artifactId> |
|
| 52 | - <version>${project.version}</version> |
|
| 53 | - </dependency> |
|
| 54 | - <dependency> |
|
| 55 | - <groupId>org.gwtproject</groupId> |
|
| 56 | - <artifactId>gwt-codeserver</artifactId> |
|
| 57 | - <version>${project.version}</version> |
|
| 58 | - </dependency> |
|
| 59 | - <dependency> |
|
| 60 | - <groupId>com.google.gwt</groupId> |
|
| 61 | - <artifactId>gwt-servlet</artifactId> |
|
| 62 | - <version>${project.version}</version> |
|
| 63 | - </dependency> |
|
| 64 | - <dependency> |
|
| 65 | - <groupId>org.gwtproject</groupId> |
|
| 66 | - <artifactId>gwt-servlet</artifactId> |
|
| 67 | - <version>${project.version}</version> |
|
| 68 | - </dependency> |
|
| 69 | - <dependency> |
|
| 70 | - <groupId>org.gwtproject.web.bindery</groupId> |
|
| 71 | - <artifactId>requestfactory</artifactId> |
|
| 72 | - <version>${project.version}</version> |
|
| 73 | - <type>pom</type> |
|
| 74 | - <scope>import</scope> |
|
| 75 | - </dependency> |
|
| 76 | - <dependency> |
|
| 77 | - <groupId>com.google.jsinterop</groupId> |
|
| 78 | - <artifactId>jsinterop-annotations</artifactId> |
|
| 79 | - <version>2.0.0</version> |
|
| 80 | - </dependency> |
|
| 81 | - <dependency> |
|
| 82 | - <groupId>javax.servlet</groupId> |
|
| 83 | - <artifactId>javax.servlet-api</artifactId> |
|
| 84 | - <version>3.1.0</version> |
|
| 85 | - </dependency> |
|
| 86 | - <dependency> |
|
| 87 | - <groupId>javax.validation</groupId> |
|
| 88 | - <artifactId>validation-api</artifactId> |
|
| 89 | - <version>1.0.0.GA</version> |
|
| 90 | - </dependency> |
|
| 91 | - <dependency> |
|
| 92 | - <groupId>javax.validation</groupId> |
|
| 93 | - <artifactId>validation-api</artifactId> |
|
| 94 | - <version>1.0.0.GA</version> |
|
| 95 | - <!-- Note: use classifier=sources rather than type=java-sources so they're added to the classpath --> |
|
| 96 | - <classifier>sources</classifier> |
|
| 97 | - </dependency> |
|
| 98 | - <dependency> |
|
| 99 | - <groupId>com.google.code.gson</groupId> |
|
| 100 | - <artifactId>gson</artifactId> |
|
| 101 | - <version>2.6.2</version> |
|
| 102 | - </dependency> |
|
| 103 | - <dependency> |
|
| 104 | - <groupId>org.ow2.asm</groupId> |
|
| 105 | - <artifactId>asm</artifactId> |
|
| 106 | - <version>${asm.version}</version> |
|
| 107 | - </dependency> |
|
| 108 | - <dependency> |
|
| 109 | - <groupId>org.ow2.asm</groupId> |
|
| 110 | - <artifactId>asm-commons</artifactId> |
|
| 111 | - <version>${asm.version}</version> |
|
| 112 | - </dependency> |
|
| 113 | - <dependency> |
|
| 114 | - <groupId>org.ow2.asm</groupId> |
|
| 115 | - <artifactId>asm-util</artifactId> |
|
| 116 | - <version>${asm.version}</version> |
|
| 117 | - </dependency> |
|
| 118 | - <dependency> |
|
| 119 | - <groupId>colt</groupId> |
|
| 120 | - <artifactId>colt</artifactId> |
|
| 121 | - <version>1.2.0</version> |
|
| 122 | - </dependency> |
|
| 123 | - <dependency> |
|
| 124 | - <groupId>commons-collections</groupId> |
|
| 125 | - <artifactId>commons-collections</artifactId> |
|
| 126 | - <version>3.2.2</version> |
|
| 127 | - </dependency> |
|
| 128 | - <dependency> |
|
| 129 | - <groupId>commons-io</groupId> |
|
| 130 | - <artifactId>commons-io</artifactId> |
|
| 131 | - <version>2.4</version> |
|
| 132 | - </dependency> |
|
| 133 | - <dependency> |
|
| 134 | - <groupId>com.ibm.icu</groupId> |
|
| 135 | - <artifactId>icu4j</artifactId> |
|
| 136 | - <version>63.1</version> |
|
| 137 | - </dependency> |
|
| 138 | - <dependency> |
|
| 139 | - <groupId>net.sourceforge.htmlunit</groupId> |
|
| 140 | - <artifactId>htmlunit</artifactId> |
|
| 141 | - <version>2.55.0</version> |
|
| 142 | - </dependency> |
|
| 143 | - <dependency> |
|
| 144 | - <groupId>org.w3c.css</groupId> |
|
| 145 | - <artifactId>sac</artifactId> |
|
| 146 | - <version>1.3</version> |
|
| 147 | - </dependency> |
|
| 148 | - <dependency> |
|
| 149 | - <groupId>tapestry</groupId> |
|
| 150 | - <artifactId>tapestry</artifactId> |
|
| 151 | - <version>4.0.2</version> |
|
| 152 | - </dependency> |
|
| 153 | - <dependency> |
|
| 154 | - <groupId>com.google.code.findbugs</groupId> |
|
| 155 | - <artifactId>jsr305</artifactId> |
|
| 156 | - <version>1.3.9</version> |
|
| 157 | - </dependency> |
|
| 158 | - <!-- For DevMode / JUnitShell (transitive dependency on jetty-server for CodeServer) --> |
|
| 159 | - <dependency> |
|
| 160 | - <groupId>org.eclipse.jetty</groupId> |
|
| 161 | - <artifactId>jetty-webapp</artifactId> |
|
| 162 | - <version>${jetty.version}</version> |
|
| 163 | - </dependency> |
|
| 164 | - <!-- For CodeServer (GZip support) --> |
|
| 165 | - <dependency> |
|
| 166 | - <groupId>org.eclipse.jetty</groupId> |
|
| 167 | - <artifactId>jetty-servlets</artifactId> |
|
| 168 | - <version>${jetty.version}</version> |
|
| 169 | - </dependency> |
|
| 170 | - <!-- For JSPs (and annotations scanning) in DevMode --> |
|
| 171 | - <!-- Those two dependencies are actually optional, included here mostly for backwards compatibility --> |
|
| 172 | - <dependency> |
|
| 173 | - <groupId>org.eclipse.jetty</groupId> |
|
| 174 | - <artifactId>jetty-annotations</artifactId> |
|
| 175 | - <version>${jetty.version}</version> |
|
| 176 | - </dependency> |
|
| 177 | - <dependency> |
|
| 178 | - <groupId>org.eclipse.jetty</groupId> |
|
| 179 | - <artifactId>apache-jsp</artifactId> |
|
| 180 | - <version>${jetty.version}</version> |
|
| 181 | - <exclusions> |
|
| 182 | - <exclusion> |
|
| 183 | - <groupId>org.eclipse.jetty.orbit</groupId> |
|
| 184 | - <artifactId>org.eclipse.jdt.core</artifactId> |
|
| 185 | - </exclusion> |
|
| 186 | - </exclusions> |
|
| 187 | - </dependency> |
|
| 188 | - <!-- Some transitive dependencies of the above, to (tentatively) prevent conflicts --> |
|
| 189 | - <dependency> |
|
| 190 | - <groupId>org.eclipse.jetty.websocket</groupId> |
|
| 191 | - <artifactId>websocket-api</artifactId> |
|
| 192 | - <version>${jetty.version}</version> |
|
| 193 | - </dependency> |
|
| 194 | - <dependency> |
|
| 195 | - <groupId>org.eclipse.jetty.websocket</groupId> |
|
| 196 | - <artifactId>websocket-common</artifactId> |
|
| 197 | - <version>${jetty.version}</version> |
|
| 198 | - </dependency> |
|
| 199 | - <dependency> |
|
| 200 | - <groupId>org.eclipse.jetty</groupId> |
|
| 201 | - <artifactId>jetty-continuation</artifactId> |
|
| 202 | - <version>${jetty.version}</version> |
|
| 203 | - </dependency> |
|
| 204 | - <dependency> |
|
| 205 | - <groupId>org.eclipse.jetty</groupId> |
|
| 206 | - <artifactId>jetty-http</artifactId> |
|
| 207 | - <version>${jetty.version}</version> |
|
| 208 | - </dependency> |
|
| 209 | - <dependency> |
|
| 210 | - <groupId>org.eclipse.jetty</groupId> |
|
| 211 | - <artifactId>jetty-io</artifactId> |
|
| 212 | - <version>${jetty.version}</version> |
|
| 213 | - </dependency> |
|
| 214 | - <dependency> |
|
| 215 | - <groupId>org.eclipse.jetty</groupId> |
|
| 216 | - <artifactId>jetty-jndi</artifactId> |
|
| 217 | - <version>${jetty.version}</version> |
|
| 218 | - </dependency> |
|
| 219 | - <dependency> |
|
| 220 | - <groupId>org.eclipse.jetty</groupId> |
|
| 221 | - <artifactId>jetty-plus</artifactId> |
|
| 222 | - <version>${jetty.version}</version> |
|
| 223 | - </dependency> |
|
| 224 | - <dependency> |
|
| 225 | - <groupId>org.eclipse.jetty</groupId> |
|
| 226 | - <artifactId>jetty-util</artifactId> |
|
| 227 | - <version>${jetty.version}</version> |
|
| 228 | - </dependency> |
|
| 229 | - <dependency> |
|
| 230 | - <groupId>org.eclipse.jetty</groupId> |
|
| 231 | - <artifactId>jetty-security</artifactId> |
|
| 232 | - <version>${jetty.version}</version> |
|
| 233 | - </dependency> |
|
| 234 | - <dependency> |
|
| 235 | - <groupId>org.eclipse.jetty</groupId> |
|
| 236 | - <artifactId>jetty-server</artifactId> |
|
| 237 | - <version>${jetty.version}</version> |
|
| 238 | - </dependency> |
|
| 239 | - <dependency> |
|
| 240 | - <groupId>org.eclipse.jetty</groupId> |
|
| 241 | - <artifactId>jetty-servlet</artifactId> |
|
| 242 | - <version>${jetty.version}</version> |
|
| 243 | - </dependency> |
|
| 244 | - <dependency> |
|
| 245 | - <groupId>org.eclipse.jetty</groupId> |
|
| 246 | - <artifactId>jetty-xml</artifactId> |
|
| 247 | - <version>${jetty.version}</version> |
|
| 248 | - </dependency> |
|
| 249 | - </dependencies> |
|
| 250 | - </dependencyManagement> |
|
| 251 | -</project> |
configuration/gwt-poms/gwt-2.12.3.pom
| ... | ... | @@ -0,0 +1,251 @@ |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
| 4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
|
| 5 | + <parent> |
|
| 6 | + <groupId>org.sonatype.oss</groupId> |
|
| 7 | + <artifactId>oss-parent</artifactId> |
|
| 8 | + <version>4</version> |
|
| 9 | + </parent> |
|
| 10 | + <modelVersion>4.0.0</modelVersion> |
|
| 11 | + <groupId>org.gwtproject</groupId> |
|
| 12 | + <artifactId>gwt</artifactId> |
|
| 13 | + <packaging>pom</packaging> |
|
| 14 | + <name>GWT</name> |
|
| 15 | + <url>http://www.gwtproject.org/</url> |
|
| 16 | + <version>2.12.3</version> |
|
| 17 | + <licenses> |
|
| 18 | + <license> |
|
| 19 | + <name>GWT Terms</name> |
|
| 20 | + <url>http://www.gwtproject.org/terms.html</url> |
|
| 21 | + </license> |
|
| 22 | + </licenses> |
|
| 23 | + <properties> |
|
| 24 | + <jetty.version>9.4.44.v20210927</jetty.version> |
|
| 25 | + <asm.version>9.2</asm.version> |
|
| 26 | + </properties> |
|
| 27 | + <dependencyManagement> |
|
| 28 | + <dependencies> |
|
| 29 | + <dependency> |
|
| 30 | + <groupId>com.google.gwt</groupId> |
|
| 31 | + <artifactId>gwt-user</artifactId> |
|
| 32 | + <version>${project.version}</version> |
|
| 33 | + </dependency> |
|
| 34 | + <dependency> |
|
| 35 | + <groupId>org.gwtproject</groupId> |
|
| 36 | + <artifactId>gwt-user</artifactId> |
|
| 37 | + <version>${project.version}</version> |
|
| 38 | + </dependency> |
|
| 39 | + <dependency> |
|
| 40 | + <groupId>com.google.gwt</groupId> |
|
| 41 | + <artifactId>gwt-dev</artifactId> |
|
| 42 | + <version>${project.version}</version> |
|
| 43 | + </dependency> |
|
| 44 | + <dependency> |
|
| 45 | + <groupId>org.gwtproject</groupId> |
|
| 46 | + <artifactId>gwt-dev</artifactId> |
|
| 47 | + <version>${project.version}</version> |
|
| 48 | + </dependency> |
|
| 49 | + <dependency> |
|
| 50 | + <groupId>com.google.gwt</groupId> |
|
| 51 | + <artifactId>gwt-codeserver</artifactId> |
|
| 52 | + <version>${project.version}</version> |
|
| 53 | + </dependency> |
|
| 54 | + <dependency> |
|
| 55 | + <groupId>org.gwtproject</groupId> |
|
| 56 | + <artifactId>gwt-codeserver</artifactId> |
|
| 57 | + <version>${project.version}</version> |
|
| 58 | + </dependency> |
|
| 59 | + <dependency> |
|
| 60 | + <groupId>com.google.gwt</groupId> |
|
| 61 | + <artifactId>gwt-servlet</artifactId> |
|
| 62 | + <version>${project.version}</version> |
|
| 63 | + </dependency> |
|
| 64 | + <dependency> |
|
| 65 | + <groupId>org.gwtproject</groupId> |
|
| 66 | + <artifactId>gwt-servlet</artifactId> |
|
| 67 | + <version>${project.version}</version> |
|
| 68 | + </dependency> |
|
| 69 | + <dependency> |
|
| 70 | + <groupId>org.gwtproject.web.bindery</groupId> |
|
| 71 | + <artifactId>requestfactory</artifactId> |
|
| 72 | + <version>${project.version}</version> |
|
| 73 | + <type>pom</type> |
|
| 74 | + <scope>import</scope> |
|
| 75 | + </dependency> |
|
| 76 | + <dependency> |
|
| 77 | + <groupId>com.google.jsinterop</groupId> |
|
| 78 | + <artifactId>jsinterop-annotations</artifactId> |
|
| 79 | + <version>2.0.0</version> |
|
| 80 | + </dependency> |
|
| 81 | + <dependency> |
|
| 82 | + <groupId>javax.servlet</groupId> |
|
| 83 | + <artifactId>javax.servlet-api</artifactId> |
|
| 84 | + <version>3.1.0</version> |
|
| 85 | + </dependency> |
|
| 86 | + <dependency> |
|
| 87 | + <groupId>javax.validation</groupId> |
|
| 88 | + <artifactId>validation-api</artifactId> |
|
| 89 | + <version>1.0.0.GA</version> |
|
| 90 | + </dependency> |
|
| 91 | + <dependency> |
|
| 92 | + <groupId>javax.validation</groupId> |
|
| 93 | + <artifactId>validation-api</artifactId> |
|
| 94 | + <version>1.0.0.GA</version> |
|
| 95 | + <!-- Note: use classifier=sources rather than type=java-sources so they're added to the classpath --> |
|
| 96 | + <classifier>sources</classifier> |
|
| 97 | + </dependency> |
|
| 98 | + <dependency> |
|
| 99 | + <groupId>com.google.code.gson</groupId> |
|
| 100 | + <artifactId>gson</artifactId> |
|
| 101 | + <version>2.6.2</version> |
|
| 102 | + </dependency> |
|
| 103 | + <dependency> |
|
| 104 | + <groupId>org.ow2.asm</groupId> |
|
| 105 | + <artifactId>asm</artifactId> |
|
| 106 | + <version>${asm.version}</version> |
|
| 107 | + </dependency> |
|
| 108 | + <dependency> |
|
| 109 | + <groupId>org.ow2.asm</groupId> |
|
| 110 | + <artifactId>asm-commons</artifactId> |
|
| 111 | + <version>${asm.version}</version> |
|
| 112 | + </dependency> |
|
| 113 | + <dependency> |
|
| 114 | + <groupId>org.ow2.asm</groupId> |
|
| 115 | + <artifactId>asm-util</artifactId> |
|
| 116 | + <version>${asm.version}</version> |
|
| 117 | + </dependency> |
|
| 118 | + <dependency> |
|
| 119 | + <groupId>colt</groupId> |
|
| 120 | + <artifactId>colt</artifactId> |
|
| 121 | + <version>1.2.0</version> |
|
| 122 | + </dependency> |
|
| 123 | + <dependency> |
|
| 124 | + <groupId>commons-collections</groupId> |
|
| 125 | + <artifactId>commons-collections</artifactId> |
|
| 126 | + <version>3.2.2</version> |
|
| 127 | + </dependency> |
|
| 128 | + <dependency> |
|
| 129 | + <groupId>commons-io</groupId> |
|
| 130 | + <artifactId>commons-io</artifactId> |
|
| 131 | + <version>2.4</version> |
|
| 132 | + </dependency> |
|
| 133 | + <dependency> |
|
| 134 | + <groupId>com.ibm.icu</groupId> |
|
| 135 | + <artifactId>icu4j</artifactId> |
|
| 136 | + <version>63.1</version> |
|
| 137 | + </dependency> |
|
| 138 | + <dependency> |
|
| 139 | + <groupId>net.sourceforge.htmlunit</groupId> |
|
| 140 | + <artifactId>htmlunit</artifactId> |
|
| 141 | + <version>2.55.0</version> |
|
| 142 | + </dependency> |
|
| 143 | + <dependency> |
|
| 144 | + <groupId>org.w3c.css</groupId> |
|
| 145 | + <artifactId>sac</artifactId> |
|
| 146 | + <version>1.3</version> |
|
| 147 | + </dependency> |
|
| 148 | + <dependency> |
|
| 149 | + <groupId>tapestry</groupId> |
|
| 150 | + <artifactId>tapestry</artifactId> |
|
| 151 | + <version>4.0.2</version> |
|
| 152 | + </dependency> |
|
| 153 | + <dependency> |
|
| 154 | + <groupId>com.google.code.findbugs</groupId> |
|
| 155 | + <artifactId>jsr305</artifactId> |
|
| 156 | + <version>1.3.9</version> |
|
| 157 | + </dependency> |
|
| 158 | + <!-- For DevMode / JUnitShell (transitive dependency on jetty-server for CodeServer) --> |
|
| 159 | + <dependency> |
|
| 160 | + <groupId>org.eclipse.jetty</groupId> |
|
| 161 | + <artifactId>jetty-webapp</artifactId> |
|
| 162 | + <version>${jetty.version}</version> |
|
| 163 | + </dependency> |
|
| 164 | + <!-- For CodeServer (GZip support) --> |
|
| 165 | + <dependency> |
|
| 166 | + <groupId>org.eclipse.jetty</groupId> |
|
| 167 | + <artifactId>jetty-servlets</artifactId> |
|
| 168 | + <version>${jetty.version}</version> |
|
| 169 | + </dependency> |
|
| 170 | + <!-- For JSPs (and annotations scanning) in DevMode --> |
|
| 171 | + <!-- Those two dependencies are actually optional, included here mostly for backwards compatibility --> |
|
| 172 | + <dependency> |
|
| 173 | + <groupId>org.eclipse.jetty</groupId> |
|
| 174 | + <artifactId>jetty-annotations</artifactId> |
|
| 175 | + <version>${jetty.version}</version> |
|
| 176 | + </dependency> |
|
| 177 | + <dependency> |
|
| 178 | + <groupId>org.eclipse.jetty</groupId> |
|
| 179 | + <artifactId>apache-jsp</artifactId> |
|
| 180 | + <version>${jetty.version}</version> |
|
| 181 | + <exclusions> |
|
| 182 | + <exclusion> |
|
| 183 | + <groupId>org.eclipse.jetty.orbit</groupId> |
|
| 184 | + <artifactId>org.eclipse.jdt.core</artifactId> |
|
| 185 | + </exclusion> |
|
| 186 | + </exclusions> |
|
| 187 | + </dependency> |
|
| 188 | + <!-- Some transitive dependencies of the above, to (tentatively) prevent conflicts --> |
|
| 189 | + <dependency> |
|
| 190 | + <groupId>org.eclipse.jetty.websocket</groupId> |
|
| 191 | + <artifactId>websocket-api</artifactId> |
|
| 192 | + <version>${jetty.version}</version> |
|
| 193 | + </dependency> |
|
| 194 | + <dependency> |
|
| 195 | + <groupId>org.eclipse.jetty.websocket</groupId> |
|
| 196 | + <artifactId>websocket-common</artifactId> |
|
| 197 | + <version>${jetty.version}</version> |
|
| 198 | + </dependency> |
|
| 199 | + <dependency> |
|
| 200 | + <groupId>org.eclipse.jetty</groupId> |
|
| 201 | + <artifactId>jetty-continuation</artifactId> |
|
| 202 | + <version>${jetty.version}</version> |
|
| 203 | + </dependency> |
|
| 204 | + <dependency> |
|
| 205 | + <groupId>org.eclipse.jetty</groupId> |
|
| 206 | + <artifactId>jetty-http</artifactId> |
|
| 207 | + <version>${jetty.version}</version> |
|
| 208 | + </dependency> |
|
| 209 | + <dependency> |
|
| 210 | + <groupId>org.eclipse.jetty</groupId> |
|
| 211 | + <artifactId>jetty-io</artifactId> |
|
| 212 | + <version>${jetty.version}</version> |
|
| 213 | + </dependency> |
|
| 214 | + <dependency> |
|
| 215 | + <groupId>org.eclipse.jetty</groupId> |
|
| 216 | + <artifactId>jetty-jndi</artifactId> |
|
| 217 | + <version>${jetty.version}</version> |
|
| 218 | + </dependency> |
|
| 219 | + <dependency> |
|
| 220 | + <groupId>org.eclipse.jetty</groupId> |
|
| 221 | + <artifactId>jetty-plus</artifactId> |
|
| 222 | + <version>${jetty.version}</version> |
|
| 223 | + </dependency> |
|
| 224 | + <dependency> |
|
| 225 | + <groupId>org.eclipse.jetty</groupId> |
|
| 226 | + <artifactId>jetty-util</artifactId> |
|
| 227 | + <version>${jetty.version}</version> |
|
| 228 | + </dependency> |
|
| 229 | + <dependency> |
|
| 230 | + <groupId>org.eclipse.jetty</groupId> |
|
| 231 | + <artifactId>jetty-security</artifactId> |
|
| 232 | + <version>${jetty.version}</version> |
|
| 233 | + </dependency> |
|
| 234 | + <dependency> |
|
| 235 | + <groupId>org.eclipse.jetty</groupId> |
|
| 236 | + <artifactId>jetty-server</artifactId> |
|
| 237 | + <version>${jetty.version}</version> |
|
| 238 | + </dependency> |
|
| 239 | + <dependency> |
|
| 240 | + <groupId>org.eclipse.jetty</groupId> |
|
| 241 | + <artifactId>jetty-servlet</artifactId> |
|
| 242 | + <version>${jetty.version}</version> |
|
| 243 | + </dependency> |
|
| 244 | + <dependency> |
|
| 245 | + <groupId>org.eclipse.jetty</groupId> |
|
| 246 | + <artifactId>jetty-xml</artifactId> |
|
| 247 | + <version>${jetty.version}</version> |
|
| 248 | + </dependency> |
|
| 249 | + </dependencies> |
|
| 250 | + </dependencyManagement> |
|
| 251 | +</project> |
configuration/gwt-poms/gwt-dev-2.12.2.pom
| ... | ... | @@ -1,118 +0,0 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | -<project xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
| 4 | - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
|
| 5 | - <modelVersion>4.0.0</modelVersion> |
|
| 6 | - <parent> |
|
| 7 | - <groupId>org.gwtproject</groupId> |
|
| 8 | - <artifactId>gwt</artifactId> |
|
| 9 | - <version>2.12.2</version> |
|
| 10 | - </parent> |
|
| 11 | - <groupId>org.gwtproject</groupId> |
|
| 12 | - <artifactId>gwt-dev</artifactId> |
|
| 13 | - <packaging>jar</packaging> |
|
| 14 | - <version>2.12.2</version> |
|
| 15 | - |
|
| 16 | - <dependencies> |
|
| 17 | - <dependency> |
|
| 18 | - <groupId>com.google.code.findbugs</groupId> |
|
| 19 | - <artifactId>jsr305</artifactId> |
|
| 20 | - </dependency> |
|
| 21 | - <dependency> |
|
| 22 | - <groupId>com.google.code.gson</groupId> |
|
| 23 | - <artifactId>gson</artifactId> |
|
| 24 | - </dependency> |
|
| 25 | - <dependency> |
|
| 26 | - <groupId>org.ow2.asm</groupId> |
|
| 27 | - <artifactId>asm</artifactId> |
|
| 28 | - </dependency> |
|
| 29 | - <dependency> |
|
| 30 | - <groupId>org.ow2.asm</groupId> |
|
| 31 | - <artifactId>asm-util</artifactId> |
|
| 32 | - </dependency> |
|
| 33 | - <dependency> |
|
| 34 | - <groupId>org.ow2.asm</groupId> |
|
| 35 | - <artifactId>asm-commons</artifactId> |
|
| 36 | - </dependency> |
|
| 37 | - <dependency> |
|
| 38 | - <groupId>colt</groupId> |
|
| 39 | - <artifactId>colt</artifactId> |
|
| 40 | - <exclusions> |
|
| 41 | - <exclusion> |
|
| 42 | - <groupId>concurrent</groupId> |
|
| 43 | - <artifactId>concurrent</artifactId> |
|
| 44 | - </exclusion> |
|
| 45 | - </exclusions> |
|
| 46 | - </dependency> |
|
| 47 | - <dependency> |
|
| 48 | - <groupId>commons-collections</groupId> |
|
| 49 | - <artifactId>commons-collections</artifactId> |
|
| 50 | - </dependency> |
|
| 51 | - <dependency> |
|
| 52 | - <groupId>commons-io</groupId> |
|
| 53 | - <artifactId>commons-io</artifactId> |
|
| 54 | - </dependency> |
|
| 55 | - <dependency> |
|
| 56 | - <groupId>com.ibm.icu</groupId> |
|
| 57 | - <artifactId>icu4j</artifactId> |
|
| 58 | - </dependency> |
|
| 59 | - <dependency> |
|
| 60 | - <groupId>tapestry</groupId> |
|
| 61 | - <artifactId>tapestry</artifactId> |
|
| 62 | - <exclusions> |
|
| 63 | - <exclusion> |
|
| 64 | - <groupId>javassist</groupId> |
|
| 65 | - <artifactId>javassist</artifactId> |
|
| 66 | - </exclusion> |
|
| 67 | - <exclusion> |
|
| 68 | - <groupId>commons-codec</groupId> |
|
| 69 | - <artifactId>commons-codec</artifactId> |
|
| 70 | - </exclusion> |
|
| 71 | - <exclusion> |
|
| 72 | - <groupId>commons-fileupload</groupId> |
|
| 73 | - <artifactId>commons-fileupload</artifactId> |
|
| 74 | - </exclusion> |
|
| 75 | - <exclusion> |
|
| 76 | - <groupId>commons-logging</groupId> |
|
| 77 | - <artifactId>commons-logging</artifactId> |
|
| 78 | - </exclusion> |
|
| 79 | - <exclusion> |
|
| 80 | - <groupId>ognl</groupId> |
|
| 81 | - <artifactId>ognl</artifactId> |
|
| 82 | - </exclusion> |
|
| 83 | - <exclusion> |
|
| 84 | - <groupId>oro</groupId> |
|
| 85 | - <artifactId>oro</artifactId> |
|
| 86 | - </exclusion> |
|
| 87 | - <exclusion> |
|
| 88 | - <groupId>hivemind</groupId> |
|
| 89 | - <artifactId>hivemind</artifactId> |
|
| 90 | - </exclusion> |
|
| 91 | - <exclusion> |
|
| 92 | - <groupId>hivemind</groupId> |
|
| 93 | - <artifactId>hivemind-lib</artifactId> |
|
| 94 | - </exclusion> |
|
| 95 | - </exclusions> |
|
| 96 | - </dependency> |
|
| 97 | - <dependency> |
|
| 98 | - <groupId>net.sourceforge.htmlunit</groupId> |
|
| 99 | - <artifactId>htmlunit</artifactId> |
|
| 100 | - </dependency> |
|
| 101 | - <dependency> |
|
| 102 | - <groupId>org.eclipse.jetty</groupId> |
|
| 103 | - <artifactId>jetty-webapp</artifactId> |
|
| 104 | - </dependency> |
|
| 105 | - <dependency> |
|
| 106 | - <groupId>org.eclipse.jetty</groupId> |
|
| 107 | - <artifactId>jetty-servlets</artifactId> |
|
| 108 | - </dependency> |
|
| 109 | - <dependency> |
|
| 110 | - <groupId>org.eclipse.jetty</groupId> |
|
| 111 | - <artifactId>jetty-annotations</artifactId> |
|
| 112 | - </dependency> |
|
| 113 | - <dependency> |
|
| 114 | - <groupId>org.eclipse.jetty</groupId> |
|
| 115 | - <artifactId>apache-jsp</artifactId> |
|
| 116 | - </dependency> |
|
| 117 | - </dependencies> |
|
| 118 | -</project> |
configuration/gwt-poms/gwt-dev-2.12.3.pom
| ... | ... | @@ -0,0 +1,118 @@ |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
| 4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
|
| 5 | + <modelVersion>4.0.0</modelVersion> |
|
| 6 | + <parent> |
|
| 7 | + <groupId>org.gwtproject</groupId> |
|
| 8 | + <artifactId>gwt</artifactId> |
|
| 9 | + <version>2.12.3</version> |
|
| 10 | + </parent> |
|
| 11 | + <groupId>org.gwtproject</groupId> |
|
| 12 | + <artifactId>gwt-dev</artifactId> |
|
| 13 | + <packaging>jar</packaging> |
|
| 14 | + <version>2.12.3</version> |
|
| 15 | + |
|
| 16 | + <dependencies> |
|
| 17 | + <dependency> |
|
| 18 | + <groupId>com.google.code.findbugs</groupId> |
|
| 19 | + <artifactId>jsr305</artifactId> |
|
| 20 | + </dependency> |
|
| 21 | + <dependency> |
|
| 22 | + <groupId>com.google.code.gson</groupId> |
|
| 23 | + <artifactId>gson</artifactId> |
|
| 24 | + </dependency> |
|
| 25 | + <dependency> |
|
| 26 | + <groupId>org.ow2.asm</groupId> |
|
| 27 | + <artifactId>asm</artifactId> |
|
| 28 | + </dependency> |
|
| 29 | + <dependency> |
|
| 30 | + <groupId>org.ow2.asm</groupId> |
|
| 31 | + <artifactId>asm-util</artifactId> |
|
| 32 | + </dependency> |
|
| 33 | + <dependency> |
|
| 34 | + <groupId>org.ow2.asm</groupId> |
|
| 35 | + <artifactId>asm-commons</artifactId> |
|
| 36 | + </dependency> |
|
| 37 | + <dependency> |
|
| 38 | + <groupId>colt</groupId> |
|
| 39 | + <artifactId>colt</artifactId> |
|
| 40 | + <exclusions> |
|
| 41 | + <exclusion> |
|
| 42 | + <groupId>concurrent</groupId> |
|
| 43 | + <artifactId>concurrent</artifactId> |
|
| 44 | + </exclusion> |
|
| 45 | + </exclusions> |
|
| 46 | + </dependency> |
|
| 47 | + <dependency> |
|
| 48 | + <groupId>commons-collections</groupId> |
|
| 49 | + <artifactId>commons-collections</artifactId> |
|
| 50 | + </dependency> |
|
| 51 | + <dependency> |
|
| 52 | + <groupId>commons-io</groupId> |
|
| 53 | + <artifactId>commons-io</artifactId> |
|
| 54 | + </dependency> |
|
| 55 | + <dependency> |
|
| 56 | + <groupId>com.ibm.icu</groupId> |
|
| 57 | + <artifactId>icu4j</artifactId> |
|
| 58 | + </dependency> |
|
| 59 | + <dependency> |
|
| 60 | + <groupId>tapestry</groupId> |
|
| 61 | + <artifactId>tapestry</artifactId> |
|
| 62 | + <exclusions> |
|
| 63 | + <exclusion> |
|
| 64 | + <groupId>javassist</groupId> |
|
| 65 | + <artifactId>javassist</artifactId> |
|
| 66 | + </exclusion> |
|
| 67 | + <exclusion> |
|
| 68 | + <groupId>commons-codec</groupId> |
|
| 69 | + <artifactId>commons-codec</artifactId> |
|
| 70 | + </exclusion> |
|
| 71 | + <exclusion> |
|
| 72 | + <groupId>commons-fileupload</groupId> |
|
| 73 | + <artifactId>commons-fileupload</artifactId> |
|
| 74 | + </exclusion> |
|
| 75 | + <exclusion> |
|
| 76 | + <groupId>commons-logging</groupId> |
|
| 77 | + <artifactId>commons-logging</artifactId> |
|
| 78 | + </exclusion> |
|
| 79 | + <exclusion> |
|
| 80 | + <groupId>ognl</groupId> |
|
| 81 | + <artifactId>ognl</artifactId> |
|
| 82 | + </exclusion> |
|
| 83 | + <exclusion> |
|
| 84 | + <groupId>oro</groupId> |
|
| 85 | + <artifactId>oro</artifactId> |
|
| 86 | + </exclusion> |
|
| 87 | + <exclusion> |
|
| 88 | + <groupId>hivemind</groupId> |
|
| 89 | + <artifactId>hivemind</artifactId> |
|
| 90 | + </exclusion> |
|
| 91 | + <exclusion> |
|
| 92 | + <groupId>hivemind</groupId> |
|
| 93 | + <artifactId>hivemind-lib</artifactId> |
|
| 94 | + </exclusion> |
|
| 95 | + </exclusions> |
|
| 96 | + </dependency> |
|
| 97 | + <dependency> |
|
| 98 | + <groupId>net.sourceforge.htmlunit</groupId> |
|
| 99 | + <artifactId>htmlunit</artifactId> |
|
| 100 | + </dependency> |
|
| 101 | + <dependency> |
|
| 102 | + <groupId>org.eclipse.jetty</groupId> |
|
| 103 | + <artifactId>jetty-webapp</artifactId> |
|
| 104 | + </dependency> |
|
| 105 | + <dependency> |
|
| 106 | + <groupId>org.eclipse.jetty</groupId> |
|
| 107 | + <artifactId>jetty-servlets</artifactId> |
|
| 108 | + </dependency> |
|
| 109 | + <dependency> |
|
| 110 | + <groupId>org.eclipse.jetty</groupId> |
|
| 111 | + <artifactId>jetty-annotations</artifactId> |
|
| 112 | + </dependency> |
|
| 113 | + <dependency> |
|
| 114 | + <groupId>org.eclipse.jetty</groupId> |
|
| 115 | + <artifactId>apache-jsp</artifactId> |
|
| 116 | + </dependency> |
|
| 117 | + </dependencies> |
|
| 118 | +</project> |
configuration/gwt-poms/gwt-servlet-2.12.2.pom
| ... | ... | @@ -1,29 +0,0 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | -<project xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
| 4 | - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
|
| 5 | - <modelVersion>4.0.0</modelVersion> |
|
| 6 | - <parent> |
|
| 7 | - <groupId>org.gwtproject</groupId> |
|
| 8 | - <artifactId>gwt</artifactId> |
|
| 9 | - <version>2.12.2</version> |
|
| 10 | - </parent> |
|
| 11 | - <groupId>org.gwtproject</groupId> |
|
| 12 | - <artifactId>gwt-servlet</artifactId> |
|
| 13 | - <packaging>jar</packaging> |
|
| 14 | - <version>2.12.2</version> |
|
| 15 | - <dependencies> |
|
| 16 | - <dependency> |
|
| 17 | - <groupId>javax.validation</groupId> |
|
| 18 | - <artifactId>validation-api</artifactId> |
|
| 19 | - <!-- needed by RequestFactory --> |
|
| 20 | - <optional>true</optional> |
|
| 21 | - </dependency> |
|
| 22 | - <dependency> |
|
| 23 | - <groupId>com.google.code.gson</groupId> |
|
| 24 | - <artifactId>gson</artifactId> |
|
| 25 | - <!-- Used for source-mapping in stacktrace deobfuscation for logging --> |
|
| 26 | - <optional>true</optional> |
|
| 27 | - </dependency> |
|
| 28 | - </dependencies> |
|
| 29 | -</project> |
configuration/gwt-poms/gwt-servlet-2.12.3.pom
| ... | ... | @@ -0,0 +1,29 @@ |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
| 4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
|
| 5 | + <modelVersion>4.0.0</modelVersion> |
|
| 6 | + <parent> |
|
| 7 | + <groupId>org.gwtproject</groupId> |
|
| 8 | + <artifactId>gwt</artifactId> |
|
| 9 | + <version>2.12.3</version> |
|
| 10 | + </parent> |
|
| 11 | + <groupId>org.gwtproject</groupId> |
|
| 12 | + <artifactId>gwt-servlet</artifactId> |
|
| 13 | + <packaging>jar</packaging> |
|
| 14 | + <version>2.12.3</version> |
|
| 15 | + <dependencies> |
|
| 16 | + <dependency> |
|
| 17 | + <groupId>javax.validation</groupId> |
|
| 18 | + <artifactId>validation-api</artifactId> |
|
| 19 | + <!-- needed by RequestFactory --> |
|
| 20 | + <optional>true</optional> |
|
| 21 | + </dependency> |
|
| 22 | + <dependency> |
|
| 23 | + <groupId>com.google.code.gson</groupId> |
|
| 24 | + <artifactId>gson</artifactId> |
|
| 25 | + <!-- Used for source-mapping in stacktrace deobfuscation for logging --> |
|
| 26 | + <optional>true</optional> |
|
| 27 | + </dependency> |
|
| 28 | + </dependencies> |
|
| 29 | +</project> |
configuration/gwt-poms/gwt-user-2.12.2.pom
| ... | ... | @@ -1,38 +0,0 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | -<project xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
| 4 | - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
|
| 5 | - <modelVersion>4.0.0</modelVersion> |
|
| 6 | - <parent> |
|
| 7 | - <groupId>org.gwtproject</groupId> |
|
| 8 | - <artifactId>gwt</artifactId> |
|
| 9 | - <version>2.12.2</version> |
|
| 10 | - </parent> |
|
| 11 | - <groupId>org.gwtproject</groupId> |
|
| 12 | - <artifactId>gwt-user</artifactId> |
|
| 13 | - <packaging>jar</packaging> |
|
| 14 | - <version>2.12.2</version> |
|
| 15 | - <dependencies> |
|
| 16 | - <dependency> |
|
| 17 | - <groupId>com.google.jsinterop</groupId> |
|
| 18 | - <artifactId>jsinterop-annotations</artifactId> |
|
| 19 | - </dependency> |
|
| 20 | - <dependency> |
|
| 21 | - <groupId>javax.validation</groupId> |
|
| 22 | - <artifactId>validation-api</artifactId> |
|
| 23 | - </dependency> |
|
| 24 | - <dependency> |
|
| 25 | - <groupId>javax.validation</groupId> |
|
| 26 | - <artifactId>validation-api</artifactId> |
|
| 27 | - <classifier>sources</classifier> |
|
| 28 | - </dependency> |
|
| 29 | - <dependency> |
|
| 30 | - <groupId>javax.servlet</groupId> |
|
| 31 | - <artifactId>javax.servlet-api</artifactId> |
|
| 32 | - </dependency> |
|
| 33 | - <dependency> |
|
| 34 | - <groupId>org.w3c.css</groupId> |
|
| 35 | - <artifactId>sac</artifactId> |
|
| 36 | - </dependency> |
|
| 37 | - </dependencies> |
|
| 38 | -</project> |
configuration/gwt-poms/gwt-user-2.12.3.pom
| ... | ... | @@ -0,0 +1,38 @@ |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
| 4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
|
| 5 | + <modelVersion>4.0.0</modelVersion> |
|
| 6 | + <parent> |
|
| 7 | + <groupId>org.gwtproject</groupId> |
|
| 8 | + <artifactId>gwt</artifactId> |
|
| 9 | + <version>2.12.3</version> |
|
| 10 | + </parent> |
|
| 11 | + <groupId>org.gwtproject</groupId> |
|
| 12 | + <artifactId>gwt-user</artifactId> |
|
| 13 | + <packaging>jar</packaging> |
|
| 14 | + <version>2.12.3</version> |
|
| 15 | + <dependencies> |
|
| 16 | + <dependency> |
|
| 17 | + <groupId>com.google.jsinterop</groupId> |
|
| 18 | + <artifactId>jsinterop-annotations</artifactId> |
|
| 19 | + </dependency> |
|
| 20 | + <dependency> |
|
| 21 | + <groupId>javax.validation</groupId> |
|
| 22 | + <artifactId>validation-api</artifactId> |
|
| 23 | + </dependency> |
|
| 24 | + <dependency> |
|
| 25 | + <groupId>javax.validation</groupId> |
|
| 26 | + <artifactId>validation-api</artifactId> |
|
| 27 | + <classifier>sources</classifier> |
|
| 28 | + </dependency> |
|
| 29 | + <dependency> |
|
| 30 | + <groupId>javax.servlet</groupId> |
|
| 31 | + <artifactId>javax.servlet-api</artifactId> |
|
| 32 | + </dependency> |
|
| 33 | + <dependency> |
|
| 34 | + <groupId>org.w3c.css</groupId> |
|
| 35 | + <artifactId>sac</artifactId> |
|
| 36 | + </dependency> |
|
| 37 | + </dependencies> |
|
| 38 | +</project> |
configuration/gwt-poms/requestfactory-2.12.2.pom
| ... | ... | @@ -1,67 +0,0 @@ |
| 1 | -<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | -<project xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
| 4 | - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
|
| 5 | - <parent> |
|
| 6 | - <groupId>org.sonatype.oss</groupId> |
|
| 7 | - <artifactId>oss-parent</artifactId> |
|
| 8 | - <version>4</version> |
|
| 9 | - </parent> |
|
| 10 | - <modelVersion>4.0.0</modelVersion> |
|
| 11 | - <groupId>org.gwtproject.web.bindery</groupId> |
|
| 12 | - <artifactId>requestfactory</artifactId> |
|
| 13 | - <packaging>pom</packaging> |
|
| 14 | - <name>RequestFactory</name> |
|
| 15 | - <url>http://www.gwtproject.org/doc/latest/DevGuideRequestFactory.html</url> |
|
| 16 | - <version>2.12.2</version> |
|
| 17 | - <licenses> |
|
| 18 | - <license> |
|
| 19 | - <name>GWT Terms</name> |
|
| 20 | - <url>http://www.gwtproject.org/terms.html</url> |
|
| 21 | - </license> |
|
| 22 | - </licenses> |
|
| 23 | - <dependencyManagement> |
|
| 24 | - <dependencies> |
|
| 25 | - <dependency> |
|
| 26 | - <groupId>com.google.web.bindery</groupId> |
|
| 27 | - <artifactId>requestfactory-apt</artifactId> |
|
| 28 | - <version>${project.version}</version> |
|
| 29 | - </dependency> |
|
| 30 | - <dependency> |
|
| 31 | - <groupId>org.gwtproject.web.bindery</groupId> |
|
| 32 | - <artifactId>requestfactory-apt</artifactId> |
|
| 33 | - <version>${project.version}</version> |
|
| 34 | - </dependency> |
|
| 35 | - <dependency> |
|
| 36 | - <groupId>com.google.web.bindery</groupId> |
|
| 37 | - <artifactId>requestfactory-client</artifactId> |
|
| 38 | - <version>${project.version}</version> |
|
| 39 | - </dependency> |
|
| 40 | - <dependency> |
|
| 41 | - <groupId>org.gwtproject.web.bindery</groupId> |
|
| 42 | - <artifactId>requestfactory-client</artifactId> |
|
| 43 | - <version>${project.version}</version> |
|
| 44 | - </dependency> |
|
| 45 | - <dependency> |
|
| 46 | - <groupId>com.google.web.bindery</groupId> |
|
| 47 | - <artifactId>requestfactory-server</artifactId> |
|
| 48 | - <version>${project.version}</version> |
|
| 49 | - </dependency> |
|
| 50 | - <dependency> |
|
| 51 | - <groupId>org.gwtproject.web.bindery</groupId> |
|
| 52 | - <artifactId>requestfactory-server</artifactId> |
|
| 53 | - <version>${project.version}</version> |
|
| 54 | - </dependency> |
|
| 55 | - <dependency> |
|
| 56 | - <groupId>javax.validation</groupId> |
|
| 57 | - <artifactId>validation-api</artifactId> |
|
| 58 | - <version>1.0.0.GA</version> |
|
| 59 | - </dependency> |
|
| 60 | - <dependency> |
|
| 61 | - <groupId>com.google.code.gson</groupId> |
|
| 62 | - <artifactId>gson</artifactId> |
|
| 63 | - <version>2.6.2</version> |
|
| 64 | - </dependency> |
|
| 65 | - </dependencies> |
|
| 66 | - </dependencyManagement> |
|
| 67 | -</project> |
configuration/gwt-poms/requestfactory-2.12.3.pom
| ... | ... | @@ -0,0 +1,67 @@ |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> |
|
| 2 | +<project xmlns="http://maven.apache.org/POM/4.0.0" |
|
| 3 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
|
| 4 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
|
| 5 | + <parent> |
|
| 6 | + <groupId>org.sonatype.oss</groupId> |
|
| 7 | + <artifactId>oss-parent</artifactId> |
|
| 8 | + <version>4</version> |
|
| 9 | + </parent> |
|
| 10 | + <modelVersion>4.0.0</modelVersion> |
|
| 11 | + <groupId>org.gwtproject.web.bindery</groupId> |
|
| 12 | + <artifactId>requestfactory</artifactId> |
|
| 13 | + <packaging>pom</packaging> |
|
| 14 | + <name>RequestFactory</name> |
|
| 15 | + <url>http://www.gwtproject.org/doc/latest/DevGuideRequestFactory.html</url> |
|
| 16 | + <version>2.12.3</version> |
|
| 17 | + <licenses> |
|
| 18 | + <license> |
|
| 19 | + <name>GWT Terms</name> |
|
| 20 | + <url>http://www.gwtproject.org/terms.html</url> |
|
| 21 | + </license> |
|
| 22 | + </licenses> |
|
| 23 | + <dependencyManagement> |
|
| 24 | + <dependencies> |
|
| 25 | + <dependency> |
|
| 26 | + <groupId>com.google.web.bindery</groupId> |
|
| 27 | + <artifactId>requestfactory-apt</artifactId> |
|
| 28 | + <version>${project.version}</version> |
|
| 29 | + </dependency> |
|
| 30 | + <dependency> |
|
| 31 | + <groupId>org.gwtproject.web.bindery</groupId> |
|
| 32 | + <artifactId>requestfactory-apt</artifactId> |
|
| 33 | + <version>${project.version}</version> |
|
| 34 | + </dependency> |
|
| 35 | + <dependency> |
|
| 36 | + <groupId>com.google.web.bindery</groupId> |
|
| 37 | + <artifactId>requestfactory-client</artifactId> |
|
| 38 | + <version>${project.version}</version> |
|
| 39 | + </dependency> |
|
| 40 | + <dependency> |
|
| 41 | + <groupId>org.gwtproject.web.bindery</groupId> |
|
| 42 | + <artifactId>requestfactory-client</artifactId> |
|
| 43 | + <version>${project.version}</version> |
|
| 44 | + </dependency> |
|
| 45 | + <dependency> |
|
| 46 | + <groupId>com.google.web.bindery</groupId> |
|
| 47 | + <artifactId>requestfactory-server</artifactId> |
|
| 48 | + <version>${project.version}</version> |
|
| 49 | + </dependency> |
|
| 50 | + <dependency> |
|
| 51 | + <groupId>org.gwtproject.web.bindery</groupId> |
|
| 52 | + <artifactId>requestfactory-server</artifactId> |
|
| 53 | + <version>${project.version}</version> |
|
| 54 | + </dependency> |
|
| 55 | + <dependency> |
|
| 56 | + <groupId>javax.validation</groupId> |
|
| 57 | + <artifactId>validation-api</artifactId> |
|
| 58 | + <version>1.0.0.GA</version> |
|
| 59 | + </dependency> |
|
| 60 | + <dependency> |
|
| 61 | + <groupId>com.google.code.gson</groupId> |
|
| 62 | + <artifactId>gson</artifactId> |
|
| 63 | + <version>2.6.2</version> |
|
| 64 | + </dependency> |
|
| 65 | + </dependencies> |
|
| 66 | + </dependencyManagement> |
|
| 67 | +</project> |
configuration/install-gwt
| ... | ... | @@ -3,16 +3,13 @@ SAILING_GIT_ROOT="${1}" |
| 3 | 3 | if [ -n "${2}" ]; then |
| 4 | 4 | OUTPUT_FOLDER_FOR_GWT_ZIP="${2}" |
| 5 | 5 | fi |
| 6 | -GWT_VERSION=2.12.2 |
|
| 6 | +GWT_VERSION=2.12.3 |
|
| 7 | 7 | GWT="`mktemp -t -d gwt.XXXXX`" |
| 8 | 8 | GWT_ROOT="${GWT}/trunk" |
| 9 | 9 | cd "${GWT}" |
| 10 | 10 | echo "GWT directory: ${GWT}" |
| 11 | -git clone https://github.com/SAP/gwt-forward-serialization-rpc.git -b issue-7987-gwt-2.12.2 trunk |
|
| 12 | -git clone https://github.com/Vertispan/tools.git -b main |
|
| 13 | -# Or alternatively: |
|
| 14 | -#git clone https://github.com/axeluhl/gwt.git -b issue-7987-compatibility trunk |
|
| 15 | -#git clone https://github.com/gwtproject/tools.git |
|
| 11 | +git clone https://github.com/SAP/gwt-forward-serialization-rpc.git -b issue-7987-gwt-${GWT_VERSION} trunk |
|
| 12 | +git clone https://github.com/gwtproject/tools.git -b main |
|
| 16 | 13 | git clone https://github.com/SAP/gwt-maven-plugin-forward-serialization-rpc.git -b ${GWT_VERSION} gwt-maven-plugin |
| 17 | 14 | cd ${GWT_ROOT} |
| 18 | 15 | ant clean dist-dev -Dgwt.version=${GWT_VERSION} |
java/com.google.gwt.dev/META-INF/MANIFEST.MF
| ... | ... | @@ -2,7 +2,7 @@ Manifest-Version: 1.0 |
| 2 | 2 | Bundle-ManifestVersion: 2 |
| 3 | 3 | Bundle-Name: gwt-dev |
| 4 | 4 | Bundle-SymbolicName: com.google.gwt.dev |
| 5 | -Bundle-Version: 2.12.2 |
|
| 5 | +Bundle-Version: 2.12.3 |
|
| 6 | 6 | Bundle-Vendor: GOOGLE |
| 7 | 7 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 |
| 8 | 8 | Bundle-ClassPath: lib/gwt-dev.jar, |
java/com.google.gwt.dev/lib/gwt-dev.jar
java/com.google.gwt.dev/pom.xml
| ... | ... | @@ -8,6 +8,6 @@ |
| 8 | 8 | <version>1.0.0-SNAPSHOT</version> |
| 9 | 9 | </parent> |
| 10 | 10 | <artifactId>com.google.gwt.dev</artifactId> |
| 11 | - <version>2.12.2</version> |
|
| 11 | + <version>2.12.3</version> |
|
| 12 | 12 | <packaging>eclipse-plugin</packaging> |
| 13 | 13 | </project> |
java/com.google.gwt.servlet/META-INF/MANIFEST.MF
| ... | ... | @@ -3,7 +3,7 @@ Bundle-ManifestVersion: 2 |
| 3 | 3 | Bundle-Name: Dev |
| 4 | 4 | Bundle-SymbolicName: com.google.gwt.servlet |
| 5 | 5 | Automatic-Module-Name: com.google.gwt.servlet |
| 6 | -Bundle-Version: 2.12.2 |
|
| 6 | +Bundle-Version: 2.12.3 |
|
| 7 | 7 | Bundle-Vendor: GOOGLE |
| 8 | 8 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 |
| 9 | 9 | Bundle-ClassPath: lib/gwt-servlet.jar, |
java/com.google.gwt.servlet/lib/gwt-servlet-deps.jar
java/com.google.gwt.servlet/lib/gwt-servlet.jar
java/com.google.gwt.servlet/pom.xml
| ... | ... | @@ -8,6 +8,6 @@ |
| 8 | 8 | <version>1.0.0-SNAPSHOT</version> |
| 9 | 9 | </parent> |
| 10 | 10 | <artifactId>com.google.gwt.servlet</artifactId> |
| 11 | - <version>2.12.2</version> |
|
| 11 | + <version>2.12.3</version> |
|
| 12 | 12 | <packaging>eclipse-plugin</packaging> |
| 13 | 13 | </project> |
java/com.google.gwt.user/META-INF/MANIFEST.MF
| ... | ... | @@ -2,7 +2,7 @@ Manifest-Version: 1.0 |
| 2 | 2 | Bundle-ManifestVersion: 2 |
| 3 | 3 | Bundle-Name: gwt-user |
| 4 | 4 | Bundle-SymbolicName: com.google.gwt.user |
| 5 | -Bundle-Version: 2.12.2 |
|
| 5 | +Bundle-Version: 2.12.3 |
|
| 6 | 6 | Bundle-Vendor: GOOGLE |
| 7 | 7 | Bundle-RequiredExecutionEnvironment: JavaSE-1.8 |
| 8 | 8 | Bundle-ClassPath: lib/gwt-user.jar, |
java/com.google.gwt.user/lib/gwt-user.jar
java/com.google.gwt.user/pom.xml
| ... | ... | @@ -8,6 +8,6 @@ |
| 8 | 8 | <version>1.0.0-SNAPSHOT</version> |
| 9 | 9 | </parent> |
| 10 | 10 | <artifactId>com.google.gwt.user</artifactId> |
| 11 | - <version>2.12.2</version> |
|
| 11 | + <version>2.12.3</version> |
|
| 12 | 12 | <packaging>eclipse-plugin</packaging> |
| 13 | 13 | </project> |
java/com.sap.sailing.aiagent.gateway/resources/shiro.ini
| ... | ... | @@ -26,7 +26,7 @@ securityManager.subjectDAO = $subjectDAO |
| 26 | 26 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 27 | 27 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 28 | 28 | securityManager.cacheManager = $cacheManager |
| 29 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 29 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 30 | 30 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 31 | 31 | |
| 32 | 32 | # Support for anonymous user permissions |
java/com.sap.sailing.dashboards.gwt/.settings/com.gwtplugins.gwt.eclipse.core.prefs
| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | //gwtVersion_/com.google.gwt.servlet/lib= |
| 2 | -//gwtVersion_/com.google.gwt.user/lib=2.11.1 |
|
| 2 | +//gwtVersion_/com.google.gwt.user/lib= |
|
| 3 | 3 | //gwtVersion_/opt/gwt-2.11.0=2.11.0 |
| 4 | 4 | //gwtVersion_/opt/gwt-2.11.1=2.11.1 |
| 5 | 5 | //gwtVersion_/opt/gwt-2.12.2=2.12.2 |
java/com.sap.sailing.dashboards.gwt/GWT Dashboards SDM.launch
| ... | ... | @@ -51,6 +51,7 @@ |
| 51 | 51 | </listAttribute> |
| 52 | 52 | <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.gwtplugins.gwt.eclipse.core.moduleClasspathProvider"/> |
| 53 | 53 | <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> |
| 54 | + <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17/"/> |
|
| 54 | 55 | <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/> |
| 55 | 56 | <stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="com.sap.sailing.dashboards.gwt"/> |
| 56 | 57 | <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-style PRETTY -logLevel INFO -noserver -incremental -war "${project_loc:com.sap.sailing.dashboards.gwt}" -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -codeServerPort 9875 -startupUrl /dashboards/RibDashboard.html com.sap.sailing.dashboards.gwt.RibDashboard"/> |
java/com.sap.sailing.dashboards.gwt/src/main/resources/shiro.ini
| ... | ... | @@ -22,7 +22,7 @@ securityManager.sessionManager.sessionDAO = $sessionDAO |
| 22 | 22 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 23 | 23 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 24 | 24 | securityManager.cacheManager = $cacheManager |
| 25 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 25 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 26 | 26 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 27 | 27 | |
| 28 | 28 | subjectDAO = com.sap.sse.security.NoSessionStorageForUnauthenticatedSessionsSessionDAO |
java/com.sap.sailing.domain.igtimiadapter.gateway/resources/shiro.ini
| ... | ... | @@ -26,7 +26,7 @@ securityManager.subjectDAO = $subjectDAO |
| 26 | 26 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 27 | 27 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 28 | 28 | securityManager.cacheManager = $cacheManager |
| 29 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 29 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 30 | 30 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 31 | 31 | |
| 32 | 32 | # Support for anonymous user permissions |
java/com.sap.sailing.domain.test/src/com/sap/sailing/domain/test/OfflineSerializationTest.java
| ... | ... | @@ -47,11 +47,11 @@ import com.sap.sse.common.Color; |
| 47 | 47 | import com.sap.sse.common.Duration; |
| 48 | 48 | import com.sap.sse.common.Util; |
| 49 | 49 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 50 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 50 | 51 | import com.sap.sse.security.SecurityService; |
| 51 | 52 | import com.sap.sse.security.interfaces.UserStore; |
| 52 | 53 | import com.sap.sse.security.shared.UserGroupManagementException; |
| 53 | 54 | import com.sap.sse.security.shared.UserManagementException; |
| 54 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 55 | 55 | import com.sap.sse.security.shared.impl.User; |
| 56 | 56 | import com.sap.sse.security.shared.impl.UserGroup; |
| 57 | 57 | import com.sap.sse.security.userstore.mongodb.UserStoreImpl; |
| ... | ... | @@ -111,7 +111,7 @@ public class OfflineSerializationTest extends AbstractSerializationTest { |
| 111 | 111 | UserStore userStore = new UserStoreImpl("defaultTenant"); |
| 112 | 112 | userStore.clear(); |
| 113 | 113 | UserGroup defaultTenant = userStore.createUserGroup(UUID.randomUUID(), "admin"+SecurityService.TENANT_SUFFIX); |
| 114 | - User user = userStore.createUser("admin", "", new LockingAndBanningImpl()); |
|
| 114 | + User user = userStore.createUser("admin", "", new TimedLockImpl()); |
|
| 115 | 115 | defaultTenant.add(user); |
| 116 | 116 | userStore.updateUserGroup(defaultTenant); |
| 117 | 117 | user.getDefaultTenantMap().put("testserver", defaultTenant); |
java/com.sap.sailing.domain/src/com/sap/sailing/domain/markpassingcalculation/MarkPassingCalculator.java
| ... | ... | @@ -11,7 +11,6 @@ import java.util.Map; |
| 11 | 11 | import java.util.Map.Entry; |
| 12 | 12 | import java.util.Set; |
| 13 | 13 | import java.util.concurrent.Callable; |
| 14 | -import java.util.concurrent.CountDownLatch; |
|
| 15 | 14 | import java.util.concurrent.ExecutorService; |
| 16 | 15 | import java.util.concurrent.LinkedBlockingQueue; |
| 17 | 16 | import java.util.logging.Level; |
| ... | ... | @@ -64,8 +63,8 @@ public class MarkPassingCalculator { |
| 64 | 63 | private CandidateChooser chooser; |
| 65 | 64 | private static final Logger logger = Logger.getLogger(MarkPassingCalculator.class.getName()); |
| 66 | 65 | private final MarkPassingUpdateListener listener; |
| 67 | - private final static ExecutorService executor = ThreadPoolUtil.INSTANCE |
|
| 68 | - .getDefaultBackgroundTaskThreadPoolExecutor(); |
|
| 66 | + private final static ExecutorService executor = ThreadPoolUtil.INSTANCE.getDefaultBackgroundTaskThreadPoolExecutor(); |
|
| 67 | + private final static ExecutorService initializationExecutor = ThreadPoolUtil.INSTANCE.createBackgroundTaskThreadPoolExecutor("MarkPassingCalculator initializations"); |
|
| 69 | 68 | private final LinkedBlockingQueue<StorePositionUpdateStrategy> queue; |
| 70 | 69 | |
| 71 | 70 | /** |
| ... | ... | @@ -150,7 +149,7 @@ public class MarkPassingCalculator { |
| 150 | 149 | } else { |
| 151 | 150 | listen = null; |
| 152 | 151 | } |
| 153 | - Thread t = new Thread(() -> { |
|
| 152 | + final Runnable waitForInitialization = () -> { |
|
| 154 | 153 | final Set<Callable<Void>> tasks = new HashSet<>(); |
| 155 | 154 | for (Competitor c : race.getRace().getCompetitors()) { |
| 156 | 155 | tasks.add(race.getTrackedRegatta().cpuMeterCallable(() -> { |
| ... | ... | @@ -174,11 +173,11 @@ public class MarkPassingCalculator { |
| 174 | 173 | } |
| 175 | 174 | } |
| 176 | 175 | } |
| 177 | - }, "MarkPassingCalculator for race " + race.getRaceIdentifier() + " initialization"); |
|
| 176 | + }; |
|
| 178 | 177 | if (waitForInitialMarkPassingCalculation) { |
| 179 | - t.run(); |
|
| 178 | + waitForInitialization.run(); |
|
| 180 | 179 | } else { |
| 181 | - t.start(); |
|
| 180 | + initializationExecutor.submit(waitForInitialization); |
|
| 182 | 181 | } |
| 183 | 182 | } |
| 184 | 183 | |
| ... | ... | @@ -461,8 +460,6 @@ public class MarkPassingCalculator { |
| 461 | 460 | fixesForCompetitor.addAll(competitorEntry.getValue()); |
| 462 | 461 | } |
| 463 | 462 | if (!newMarkFixes.isEmpty()) { |
| 464 | - // FIXME bug 2745 use new mark fixes to invalidate chooser's mark position and mutual mark/waypoint |
|
| 465 | - // distance cache |
|
| 466 | 463 | for (Entry<Competitor, List<GPSFixMoving>> fixesAffectedByNewMarkFixes : finder |
| 467 | 464 | .calculateFixesAffectedByNewMarkFixes(newMarkFixes).entrySet()) { |
| 468 | 465 | Collection<GPSFixMoving> fixes = combinedCompetitorFixesFinderConsidersAffected |
| ... | ... | @@ -593,7 +590,6 @@ public class MarkPassingCalculator { |
| 593 | 590 | suspended = false; |
| 594 | 591 | } else { |
| 595 | 592 | suspended = false; |
| 596 | - final CountDownLatch latchForRunningListenRun = new CountDownLatch(1); |
|
| 597 | 593 | enqueueUpdate(new StorePositionUpdateStrategy() { |
| 598 | 594 | @Override |
| 599 | 595 | public void storePositionUpdate(Map<Competitor, List<GPSFixMoving>> competitorFixes, |
| ... | ... | @@ -605,26 +601,16 @@ public class MarkPassingCalculator { |
| 605 | 601 | List<Pair<Competitor, Integer>> suppressedMarkPassings, |
| 606 | 602 | List<Competitor> unSuppressedMarkPassings, CandidateFinder candidateFinder, |
| 607 | 603 | CandidateChooser candidateChooser) { |
| 608 | - latchForRunningListenRun.countDown(); |
|
| 609 | - assert latchForRunningListenRun.getCount() == 0; |
|
| 604 | + if (markPassingRaceFingerprintRegistry != null) { |
|
| 605 | + initializationExecutor.submit(()->{ |
|
| 606 | + final Map<Competitor, Map<Waypoint, MarkPassing>> markPassings = race.getMarkPassings(/* waitForLatestUpdates */ true); |
|
| 607 | + markPassingRaceFingerprintRegistry.storeMarkPassings(race.getRaceIdentifier(), |
|
| 608 | + MarkPassingRaceFingerprintFactory.INSTANCE.createFingerprint(race), |
|
| 609 | + markPassings, race.getRace().getCourse()); |
|
| 610 | + }); |
|
| 611 | + } |
|
| 610 | 612 | } |
| 611 | 613 | }); |
| 612 | - if (markPassingRaceFingerprintRegistry != null) { |
|
| 613 | - // FIXME bug5971: the thread must not be started before Listen.run() has obtained the MarkPassingCalculator's write lock! |
|
| 614 | - new Thread(()->{ |
|
| 615 | - try { |
|
| 616 | - latchForRunningListenRun.await(); |
|
| 617 | - final Map<Competitor, Map<Waypoint, MarkPassing>> markPassings = race.getMarkPassings(/* waitForLatestUpdates */ true); |
|
| 618 | - markPassingRaceFingerprintRegistry.storeMarkPassings(race.getRaceIdentifier(), |
|
| 619 | - MarkPassingRaceFingerprintFactory.INSTANCE.createFingerprint(race), |
|
| 620 | - markPassings, race.getRace().getCourse()); |
|
| 621 | - } catch (InterruptedException e) { |
|
| 622 | - logger.log(Level.SEVERE, "Exception while waiting for Listen.run() to start processing in MarkPassingCalculator for "+ |
|
| 623 | - race.getName(), e); |
|
| 624 | - } |
|
| 625 | - }, "Waiting for mark passings for "+race.getName()+" after having resumed to store the results in registry") |
|
| 626 | - .start(); |
|
| 627 | - } |
|
| 628 | 614 | } |
| 629 | 615 | } |
| 630 | 616 | } finally { |
| ... | ... | @@ -681,4 +667,4 @@ public class MarkPassingCalculator { |
| 681 | 667 | public String toString() { |
| 682 | 668 | return getClass().getName() + " for " + race + " / " + race.getTrackedRegatta().getRegatta() + " with chooser " + chooser; |
| 683 | 669 | } |
| 684 | -} |
|
| ... | ... | \ No newline at end of file |
| 0 | +} |
java/com.sap.sailing.gwt.ui/GWT Sailing SDM ManagementConsole.launch
| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | <booleanAttribute key="com.gwtplugins.gdt.eclipse.core.RUN_SERVER" value="false"/> |
| 4 | 4 | <stringAttribute key="com.gwtplugins.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.DevMode"/> |
| 5 | 5 | <booleanAttribute key="com.gwtplugins.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/> |
| 6 | - <stringAttribute key="com.gwtplugins.gwt.eclipse.core.CLASSIC_DEVMODE_CODE_SERVER_PORT" value="9876"/> |
|
| 6 | + <stringAttribute key="com.gwtplugins.gwt.eclipse.core.CLASSIC_DEVMODE_CODE_SERVER_PORT" value="9879"/> |
|
| 7 | 7 | <listAttribute key="com.gwtplugins.gwt.eclipse.core.ENTRY_POINT_MODULES"> |
| 8 | 8 | <listEntry value="com.sap.sailing.gwt.ui.AdminConsole"/> |
| 9 | 9 | <listEntry value="com.sap.sailing.gwt.home.Home"/> |
| ... | ... | @@ -104,7 +104,7 @@ |
| 104 | 104 | <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> |
| 105 | 105 | <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/> |
| 106 | 106 | <stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="com.sap.sailing.gwt.ui"/> |
| 107 | - <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-style PRETTY -incremental -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9876 -startupUrl /gwt/Home.html -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole"/> |
|
| 107 | + <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-style PRETTY -incremental -war "${project_loc:com.sap.sailing.gwt.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9879 -startupUrl /gwt/Home.html -startupUrl /gwt/AdminConsole.html com.sap.sailing.gwt.home.Home com.sap.sailing.gwt.ui.AdminConsole"/> |
|
| 108 | 108 | <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sailing.gwt.ui"/> |
| 109 | 109 | <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XX:+UseG1GC -XX:+UseStringDeduplication -Dgwt.watchFileChanges=false -Xmx2048m -Dgwt-usearchives=false -Dgwt.persistentunitcache=false"/> |
| 110 | 110 | <stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work"/> |
java/com.sap.sailing.gwt.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sse/security/ui/shared/IpToTimedLockDTO_CustomFieldSerializer.java
| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | +package com.google.gwt.user.client.rpc.core.com.sap.sse.security.ui.shared; |
|
| 2 | + |
|
| 3 | +import com.google.gwt.user.client.rpc.CustomFieldSerializer; |
|
| 4 | +import com.google.gwt.user.client.rpc.SerializationException; |
|
| 5 | +import com.google.gwt.user.client.rpc.SerializationStreamReader; |
|
| 6 | +import com.google.gwt.user.client.rpc.SerializationStreamWriter; |
|
| 7 | +import com.sap.sse.common.TimedLock; |
|
| 8 | +import com.sap.sse.security.ui.shared.IpToTimedLockDTO; |
|
| 9 | + |
|
| 10 | +public class IpToTimedLockDTO_CustomFieldSerializer extends CustomFieldSerializer<IpToTimedLockDTO> { |
|
| 11 | + @Override |
|
| 12 | + public void serializeInstance(SerializationStreamWriter streamWriter, IpToTimedLockDTO instance) |
|
| 13 | + throws SerializationException { |
|
| 14 | + serialize(streamWriter, instance); |
|
| 15 | + } |
|
| 16 | + |
|
| 17 | + public static void serialize(SerializationStreamWriter streamWriter, IpToTimedLockDTO instance) |
|
| 18 | + throws SerializationException { |
|
| 19 | + streamWriter.writeString(instance.getIp()); |
|
| 20 | + streamWriter.writeObject(instance.getTimedLock()); |
|
| 21 | + } |
|
| 22 | + |
|
| 23 | + @Override |
|
| 24 | + public boolean hasCustomInstantiateInstance() { |
|
| 25 | + return true; |
|
| 26 | + } |
|
| 27 | + |
|
| 28 | + @Override |
|
| 29 | + public IpToTimedLockDTO instantiateInstance(SerializationStreamReader streamReader) |
|
| 30 | + throws SerializationException { |
|
| 31 | + return instantiate(streamReader); |
|
| 32 | + } |
|
| 33 | + |
|
| 34 | + public static IpToTimedLockDTO instantiate(SerializationStreamReader streamReader) |
|
| 35 | + throws SerializationException { |
|
| 36 | + return new IpToTimedLockDTO(streamReader.readString(), (TimedLock) streamReader.readObject()); |
|
| 37 | + } |
|
| 38 | + |
|
| 39 | + @Override |
|
| 40 | + public void deserializeInstance(SerializationStreamReader streamReader, IpToTimedLockDTO instance) |
|
| 41 | + throws SerializationException { |
|
| 42 | + deserialize(streamReader, instance); |
|
| 43 | + } |
|
| 44 | + |
|
| 45 | + public static void deserialize(SerializationStreamReader streamReader, IpToTimedLockDTO instance) { |
|
| 46 | + // Done by instantiateInstance |
|
| 47 | + } |
|
| 48 | +} |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/IPBlocklistTableWrapper.java
| ... | ... | @@ -0,0 +1,172 @@ |
| 1 | +package com.sap.sailing.gwt.ui.adminconsole; |
|
| 2 | + |
|
| 3 | +import java.util.ArrayList; |
|
| 4 | +import java.util.Comparator; |
|
| 5 | +import java.util.List; |
|
| 6 | + |
|
| 7 | +import com.google.gwt.event.dom.client.ClickEvent; |
|
| 8 | +import com.google.gwt.event.dom.client.ClickHandler; |
|
| 9 | +import com.google.gwt.user.cellview.client.AbstractCellTable; |
|
| 10 | +import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; |
|
| 11 | +import com.google.gwt.user.client.rpc.AsyncCallback; |
|
| 12 | +import com.google.gwt.user.client.ui.Button; |
|
| 13 | +import com.google.gwt.user.client.ui.HasVerticalAlignment; |
|
| 14 | +import com.google.gwt.user.client.ui.HorizontalPanel; |
|
| 15 | +import com.google.gwt.user.client.ui.Label; |
|
| 16 | +import com.google.gwt.user.client.ui.Widget; |
|
| 17 | +import com.sap.sailing.gwt.ui.client.SailingServiceWriteAsync; |
|
| 18 | +import com.sap.sailing.gwt.ui.client.StringMessages; |
|
| 19 | +import com.sap.sse.gwt.client.ErrorReporter; |
|
| 20 | +import com.sap.sse.gwt.client.celltable.EntityIdentityComparator; |
|
| 21 | +import com.sap.sse.gwt.client.celltable.RefreshableSelectionModel; |
|
| 22 | +import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel; |
|
| 23 | +import com.sap.sse.security.shared.HasPermissions.DefaultActions; |
|
| 24 | +import com.sap.sse.security.shared.WildcardPermission; |
|
| 25 | +import com.sap.sse.security.shared.impl.SecuredSecurityTypes; |
|
| 26 | +import com.sap.sse.security.ui.client.UserService; |
|
| 27 | +import com.sap.sse.security.ui.client.component.SelectedElementsCountingButton; |
|
| 28 | +import com.sap.sse.security.ui.shared.IpToTimedLockDTO; |
|
| 29 | + |
|
| 30 | +abstract class IPBlocklistTableWrapper |
|
| 31 | + extends TableWrapper<IpToTimedLockDTO, RefreshableSelectionModel<IpToTimedLockDTO>> { |
|
| 32 | + private final UserService userService; |
|
| 33 | + private final LabeledAbstractFilterablePanel<IpToTimedLockDTO> filterField; |
|
| 34 | + private final String errorMessageOnDataFailureString; |
|
| 35 | + |
|
| 36 | + protected abstract void fetchData(AsyncCallback<ArrayList<IpToTimedLockDTO>> callback); |
|
| 37 | + |
|
| 38 | + protected abstract void unlockIP(String ip, AsyncCallback<Void> asyncCallback); |
|
| 39 | + |
|
| 40 | + public IPBlocklistTableWrapper(final SailingServiceWriteAsync sailingServiceWrite, final UserService userService, |
|
| 41 | + final String errorMessageOnDataFailureString, final StringMessages stringMessages, |
|
| 42 | + final ErrorReporter errorReporter) { |
|
| 43 | + super(sailingServiceWrite, stringMessages, errorReporter, true, true, |
|
| 44 | + new EntityIdentityComparator<IpToTimedLockDTO>() { |
|
| 45 | + @Override |
|
| 46 | + public boolean representSameEntity(IpToTimedLockDTO dto1, IpToTimedLockDTO dto2) { |
|
| 47 | + return dto1.getIp().equals(dto2.getIp()); |
|
| 48 | + } |
|
| 49 | + |
|
| 50 | + @Override |
|
| 51 | + public int hashCode(IpToTimedLockDTO t) { |
|
| 52 | + return t.getIp().hashCode(); |
|
| 53 | + } |
|
| 54 | + }); |
|
| 55 | + this.userService = userService; |
|
| 56 | + this.errorMessageOnDataFailureString = errorMessageOnDataFailureString; |
|
| 57 | + this.filterField = composeFilterField(); |
|
| 58 | + this.asWidget().ensureDebugId("wrappedTable"); |
|
| 59 | + this.table.ensureDebugId("cellTable"); |
|
| 60 | + configureDataColumns(); |
|
| 61 | + setButtonsAndFilterOnMainPanel(); |
|
| 62 | + loadDataAndPopulateTable(); |
|
| 63 | + } |
|
| 64 | + |
|
| 65 | + private void setButtonsAndFilterOnMainPanel() { |
|
| 66 | + final HorizontalPanel searchPanel = new HorizontalPanel(); |
|
| 67 | + searchPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); |
|
| 68 | + searchPanel.setSpacing(5); |
|
| 69 | + final Label label = new Label(getStringMessages().filterIpAddresses() + ": "); |
|
| 70 | + searchPanel.add(label); |
|
| 71 | + searchPanel.add(filterField.getTextBox()); |
|
| 72 | + // inserted with indices to put them above the table |
|
| 73 | + mainPanel.insert(searchPanel, 0); |
|
| 74 | + mainPanel.insert(composeButtonPanel(), 1); |
|
| 75 | + mainPanel.setSpacing(5); |
|
| 76 | + } |
|
| 77 | + |
|
| 78 | + private Widget composeButtonPanel() { |
|
| 79 | + final HorizontalPanel buttonPanel = new HorizontalPanel(); |
|
| 80 | + buttonPanel.setSpacing(5); |
|
| 81 | + final Button refreshButton = new Button(getStringMessages().refresh(), new ClickHandler() { |
|
| 82 | + @Override |
|
| 83 | + public void onClick(ClickEvent event) { |
|
| 84 | + loadDataAndPopulateTable(); |
|
| 85 | + } |
|
| 86 | + }); |
|
| 87 | + refreshButton.ensureDebugId("refreshButton"); |
|
| 88 | + buttonPanel.add(refreshButton); |
|
| 89 | + if (hasUnlockPermission()) { |
|
| 90 | + final Button unlockButton = composeUnlockButton(); |
|
| 91 | + unlockButton.ensureDebugId("unlockButton"); |
|
| 92 | + buttonPanel.add(unlockButton); |
|
| 93 | + } |
|
| 94 | + return buttonPanel; |
|
| 95 | + } |
|
| 96 | + |
|
| 97 | + private boolean hasUnlockPermission() { |
|
| 98 | + final WildcardPermission unlockIpPermission = SecuredSecurityTypes.LOCKED_IP |
|
| 99 | + .getPermission(DefaultActions.DELETE); |
|
| 100 | + return userService.hasPermission(unlockIpPermission, userService.getServerInfo().getOwnership()); |
|
| 101 | + } |
|
| 102 | + |
|
| 103 | + private SelectedElementsCountingButton<IpToTimedLockDTO> composeUnlockButton() { |
|
| 104 | + return new SelectedElementsCountingButton<IpToTimedLockDTO>(getStringMessages().unlock(), getSelectionModel(), |
|
| 105 | + new ClickHandler() { |
|
| 106 | + @Override |
|
| 107 | + public void onClick(ClickEvent event) { |
|
| 108 | + for (IpToTimedLockDTO e : getSelectionModel().getSelectedSet()) { |
|
| 109 | + unlockIP(e.getIp(), new AsyncCallback<Void>() { |
|
| 110 | + @Override |
|
| 111 | + public void onFailure(Throwable caught) { |
|
| 112 | + errorReporter.reportError(errorMessageOnDataFailureString); |
|
| 113 | + } |
|
| 114 | + |
|
| 115 | + @Override |
|
| 116 | + public void onSuccess(Void result) { |
|
| 117 | + filterField.remove(e); |
|
| 118 | + } |
|
| 119 | + }); |
|
| 120 | + } |
|
| 121 | + } |
|
| 122 | + }); |
|
| 123 | + } |
|
| 124 | + |
|
| 125 | + private void loadDataAndPopulateTable() { |
|
| 126 | + final AsyncCallback<ArrayList<IpToTimedLockDTO>> dataInitializationCallback = new AsyncCallback<ArrayList<IpToTimedLockDTO>>() { |
|
| 127 | + @Override |
|
| 128 | + public void onFailure(Throwable caught) { |
|
| 129 | + errorReporter.reportError(errorMessageOnDataFailureString); |
|
| 130 | + } |
|
| 131 | + |
|
| 132 | + @Override |
|
| 133 | + public void onSuccess(ArrayList<IpToTimedLockDTO> result) { |
|
| 134 | + filterField.clear(); |
|
| 135 | + clear(); |
|
| 136 | + filterField.addAll(result); |
|
| 137 | + } |
|
| 138 | + }; |
|
| 139 | + fetchData(dataInitializationCallback); |
|
| 140 | + } |
|
| 141 | + |
|
| 142 | + private void configureDataColumns() { |
|
| 143 | + final ListHandler<IpToTimedLockDTO> columnListHandler = getColumnSortHandler(); |
|
| 144 | + addColumn(record -> record.getIp(), getStringMessages().ipAddress()); |
|
| 145 | + final Comparator<IpToTimedLockDTO> expiryComparator = (o1, o2) -> { |
|
| 146 | + return o1.getTimedLock().getLockedUntil().compareTo(o2.getTimedLock().getLockedUntil()); |
|
| 147 | + }; |
|
| 148 | + addColumn(record -> record.getTimedLock().getLockedUntil().toString(), getStringMessages().lockedUntil(), |
|
| 149 | + expiryComparator); |
|
| 150 | + table.addColumnSortHandler(columnListHandler); |
|
| 151 | + } |
|
| 152 | + |
|
| 153 | + private LabeledAbstractFilterablePanel<IpToTimedLockDTO> composeFilterField() { |
|
| 154 | + final LabeledAbstractFilterablePanel<IpToTimedLockDTO> filterField = new LabeledAbstractFilterablePanel<IpToTimedLockDTO>( |
|
| 155 | + new Label(getStringMessages().filterIpAddresses()), new ArrayList<>(), getDataProvider(), |
|
| 156 | + getStringMessages()) { |
|
| 157 | + @Override |
|
| 158 | + public Iterable<String> getSearchableStrings(IpToTimedLockDTO dto) { |
|
| 159 | + final List<String> string = new ArrayList<String>(); |
|
| 160 | + string.add(dto.getIp()); |
|
| 161 | + return string; |
|
| 162 | + } |
|
| 163 | + |
|
| 164 | + @Override |
|
| 165 | + public AbstractCellTable<IpToTimedLockDTO> getCellTable() { |
|
| 166 | + return table; |
|
| 167 | + } |
|
| 168 | + }; |
|
| 169 | + registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider()); |
|
| 170 | + return filterField; |
|
| 171 | + } |
|
| 172 | +} |
|
| ... | ... | \ No newline at end of file |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/LocalServerManagementPanel.java
| ... | ... | @@ -52,6 +52,7 @@ import com.sap.sse.security.ui.client.UserStatusEventHandler; |
| 52 | 52 | import com.sap.sse.security.ui.client.component.AccessControlledButtonPanel; |
| 53 | 53 | import com.sap.sse.security.ui.client.component.EditOwnershipDialog; |
| 54 | 54 | import com.sap.sse.security.ui.client.component.editacl.EditACLDialog; |
| 55 | +import com.sap.sse.security.ui.shared.IpToTimedLockDTO; |
|
| 55 | 56 | |
| 56 | 57 | public class LocalServerManagementPanel extends SimplePanel { |
| 57 | 58 | private final SailingServiceWriteAsync sailingService; |
| ... | ... | @@ -87,6 +88,8 @@ public class LocalServerManagementPanel extends SimplePanel { |
| 87 | 88 | mainPanel.add(this.buttonPanel = createServerActionsUi(userService)); |
| 88 | 89 | mainPanel.add(createServerInfoUI()); |
| 89 | 90 | mainPanel.add(createServerConfigurationUI()); |
| 91 | + mainPanel.add(createBearerTokenAbusePanel()); |
|
| 92 | + mainPanel.add(createUserCreationAbusePanel()); |
|
| 90 | 93 | refreshServerConfiguration(); |
| 91 | 94 | if (userService.hasServerPermission(ServerActions.CONFIGURE_CORS_FILTER)) { |
| 92 | 95 | mainPanel.add(createCORSFilterConfigurationUI()); |
| ... | ... | @@ -157,6 +160,44 @@ public class LocalServerManagementPanel extends SimplePanel { |
| 157 | 160 | return captionPanel; |
| 158 | 161 | } |
| 159 | 162 | |
| 163 | + private Widget createBearerTokenAbusePanel() { |
|
| 164 | + final ServerDataCaptionPanel panel = new ServerDataCaptionPanel(stringMessages.ipsLockedForBearerTokenAbuse(), 3); |
|
| 165 | + panel.ensureDebugId("bearerTokenAbusePanel"); |
|
| 166 | + final IPBlocklistTableWrapper table = new IPBlocklistTableWrapper(sailingService, userService, |
|
| 167 | + stringMessages.unableToLoadIpsBlockedForBearerTokenAbuse(), stringMessages, errorReporter) { |
|
| 168 | + @Override |
|
| 169 | + protected void fetchData(AsyncCallback<ArrayList<IpToTimedLockDTO>> callback) { |
|
| 170 | + userService.getUserManagementService().getClientIPBasedTimedLocksForBearerTokenAbuse(callback); |
|
| 171 | + } |
|
| 172 | + |
|
| 173 | + @Override |
|
| 174 | + protected void unlockIP(String ip, AsyncCallback<Void> asyncCallback) { |
|
| 175 | + userService.getUserManagementWriteService().releaseBearerTokenLockOnIp(ip, asyncCallback); |
|
| 176 | + } |
|
| 177 | + }; |
|
| 178 | + panel.setContentWidget(table.asWidget()); |
|
| 179 | + return panel; |
|
| 180 | + } |
|
| 181 | + |
|
| 182 | + private Widget createUserCreationAbusePanel() { |
|
| 183 | + final ServerDataCaptionPanel panel = new ServerDataCaptionPanel(stringMessages.ipsLockedForUserCreationAbuse(), 3); |
|
| 184 | + panel.ensureDebugId("userCreationAbusePanel"); |
|
| 185 | + final IPBlocklistTableWrapper table = new IPBlocklistTableWrapper(sailingService, userService, |
|
| 186 | + stringMessages.unableToLoadIpsBlockedForUserCreationAbuse(), stringMessages, errorReporter) { |
|
| 187 | + @Override |
|
| 188 | + protected void fetchData(AsyncCallback<ArrayList<IpToTimedLockDTO>> callback) { |
|
| 189 | + userService.getUserManagementService().getClientIPBasedTimedLocksForUserCreation(callback); |
|
| 190 | + } |
|
| 191 | + |
|
| 192 | + @Override |
|
| 193 | + protected void unlockIP(String ip, AsyncCallback<Void> asyncCallback) { |
|
| 194 | + userService.getUserManagementWriteService().releaseUserCreationLockOnIp(ip, asyncCallback); |
|
| 195 | + } |
|
| 196 | + }; |
|
| 197 | + panel.setContentWidget(table.asWidget()); |
|
| 198 | + return panel; |
|
| 199 | + } |
|
| 200 | + |
|
| 160 | 201 | private Widget createCORSFilterConfigurationUI() { |
| 161 | 202 | final ServerDataCaptionPanel captionPanel = new ServerDataCaptionPanel(stringMessages.corsAndCSPFilterConfiguration(), 4); |
| 162 | 203 | captionPanel.addWidget("", new Label(stringMessages.corsAndCSPFilterConfigurationHint())); |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.java
| ... | ... | @@ -2547,4 +2547,11 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, |
| 2547 | 2547 | String strategySimulatorReadMore(); |
| 2548 | 2548 | String testConnection(); |
| 2549 | 2549 | String tracTracConnectionTestFailed(String message); |
| 2550 | + String ipsLockedForBearerTokenAbuse(); |
|
| 2551 | + String unableToLoadIpsBlockedForBearerTokenAbuse(); |
|
| 2552 | + String ipAddress(); |
|
| 2553 | + String filterIpAddresses(); |
|
| 2554 | + String unlock(); |
|
| 2555 | + String ipsLockedForUserCreationAbuse(); |
|
| 2556 | + String unableToLoadIpsBlockedForUserCreationAbuse(); |
|
| 2550 | 2557 | } |
| ... | ... | \ No newline at end of file |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages.properties
| ... | ... | @@ -2582,4 +2582,11 @@ exportTWAHistogramToCsv=Export True Wind Angle histogram to CSV |
| 2582 | 2582 | exportWindSpeedHistogramToCsv=Export Wind Speed histogram to CSV |
| 2583 | 2583 | optionalBearerTokenForWindImport=Optional bearer token for wind import |
| 2584 | 2584 | testConnection=Test Connection |
| 2585 | -tracTracConnectionTestFailed=TracTrac connection test failed: {0} |
|
| ... | ... | \ No newline at end of file |
| 0 | +tracTracConnectionTestFailed=TracTrac connection test failed: {0} |
|
| 1 | +ipsLockedForBearerTokenAbuse=IPs locked for Bearer Token abuse |
|
| 2 | +unableToLoadIpsBlockedForBearerTokenAbuse=Unable to load IPs blocked for bearer token abuse |
|
| 3 | +ipAddress=IP Address |
|
| 4 | +filterIpAddresses=Filter IP Addresses |
|
| 5 | +unlock=Unlock |
|
| 6 | +ipsLockedForUserCreationAbuse=IPs Locked for User Creation Abuse |
|
| 7 | +unableToLoadIpsBlockedForUserCreationAbuse=Unable to load IPs Blocked for User Creation Abuse |
java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/StringMessages_de.properties
| ... | ... | @@ -2576,4 +2576,11 @@ exportTWAHistogramToCsv=Histogramm der wahren Windwinkel in CSV exportieren |
| 2576 | 2576 | exportWindSpeedHistogramToCsv=Histogramm der wahren Windgeschwindigkeiten in CSV exportieren |
| 2577 | 2577 | optionalBearerTokenForWindImport=Optionales Bearer Token für Wind-Import |
| 2578 | 2578 | testConnection=Verbindung testen |
| 2579 | -tracTracConnectionTestFailed=TracTrac-Verbindungstest fehlgeschlagen: {0} |
|
| ... | ... | \ No newline at end of file |
| 0 | +tracTracConnectionTestFailed=TracTrac-Verbindungstest fehlgeschlagen: {0} |
|
| 1 | +ipsLockedForBearerTokenAbuse=IPs wegen Missbrauchs von Bearer-Token gesperrt |
|
| 2 | +unableToLoadIpsBlockedForBearerTokenAbuse=Aufgrund von Missbrauch des Inhabertokens blockierte IPs können nicht geladen werden |
|
| 3 | +ipAddress=IP-Addresse |
|
| 4 | +filterIpAddresses=IP-Adressen filtern |
|
| 5 | +unlock=Entsperren |
|
| 6 | +ipsLockedForUserCreationAbuse=Wegen Missbrauchs bei der Benutzererstellung gesperrte IPs |
|
| 7 | +unableToLoadIpsBlockedForUserCreationAbuse=Wegen Missbrauchs der Benutzererstellung blockierte IPs können nicht geladen werden |
java/com.sap.sailing.gwt.ui/src/main/resources/shiro.ini
| ... | ... | @@ -22,7 +22,7 @@ securityManager.sessionManager.sessionDAO = $sessionDAO |
| 22 | 22 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 23 | 23 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 24 | 24 | securityManager.cacheManager = $cacheManager |
| 25 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 25 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 26 | 26 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 27 | 27 | |
| 28 | 28 | subjectDAO = com.sap.sse.security.NoSessionStorageForUnauthenticatedSessionsSessionDAO |
java/com.sap.sailing.hanaexport/resources/shiro.ini
| ... | ... | @@ -26,7 +26,7 @@ securityManager.subjectDAO = $subjectDAO |
| 26 | 26 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 27 | 27 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 28 | 28 | securityManager.cacheManager = $cacheManager |
| 29 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 29 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 30 | 30 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 31 | 31 | |
| 32 | 32 | # Support for anonymous user permissions |
java/com.sap.sailing.landscape.gateway/resources/shiro.ini
| ... | ... | @@ -26,7 +26,7 @@ securityManager.subjectDAO = $subjectDAO |
| 26 | 26 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 27 | 27 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 28 | 28 | securityManager.cacheManager = $cacheManager |
| 29 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 29 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 30 | 30 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 31 | 31 | |
| 32 | 32 | # Support for anonymous user permissions |
java/com.sap.sailing.landscape.ui/resources/shiro.ini
| ... | ... | @@ -24,7 +24,7 @@ securityManager.sessionManager.sessionDAO = $sessionDAO |
| 24 | 24 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 25 | 25 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 26 | 26 | securityManager.cacheManager = $cacheManager |
| 27 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 27 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 28 | 28 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 29 | 29 | |
| 30 | 30 | subjectDAO = com.sap.sse.security.NoSessionStorageForUnauthenticatedSessionsSessionDAO |
java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/LandscapeManagementPanel.java
| ... | ... | @@ -1561,7 +1561,7 @@ public class LandscapeManagementPanel extends SimplePanel { |
| 1561 | 1561 | new AsyncCallback<Void>() { |
| 1562 | 1562 | @Override |
| 1563 | 1563 | public void onSuccess(Void result) { |
| 1564 | - Notification.notify(stringMessages.success(), NotificationType.SUCCESS); |
|
| 1564 | + Notification.notify(stringMessages.unlockedSuccessfully(), NotificationType.SUCCESS); |
|
| 1565 | 1565 | proxiesTableBusy.setBusy(false); |
| 1566 | 1566 | refreshProxiesTable(); |
| 1567 | 1567 | } |
java/com.sap.sailing.landscape.ui/src/com/sap/sailing/landscape/ui/client/i18n/StringMessages.java
| ... | ... | @@ -172,7 +172,7 @@ com.sap.sse.gwt.adminconsole.StringMessages { |
| 172 | 172 | String successfullyRotatedHttpdLogsOnInstance(String instance); |
| 173 | 173 | String invalidOperationForThisProxy(); |
| 174 | 174 | String pleaseProvideNonEmptyNameAndAZ(); |
| 175 | - String success(); |
|
| 175 | + String unlockedSuccessfully(); |
|
| 176 | 176 | String availabilityZone(); |
| 177 | 177 | String runOnExisting(); |
| 178 | 178 | String publicIp(); |
java/com.sap.sailing.polars/resources/shiro.ini
| ... | ... | @@ -26,7 +26,7 @@ securityManager.subjectDAO = $subjectDAO |
| 26 | 26 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 27 | 27 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 28 | 28 | securityManager.cacheManager = $cacheManager |
| 29 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 29 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 30 | 30 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 31 | 31 | |
| 32 | 32 | # Support for anonymous user permissions |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/api/core/ApiContext.java
| ... | ... | @@ -30,6 +30,7 @@ public class ApiContext { |
| 30 | 30 | public static final String SECURITY_CONTEXT = "security"; //$NON-NLS-1$ |
| 31 | 31 | public static final String ADMIN_USERNAME = "admin"; //$NON-NLS-1$ |
| 32 | 32 | public static final String ADMIN_PASSWORD = "admin"; //$NON-NLS-1$ |
| 33 | + public static final String INVALID_TOKEN_SAMPLE = "INVALID_TOKEN_SAMPLE"; |
|
| 33 | 34 | |
| 34 | 35 | private static final Logger logger = Logger.getLogger(ApiContext.class.getName()); |
| 35 | 36 | |
| ... | ... | @@ -75,6 +76,19 @@ public class ApiContext { |
| 75 | 76 | } |
| 76 | 77 | |
| 77 | 78 | /** |
| 79 | + * Creates an ApiContext with an invalid token. Useful for testing. |
|
| 80 | + * |
|
| 81 | + * @param contextRoot |
|
| 82 | + * server instance |
|
| 83 | + * @param context |
|
| 84 | + * web application context |
|
| 85 | + * @return ApiContext with invalid token |
|
| 86 | + */ |
|
| 87 | + public static ApiContext createApiContextWithInvalidToken(String contextRoot, String context) { |
|
| 88 | + return new ApiContext(contextRoot, context, INVALID_TOKEN_SAMPLE); |
|
| 89 | + } |
|
| 90 | + |
|
| 91 | + /** |
|
| 78 | 92 | * Creates an ApiContext with administrator privileges. |
| 79 | 93 | * |
| 80 | 94 | * @param contextRoot |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/core/SeleniumTestInvocationProvider.java
| ... | ... | @@ -18,9 +18,10 @@ import com.sap.sailing.selenium.test.AbstractSeleniumTest; |
| 18 | 18 | * Used to extend the {@link SeleniumTestCase} annotation which in turn is used to mark the test methods of all Selenium |
| 19 | 19 | * tests declared in subclasses of {@link AbstractSeleniumTest}. This provider produces test invocation contexts, one |
| 20 | 20 | * for each {@link TestEnvironmentConfiguration#getDriverDefinitions() driver definition} found in the test environment |
| 21 | - * configuration. These contexts provide a test instance-specific extension of type {@link SeleniumTestEnvironmentInjector} |
|
| 22 | - * which is in particular a {@link TestInstancePostProcessor} that creates and injects a {@link TestEnvironment} created |
|
| 23 | - * for the driver definition known by the parameter resolver.<p> |
|
| 21 | + * configuration. These contexts provide a test instance-specific extension of type |
|
| 22 | + * {@link SeleniumTestEnvironmentInjector} which is in particular a {@link TestInstancePostProcessor} that creates and |
|
| 23 | + * injects a {@link TestEnvironment} created for the driver definition known by the parameter resolver. |
|
| 24 | + * <p> |
|
| 24 | 25 | * |
| 25 | 26 | * @author Axel Uhl (d043530) |
| 26 | 27 | * |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/ActionsHelper.java
| ... | ... | @@ -23,8 +23,9 @@ public class ActionsHelper { |
| 23 | 23 | public static final String UNLINK_RACE_ACTION = "ACTION_UNLINK"; |
| 24 | 24 | public static final String REFRESH_RACE_ACTION = "ACTION_REFRESH_RACE"; |
| 25 | 25 | public static final String SET_START_TIME_ACTION = "ACTION_SET_STARTTIME"; |
| 26 | - |
|
| 26 | + |
|
| 27 | 27 | public static final String UPDATE_ACTION = "UPDATE"; |
| 28 | + public static final String UNLOCK_ACTION = "MANAGE_LOCK"; |
|
| 28 | 29 | public static final String DELETE_ACTION = "DELETE"; |
| 29 | 30 | public static final String CHANGE_OWNERSHIP_ACTION = "CHANGE_OWNERSHIP"; |
| 30 | 31 | |
| ... | ... | @@ -59,6 +60,10 @@ public class ActionsHelper { |
| 59 | 60 | public static WebElement findUpdateAction(SearchContext context) { |
| 60 | 61 | return context.findElement(By.xpath(String.format(ACTION_XPATH, UPDATE_ACTION))); |
| 61 | 62 | } |
| 63 | + |
|
| 64 | + public static WebElement findUnlockAction(SearchContext context) { |
|
| 65 | + return context.findElement(By.xpath(String.format(ACTION_XPATH, UNLOCK_ACTION))); |
|
| 66 | + } |
|
| 62 | 67 | |
| 63 | 68 | public static WebElement findDeleteAction(SearchContext context) { |
| 64 | 69 | return context.findElement(By.xpath(String.format(ACTION_XPATH, DELETE_ACTION))); |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/advanced/IpBlocklistPanelPO.java
| ... | ... | @@ -0,0 +1,75 @@ |
| 1 | +package com.sap.sailing.selenium.pages.adminconsole.advanced; |
|
| 2 | + |
|
| 3 | +import org.openqa.selenium.WebDriver; |
|
| 4 | +import org.openqa.selenium.WebElement; |
|
| 5 | + |
|
| 6 | +import com.sap.sailing.selenium.core.BySeleniumId; |
|
| 7 | +import com.sap.sailing.selenium.core.FindBy; |
|
| 8 | +import com.sap.sailing.selenium.pages.PageArea; |
|
| 9 | +import com.sap.sailing.selenium.pages.gwt.CellTablePO; |
|
| 10 | +import com.sap.sailing.selenium.pages.gwt.DataEntryPO; |
|
| 11 | + |
|
| 12 | +public class IpBlocklistPanelPO extends PageArea { |
|
| 13 | + static class IPBlocklistTablePO extends CellTablePO<IPLockEntry> { |
|
| 14 | + public IPBlocklistTablePO(WebDriver driver, WebElement element) { |
|
| 15 | + super(driver, element); |
|
| 16 | + } |
|
| 17 | + |
|
| 18 | + @Override |
|
| 19 | + protected IPLockEntry createDataEntry(WebElement element) { |
|
| 20 | + return new IPLockEntry(this, element); |
|
| 21 | + } |
|
| 22 | + |
|
| 23 | + } |
|
| 24 | + |
|
| 25 | + public static class IPLockEntry extends DataEntryPO { |
|
| 26 | + private static final String IP_COLUMN = "IP Address"; |
|
| 27 | + private static final String LOCKED_UNTIL_COLUMN = "Locked until"; |
|
| 28 | + |
|
| 29 | + protected IPLockEntry(CellTablePO<IPLockEntry> table, WebElement element) { |
|
| 30 | + super(table, element); |
|
| 31 | + } |
|
| 32 | + |
|
| 33 | + @Override |
|
| 34 | + public String getIdentifier() { |
|
| 35 | + return getIp(); |
|
| 36 | + } |
|
| 37 | + |
|
| 38 | + public String getIp() { |
|
| 39 | + return getColumnContent(IP_COLUMN); |
|
| 40 | + } |
|
| 41 | + |
|
| 42 | + public String getLockedUntil() { |
|
| 43 | + return getColumnContent(LOCKED_UNTIL_COLUMN); |
|
| 44 | + } |
|
| 45 | + } |
|
| 46 | + |
|
| 47 | + public IpBlocklistPanelPO(WebDriver driver, WebElement element) { |
|
| 48 | + super(driver, element); |
|
| 49 | + final WebElement cellTableWebElement = this.findElementBySeleniumId("cellTable"); |
|
| 50 | + this.cellTable = new IPBlocklistTablePO(driver, cellTableWebElement); |
|
| 51 | + } |
|
| 52 | + |
|
| 53 | + @FindBy(how = BySeleniumId.class, using = "refreshButton") |
|
| 54 | + private WebElement refreshButton; |
|
| 55 | + |
|
| 56 | + @FindBy(how = BySeleniumId.class, using = "unlockButton") |
|
| 57 | + private WebElement unlockButton; |
|
| 58 | + |
|
| 59 | + private final IPBlocklistTablePO cellTable; |
|
| 60 | + |
|
| 61 | + public void refresh() { |
|
| 62 | + refreshButton.click(); |
|
| 63 | + } |
|
| 64 | + |
|
| 65 | + public boolean isIpInTable(final String ip) { |
|
| 66 | + final IPLockEntry entry = cellTable.getEntry(ip); |
|
| 67 | + final boolean wasFound = entry != null; |
|
| 68 | + return wasFound; |
|
| 69 | + } |
|
| 70 | + |
|
| 71 | + public void unblockIP(String ip) { |
|
| 72 | + cellTable.getEntry(ip).select(); |
|
| 73 | + unlockButton.click(); |
|
| 74 | + } |
|
| 75 | +} |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/advanced/LocalServerPO.java
| ... | ... | @@ -15,12 +15,28 @@ public class LocalServerPO extends PageArea { |
| 15 | 15 | |
| 16 | 16 | @FindBy(how = BySeleniumId.class, using = "isSelfServiceServerCheckbox-input") |
| 17 | 17 | private WebElement isSelfServiceServerCheckbox; |
| 18 | - |
|
| 18 | + |
|
| 19 | 19 | @FindBy(how = BySeleniumId.class, using = "isPublicServerCheckbox-input") |
| 20 | 20 | private WebElement isPublicServerCheckbox; |
| 21 | - |
|
| 21 | + |
|
| 22 | 22 | @FindBy(how = BySeleniumId.class, using = "isStandaloneServerCheckbox-input") |
| 23 | 23 | private WebElement isStandaloneServerCheckbox; |
| 24 | + |
|
| 25 | + @FindBy(how = BySeleniumId.class, using = "bearerTokenAbusePanel") |
|
| 26 | + private WebElement bearerTokenAbusePanel; |
|
| 27 | + |
|
| 28 | + @FindBy(how = BySeleniumId.class, using = "userCreationAbusePanel") |
|
| 29 | + private WebElement userCreationAbusePanel; |
|
| 30 | + |
|
| 31 | + public IpBlocklistPanelPO getBearerTokenAbusePO() { |
|
| 32 | + final WebElement wrappedTable = bearerTokenAbusePanel.findElement(new BySeleniumId("wrappedTable")); |
|
| 33 | + return new IpBlocklistPanelPO(this.driver, wrappedTable); |
|
| 34 | + } |
|
| 35 | + |
|
| 36 | + public IpBlocklistPanelPO getUserCreationAbusePO() { |
|
| 37 | + final WebElement wrappedTable = userCreationAbusePanel.findElement(new BySeleniumId("wrappedTable")); |
|
| 38 | + return new IpBlocklistPanelPO(this.driver, wrappedTable); |
|
| 39 | + } |
|
| 24 | 40 | |
| 25 | 41 | public void setSelfServiceServer(boolean selfService) { |
| 26 | 42 | if (selfService != isSelfServiceServerCheckbox.isSelected()) { |
| ... | ... | @@ -28,14 +44,14 @@ public class LocalServerPO extends PageArea { |
| 28 | 44 | awaitServerConfigurationUpdated(); |
| 29 | 45 | } |
| 30 | 46 | } |
| 31 | - |
|
| 47 | + |
|
| 32 | 48 | public void setPublicServer(boolean publicServer) { |
| 33 | 49 | if (publicServer != isPublicServerCheckbox.isSelected()) { |
| 34 | 50 | isPublicServerCheckbox.click(); |
| 35 | 51 | awaitServerConfigurationUpdated(); |
| 36 | 52 | } |
| 37 | 53 | } |
| 38 | - |
|
| 54 | + |
|
| 39 | 55 | public void setStandaloneServer(boolean standalone) { |
| 40 | 56 | if (standalone != isStandaloneServerCheckbox.isSelected()) { |
| 41 | 57 | isStandaloneServerCheckbox.click(); |
| ... | ... | @@ -52,5 +68,4 @@ public class LocalServerPO extends PageArea { |
| 52 | 68 | final String updating = isSelfServiceServerCheckbox.getAttribute("updating"); |
| 53 | 69 | return "true".equals(updating); |
| 54 | 70 | } |
| 55 | - |
|
| 56 | 71 | } |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/regatta/RegattaDetailsCompositePO.java
| ... | ... | @@ -72,8 +72,8 @@ public class RegattaDetailsCompositePO extends PageArea { |
| 72 | 72 | if (entry != null) { |
| 73 | 73 | WebElement removeAction = ActionsHelper.findRemoveAction(entry.getWebElement()); |
| 74 | 74 | removeAction.click(); |
| 75 | - ActionsHelper.acceptAlert(this.driver); |
|
| 76 | - waitForAjaxRequests(); |
|
| 75 | + ActionsHelper.acceptAlert(this.driver); |
|
| 76 | + waitForAjaxRequests(); |
|
| 77 | 77 | } |
| 78 | 78 | } |
| 79 | 79 |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/adminconsole/usermanagement/UserManagementPanelPO.java
| ... | ... | @@ -30,7 +30,10 @@ public class UserManagementPanelPO extends PageArea { |
| 30 | 30 | private WebElement createUserButton; |
| 31 | 31 | |
| 32 | 32 | @FindBy(how = BySeleniumId.class, using = "DeleteUserButton") |
| 33 | - private WebElement deleteUserButton; |
|
| 33 | + private WebElement deleteUserButton; |
|
| 34 | + |
|
| 35 | + @FindBy(how = BySeleniumId.class, using = "UnlockUserButton") |
|
| 36 | + private WebElement unlockUserButton; |
|
| 34 | 37 | |
| 35 | 38 | @FindBy(how = BySeleniumId.class, using = "UserNameTextbox") |
| 36 | 39 | private WebElement userNameTextbox; |
| ... | ... | @@ -152,6 +155,43 @@ public class UserManagementPanelPO extends PageArea { |
| 152 | 155 | deleteUserButton.click(); |
| 153 | 156 | } |
| 154 | 157 | |
| 158 | + public void unlockSelectedUsers() { |
|
| 159 | + final List<DataEntryPO> selection = getUserTable().getSelectedEntries(); |
|
| 160 | + final List<String> selectedUsersNames = new ArrayList<String>(); |
|
| 161 | + for (DataEntryPO dataEntryPO : selection) { |
|
| 162 | + final String username = dataEntryPO.getColumnContent("User name"); |
|
| 163 | + selectedUsersNames.add(username); |
|
| 164 | + } |
|
| 165 | + unlockUserButton.click(); |
|
| 166 | + // confirmation dialog |
|
| 167 | + waitForAlertAndAccept(); |
|
| 168 | + // response dialog |
|
| 169 | + waitForAlertAndAccept(); |
|
| 170 | + // wait until all locked untils of previously selected then unlocked users are blanked out |
|
| 171 | + waitUntil(() -> { |
|
| 172 | + for (String selectedUsersName : selectedUsersNames) { |
|
| 173 | + final String lockedUntilVal = findUser(selectedUsersName).getColumnContent("Locked until"); |
|
| 174 | + if (!lockedUntilVal.equals("")) { |
|
| 175 | + return false; |
|
| 176 | + } |
|
| 177 | + } |
|
| 178 | + return true; |
|
| 179 | + }); |
|
| 180 | + |
|
| 181 | + } |
|
| 182 | + |
|
| 183 | + public void unlockUser(String name) { |
|
| 184 | + selectUser(name); |
|
| 185 | + final DataEntryPO entry = findUser(name); |
|
| 186 | + if (entry != null) { |
|
| 187 | + final WebElement action = ActionsHelper.findUnlockAction(entry.getWebElement()); |
|
| 188 | + action.click(); |
|
| 189 | + } |
|
| 190 | + waitUntilAlertIsPresent(); |
|
| 191 | + driver.switchTo().alert().accept(); |
|
| 192 | + waitForAjaxRequests(); |
|
| 193 | + } |
|
| 194 | + |
|
| 155 | 195 | public void waitUntilUserFound(String userName) { |
| 156 | 196 | waitUntil(() -> findUser(userName) != null); |
| 157 | 197 | } |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/pages/authentication/AuthenticationMenuPO.java
| ... | ... | @@ -7,29 +7,32 @@ import com.sap.sailing.selenium.pages.PageArea; |
| 7 | 7 | import com.sap.sailing.selenium.pages.common.AttributeHelper; |
| 8 | 8 | |
| 9 | 9 | public class AuthenticationMenuPO extends PageArea { |
| 10 | - |
|
| 10 | + |
|
| 11 | 11 | public AuthenticationMenuPO(WebDriver driver, WebElement element) { |
| 12 | 12 | super(driver, element); |
| 13 | 13 | } |
| 14 | - |
|
| 14 | + |
|
| 15 | 15 | public boolean isOpen() { |
| 16 | 16 | return AttributeHelper.isEnabled(getWebElement(), "data-open"); |
| 17 | 17 | } |
| 18 | - |
|
| 18 | + |
|
| 19 | 19 | public boolean isLoggedIn() { |
| 20 | 20 | return AttributeHelper.isEnabled(getWebElement(), "data-auth"); |
| 21 | 21 | } |
| 22 | - |
|
| 23 | - public void doLogin(String username, String password) { |
|
| 22 | + |
|
| 23 | + public boolean attemptLogin(String username, String password) { |
|
| 24 | 24 | AuthenticationViewPO authenticationView = showAuthenticationView(); |
| 25 | 25 | authenticationView.getSignInView().doLogin(username, password); |
| 26 | - waitUntil(this::isLoggedIn); |
|
| 26 | + waitForAjaxRequests(); |
|
| 27 | + return isLoggedIn(); |
|
| 27 | 28 | } |
| 28 | - |
|
| 29 | + |
|
| 29 | 30 | private AuthenticationViewPO showAuthenticationView() { |
| 30 | - getWebElement().click(); |
|
| 31 | + if (!this.isOpen()) { |
|
| 32 | + getWebElement().click(); |
|
| 33 | + } |
|
| 31 | 34 | waitUntil(this::isOpen); |
| 32 | 35 | return getPO(AuthenticationViewPO::new, "authenticationView"); |
| 33 | 36 | } |
| 34 | - |
|
| 37 | + |
|
| 35 | 38 | } |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/TestIpLocking.java
| ... | ... | @@ -0,0 +1,113 @@ |
| 1 | +package com.sap.sailing.selenium.test.adminconsole; |
|
| 2 | + |
|
| 3 | +import static org.junit.jupiter.api.Assertions.assertFalse; |
|
| 4 | +import static org.junit.jupiter.api.Assertions.assertTrue; |
|
| 5 | + |
|
| 6 | +import java.util.HashMap; |
|
| 7 | +import java.util.Map; |
|
| 8 | + |
|
| 9 | +import org.junit.jupiter.api.BeforeEach; |
|
| 10 | + |
|
| 11 | +import com.sap.sailing.selenium.api.core.ApiContext; |
|
| 12 | +import com.sap.sailing.selenium.api.core.HttpException.Unauthorized; |
|
| 13 | +import com.sap.sailing.selenium.api.event.PreferencesApi; |
|
| 14 | +import com.sap.sailing.selenium.api.event.SecurityApi; |
|
| 15 | +import com.sap.sailing.selenium.core.SeleniumTestCase; |
|
| 16 | +import com.sap.sailing.selenium.pages.adminconsole.AdminConsolePage; |
|
| 17 | +import com.sap.sailing.selenium.pages.adminconsole.advanced.IpBlocklistPanelPO; |
|
| 18 | +import com.sap.sailing.selenium.pages.adminconsole.advanced.LocalServerPO; |
|
| 19 | +import com.sap.sailing.selenium.test.AbstractSeleniumTest; |
|
| 20 | + |
|
| 21 | +public class TestIpLocking extends AbstractSeleniumTest { |
|
| 22 | + @Override |
|
| 23 | + @BeforeEach |
|
| 24 | + public void setUp() { |
|
| 25 | + clearState(getContextRoot()); |
|
| 26 | + super.setUp(); |
|
| 27 | + } |
|
| 28 | + |
|
| 29 | + @SeleniumTestCase |
|
| 30 | + public void testUnlockingForBearerTokenAbuser() throws InterruptedException { |
|
| 31 | + final AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot()); |
|
| 32 | + final LocalServerPO localServerPanel = adminConsole.goToLocalServerPanel(); |
|
| 33 | + IpBlocklistPanelPO tablePO = localServerPanel.getBearerTokenAbusePO(); |
|
| 34 | + attemptBearerTokenAbuse(4); |
|
| 35 | + tablePO.refresh(); |
|
| 36 | + final String ip = "127.0.0.1"; |
|
| 37 | + assertTrue(tablePO.isIpInTable(ip)); |
|
| 38 | + tablePO.unblockIP(ip); |
|
| 39 | + // reference was getting stale otherwise |
|
| 40 | + tablePO = localServerPanel.getBearerTokenAbusePO(); |
|
| 41 | + assertFalse(tablePO.isIpInTable(ip)); |
|
| 42 | + attemptValidBearerTokenUse(); |
|
| 43 | + } |
|
| 44 | + |
|
| 45 | + private void attemptValidBearerTokenUse() { |
|
| 46 | + // prepare api |
|
| 47 | + final ApiContext ctx = ApiContext.createAdminApiContext(getContextRoot(), ApiContext.SECURITY_CONTEXT); |
|
| 48 | + final Map<String, String> prefObjectAttr = new HashMap<String, String>(); |
|
| 49 | + prefObjectAttr.put("key1", "value1"); |
|
| 50 | + PreferencesApi preferencesApi = new PreferencesApi(); |
|
| 51 | + preferencesApi.createPreference(ctx, "pref1", prefObjectAttr); |
|
| 52 | + } |
|
| 53 | + |
|
| 54 | + private void attemptBearerTokenAbuse(final int attempts) throws InterruptedException { |
|
| 55 | + // prepare api |
|
| 56 | + final ApiContext wrongCtx = ApiContext.createApiContextWithInvalidToken(getContextRoot(), |
|
| 57 | + ApiContext.SECURITY_CONTEXT); |
|
| 58 | + final Map<String, String> prefObjectAttr = new HashMap<String, String>(); |
|
| 59 | + prefObjectAttr.put("key1", "value1"); |
|
| 60 | + final PreferencesApi preferencesApi = new PreferencesApi(); |
|
| 61 | + for (int i = 0; i < attempts; i++) { |
|
| 62 | + // call api |
|
| 63 | + try { |
|
| 64 | + preferencesApi.createPreference(wrongCtx, "pref1", prefObjectAttr); |
|
| 65 | + } catch (Unauthorized e) { |
|
| 66 | + // do nothing as this is expected |
|
| 67 | + } |
|
| 68 | + // wait for lock to expire |
|
| 69 | + long lockDuration = (long) Math.pow(2, i) * 1000; |
|
| 70 | + boolean isFinalAttempt = i == (attempts - 1); |
|
| 71 | + if (!isFinalAttempt) { |
|
| 72 | + Thread.sleep(lockDuration); |
|
| 73 | + } |
|
| 74 | + } |
|
| 75 | + } |
|
| 76 | + |
|
| 77 | + @SeleniumTestCase |
|
| 78 | + public void testUnlockingForUserCreationAbuser() throws InterruptedException { |
|
| 79 | + final AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot()); |
|
| 80 | + final LocalServerPO localServerPanel = adminConsole.goToLocalServerPanel(); |
|
| 81 | + IpBlocklistPanelPO tablePO = localServerPanel.getUserCreationAbusePO(); |
|
| 82 | + spamUserCreation(4); |
|
| 83 | + tablePO.refresh(); |
|
| 84 | + final String ip = "127.0.0.1"; |
|
| 85 | + assertTrue(tablePO.isIpInTable(ip)); |
|
| 86 | + tablePO.unblockIP(ip); |
|
| 87 | + // reference was getting stale otherwise |
|
| 88 | + tablePO = localServerPanel.getUserCreationAbusePO(); |
|
| 89 | + assertFalse(tablePO.isIpInTable(ip)); |
|
| 90 | + attemptValidBearerTokenUse(); |
|
| 91 | + } |
|
| 92 | + |
|
| 93 | + private void spamUserCreation(final int attempts) throws InterruptedException { |
|
| 94 | + for (int i = 0; i < attempts; i++) { |
|
| 95 | + attemptUserCreation(String.valueOf(i)); |
|
| 96 | + // wait for lock to expire |
|
| 97 | + final long lockDuration = (long) Math.pow(2, i) * 1000; |
|
| 98 | + final boolean isFinalAttempt = i == (attempts - 1); |
|
| 99 | + if (!isFinalAttempt) { |
|
| 100 | + Thread.sleep(lockDuration); |
|
| 101 | + } |
|
| 102 | + } |
|
| 103 | + } |
|
| 104 | + |
|
| 105 | + private boolean attemptUserCreation(String seed) { |
|
| 106 | + try { |
|
| 107 | + SecurityApi.createUser("USERNAME" + seed, "PASSWORD").run(); |
|
| 108 | + return true; |
|
| 109 | + } catch (Exception e) { |
|
| 110 | + return false; |
|
| 111 | + } |
|
| 112 | + } |
|
| 113 | +} |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/adminconsole/usermanagement/TestUserManagement.java
| ... | ... | @@ -1,7 +1,9 @@ |
| 1 | 1 | package com.sap.sailing.selenium.test.adminconsole.usermanagement; |
| 2 | 2 | |
| 3 | +import static org.junit.jupiter.api.Assertions.assertFalse; |
|
| 3 | 4 | import static org.junit.jupiter.api.Assertions.assertNotNull; |
| 4 | 5 | import static org.junit.jupiter.api.Assertions.assertNull; |
| 6 | +import static org.junit.jupiter.api.Assertions.assertTrue; |
|
| 5 | 7 | |
| 6 | 8 | import org.junit.jupiter.api.BeforeEach; |
| 7 | 9 | |
| ... | ... | @@ -13,6 +15,7 @@ import com.sap.sailing.selenium.pages.adminconsole.usermanagement.EditUserDialog |
| 13 | 15 | import com.sap.sailing.selenium.pages.adminconsole.usermanagement.UserManagementPanelPO; |
| 14 | 16 | import com.sap.sailing.selenium.pages.adminconsole.usermanagement.UserRoleDefinitionPanelPO; |
| 15 | 17 | import com.sap.sailing.selenium.pages.adminconsole.usermanagement.WildcardPermissionPanelPO; |
| 18 | +import com.sap.sailing.selenium.pages.authentication.AuthenticationMenuPO; |
|
| 16 | 19 | import com.sap.sailing.selenium.test.AbstractSeleniumTest; |
| 17 | 20 | |
| 18 | 21 | public class TestUserManagement extends AbstractSeleniumTest { |
| ... | ... | @@ -55,7 +58,7 @@ public class TestUserManagement extends AbstractSeleniumTest { |
| 55 | 58 | assertNull(userRolesPO.findRole(TEST_ROLE)); |
| 56 | 59 | createRole(userRolesPO); |
| 57 | 60 | userManagementPanel.selectUser(TEST_USER_NAME); |
| 58 | - assertNotNull(userRolesPO.findRole(TEST_ROLE + ":"+ TEST_GROUP + ":" + TEST_USER_NAME)); |
|
| 61 | + assertNotNull(userRolesPO.findRole(TEST_ROLE + ":" + TEST_GROUP + ":" + TEST_USER_NAME)); |
|
| 59 | 62 | } |
| 60 | 63 | |
| 61 | 64 | private void createRole(final UserRoleDefinitionPanelPO userRolesPO) { |
| ... | ... | @@ -101,6 +104,63 @@ public class TestUserManagement extends AbstractSeleniumTest { |
| 101 | 104 | } |
| 102 | 105 | |
| 103 | 106 | @SeleniumTestCase |
| 107 | + public void testUnlockUser() throws InterruptedException { |
|
| 108 | + // at admin |
|
| 109 | + UserManagementPanelPO userManagementPanel = goToUserManagementPanel(); |
|
| 110 | + createUser(userManagementPanel); |
|
| 111 | + // logout so test user can login |
|
| 112 | + AuthenticationMenuPO authenticationMenu = logoutAndGoToAdminConsolePage().getAuthenticationMenu(); |
|
| 113 | + attemptAbusiveLogins(TEST_USER_NAME, "wrongPassword", 6, authenticationMenu); |
|
| 114 | + // 16s lock window in place now, sufficient to log into admin, unlock user |
|
| 115 | + // and return till test user can login, within the erstwhile lock window |
|
| 116 | + assertTrue(authenticationMenu.attemptLogin("admin", "admin")); |
|
| 117 | + userManagementPanel = goToUserManagementPanel(); |
|
| 118 | + userManagementPanel.unlockUser(TEST_USER_NAME); |
|
| 119 | + // logout and correct login within now-unlocked lock window |
|
| 120 | + authenticationMenu = logoutAndGoToAdminConsolePage().getAuthenticationMenu(); |
|
| 121 | + assertTrue( |
|
| 122 | + authenticationMenu.attemptLogin( |
|
| 123 | + TEST_USER_NAME, TEST_USER_PASSWORD + UserManagementPanelPO.PASSWORD_COMPLEXITY_SALT)); |
|
| 124 | + } |
|
| 125 | + |
|
| 126 | + @SeleniumTestCase |
|
| 127 | + public void testUnlockSelectionOfUsers() throws InterruptedException { |
|
| 128 | + // at admin |
|
| 129 | + UserManagementPanelPO userManagementPanel = goToUserManagementPanel(); |
|
| 130 | + createUser(userManagementPanel); |
|
| 131 | + // logout so test user can login |
|
| 132 | + AuthenticationMenuPO authenticationMenu = logoutAndGoToAdminConsolePage().getAuthenticationMenu(); |
|
| 133 | + attemptAbusiveLogins(TEST_USER_NAME, "wrongPassword", 5, authenticationMenu); |
|
| 134 | + // 16s lock window in place now, sufficient to log into admin, unlock user |
|
| 135 | + // and return till test user can login, within the erstwhile lock window |
|
| 136 | + assertTrue(authenticationMenu.attemptLogin("admin", "admin")); |
|
| 137 | + userManagementPanel = goToUserManagementPanel(); |
|
| 138 | + userManagementPanel.selectUser(TEST_USER_NAME); |
|
| 139 | + userManagementPanel.unlockSelectedUsers(); |
|
| 140 | + // logout and correct login within now-unlocked lock window |
|
| 141 | + authenticationMenu = logoutAndGoToAdminConsolePage().getAuthenticationMenu(); |
|
| 142 | + assertTrue( |
|
| 143 | + authenticationMenu.attemptLogin( |
|
| 144 | + TEST_USER_NAME, TEST_USER_PASSWORD + UserManagementPanelPO.PASSWORD_COMPLEXITY_SALT)); |
|
| 145 | + } |
|
| 146 | + |
|
| 147 | + private void attemptAbusiveLogins(final String username, final String wrongPassword, final int attempts, AuthenticationMenuPO authenticationMenu) |
|
| 148 | + throws InterruptedException { |
|
| 149 | + // logout so test user can login |
|
| 150 | + for (int i = 0; i < attempts; i++) { |
|
| 151 | + // attempt login with wrong password |
|
| 152 | + boolean didSucceed = authenticationMenu.attemptLogin(username, wrongPassword); |
|
| 153 | + assertFalse(didSucceed); |
|
| 154 | + // wait for lock to pass |
|
| 155 | + long lockDuration = (long) Math.pow(2, i) * 1000; |
|
| 156 | + boolean isFinalAttempt = i == (attempts - 1); |
|
| 157 | + if (!isFinalAttempt) { |
|
| 158 | + Thread.sleep(lockDuration); |
|
| 159 | + } |
|
| 160 | + } |
|
| 161 | + } |
|
| 162 | + |
|
| 163 | + @SeleniumTestCase |
|
| 104 | 164 | public void testRemoveUserPermission() { |
| 105 | 165 | final UserManagementPanelPO userManagementPanel = goToUserManagementPanel(); |
| 106 | 166 | createUser(userManagementPanel); |
| ... | ... | @@ -128,4 +188,9 @@ public class TestUserManagement extends AbstractSeleniumTest { |
| 128 | 188 | final AdminConsolePage adminConsole = AdminConsolePage.goToPage(getWebDriver(), getContextRoot()); |
| 129 | 189 | return adminConsole.goToUserManagement(); |
| 130 | 190 | } |
| 191 | + |
|
| 192 | + private AdminConsolePage logoutAndGoToAdminConsolePage() { |
|
| 193 | + getWebDriver().manage().deleteCookieNamed("JSESSIONID"); |
|
| 194 | + return AdminConsolePage.goToPage(getWebDriver(), getContextRoot()); |
|
| 195 | + } |
|
| 131 | 196 | } |
java/com.sap.sailing.selenium.test/src/com/sap/sailing/selenium/test/authentication/TestAuthenticationSignIn.java
| ... | ... | @@ -18,16 +18,44 @@ public class TestAuthenticationSignIn extends AbstractSeleniumTest { |
| 18 | 18 | clearState(getContextRoot()); |
| 19 | 19 | getWebDriver().manage().deleteCookieNamed("JSESSIONID"); |
| 20 | 20 | } |
| 21 | - |
|
| 21 | + |
|
| 22 | 22 | @SeleniumTestCase |
| 23 | 23 | public void testSignInWithExistingUserAdmin() { |
| 24 | 24 | AdminConsolePage adminConsolePage = AdminConsolePage.goToPage(getWebDriver(), getContextRoot()); |
| 25 | 25 | AuthenticationMenuPO authenticationMenu = adminConsolePage.getAuthenticationMenu(); |
| 26 | 26 | assertFalse(authenticationMenu.isOpen()); |
| 27 | 27 | assertFalse(authenticationMenu.isLoggedIn()); |
| 28 | - authenticationMenu.doLogin("admin", "admin"); |
|
| 29 | - assertTrue(authenticationMenu.isOpen()); |
|
| 30 | - assertTrue(authenticationMenu.isLoggedIn()); |
|
| 28 | + final boolean didSucceed = authenticationMenu.attemptLogin("admin", "admin"); |
|
| 29 | + assertTrue(didSucceed); |
|
| 30 | + } |
|
| 31 | + |
|
| 32 | + // test logic is brittle, it is expected that |
|
| 33 | + // login in test environment takes reliably under |
|
| 34 | + // 4 seconds |
|
| 35 | + @SeleniumTestCase |
|
| 36 | + public void testOffendingSignInWithTimedLock() throws InterruptedException { |
|
| 37 | + AdminConsolePage adminConsolePage = AdminConsolePage.goToPage(getWebDriver(), getContextRoot()); |
|
| 38 | + AuthenticationMenuPO authenticationMenu = adminConsolePage.getAuthenticationMenu(); |
|
| 39 | + assertFalse(authenticationMenu.isOpen()); |
|
| 40 | + assertFalse(authenticationMenu.isLoggedIn()); |
|
| 41 | + // wrong login 1 |
|
| 42 | + boolean didSucceed = authenticationMenu.attemptLogin("admin", "wrongPassword"); |
|
| 43 | + assertFalse(didSucceed); |
|
| 44 | + Thread.sleep(2000); // wait for 2s lock to pass |
|
| 45 | + didSucceed = authenticationMenu.attemptLogin("admin", "wrongPassword"); |
|
| 46 | + assertFalse(didSucceed); |
|
| 47 | + Thread.sleep(4000); // wait for 4s lock to pass |
|
| 48 | + didSucceed = authenticationMenu.attemptLogin("admin", "wrongPassword"); |
|
| 49 | + assertFalse(didSucceed); |
|
| 50 | + // 4s lock window in place now |
|
| 51 | + // we assert that even correct credentials |
|
| 52 | + // attempted within this lock window will fail. |
|
| 53 | + didSucceed = authenticationMenu.attemptLogin("admin", "admin"); |
|
| 54 | + assertFalse(didSucceed); |
|
| 55 | + Thread.sleep(8000); // wait for 8s lock to pass (inefficient, but correct) |
|
| 56 | + // correct credentials should work after lock window lapses |
|
| 57 | + didSucceed = authenticationMenu.attemptLogin("admin", "admin"); |
|
| 58 | + assertTrue(didSucceed); |
|
| 31 | 59 | } |
| 32 | 60 | |
| 33 | 61 | } |
java/com.sap.sailing.server.gateway.test.support/resources/shiro.ini
| ... | ... | @@ -32,7 +32,7 @@ securityManager.sessionManager.sessionDAO = $sessionDAO |
| 32 | 32 | securityManager.sessionManager.globalSessionTimeout = 31536000000
|
| 33 | 33 | cacheManager = com.sap.sse.security.SessionCacheManager
|
| 34 | 34 | securityManager.cacheManager = $cacheManager
|
| 35 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
|
|
| 35 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks
|
|
| 36 | 36 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy
|
| 37 | 37 | |
| 38 | 38 | # Authentication Filter Configurations
|
java/com.sap.sailing.server.gateway.test/src/com/sap/sailing/server/gateway/test/jaxrs/RegattasResourceTest.java
| ... | ... | @@ -49,11 +49,11 @@ import com.sap.sailing.domain.ranking.OneDesignRankingMetric; |
| 49 | 49 | import com.sap.sse.common.Color; |
| 50 | 50 | import com.sap.sse.common.TimePoint; |
| 51 | 51 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 52 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 52 | 53 | import com.sap.sse.rest.StreamingOutputUtil; |
| 53 | 54 | import com.sap.sse.security.SecurityService; |
| 54 | 55 | import com.sap.sse.security.interfaces.UserImpl; |
| 55 | 56 | import com.sap.sse.security.shared.Account; |
| 56 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 57 | 57 | import com.sap.sse.security.shared.impl.User; |
| 58 | 58 | |
| 59 | 59 | public class RegattasResourceTest extends AbstractJaxRsApiTest { |
| ... | ... | @@ -160,7 +160,7 @@ public class RegattasResourceTest extends AbstractJaxRsApiTest { |
| 160 | 160 | public void testCompetitorRegistrationByAdmin() throws Exception { |
| 161 | 161 | doReturn(securityService).when(regattasResource).getService(SecurityService.class); |
| 162 | 162 | doReturn(true).when(securityService).hasCurrentUserUpdatePermission(Mockito.any()); |
| 163 | - User user = new UserImpl("admin", "noreply@sapsailing.com", null, new ArrayList<Account>(0), null, new LockingAndBanningImpl()); |
|
| 163 | + User user = new UserImpl("admin", "noreply@sapsailing.com", null, new ArrayList<Account>(0), null, new TimedLockImpl()); |
|
| 164 | 164 | setUser(user); |
| 165 | 165 | when(securityService.getCurrentUser()).thenReturn(user); |
| 166 | 166 | Response response = regattasResource.createAndAddCompetitor(closedRegattaName, boatClassName, null, "GER", |
| ... | ... | @@ -218,7 +218,7 @@ public class RegattasResourceTest extends AbstractJaxRsApiTest { |
| 218 | 218 | @Test |
| 219 | 219 | public void testCompetitorRegistrationAuthenticatedOnOpenRegatta() throws Exception { |
| 220 | 220 | doReturn(securityService).when(regattasResource).getService(SecurityService.class); |
| 221 | - User user = new UserImpl("max", "noreply@sapsailing.com", null, new ArrayList<Account>(0), null, new LockingAndBanningImpl()); |
|
| 221 | + User user = new UserImpl("max", "noreply@sapsailing.com", null, new ArrayList<Account>(0), null, new TimedLockImpl()); |
|
| 222 | 222 | setUser(user); |
| 223 | 223 | Regatta regatta = racingEventService.getRegattaByName(openRegattaName); |
| 224 | 224 | Response response = regattasResource.createAndAddCompetitor(openRegattaName, boatClassName, null, "GER", "#F00", |
java/com.sap.sailing.server.gateway/resources/shiro.ini
| ... | ... | @@ -26,7 +26,7 @@ securityManager.subjectDAO = $subjectDAO |
| 26 | 26 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 27 | 27 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 28 | 28 | securityManager.cacheManager = $cacheManager |
| 29 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 29 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 30 | 30 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 31 | 31 | |
| 32 | 32 | # Support for anonymous user permissions |
java/com.sap.sailing.server.replication.test/src/com/sap/sailing/server/replication/test/MediaReplicationTest.java
| ... | ... | @@ -57,6 +57,7 @@ import com.sap.sse.common.TimePoint; |
| 57 | 57 | import com.sap.sse.common.Util; |
| 58 | 58 | import com.sap.sse.common.impl.MillisecondsDurationImpl; |
| 59 | 59 | import com.sap.sse.common.impl.MillisecondsTimePoint; |
| 60 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 60 | 61 | import com.sap.sse.common.media.MimeType; |
| 61 | 62 | import com.sap.sse.mongodb.MongoDBConfiguration; |
| 62 | 63 | import com.sap.sse.mongodb.MongoDBService; |
| ... | ... | @@ -64,7 +65,6 @@ import com.sap.sse.replication.FullyInitializedReplicableTracker; |
| 64 | 65 | import com.sap.sse.security.SecurityService; |
| 65 | 66 | import com.sap.sse.security.interfaces.UserImpl; |
| 66 | 67 | import com.sap.sse.security.shared.WithQualifiedObjectIdentifier; |
| 67 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 68 | 68 | import com.sap.sse.security.shared.impl.SecuredSecurityTypes.PublicReadableActions; |
| 69 | 69 | import com.sap.sse.security.shared.impl.SecuredSecurityTypes.ServerActions; |
| 70 | 70 | import com.sap.sse.security.shared.impl.User; |
| ... | ... | @@ -248,7 +248,7 @@ public class MediaReplicationTest extends AbstractServerReplicationTest { |
| 248 | 248 | @Test |
| 249 | 249 | public void testMasterDataImportForMediaTracks() throws Exception { |
| 250 | 250 | UserGroupImpl defaultTenant = new UserGroupImpl(new UUID(0, 1), "defaultTenant"); |
| 251 | - User currentUser = new UserImpl("test", "email@test", Collections.emptyMap(), null, new LockingAndBanningImpl()); |
|
| 251 | + User currentUser = new UserImpl("test", "email@test", Collections.emptyMap(), null, new TimedLockImpl()); |
|
| 252 | 252 | SecurityService securityService = Mockito.mock(SecurityService.class); |
| 253 | 253 | Mockito.doReturn(defaultTenant).when(securityService).getServerGroup(); |
| 254 | 254 | Mockito.doReturn(currentUser).when(securityService).getCurrentUser(); |
java/com.sap.sailing.shared.server.gateway/resources/shiro.ini
| ... | ... | @@ -26,7 +26,7 @@ securityManager.subjectDAO = $subjectDAO |
| 26 | 26 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 27 | 27 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 28 | 28 | securityManager.cacheManager = $cacheManager |
| 29 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 29 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 30 | 30 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 31 | 31 | |
| 32 | 32 | # Support for anonymous user permissions |
java/com.sap.sailing.windestimation/resources/shiro.ini
| ... | ... | @@ -26,7 +26,7 @@ securityManager.subjectDAO = $subjectDAO |
| 26 | 26 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 27 | 27 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 28 | 28 | securityManager.cacheManager = $cacheManager |
| 29 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 29 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 30 | 30 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 31 | 31 | |
| 32 | 32 | # Support for anonymous user permissions |
java/com.sap.sailing.www/resources/shiro.ini
| ... | ... | @@ -26,7 +26,7 @@ securityManager.subjectDAO = $subjectDAO |
| 26 | 26 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 27 | 27 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 28 | 28 | securityManager.cacheManager = $cacheManager |
| 29 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 29 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 30 | 30 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 31 | 31 | |
| 32 | 32 | # Support for anonymous user permissions |
java/com.sap.sse.common.test/src/com/sap/sse/common/impl/test/TimedLockImplTest.java
| ... | ... | @@ -0,0 +1,63 @@ |
| 1 | +/** |
|
| 2 | + * |
|
| 3 | + */ |
|
| 4 | +package com.sap.sse.common.impl.test; |
|
| 5 | + |
|
| 6 | +import static org.junit.jupiter.api.Assertions.*; |
|
| 7 | + |
|
| 8 | +import org.junit.jupiter.api.BeforeEach; |
|
| 9 | +import org.junit.jupiter.api.Test; |
|
| 10 | + |
|
| 11 | +import com.sap.sse.common.Duration; |
|
| 12 | +import com.sap.sse.common.TimePoint; |
|
| 13 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 14 | + |
|
| 15 | +/** |
|
| 16 | + * |
|
| 17 | + */ |
|
| 18 | +class TimedLockImplTest { |
|
| 19 | + |
|
| 20 | + /** |
|
| 21 | + * @throws java.lang.Exception |
|
| 22 | + */ |
|
| 23 | + @BeforeEach |
|
| 24 | + void setUp() throws Exception { |
|
| 25 | + } |
|
| 26 | + |
|
| 27 | + /** |
|
| 28 | + * Test method for {@link com.sap.sse.common.impl.TimedLockImpl#extendLockDuration()}. |
|
| 29 | + */ |
|
| 30 | + @Test |
|
| 31 | + void testExtendLockDuration() { |
|
| 32 | + final TimedLockImpl lock = new TimedLockImpl(); |
|
| 33 | + final Duration firstLockingDelay = lock.getNextLockingDelay(); |
|
| 34 | + // initial locking delay should be greater than 0 |
|
| 35 | + assertTrue(firstLockingDelay.compareTo(Duration.NULL) > 0); |
|
| 36 | + assertTrue(firstLockingDelay.compareTo(Duration.ofMillis(0)) > 0); |
|
| 37 | + final TimePoint expectedLockedUntil = TimePoint.now().plus(firstLockingDelay); |
|
| 38 | + // locking delay should be applied to lockedUntil |
|
| 39 | + lock.extendLockDuration(); |
|
| 40 | + assertEquals(lock.getLockedUntil(), expectedLockedUntil); |
|
| 41 | + // locking delay should double |
|
| 42 | + final Duration secondLockingDelay = firstLockingDelay.plus(firstLockingDelay); |
|
| 43 | + assertEquals(lock.getNextLockingDelay(), secondLockingDelay); |
|
| 44 | + // double locking delay should be applied to lockedUntil |
|
| 45 | + lock.extendLockDuration(); |
|
| 46 | + assertEquals(lock.getLockedUntil(), TimePoint.now().plus(secondLockingDelay)); |
|
| 47 | + } |
|
| 48 | + |
|
| 49 | + /** |
|
| 50 | + * Test method for {@link com.sap.sse.common.impl.TimedLockImpl#resetLock()}. |
|
| 51 | + */ |
|
| 52 | + @Test |
|
| 53 | + void testResetLock() { |
|
| 54 | + final TimedLockImpl lock = new TimedLockImpl(); |
|
| 55 | + lock.extendLockDuration(); |
|
| 56 | + lock.extendLockDuration(); |
|
| 57 | + lock.extendLockDuration(); |
|
| 58 | + assertTrue(lock.isLocked()); |
|
| 59 | + lock.resetLock(); |
|
| 60 | + assertFalse(lock.isLocked()); |
|
| 61 | + } |
|
| 62 | + |
|
| 63 | +} |
java/com.sap.sse.common/src/com/sap/sse/common/TimedLock.java
| ... | ... | @@ -0,0 +1,33 @@ |
| 1 | +package com.sap.sse.common; |
|
| 2 | + |
|
| 3 | +import java.io.Serializable; |
|
| 4 | + |
|
| 5 | +/** |
|
| 6 | + * Holds information about a user's log-on history which is then used to decide whether the user account should be |
|
| 7 | + * locked temporarily or permanently for certain forms of authentication. |
|
| 8 | + * <p> |
|
| 9 | + * |
|
| 10 | + * For example, failed password authentication requests shall be logged by the realm using calls to |
|
| 11 | + * {@link #extendLockDuration()}, successful ones with {@link #resetLock()}. Using the |
|
| 12 | + * {@link #isLocked()} method, a realm can determine if the user account to which this object belongs |
|
| 13 | + * shall currently accept password authentication. |
|
| 14 | + * <p> |
|
| 15 | + * |
|
| 16 | + * A possible strategy for an implementation could be to add an increasing delay for each failed password |
|
| 17 | + * authentication, but reduce or clear the delay after a successful password authentication. |
|
| 18 | + * |
|
| 19 | + * @author Axel Uhl (d043530) |
|
| 20 | + * |
|
| 21 | + */ |
|
| 22 | +public interface TimedLock extends Serializable { |
|
| 23 | + void extendLockDuration(); |
|
| 24 | + |
|
| 25 | + /** |
|
| 26 | + * @return {@code true} if this locking and banning record changed due to this call |
|
| 27 | + */ |
|
| 28 | + boolean resetLock(); |
|
| 29 | + |
|
| 30 | + boolean isLocked(); |
|
| 31 | + |
|
| 32 | + TimePoint getLockedUntil(); |
|
| 33 | +} |
java/com.sap.sse.common/src/com/sap/sse/common/impl/RenamableImpl.java
| ... | ... | @@ -25,5 +25,4 @@ public class RenamableImpl implements Renamable { |
| 25 | 25 | public void setName(String newName) { |
| 26 | 26 | this.name = newName; |
| 27 | 27 | } |
| 28 | - |
|
| 29 | 28 | } |
java/com.sap.sse.common/src/com/sap/sse/common/impl/TimedLockImpl.java
| ... | ... | @@ -0,0 +1,83 @@ |
| 1 | +package com.sap.sse.common.impl; |
|
| 2 | + |
|
| 3 | +import com.sap.sse.common.Duration; |
|
| 4 | +import com.sap.sse.common.TimePoint; |
|
| 5 | +import com.sap.sse.common.TimedLock; |
|
| 6 | +import com.sap.sse.common.Util; |
|
| 7 | + |
|
| 8 | +public class TimedLockImpl implements TimedLock { |
|
| 9 | + private static final long serialVersionUID = 3547356744366236677L; |
|
| 10 | + |
|
| 11 | + public static final Duration DEFAULT_INITIAL_LOCKING_DELAY = Duration.ONE_SECOND; |
|
| 12 | + |
|
| 13 | + /** |
|
| 14 | + * An always valid time point which may be in the past. If it is in the future, |
|
| 15 | + * {@link #isLocked()} will return {@code true}. |
|
| 16 | + */ |
|
| 17 | + private TimePoint lockedUntil; |
|
| 18 | + |
|
| 19 | + /** |
|
| 20 | + * An always valid, non-zero duration that indicates for how long into the future the {@link #lockedUntil} time |
|
| 21 | + * point will be set in case a {@link #extendLockDuration() failed password authentication} is notified. |
|
| 22 | + */ |
|
| 23 | + private Duration nextLockingDelay; |
|
| 24 | + |
|
| 25 | + /** |
|
| 26 | + * Creates an instance that is unlocked and has a "last locking delay" of one second |
|
| 27 | + */ |
|
| 28 | + public TimedLockImpl() { |
|
| 29 | + this(TimePoint.BeginningOfTime, DEFAULT_INITIAL_LOCKING_DELAY); |
|
| 30 | + } |
|
| 31 | + |
|
| 32 | + public TimedLockImpl(TimePoint lockedUntil, Duration nextLockingDelay) { |
|
| 33 | + super(); |
|
| 34 | + this.lockedUntil = lockedUntil; |
|
| 35 | + this.nextLockingDelay = nextLockingDelay; |
|
| 36 | + } |
|
| 37 | + |
|
| 38 | + /** |
|
| 39 | + * Locks for the {@link #nextLockingDelay} and doubles the delay for the next failed attempt. |
|
| 40 | + */ |
|
| 41 | + @Override |
|
| 42 | + public void extendLockDuration() { |
|
| 43 | + lockedUntil = TimePoint.now().plus(nextLockingDelay); |
|
| 44 | + nextLockingDelay = nextLockingDelay.times(2); |
|
| 45 | + } |
|
| 46 | + |
|
| 47 | + @Override |
|
| 48 | + public boolean resetLock() { |
|
| 49 | + final Duration oldLockingDelay = nextLockingDelay; |
|
| 50 | + nextLockingDelay = DEFAULT_INITIAL_LOCKING_DELAY; |
|
| 51 | + final TimePoint oldLockedUntil = lockedUntil; |
|
| 52 | + lockedUntil = TimePoint.BeginningOfTime; |
|
| 53 | + return !Util.equalsWithNull(oldLockingDelay, nextLockingDelay) || !Util.equalsWithNull(oldLockedUntil, lockedUntil); |
|
| 54 | + } |
|
| 55 | + |
|
| 56 | + @Override |
|
| 57 | + public boolean isLocked() { |
|
| 58 | + return TimePoint.now().before(lockedUntil); |
|
| 59 | + } |
|
| 60 | + |
|
| 61 | + @Override |
|
| 62 | + public TimePoint getLockedUntil() { |
|
| 63 | + return lockedUntil; |
|
| 64 | + } |
|
| 65 | + |
|
| 66 | + public Duration getNextLockingDelay() { |
|
| 67 | + return nextLockingDelay; |
|
| 68 | + } |
|
| 69 | + |
|
| 70 | + @Override |
|
| 71 | + public String toString() { |
|
| 72 | + final StringBuilder result = new StringBuilder(); |
|
| 73 | + if (isLocked()) { |
|
| 74 | + result.append("locked until "); |
|
| 75 | + result.append(getLockedUntil()); |
|
| 76 | + } else { |
|
| 77 | + result.append("unlocked"); |
|
| 78 | + } |
|
| 79 | + result.append(", next locking duration: "); |
|
| 80 | + result.append(getNextLockingDelay()); |
|
| 81 | + return result.toString(); |
|
| 82 | + } |
|
| 83 | +} |
java/com.sap.sse.feature/feature.xml
| ... | ... | @@ -42,7 +42,7 @@ Computes leaderboard information for sailing races and offers RESTful APIs to al |
| 42 | 42 | id="com.google.gwt.servlet" |
| 43 | 43 | download-size="0" |
| 44 | 44 | install-size="0" |
| 45 | - version="2.12.2" |
|
| 45 | + version="2.12.3" |
|
| 46 | 46 | unpack="false"/> |
| 47 | 47 | |
| 48 | 48 | <plugin |
java/com.sap.sse.gwt.test/.settings/com.gwtplugins.gwt.eclipse.core.prefs
| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | -//gwtVersion_/com.google.gwt.user/lib=2.11.1 |
|
| 1 | +//gwtVersion_/com.google.gwt.user/lib= |
|
| 2 | 2 | //gwtVersion_/opt/gwt-2.11.0=2.11.0 |
| 3 | 3 | //gwtVersion_/opt/gwt-2.11.1=2.11.1 |
| 4 | 4 | //gwtVersion_/opt/gwt-2.12.2=2.12.2 |
java/com.sap.sse.gwt/.settings/com.gwtplugins.gwt.eclipse.core.prefs
| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | -//gwtVersion_/com.google.gwt.user/lib=2.11.1 |
|
| 1 | +//gwtVersion_/com.google.gwt.user/lib= |
|
| 2 | 2 | //gwtVersion_/opt/gwt-2.11.0=2.11.0 |
| 3 | 3 | //gwtVersion_/opt/gwt-2.11.1=2.11.1 |
| 4 | 4 | //gwtVersion_/opt/gwt-2.12.2=2.12.2 |
java/com.sap.sse.gwt/GWT xdStorage Sample SDM.launch
| ... | ... | @@ -3,13 +3,14 @@ |
| 3 | 3 | <booleanAttribute key="com.gwtplugins.gdt.eclipse.core.RUN_SERVER" value="false"/> |
| 4 | 4 | <stringAttribute key="com.gwtplugins.gdt.eclipse.suiteMainTypeProcessor.PREVIOUSLY_SET_MAIN_TYPE_NAME" value="com.google.gwt.dev.DevMode"/> |
| 5 | 5 | <booleanAttribute key="com.gwtplugins.gdt.eclipse.suiteWarArgumentProcessor.IS_WAR_FROM_PROJECT_PROPERTIES" value="true"/> |
| 6 | - <stringAttribute key="com.gwtplugins.gwt.eclipse.core.CLASSIC_DEVMODE_CODE_SERVER_PORT" value="9877"/> |
|
| 6 | + <stringAttribute key="com.gwtplugins.gwt.eclipse.core.CLASSIC_DEVMODE_CODE_SERVER_PORT" value="9878"/> |
|
| 7 | 7 | <listAttribute key="com.gwtplugins.gwt.eclipse.core.ENTRY_POINT_MODULES"> |
| 8 | 8 | <listEntry value="com.sap.sse.gwt.StorageMessagingTest"/> |
| 9 | 9 | <listEntry value="com.sap.sse.gwt.StorageMessaging"/> |
| 10 | 10 | </listAttribute> |
| 11 | 11 | <booleanAttribute key="com.gwtplugins.gwt.eclipse.core.SUPERDEVMODE_ENABLED" value="true"/> |
| 12 | 12 | <stringAttribute key="com.gwtplugins.gwt.eclipse.core.URL" value="/gwt-base/StorageMessagingTest.html"/> |
| 13 | + <booleanAttribute key="org.eclipse.debug.core.ATTR_FORCE_SYSTEM_CONSOLE_ENCODING" value="false"/> |
|
| 13 | 14 | <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> |
| 14 | 15 | <listEntry value="/com.sap.sse.gwt"/> |
| 15 | 16 | </listAttribute> |
| ... | ... | @@ -22,6 +23,8 @@ |
| 22 | 23 | </listAttribute> |
| 23 | 24 | <booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" value="true"/> |
| 24 | 25 | <booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" value="true"/> |
| 26 | + <booleanAttribute key="org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE" value="false"/> |
|
| 27 | + <booleanAttribute key="org.eclipse.jdt.launching.ATTR_SHOW_CODEDETAILS_IN_EXCEPTION_MESSAGES" value="true"/> |
|
| 25 | 28 | <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_CLASSPATH_ONLY_JAR" value="false"/> |
| 26 | 29 | <listAttribute key="org.eclipse.jdt.launching.CLASSPATH"> |
| 27 | 30 | <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8" javaProject="com.sap.sse.gwt" path="1" type="4"/> "/> |
| ... | ... | @@ -49,9 +52,10 @@ |
| 49 | 52 | </listAttribute> |
| 50 | 53 | <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.gwtplugins.gwt.eclipse.core.moduleClasspathProvider"/> |
| 51 | 54 | <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> |
| 55 | + <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17/"/> |
|
| 52 | 56 | <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/> |
| 53 | 57 | <stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="com.sap.sse.gwt"/> |
| 54 | - <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-style PRETTY -incremental -workDir "${project_loc:com.sap.sse.gwt}/.tmp/gwt-work" -war "${project_loc:com.sap.sse.gwt}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9877 -startupUrl /gwt-base/StorageMessagingTest.html -startupUrl /gwt-base/StorageMessaging.html com.sap.sse.gwt.StorageMessaging com.sap.sse.gwt.StorageMessagingTest"/> |
|
| 58 | + <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-style PRETTY -incremental -workDir "${project_loc:com.sap.sse.gwt}/.tmp/gwt-work" -war "${project_loc:com.sap.sse.gwt}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9878 -startupUrl /gwt-base/StorageMessagingTest.html -startupUrl /gwt-base/StorageMessaging.html com.sap.sse.gwt.StorageMessaging com.sap.sse.gwt.StorageMessagingTest"/> |
|
| 55 | 59 | <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sse.gwt"/> |
| 56 | 60 | <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XX:+UseG1GC -XX:-UseStringDeduplication -Dgwt.watchFileChanges=false -Xmx2048m -Dgwt-usearchives=false -Dgwt.persistentunitcache=false"/> |
| 57 | 61 | <stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work"/> |
java/com.sap.sse.gwt/resources/com/sap/sse/gwt/client/images/unlock.png
| ... | ... | Binary files /dev/null and b/java/com.sap.sse.gwt/resources/com/sap/sse/gwt/client/images/unlock.png differ |
java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/IconResources.java
| ... | ... | @@ -11,6 +11,9 @@ public interface IconResources extends ClientBundle { |
| 11 | 11 | @Source("images/change-acl.png") |
| 12 | 12 | ImageResource changeACLIcon(); |
| 13 | 13 | |
| 14 | + @Source("images/unlock.png") |
|
| 15 | + ImageResource resetLockIcon(); |
|
| 16 | + |
|
| 14 | 17 | @Source("images/change-ownership.png") |
| 15 | 18 | ImageResource changeOwnershipIcon(); |
| 16 | 19 |
java/com.sap.sse.landscape.aws/resources/shiro.ini
| ... | ... | @@ -26,7 +26,7 @@ securityManager.subjectDAO = $subjectDAO |
| 26 | 26 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 27 | 27 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 28 | 28 | securityManager.cacheManager = $cacheManager |
| 29 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 29 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 30 | 30 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 31 | 31 | |
| 32 | 32 | # Support for anonymous user permissions |
java/com.sap.sse.replication/resources/shiro.ini
| ... | ... | @@ -26,7 +26,7 @@ securityManager.subjectDAO = $subjectDAO |
| 26 | 26 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 27 | 27 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 28 | 28 | securityManager.cacheManager = $cacheManager |
| 29 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 29 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 30 | 30 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 31 | 31 | |
| 32 | 32 | # Support for anonymous user permissions |
java/com.sap.sse.security.common/src/com/sap/sse/security/shared/BasicUserStore.java
| ... | ... | @@ -5,8 +5,8 @@ import java.util.Set; |
| 5 | 5 | import java.util.UUID; |
| 6 | 6 | |
| 7 | 7 | import com.sap.sse.common.Named; |
| 8 | +import com.sap.sse.common.TimedLock; |
|
| 8 | 9 | import com.sap.sse.common.Util.Pair; |
| 9 | -import com.sap.sse.security.shared.impl.LockingAndBanning; |
|
| 10 | 10 | import com.sap.sse.security.shared.impl.Ownership; |
| 11 | 11 | import com.sap.sse.security.shared.impl.Role; |
| 12 | 12 | import com.sap.sse.security.shared.impl.SecuredSecurityTypes; |
| ... | ... | @@ -60,7 +60,7 @@ public interface BasicUserStore extends UserGroupProvider, Named { |
| 60 | 60 | |
| 61 | 61 | User getUserByAccessToken(String accessToken); |
| 62 | 62 | |
| 63 | - User createUser(String name, String email, LockingAndBanning lockingAndBanning, Account... accounts) |
|
| 63 | + User createUser(String name, String email, TimedLock timedLock, Account... accounts) |
|
| 64 | 64 | throws UserManagementException; |
| 65 | 65 | |
| 66 | 66 | void addUser(User user) throws UserManagementException; |
java/com.sap.sse.security.common/src/com/sap/sse/security/shared/IPAddress.java
| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | +package com.sap.sse.security.shared; |
|
| 2 | + |
|
| 3 | +import com.sap.sse.security.shared.impl.SecuredSecurityTypes; |
|
| 4 | + |
|
| 5 | +public class IPAddress implements WithQualifiedObjectIdentifier { |
|
| 6 | + private static final long serialVersionUID = 8016397230668484898L; |
|
| 7 | + private final String ipAddress; |
|
| 8 | + |
|
| 9 | + public IPAddress(final String ipAddress) { |
|
| 10 | + this.ipAddress = ipAddress; |
|
| 11 | + } |
|
| 12 | + |
|
| 13 | + @Override |
|
| 14 | + public String getName() { |
|
| 15 | + return ipAddress; |
|
| 16 | + } |
|
| 17 | + |
|
| 18 | + @Override |
|
| 19 | + public QualifiedObjectIdentifier getIdentifier() { |
|
| 20 | + return getPermissionType().getQualifiedObjectIdentifier(new TypeRelativeObjectIdentifier(ipAddress)); |
|
| 21 | + } |
|
| 22 | + |
|
| 23 | + @Override |
|
| 24 | + public HasPermissions getPermissionType() { |
|
| 25 | + return SecuredSecurityTypes.LOCKED_IP; |
|
| 26 | + } |
|
| 27 | + |
|
| 28 | +} |
java/com.sap.sse.security.common/src/com/sap/sse/security/shared/dto/UserDTO.java
| ... | ... | @@ -31,7 +31,7 @@ public class UserDTO extends |
| 31 | 31 | private SecurityInformationDTO securityInformation = new SecurityInformationDTO(); |
| 32 | 32 | private StrippedUserGroupDTO defaultTenantForCurrentServer; |
| 33 | 33 | |
| 34 | - private Set<RoleWithSecurityDTO> roles; |
|
| 34 | + private Set<RoleWithSecurityDTO> roles; // TODO turn to HashSet to reduce number of serializers to generate |
|
| 35 | 35 | |
| 36 | 36 | @Deprecated // gwt only |
| 37 | 37 | UserDTO() { |
| ... | ... | @@ -59,7 +59,22 @@ public class UserDTO extends |
| 59 | 59 | Util.addAll(roles, this.getRolesInternal()); |
| 60 | 60 | this.lockedUntil = lockedUntil; |
| 61 | 61 | } |
| 62 | - |
|
| 62 | + |
|
| 63 | + public UserDTO copyWithTimePoint(TimePoint lockedUntil) { |
|
| 64 | + final List<AccountDTO> accountsCopy = new ArrayList<AccountDTO>(); |
|
| 65 | + Util.addAll(this.accounts, accountsCopy); |
|
| 66 | + final HashSet<RoleWithSecurityDTO> rolesCopy = new HashSet<>(); |
|
| 67 | + Util.addAll(this.roles, rolesCopy); |
|
| 68 | + final List<WildcardPermissionWithSecurityDTO> permissionsCopy = new ArrayList<WildcardPermissionWithSecurityDTO>(); |
|
| 69 | + for (WildcardPermission wp : this.getPermissions()) { |
|
| 70 | + permissionsCopy.add((WildcardPermissionWithSecurityDTO) wp); |
|
| 71 | + } |
|
| 72 | + final List<StrippedUserGroupDTO> groupsCopy = new ArrayList<StrippedUserGroupDTO>(); |
|
| 73 | + Util.addAll(this.groups, groupsCopy); |
|
| 74 | + return new UserDTO(this.getName(), this.email, this.fullName, this.company, this.locale, this.emailValidated, |
|
| 75 | + accountsCopy, rolesCopy, this.defaultTenantForCurrentServer, permissionsCopy, groupsCopy, lockedUntil); |
|
| 76 | + } |
|
| 77 | + |
|
| 63 | 78 | @Override |
| 64 | 79 | protected Set<RoleWithSecurityDTO> getRolesInternal() { |
| 65 | 80 | return roles; |
java/com.sap.sse.security.common/src/com/sap/sse/security/shared/impl/LockingAndBanning.java
| ... | ... | @@ -1,35 +0,0 @@ |
| 1 | -package com.sap.sse.security.shared.impl; |
|
| 2 | - |
|
| 3 | -import java.io.Serializable; |
|
| 4 | - |
|
| 5 | -import com.sap.sse.common.TimePoint; |
|
| 6 | - |
|
| 7 | -/** |
|
| 8 | - * Holds information about a user's log-on history which is then used to decide whether the user account should be |
|
| 9 | - * locked temporarily or permanently for certain forms of authentication. |
|
| 10 | - * <p> |
|
| 11 | - * |
|
| 12 | - * For example, failed password authentication requests shall be logged by the realm using calls to |
|
| 13 | - * {@link #failedPasswordAuthentication()}, successful ones with {@link #successfulPasswordAuthentication()}. Using the |
|
| 14 | - * {@link #isAuthenticationLocked()} method, a realm can determine if the user account to which this object belongs |
|
| 15 | - * shall currently accept password authentication. |
|
| 16 | - * <p> |
|
| 17 | - * |
|
| 18 | - * A possible strategy for an implementation could be to add an increasing delay for each failed password |
|
| 19 | - * authentication, but reduce or clear the delay after a successful password authentication. |
|
| 20 | - * |
|
| 21 | - * @author Axel Uhl (d043530) |
|
| 22 | - * |
|
| 23 | - */ |
|
| 24 | -public interface LockingAndBanning extends Serializable { |
|
| 25 | - void failedPasswordAuthentication(); |
|
| 26 | - |
|
| 27 | - /** |
|
| 28 | - * @return {@code true} if this locking and banning record changed due to this call |
|
| 29 | - */ |
|
| 30 | - boolean successfulPasswordAuthentication(); |
|
| 31 | - |
|
| 32 | - boolean isAuthenticationLocked(); |
|
| 33 | - |
|
| 34 | - TimePoint getLockedUntil(); |
|
| 35 | -} |
java/com.sap.sse.security.common/src/com/sap/sse/security/shared/impl/LockingAndBanningImpl.java
| ... | ... | @@ -1,82 +0,0 @@ |
| 1 | -package com.sap.sse.security.shared.impl; |
|
| 2 | - |
|
| 3 | -import com.sap.sse.common.Duration; |
|
| 4 | -import com.sap.sse.common.TimePoint; |
|
| 5 | -import com.sap.sse.common.Util; |
|
| 6 | - |
|
| 7 | -public class LockingAndBanningImpl implements LockingAndBanning { |
|
| 8 | - private static final long serialVersionUID = 3547356744366236677L; |
|
| 9 | - |
|
| 10 | - public static final Duration DEFAULT_INITIAL_LOCKING_DELAY = Duration.ONE_SECOND; |
|
| 11 | - |
|
| 12 | - /** |
|
| 13 | - * An always valid time point which may be in the past. If it is in the future, |
|
| 14 | - * {@link #isAuthenticationLocked()} will return {@code true}. |
|
| 15 | - */ |
|
| 16 | - private TimePoint lockedUntil; |
|
| 17 | - |
|
| 18 | - /** |
|
| 19 | - * An always valid, non-zero duration that indicates for how long into the future the {@link #lockedUntil} time |
|
| 20 | - * point will be set in case a {@link #failedPasswordAuthentication() failed password authentication} is notified. |
|
| 21 | - */ |
|
| 22 | - private Duration nextLockingDelay; |
|
| 23 | - |
|
| 24 | - /** |
|
| 25 | - * Creates an instance that is unlocked and has a "last locking delay" of one second |
|
| 26 | - */ |
|
| 27 | - public LockingAndBanningImpl() { |
|
| 28 | - this(TimePoint.BeginningOfTime, DEFAULT_INITIAL_LOCKING_DELAY); |
|
| 29 | - } |
|
| 30 | - |
|
| 31 | - public LockingAndBanningImpl(TimePoint lockedUntil, Duration nextLockingDelay) { |
|
| 32 | - super(); |
|
| 33 | - this.lockedUntil = lockedUntil; |
|
| 34 | - this.nextLockingDelay = nextLockingDelay; |
|
| 35 | - } |
|
| 36 | - |
|
| 37 | - /** |
|
| 38 | - * Locks for the {@link #nextLockingDelay} and doubles the delay for the next failed attempt. |
|
| 39 | - */ |
|
| 40 | - @Override |
|
| 41 | - public void failedPasswordAuthentication() { |
|
| 42 | - lockedUntil = TimePoint.now().plus(nextLockingDelay); |
|
| 43 | - nextLockingDelay = nextLockingDelay.times(2); |
|
| 44 | - } |
|
| 45 | - |
|
| 46 | - @Override |
|
| 47 | - public boolean successfulPasswordAuthentication() { |
|
| 48 | - final Duration oldLockingDelay = nextLockingDelay; |
|
| 49 | - nextLockingDelay = DEFAULT_INITIAL_LOCKING_DELAY; |
|
| 50 | - final TimePoint oldLockedUntil = lockedUntil; |
|
| 51 | - lockedUntil = TimePoint.BeginningOfTime; |
|
| 52 | - return !Util.equalsWithNull(oldLockingDelay, nextLockingDelay) || !Util.equalsWithNull(oldLockedUntil, lockedUntil); |
|
| 53 | - } |
|
| 54 | - |
|
| 55 | - @Override |
|
| 56 | - public boolean isAuthenticationLocked() { |
|
| 57 | - return TimePoint.now().before(lockedUntil); |
|
| 58 | - } |
|
| 59 | - |
|
| 60 | - @Override |
|
| 61 | - public TimePoint getLockedUntil() { |
|
| 62 | - return lockedUntil; |
|
| 63 | - } |
|
| 64 | - |
|
| 65 | - public Duration getNextLockingDelay() { |
|
| 66 | - return nextLockingDelay; |
|
| 67 | - } |
|
| 68 | - |
|
| 69 | - @Override |
|
| 70 | - public String toString() { |
|
| 71 | - final StringBuilder result = new StringBuilder(); |
|
| 72 | - if (isAuthenticationLocked()) { |
|
| 73 | - result.append("locked until "); |
|
| 74 | - result.append(getLockedUntil()); |
|
| 75 | - } else { |
|
| 76 | - result.append("unlocked"); |
|
| 77 | - } |
|
| 78 | - result.append(", next locking duration: "); |
|
| 79 | - result.append(getNextLockingDelay()); |
|
| 80 | - return result.toString(); |
|
| 81 | - } |
|
| 82 | -} |
java/com.sap.sse.security.common/src/com/sap/sse/security/shared/impl/SecuredSecurityTypes.java
| ... | ... | @@ -5,6 +5,7 @@ import java.util.HashSet; |
| 5 | 5 | import java.util.Set; |
| 6 | 6 | |
| 7 | 7 | import com.sap.sse.security.shared.HasPermissions; |
| 8 | +import com.sap.sse.security.shared.IPAddress; |
|
| 8 | 9 | import com.sap.sse.security.shared.RoleDefinition; |
| 9 | 10 | |
| 10 | 11 | /** |
| ... | ... | @@ -41,14 +42,20 @@ public class SecuredSecurityTypes extends HasPermissionsImpl { |
| 41 | 42 | |
| 42 | 43 | public static enum UserActions implements Action { |
| 43 | 44 | /** Update a user's password without knowing the old password. */ |
| 44 | - FORCE_OVERWRITE_PASSWORD, ADD_SUBSCRIPTION, BE_PREMIUM |
|
| 45 | + FORCE_OVERWRITE_PASSWORD, ADD_SUBSCRIPTION, BE_PREMIUM, MANAGE_LOCK |
|
| 45 | 46 | }; |
| 46 | 47 | /** |
| 47 | 48 | * type-relative identifier is the {@link User#getName() username}. |
| 48 | 49 | */ |
| 49 | 50 | public static final HasPermissions USER = new SecuredSecurityTypes("USER", DefaultActions |
| 50 | 51 | .plus(UserActions.FORCE_OVERWRITE_PASSWORD, PublicReadableActions.READ_PUBLIC, |
| 51 | - UserActions.ADD_SUBSCRIPTION, UserActions.BE_PREMIUM)); |
|
| 52 | + UserActions.ADD_SUBSCRIPTION, UserActions.BE_PREMIUM, UserActions.MANAGE_LOCK)); |
|
| 53 | + |
|
| 54 | + |
|
| 55 | + /** |
|
| 56 | + * type-relative identifier is the {@link IPAddress#getName() ip address as String}. |
|
| 57 | + */ |
|
| 58 | + public static final HasPermissions LOCKED_IP = new SecuredSecurityTypes("LOCKED_IP", DefaultActions.values()); |
|
| 52 | 59 | |
| 53 | 60 | /** |
| 54 | 61 | * type-relative identifier is the {@link RoleDefinition#getId() role ID's} string representation |
| ... | ... | @@ -115,8 +122,8 @@ public class SecuredSecurityTypes extends HasPermissionsImpl { |
| 115 | 122 | private static final Action[] ALL_ACTIONS = new Action[] { CONFIGURE_FILE_STORAGE, CONFIGURE_LOCAL_SERVER, |
| 116 | 123 | CONFIGURE_REMOTE_INSTANCES, CREATE_OBJECT, CAN_IMPORT_MASTERDATA, CAN_EXPORT_MASTERDATA, DATA_MINING, |
| 117 | 124 | REPLICATE, START_REPLICATION, READ_REPLICATOR, THREADS, CONFIGURE_AI_AGENT, CONFIGURE_CORS_FILTER, |
| 118 | - DefaultActions.CHANGE_OWNERSHIP, DefaultActions.CHANGE_ACL, DefaultActions.CREATE, DefaultActions.DELETE, |
|
| 119 | - DefaultActions.READ, DefaultActions.UPDATE }; |
|
| 125 | + DefaultActions.CHANGE_OWNERSHIP, DefaultActions.CHANGE_ACL, DefaultActions.CREATE, |
|
| 126 | + DefaultActions.DELETE, DefaultActions.READ, DefaultActions.UPDATE }; |
|
| 120 | 127 | } |
| 121 | 128 | |
| 122 | 129 | /** |
java/com.sap.sse.security.common/src/com/sap/sse/security/shared/impl/User.java
| ... | ... | @@ -4,6 +4,7 @@ import java.util.Locale; |
| 4 | 4 | import java.util.Map; |
| 5 | 5 | |
| 6 | 6 | import com.sap.sse.common.Named; |
| 7 | +import com.sap.sse.common.TimedLock; |
|
| 7 | 8 | import com.sap.sse.common.WithID; |
| 8 | 9 | import com.sap.sse.security.shared.Account; |
| 9 | 10 | import com.sap.sse.security.shared.Account.AccountType; |
| ... | ... | @@ -125,5 +126,5 @@ public interface User extends SecurityUser<RoleDefinition, Role, UserGroup> { |
| 125 | 126 | |
| 126 | 127 | Subscription getSubscriptionById(String subscriptionId); |
| 127 | 128 | |
| 128 | - LockingAndBanning getLockingAndBanning(); |
|
| 129 | + TimedLock getTimedLock(); |
|
| 129 | 130 | } |
java/com.sap.sse.security.interface/src/com/sap/sse/security/interfaces/UserImpl.java
| ... | ... | @@ -19,12 +19,12 @@ import java.util.Set; |
| 19 | 19 | |
| 20 | 20 | import org.apache.shiro.crypto.hash.Sha256Hash; |
| 21 | 21 | |
| 22 | +import com.sap.sse.common.TimedLock; |
|
| 22 | 23 | import com.sap.sse.security.shared.Account; |
| 23 | 24 | import com.sap.sse.security.shared.Account.AccountType; |
| 24 | 25 | import com.sap.sse.security.shared.RoleDefinition; |
| 25 | 26 | import com.sap.sse.security.shared.UserGroupProvider; |
| 26 | 27 | import com.sap.sse.security.shared.WildcardPermission; |
| 27 | -import com.sap.sse.security.shared.impl.LockingAndBanning; |
|
| 28 | 28 | import com.sap.sse.security.shared.impl.Ownership; |
| 29 | 29 | import com.sap.sse.security.shared.impl.Role; |
| 30 | 30 | import com.sap.sse.security.shared.impl.SecurityUserImpl; |
| ... | ... | @@ -101,25 +101,25 @@ public class UserImpl extends SecurityUserImpl<RoleDefinition, Role, UserGroup, |
| 101 | 101 | |
| 102 | 102 | private Subscription[] subscriptions; |
| 103 | 103 | |
| 104 | - private final LockingAndBanning lockingAndBanning; |
|
| 104 | + private final TimedLock timedLock; |
|
| 105 | 105 | |
| 106 | 106 | public UserImpl(String name, String email, Map<String, UserGroup> defaultTenantForServer, |
| 107 | - UserGroupProvider userGroupProvider, LockingAndBanning lockingAndBanning, Account... accounts) { |
|
| 108 | - this(name, email, defaultTenantForServer, Arrays.asList(accounts), userGroupProvider, lockingAndBanning); |
|
| 107 | + UserGroupProvider userGroupProvider, TimedLock timedLock, Account... accounts) { |
|
| 108 | + this(name, email, defaultTenantForServer, Arrays.asList(accounts), userGroupProvider, timedLock); |
|
| 109 | 109 | } |
| 110 | 110 | |
| 111 | 111 | public UserImpl(String name, String email, Map<String, UserGroup> defaultTenantForServer, |
| 112 | - Collection<Account> accounts, UserGroupProvider userGroupProvider, LockingAndBanning lockingAndBanning) { |
|
| 112 | + Collection<Account> accounts, UserGroupProvider userGroupProvider, TimedLock timedLock) { |
|
| 113 | 113 | this(name, email, /* fullName */ null, /* company */ null, /* locale */ null, /* is email validated */ false, |
| 114 | 114 | /* password reset secret */ null, /* validation secret */ null, defaultTenantForServer, accounts, |
| 115 | - userGroupProvider, lockingAndBanning); |
|
| 115 | + userGroupProvider, timedLock); |
|
| 116 | 116 | } |
| 117 | 117 | |
| 118 | 118 | public UserImpl(String name, String email, String fullName, String company, Locale locale, Boolean emailValidated, |
| 119 | 119 | String passwordResetSecret, String validationSecret, Map<String, UserGroup> defaultTenantForServer, |
| 120 | - Collection<Account> accounts, UserGroupProvider userGroupProvider, LockingAndBanning lockingAndBanning) { |
|
| 120 | + Collection<Account> accounts, UserGroupProvider userGroupProvider, TimedLock timedLock) { |
|
| 121 | 121 | super(name); |
| 122 | - this.lockingAndBanning = lockingAndBanning; |
|
| 122 | + this.timedLock = timedLock; |
|
| 123 | 123 | this.defaultTenantForServer = defaultTenantForServer; |
| 124 | 124 | this.fullName = fullName; |
| 125 | 125 | this.company = company; |
| ... | ... | @@ -469,7 +469,7 @@ public class UserImpl extends SecurityUserImpl<RoleDefinition, Role, UserGroup, |
| 469 | 469 | } |
| 470 | 470 | |
| 471 | 471 | @Override |
| 472 | - public LockingAndBanning getLockingAndBanning() { |
|
| 473 | - return lockingAndBanning; |
|
| 472 | + public TimedLock getTimedLock() { |
|
| 473 | + return timedLock; |
|
| 474 | 474 | } |
| 475 | 475 | } |
java/com.sap.sse.security.replication.test/src/com/sap/sse/security/replication/test/SimpleSecurityReplicationTest.java
| ... | ... | @@ -99,7 +99,7 @@ public class SimpleSecurityReplicationTest extends AbstractSecurityReplicationTe |
| 99 | 99 | assertEquals(ERNIE, replicatedErnie.getName()); |
| 100 | 100 | assertFalse(replica.checkPassword(ERNIE, BERT_MY_FRIEND)); |
| 101 | 101 | // checking with incorrect password locks user for some time; wait long enough before retrying with correct password |
| 102 | - final TimePoint lockedUntil = replicatedErnie.getLockingAndBanning().getLockedUntil(); |
|
| 102 | + final TimePoint lockedUntil = replicatedErnie.getTimedLock().getLockedUntil(); |
|
| 103 | 103 | Thread.sleep(Math.max(0, TimePoint.now().until(lockedUntil).asMillis()+10)); |
| 104 | 104 | assertTrue(replica.checkPassword(ERNIE, newPassword)); |
| 105 | 105 | } |
java/com.sap.sse.security.storemerging.test/src/com/sap/sse/security/storemerging/TestGroupIdentity.java
| ... | ... | @@ -10,9 +10,9 @@ import java.util.UUID; |
| 10 | 10 | |
| 11 | 11 | import org.junit.jupiter.api.Test; |
| 12 | 12 | |
| 13 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 13 | 14 | import com.sap.sse.security.SecurityService; |
| 14 | 15 | import com.sap.sse.security.interfaces.UserImpl; |
| 15 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 16 | 16 | import com.sap.sse.security.shared.impl.User; |
| 17 | 17 | import com.sap.sse.security.shared.impl.UserGroup; |
| 18 | 18 | import com.sap.sse.security.shared.impl.UserGroupImpl; |
| ... | ... | @@ -51,7 +51,7 @@ public class TestGroupIdentity { |
| 51 | 51 | final UUID uuid2 = UUID.randomUUID(); |
| 52 | 52 | final String username = "user"; |
| 53 | 53 | final UserGroup g1 = new UserGroupImpl(uuid1, username+SecurityService.TENANT_SUFFIX); |
| 54 | - final User user = new UserImpl(username, /* email */ null, (Map<String, UserGroup>) /* defaultTenantForServer */ null, /* userGroupProvider */ null, new LockingAndBanningImpl()); |
|
| 54 | + final User user = new UserImpl(username, /* email */ null, (Map<String, UserGroup>) /* defaultTenantForServer */ null, /* userGroupProvider */ null, new TimedLockImpl()); |
|
| 55 | 55 | g1.add(user); |
| 56 | 56 | final UserGroup g2 = new UserGroupImpl(uuid2, username+SecurityService.TENANT_SUFFIX); |
| 57 | 57 | assertFalse(SecurityStoreMerger.considerGroupsIdentical(g1, g2, Collections.emptyMap())); |
| ... | ... | @@ -63,10 +63,10 @@ public class TestGroupIdentity { |
| 63 | 63 | final UUID uuid2 = UUID.randomUUID(); |
| 64 | 64 | final String username = "user"; |
| 65 | 65 | final UserGroup g1 = new UserGroupImpl(uuid1, username+SecurityService.TENANT_SUFFIX); |
| 66 | - final User user1 = new UserImpl(username, /* email */ null, (Map<String, UserGroup>) /* defaultTenantForServer */ null, /* userGroupProvider */ null, new LockingAndBanningImpl()); |
|
| 66 | + final User user1 = new UserImpl(username, /* email */ null, (Map<String, UserGroup>) /* defaultTenantForServer */ null, /* userGroupProvider */ null, new TimedLockImpl()); |
|
| 67 | 67 | g1.add(user1); |
| 68 | 68 | final UserGroup g2 = new UserGroupImpl(uuid2, username+SecurityService.TENANT_SUFFIX); |
| 69 | - final User user2 = new UserImpl(username, /* email */ null, (Map<String, UserGroup>) /* defaultTenantForServer */ null, /* userGroupProvider */ null, new LockingAndBanningImpl()); |
|
| 69 | + final User user2 = new UserImpl(username, /* email */ null, (Map<String, UserGroup>) /* defaultTenantForServer */ null, /* userGroupProvider */ null, new TimedLockImpl()); |
|
| 70 | 70 | g2.add(user2); |
| 71 | 71 | final Map<User, User> userMap = new HashMap<>(); |
| 72 | 72 | userMap.put(user2, user1); // user2 assumed to get merged with user1 |
java/com.sap.sse.security.test/src/com/sap/sse/security/test/AccessControlStoreTest.java
| ... | ... | @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; |
| 18 | 18 | |
| 19 | 19 | import com.mongodb.MongoException; |
| 20 | 20 | import com.mongodb.client.MongoDatabase; |
| 21 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 21 | 22 | import com.sap.sse.mongodb.MongoDBConfiguration; |
| 22 | 23 | import com.sap.sse.mongodb.MongoDBService; |
| 23 | 24 | import com.sap.sse.security.interfaces.AccessControlStore; |
| ... | ... | @@ -29,7 +30,6 @@ import com.sap.sse.security.shared.TypeRelativeObjectIdentifier; |
| 29 | 30 | import com.sap.sse.security.shared.UserGroupManagementException; |
| 30 | 31 | import com.sap.sse.security.shared.UserStoreManagementException; |
| 31 | 32 | import com.sap.sse.security.shared.WildcardPermission; |
| 32 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 33 | 33 | import com.sap.sse.security.shared.impl.QualifiedObjectIdentifierImpl; |
| 34 | 34 | import com.sap.sse.security.shared.impl.User; |
| 35 | 35 | import com.sap.sse.security.shared.impl.UserGroup; |
| ... | ... | @@ -69,7 +69,7 @@ public class AccessControlStoreTest { |
| 69 | 69 | Map<String, UserGroup> defaultTenantForUser = new HashMap<>(); |
| 70 | 70 | defaultTenantForUser.put("dummyServer", adminTenant); |
| 71 | 71 | testOwner = new UserImpl("admin", "admin@sapsailing.com", defaultTenantForUser, |
| 72 | - /* userGroupProvider */ null, new LockingAndBanningImpl()); |
|
| 72 | + /* userGroupProvider */ null, new TimedLockImpl()); |
|
| 73 | 73 | } |
| 74 | 74 | |
| 75 | 75 | private void newStores() { |
java/com.sap.sse.security.test/src/com/sap/sse/security/test/LoginTest.java
| ... | ... | @@ -8,11 +8,13 @@ import static org.junit.jupiter.api.Assertions.assertNull; |
| 8 | 8 | import static org.junit.jupiter.api.Assertions.assertSame; |
| 9 | 9 | import static org.junit.jupiter.api.Assertions.assertTrue; |
| 10 | 10 | |
| 11 | +import java.io.IOException; |
|
| 11 | 12 | import java.net.UnknownHostException; |
| 12 | 13 | import java.util.Arrays; |
| 13 | 14 | import java.util.Collections; |
| 14 | 15 | import java.util.HashMap; |
| 15 | 16 | import java.util.HashSet; |
| 17 | +import java.util.Locale; |
|
| 16 | 18 | import java.util.Map; |
| 17 | 19 | import java.util.Set; |
| 18 | 20 | import java.util.UUID; |
| ... | ... | @@ -25,6 +27,7 @@ import org.junit.jupiter.api.Test; |
| 25 | 27 | import com.mongodb.MongoException; |
| 26 | 28 | import com.mongodb.client.MongoDatabase; |
| 27 | 29 | import com.sap.sse.common.Util; |
| 30 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 28 | 31 | import com.sap.sse.common.mail.MailException; |
| 29 | 32 | import com.sap.sse.mongodb.MongoDBConfiguration; |
| 30 | 33 | import com.sap.sse.mongodb.MongoDBService; |
| ... | ... | @@ -44,7 +47,6 @@ import com.sap.sse.security.shared.UserStoreManagementException; |
| 44 | 47 | import com.sap.sse.security.shared.WildcardPermission; |
| 45 | 48 | import com.sap.sse.security.shared.WithQualifiedObjectIdentifier; |
| 46 | 49 | import com.sap.sse.security.shared.impl.AccessControlList; |
| 47 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 48 | 50 | import com.sap.sse.security.shared.impl.Ownership; |
| 49 | 51 | import com.sap.sse.security.shared.impl.QualifiedObjectIdentifierImpl; |
| 50 | 52 | import com.sap.sse.security.shared.impl.Role; |
| ... | ... | @@ -242,7 +244,7 @@ public class LoginTest { |
| 242 | 244 | |
| 243 | 245 | @Test |
| 244 | 246 | public void rolesTest() throws UserStoreManagementException { |
| 245 | - userStore.createUser("me", "me@sap.com", new LockingAndBanningImpl()); |
|
| 247 | + userStore.createUser("me", "me@sap.com", new TimedLockImpl()); |
|
| 246 | 248 | RoleDefinition testRoleDefinition = userStore.createRoleDefinition(UUID.randomUUID(), "testRole", |
| 247 | 249 | Collections.emptySet()); |
| 248 | 250 | final Role testRole = new Role(testRoleDefinition, true); |
| ... | ... | @@ -254,7 +256,7 @@ public class LoginTest { |
| 254 | 256 | @Test |
| 255 | 257 | public void roleWithQualifiersTest() throws UserStoreManagementException { |
| 256 | 258 | UserGroupImpl userDefaultTenant = userStore.createUserGroup(UUID.randomUUID(), "me-tenant"); |
| 257 | - User meUser = userStore.createUser("me", "me@sap.com", new LockingAndBanningImpl()); |
|
| 259 | + User meUser = userStore.createUser("me", "me@sap.com", new TimedLockImpl()); |
|
| 258 | 260 | RoleDefinition testRoleDefinition = userStore.createRoleDefinition(UUID.randomUUID(), "testRole", |
| 259 | 261 | Collections.emptySet()); |
| 260 | 262 | final Role testRole = new Role(testRoleDefinition, userDefaultTenant, meUser, true); |
| ... | ... | @@ -268,7 +270,7 @@ public class LoginTest { |
| 268 | 270 | |
| 269 | 271 | @Test |
| 270 | 272 | public void permissionsTest() throws UserStoreManagementException { |
| 271 | - userStore.createUser("me", "me@sap.com", new LockingAndBanningImpl()); |
|
| 273 | + userStore.createUser("me", "me@sap.com", new TimedLockImpl()); |
|
| 272 | 274 | userStore.addPermissionForUser("me", new WildcardPermission("a:b:c")); |
| 273 | 275 | UserStoreImpl store2 = createAndLoadUserStore(); |
| 274 | 276 | User allUser = userStore.getUserByName(SecurityService.ALL_USERNAME); |
| ... | ... | @@ -276,6 +278,46 @@ public class LoginTest { |
| 276 | 278 | assertTrue(PermissionChecker.isPermitted(new WildcardPermission("a:b:c"), user, allUser, null, null)); |
| 277 | 279 | } |
| 278 | 280 | |
| 281 | + @Test |
|
| 282 | + public void testUnlockBearerTokenAbuser() throws UserStoreManagementException, IOException, InterruptedException { |
|
| 283 | + final String localhost = "127.0.0.1"; |
|
| 284 | + final int attempts = 4; |
|
| 285 | + for(int i = 0; i < attempts; i++) { |
|
| 286 | + securityService.failedBearerTokenAuthentication(localhost); |
|
| 287 | + final long lockDuration = (long) Math.pow(2, i) * 1000; |
|
| 288 | + final boolean isFinalAttempt = i == (attempts - 1); |
|
| 289 | + if (!isFinalAttempt) { |
|
| 290 | + Thread.sleep(lockDuration); |
|
| 291 | + } |
|
| 292 | + } |
|
| 293 | + assertTrue(securityService.isClientIPLockedForBearerTokenAuthentication(localhost)); |
|
| 294 | + securityService.releaseBearerTokenLockOnIp(localhost); |
|
| 295 | + assertFalse(securityService.isClientIPLockedForBearerTokenAuthentication(localhost)); |
|
| 296 | + } |
|
| 297 | + |
|
| 298 | + @Test |
|
| 299 | + public void testUnlockUserCreationAbuser() throws UserStoreManagementException, IOException, InterruptedException, MailException { |
|
| 300 | + final String localhost = "127.0.0.1"; |
|
| 301 | + final int attempts = 4; |
|
| 302 | + for(int i = 0; i < attempts; i++) { |
|
| 303 | + try { |
|
| 304 | + securityService.createSimpleUser("USERNAME" + i, "a@b.c", "PASSWORD", "The User", "SAP SE", |
|
| 305 | + /* validation URL */ Locale.ENGLISH, null, null, /* clientIP */ localhost, |
|
| 306 | + /* enforce strong password */ false); |
|
| 307 | + } catch (UserManagementException e) { |
|
| 308 | + // do nothing, expected due to lock |
|
| 309 | + } |
|
| 310 | + final long lockDuration = (long) Math.pow(2, i) * 1000; |
|
| 311 | + final boolean isFinalAttempt = i == (attempts - 1); |
|
| 312 | + if (!isFinalAttempt) { |
|
| 313 | + Thread.sleep(lockDuration); |
|
| 314 | + } |
|
| 315 | + } |
|
| 316 | + assertTrue(securityService.isUserCreationLockedForClientIP(localhost)); |
|
| 317 | + securityService.releaseUserCreationLockOnIp(localhost); |
|
| 318 | + assertFalse(securityService.isUserCreationLockedForClientIP(localhost)); |
|
| 319 | + } |
|
| 320 | + |
|
| 279 | 321 | private UserStoreImpl createAndLoadUserStore() throws UserStoreManagementException { |
| 280 | 322 | final UserStoreImpl store = new UserStoreImpl(DEFAULT_TENANT_NAME); |
| 281 | 323 | store.loadAndMigrateUsers(); |
java/com.sap.sse.security.test/src/com/sap/sse/security/test/PermissionCheckerTest.java
| ... | ... | @@ -21,6 +21,7 @@ import org.junit.jupiter.api.BeforeEach; |
| 21 | 21 | import org.junit.jupiter.api.Test; |
| 22 | 22 | |
| 23 | 23 | import com.sap.sailing.domain.common.security.SecuredDomainType; |
| 24 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 24 | 25 | import com.sap.sse.security.AbstractCompositeAuthorizingRealm; |
| 25 | 26 | import com.sap.sse.security.UsernamePasswordRealm; |
| 26 | 27 | import com.sap.sse.security.interfaces.AccessControlStore; |
| ... | ... | @@ -39,7 +40,6 @@ import com.sap.sse.security.shared.UserManagementException; |
| 39 | 40 | import com.sap.sse.security.shared.WildcardPermission; |
| 40 | 41 | import com.sap.sse.security.shared.impl.AccessControlList; |
| 41 | 42 | import com.sap.sse.security.shared.impl.HasPermissionsImpl; |
| 42 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 43 | 43 | import com.sap.sse.security.shared.impl.Ownership; |
| 44 | 44 | import com.sap.sse.security.shared.impl.Role; |
| 45 | 45 | import com.sap.sse.security.shared.impl.User; |
| ... | ... | @@ -94,7 +94,7 @@ public class PermissionCheckerTest { |
| 94 | 94 | userStore.deleteUser("jonas"); |
| 95 | 95 | } |
| 96 | 96 | userTenant = userStore.createUserGroup(userTenantId, "jonas-tenant"); |
| 97 | - user = userStore.createUser("jonas", "jonas@dann.io", new LockingAndBanningImpl()); |
|
| 97 | + user = userStore.createUser("jonas", "jonas@dann.io", new TimedLockImpl()); |
|
| 98 | 98 | userTenant.add(user); |
| 99 | 99 | userStore.updateUserGroup(userTenant); |
| 100 | 100 | ownership = new Ownership(user, userTenant); |
java/com.sap.sse.security.test/src/com/sap/sse/security/test/PreferenceObjectBasedNotificationSetTest.java
| ... | ... | @@ -18,6 +18,7 @@ import org.junit.jupiter.api.Test; |
| 18 | 18 | import com.mongodb.MongoException; |
| 19 | 19 | import com.mongodb.client.MongoDatabase; |
| 20 | 20 | import com.sap.sse.common.Util; |
| 21 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 21 | 22 | import com.sap.sse.mongodb.MongoDBConfiguration; |
| 22 | 23 | import com.sap.sse.mongodb.MongoDBService; |
| 23 | 24 | import com.sap.sse.security.PreferenceObjectBasedNotificationSet; |
| ... | ... | @@ -25,7 +26,6 @@ import com.sap.sse.security.interfaces.UserImpl; |
| 25 | 26 | import com.sap.sse.security.interfaces.UserStore; |
| 26 | 27 | import com.sap.sse.security.shared.UserGroupManagementException; |
| 27 | 28 | import com.sap.sse.security.shared.UserManagementException; |
| 28 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 29 | 29 | import com.sap.sse.security.shared.impl.User; |
| 30 | 30 | import com.sap.sse.security.shared.impl.UserGroup; |
| 31 | 31 | import com.sap.sse.security.userstore.mongodb.UserStoreImpl; |
| ... | ... | @@ -191,7 +191,7 @@ public class PreferenceObjectBasedNotificationSetTest { |
| 191 | 191 | |
| 192 | 192 | @Test |
| 193 | 193 | public void userWithNonVerifiedEmailIsSkippedTest() throws UserManagementException, UserGroupManagementException { |
| 194 | - store.createUser(user1, mail, new LockingAndBanningImpl()); |
|
| 194 | + store.createUser(user1, mail, new TimedLockImpl()); |
|
| 195 | 195 | store.registerPreferenceConverter(prefKey, prefConverter); |
| 196 | 196 | store.setPreferenceObject(user1, prefKey, values1); |
| 197 | 197 | PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); |
| ... | ... | @@ -238,7 +238,7 @@ public class PreferenceObjectBasedNotificationSetTest { |
| 238 | 238 | */ |
| 239 | 239 | @Test |
| 240 | 240 | public void deleteUserWithMappingTest() throws UserManagementException, UserGroupManagementException { |
| 241 | - store.createUser(user1, mail, new LockingAndBanningImpl()); |
|
| 241 | + store.createUser(user1, mail, new TimedLockImpl()); |
|
| 242 | 242 | store.registerPreferenceConverter(prefKey, prefConverter); |
| 243 | 243 | store.setPreferenceObject(user1, prefKey, values1); |
| 244 | 244 | PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); |
| ... | ... | @@ -250,7 +250,7 @@ public class PreferenceObjectBasedNotificationSetTest { |
| 250 | 250 | |
| 251 | 251 | @Test |
| 252 | 252 | public void removePreferenceConverterTest() throws UserManagementException, UserGroupManagementException { |
| 253 | - store.createUser(user1, mail, new LockingAndBanningImpl()); |
|
| 253 | + store.createUser(user1, mail, new TimedLockImpl()); |
|
| 254 | 254 | store.registerPreferenceConverter(prefKey, prefConverter); |
| 255 | 255 | store.setPreferenceObject(user1, prefKey, values1); |
| 256 | 256 | PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store); |
| ... | ... | @@ -272,9 +272,9 @@ public class PreferenceObjectBasedNotificationSetTest { |
| 272 | 272 | UserGroup defaultTenantForSingleServer = store.createUserGroup(UUID.randomUUID(), username + "-tenant"); |
| 273 | 273 | Map<String, UserGroup> defaultTenantForServer = new ConcurrentHashMap<>(); |
| 274 | 274 | defaultTenantForServer.put(serverName, defaultTenantForSingleServer); |
| 275 | - store.createUser(username, email, new LockingAndBanningImpl()); |
|
| 275 | + store.createUser(username, email, new TimedLockImpl()); |
|
| 276 | 276 | store.updateUser(new UserImpl(username, email, null, null, null, true, null, null, defaultTenantForServer, |
| 277 | - Collections.emptySet(), /* userGroupProvider */ null, new LockingAndBanningImpl())); |
|
| 277 | + Collections.emptySet(), /* userGroupProvider */ null, new TimedLockImpl())); |
|
| 278 | 278 | } |
| 279 | 279 | |
| 280 | 280 | private static class PreferenceObjectBasedNotificationSetImpl extends PreferenceObjectBasedNotificationSet<HashSet<String>, String> { |
java/com.sap.sse.security.test/src/com/sap/sse/security/test/PrivilegeEscalationTest.java
| ... | ... | @@ -11,6 +11,7 @@ import org.junit.jupiter.api.AfterEach; |
| 11 | 11 | import org.junit.jupiter.api.BeforeEach; |
| 12 | 12 | import org.junit.jupiter.api.Test; |
| 13 | 13 | |
| 14 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 14 | 15 | import com.sap.sse.security.SecurityService; |
| 15 | 16 | import com.sap.sse.security.impl.SecurityServiceImpl; |
| 16 | 17 | import com.sap.sse.security.shared.HasPermissions; |
| ... | ... | @@ -26,7 +27,6 @@ import com.sap.sse.security.shared.UserStoreManagementException; |
| 26 | 27 | import com.sap.sse.security.shared.WildcardPermission; |
| 27 | 28 | import com.sap.sse.security.shared.impl.AccessControlList; |
| 28 | 29 | import com.sap.sse.security.shared.impl.HasPermissionsImpl; |
| 29 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 30 | 30 | import com.sap.sse.security.shared.impl.Ownership; |
| 31 | 31 | import com.sap.sse.security.shared.impl.Role; |
| 32 | 32 | import com.sap.sse.security.shared.impl.SecuredSecurityTypes; |
| ... | ... | @@ -65,8 +65,8 @@ public class PrivilegeEscalationTest { |
| 65 | 65 | PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(), TEST_DEFAULT_TENANT); |
| 66 | 66 | userStore.ensureDefaultRolesExist(); |
| 67 | 67 | userStore.loadAndMigrateUsers(); |
| 68 | - user = userStore.createUser(USER_USERNAME, null, new LockingAndBanningImpl()); |
|
| 69 | - user2 = userStore.createUser(USER2_USERNAME, null, new LockingAndBanningImpl()); |
|
| 68 | + user = userStore.createUser(USER_USERNAME, null, new TimedLockImpl()); |
|
| 69 | + user2 = userStore.createUser(USER2_USERNAME, null, new TimedLockImpl()); |
|
| 70 | 70 | userGroup = userStore.createUserGroup(USER_GROUP_UUID, USER_USERNAME+"-tenant"); |
| 71 | 71 | userGroup.add(user); |
| 72 | 72 | userGroup.add(user2); |
java/com.sap.sse.security.test/src/com/sap/sse/security/test/RoleDefinitionsTest.java
| ... | ... | @@ -8,11 +8,11 @@ import java.util.UUID; |
| 8 | 8 | import org.junit.jupiter.api.BeforeEach; |
| 9 | 9 | import org.junit.jupiter.api.Test; |
| 10 | 10 | |
| 11 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 11 | 12 | import com.sap.sse.security.interfaces.UserStore; |
| 12 | 13 | import com.sap.sse.security.shared.RoleDefinition; |
| 13 | 14 | import com.sap.sse.security.shared.UserManagementException; |
| 14 | 15 | import com.sap.sse.security.shared.UserStoreManagementException; |
| 15 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 16 | 16 | import com.sap.sse.security.shared.impl.Role; |
| 17 | 17 | import com.sap.sse.security.shared.impl.User; |
| 18 | 18 | import com.sap.sse.security.shared.impl.UserGroup; |
| ... | ... | @@ -37,7 +37,7 @@ public class RoleDefinitionsTest { |
| 37 | 37 | @BeforeEach |
| 38 | 38 | public void doBefore() throws UserStoreManagementException { |
| 39 | 39 | userStore.clear(); |
| 40 | - user = userStore.createUser(username, email, new LockingAndBanningImpl()); |
|
| 40 | + user = userStore.createUser(username, email, new TimedLockImpl()); |
|
| 41 | 41 | roleDefinition = userStore.createRoleDefinition(testRoleUUID, TEST_ROLE, Collections.emptySet()); |
| 42 | 42 | userGroup = userStore.createUserGroup(testGroupUUID, groupName); |
| 43 | 43 | } |
java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserPreferenceObjectAndConverterTest.java
| ... | ... | @@ -9,11 +9,11 @@ import org.junit.jupiter.api.Test; |
| 9 | 9 | |
| 10 | 10 | import com.mongodb.MongoException; |
| 11 | 11 | import com.mongodb.client.MongoDatabase; |
| 12 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 12 | 13 | import com.sap.sse.mongodb.MongoDBConfiguration; |
| 13 | 14 | import com.sap.sse.mongodb.MongoDBService; |
| 14 | 15 | import com.sap.sse.security.shared.UserGroupManagementException; |
| 15 | 16 | import com.sap.sse.security.shared.UserManagementException; |
| 16 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 17 | 17 | import com.sap.sse.security.userstore.mongodb.UserStoreImpl; |
| 18 | 18 | import com.sap.sse.security.userstore.mongodb.impl.CollectionNames; |
| 19 | 19 | |
| ... | ... | @@ -115,7 +115,7 @@ public class UserPreferenceObjectAndConverterTest { |
| 115 | 115 | */ |
| 116 | 116 | @Test |
| 117 | 117 | public void deleteUserWithPreferenceObjectTest() throws UserManagementException, UserGroupManagementException { |
| 118 | - store.createUser(user1, email, new LockingAndBanningImpl()); |
|
| 118 | + store.createUser(user1, email, new TimedLockImpl()); |
|
| 119 | 119 | store.registerPreferenceConverter(prefKey1, prefConverter); |
| 120 | 120 | store.setPreferenceObject(user1, prefKey1, pref1); |
| 121 | 121 | store.deleteUser(user1); |
| ... | ... | @@ -124,7 +124,7 @@ public class UserPreferenceObjectAndConverterTest { |
| 124 | 124 | |
| 125 | 125 | @Test |
| 126 | 126 | public void removeConverterTest() throws UserManagementException, UserGroupManagementException { |
| 127 | - store.createUser(user1, email, new LockingAndBanningImpl()); |
|
| 127 | + store.createUser(user1, email, new TimedLockImpl()); |
|
| 128 | 128 | store.registerPreferenceConverter(prefKey1, prefConverter); |
| 129 | 129 | store.setPreference(user1, prefKey1, serializedPref1); |
| 130 | 130 | store.removePreferenceConverter(prefKey1); |
java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreTest.java
| ... | ... | @@ -6,10 +6,10 @@ import static org.junit.jupiter.api.Assertions.assertNull; |
| 6 | 6 | import org.junit.jupiter.api.BeforeEach; |
| 7 | 7 | import org.junit.jupiter.api.Test; |
| 8 | 8 | |
| 9 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 9 | 10 | import com.sap.sse.security.interfaces.UserStore; |
| 10 | 11 | import com.sap.sse.security.shared.UserGroupManagementException; |
| 11 | 12 | import com.sap.sse.security.shared.UserManagementException; |
| 12 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 13 | 13 | import com.sap.sse.security.userstore.mongodb.UserStoreImpl; |
| 14 | 14 | |
| 15 | 15 | public class UserStoreTest { |
| ... | ... | @@ -26,7 +26,7 @@ public class UserStoreTest { |
| 26 | 26 | |
| 27 | 27 | @BeforeEach |
| 28 | 28 | public void setUp() throws UserManagementException, UserGroupManagementException { |
| 29 | - userStore.createUser(username, email, new LockingAndBanningImpl()); |
|
| 29 | + userStore.createUser(username, email, new TimedLockImpl()); |
|
| 30 | 30 | userStore.setAccessToken(username, accessToken); |
| 31 | 31 | userStore.setPreference(username, prefKey, prefValue); |
| 32 | 32 | } |
java/com.sap.sse.security.test/src/com/sap/sse/security/test/UserStoreWithPersistenceTest.java
| ... | ... | @@ -24,6 +24,7 @@ import com.mongodb.MongoException; |
| 24 | 24 | import com.mongodb.client.MongoDatabase; |
| 25 | 25 | import com.sap.sse.common.Util; |
| 26 | 26 | import com.sap.sse.common.Util.Pair; |
| 27 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 27 | 28 | import com.sap.sse.mongodb.MongoDBConfiguration; |
| 28 | 29 | import com.sap.sse.mongodb.MongoDBService; |
| 29 | 30 | import com.sap.sse.security.interfaces.UserImpl; |
| ... | ... | @@ -34,7 +35,6 @@ import com.sap.sse.security.shared.SecurityUser; |
| 34 | 35 | import com.sap.sse.security.shared.UserGroupManagementException; |
| 35 | 36 | import com.sap.sse.security.shared.UserManagementException; |
| 36 | 37 | import com.sap.sse.security.shared.UserStoreManagementException; |
| 37 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 38 | 38 | import com.sap.sse.security.shared.impl.Ownership; |
| 39 | 39 | import com.sap.sse.security.shared.impl.Role; |
| 40 | 40 | import com.sap.sse.security.shared.impl.User; |
| ... | ... | @@ -92,7 +92,7 @@ public class UserStoreWithPersistenceTest { |
| 92 | 92 | |
| 93 | 93 | @Test |
| 94 | 94 | public void testCreateUser() throws UserManagementException { |
| 95 | - store.createUser(username, email, new LockingAndBanningImpl()); |
|
| 95 | + store.createUser(username, email, new TimedLockImpl()); |
|
| 96 | 96 | assertNotNull(store.getUserByName(username)); |
| 97 | 97 | assertNotNull(store.getUserByEmail(email)); |
| 98 | 98 | |
| ... | ... | @@ -103,12 +103,12 @@ public class UserStoreWithPersistenceTest { |
| 103 | 103 | |
| 104 | 104 | @Test |
| 105 | 105 | public void testMasterdataIsSaved() throws UserStoreManagementException { |
| 106 | - store.createUser(username, email, new LockingAndBanningImpl()); |
|
| 106 | + store.createUser(username, email, new TimedLockImpl()); |
|
| 107 | 107 | UserGroupImpl defaultTenant = createUserGroup(); |
| 108 | 108 | HashMap<String, UserGroup> defaultTenantForServers = new HashMap<>(); |
| 109 | 109 | defaultTenantForServers.put(serverName, defaultTenant); |
| 110 | 110 | store.updateUser(new UserImpl(username, email, fullName, company, Locale.GERMAN, false, null, null, |
| 111 | - defaultTenantForServers, Collections.emptySet(), /* userGroupProvider */ null, new LockingAndBanningImpl())); |
|
| 111 | + defaultTenantForServers, Collections.emptySet(), /* userGroupProvider */ null, new TimedLockImpl())); |
|
| 112 | 112 | newStore(); |
| 113 | 113 | User savedUser = store.getUserByName(username); |
| 114 | 114 | assertEquals(username, savedUser.getName()); |
| ... | ... | @@ -123,7 +123,7 @@ public class UserStoreWithPersistenceTest { |
| 123 | 123 | */ |
| 124 | 124 | @Test |
| 125 | 125 | public void testDeleteUser() throws UserManagementException { |
| 126 | - store.createUser(username, email, new LockingAndBanningImpl()); |
|
| 126 | + store.createUser(username, email, new TimedLockImpl()); |
|
| 127 | 127 | store.deleteUser(username); |
| 128 | 128 | assertNull(store.getUserByName(username)); |
| 129 | 129 | assertNull(store.getUserByEmail(email)); |
| ... | ... | @@ -135,7 +135,7 @@ public class UserStoreWithPersistenceTest { |
| 135 | 135 | |
| 136 | 136 | @Test |
| 137 | 137 | public void testSetPreferences() throws UserManagementException { |
| 138 | - store.createUser(username, email, new LockingAndBanningImpl()); |
|
| 138 | + store.createUser(username, email, new TimedLockImpl()); |
|
| 139 | 139 | store.setPreference(username, prefKey, prefValue); |
| 140 | 140 | assertEquals(prefValue, store.getPreference(username, prefKey)); |
| 141 | 141 | newStore(); |
| ... | ... | @@ -144,7 +144,7 @@ public class UserStoreWithPersistenceTest { |
| 144 | 144 | |
| 145 | 145 | @Test |
| 146 | 146 | public void testUnsetPreferences() throws UserManagementException { |
| 147 | - store.createUser(username, email, new LockingAndBanningImpl()); |
|
| 147 | + store.createUser(username, email, new TimedLockImpl()); |
|
| 148 | 148 | store.setPreference(username, prefKey, prefValue); |
| 149 | 149 | store.unsetPreference(username, prefKey); |
| 150 | 150 | assertNull(store.getPreference(username, prefKey)); |
| ... | ... | @@ -157,7 +157,7 @@ public class UserStoreWithPersistenceTest { |
| 157 | 157 | */ |
| 158 | 158 | @Test |
| 159 | 159 | public void testDeleteUserWithPreferences() throws UserManagementException { |
| 160 | - store.createUser(username, email, new LockingAndBanningImpl()); |
|
| 160 | + store.createUser(username, email, new TimedLockImpl()); |
|
| 161 | 161 | store.setPreference(username, prefKey, prefValue); |
| 162 | 162 | store.deleteUser(username); |
| 163 | 163 | assertNull(store.getPreference(username, prefKey)); |
| ... | ... | @@ -167,7 +167,7 @@ public class UserStoreWithPersistenceTest { |
| 167 | 167 | |
| 168 | 168 | @Test |
| 169 | 169 | public void testCreateUserGroup() throws UserGroupManagementException, UserManagementException { |
| 170 | - final User user = store.createUser(username, email, new LockingAndBanningImpl()); |
|
| 170 | + final User user = store.createUser(username, email, new TimedLockImpl()); |
|
| 171 | 171 | UserGroupImpl createUserGroup = createUserGroup(); |
| 172 | 172 | createUserGroup.add(user); |
| 173 | 173 | store.updateUserGroup(createUserGroup); |
| ... | ... | @@ -196,7 +196,7 @@ public class UserStoreWithPersistenceTest { |
| 196 | 196 | @Test |
| 197 | 197 | public void testTenantUsers() throws UserManagementException, UserGroupManagementException { |
| 198 | 198 | UserGroupImpl defaultTenant = createUserGroup(); |
| 199 | - final User user = store.createUser(username, email, new LockingAndBanningImpl()); |
|
| 199 | + final User user = store.createUser(username, email, new TimedLockImpl()); |
|
| 200 | 200 | defaultTenant.add(user); |
| 201 | 201 | store.updateUserGroup(defaultTenant); |
| 202 | 202 | user.getDefaultTenantMap().put(serverName, defaultTenant); |
| ... | ... | @@ -218,7 +218,7 @@ public class UserStoreWithPersistenceTest { |
| 218 | 218 | |
| 219 | 219 | @Test |
| 220 | 220 | public void testUserGroups() throws UserManagementException, UserGroupManagementException { |
| 221 | - final User user = store.createUser(username, email, new LockingAndBanningImpl()); |
|
| 221 | + final User user = store.createUser(username, email, new TimedLockImpl()); |
|
| 222 | 222 | final String GROUP_NAME = "group"; |
| 223 | 223 | final UserGroupImpl group = store.createUserGroup(UUID.randomUUID(), GROUP_NAME); |
| 224 | 224 | group.add(user); |
| ... | ... | @@ -242,7 +242,7 @@ public class UserStoreWithPersistenceTest { |
| 242 | 242 | @Test |
| 243 | 243 | public void testGetExistingQualificationsForRoleDefinition() |
| 244 | 244 | throws UserManagementException, UserGroupManagementException { |
| 245 | - User user = store.createUser("def", "d@test.de", new LockingAndBanningImpl()); |
|
| 245 | + User user = store.createUser("def", "d@test.de", new TimedLockImpl()); |
|
| 246 | 246 | RoleDefinitionImpl roleDefinition = new RoleDefinitionImpl(UUID.randomUUID(), "My-Test-Role"); |
| 247 | 247 | store.createRoleDefinition(roleDefinition.getId(), roleDefinition.getName(), new ArrayList<>()); |
| 248 | 248 | UserGroupImpl userGroup = store.createUserGroup(UUID.randomUUID(), "Test-Usergroup"); |
java/com.sap.sse.security.ui/.settings/com.gwtplugins.gwt.eclipse.core.prefs
| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | -//gwtVersion_/com.google.gwt.user/lib=2.11.1 |
|
| 1 | +//gwtVersion_/com.google.gwt.user/lib= |
|
| 2 | 2 | //gwtVersion_/opt/gwt-2.11.0=2.11.0 |
| 3 | 3 | //gwtVersion_/opt/gwt-2.11.1=2.11.1 |
| 4 | 4 | //gwtVersion_/opt/gwt-2.12.2=2.12.2 |
java/com.sap.sse.security.ui/GWT Security SDM.launch
| ... | ... | @@ -27,6 +27,8 @@ |
| 27 | 27 | </listAttribute> |
| 28 | 28 | <booleanAttribute key="org.eclipse.jdt.debug.ui.CONSIDER_INHERITED_MAIN" value="true"/> |
| 29 | 29 | <booleanAttribute key="org.eclipse.jdt.debug.ui.INCLUDE_EXTERNAL_JARS" value="true"/> |
| 30 | + <booleanAttribute key="org.eclipse.jdt.launching.ATTR_ATTR_USE_ARGFILE" value="false"/> |
|
| 31 | + <booleanAttribute key="org.eclipse.jdt.launching.ATTR_SHOW_CODEDETAILS_IN_EXCEPTION_MESSAGES" value="true"/> |
|
| 30 | 32 | <booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_CLASSPATH_ONLY_JAR" value="false"/> |
| 31 | 33 | <listAttribute key="org.eclipse.jdt.launching.CLASSPATH"> |
| 32 | 34 | <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8" javaProject="com.sap.sailing.gwt.ui" path="1" type="4"/> "/> |
| ... | ... | @@ -101,12 +103,14 @@ |
| 101 | 103 | <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry id="org.eclipse.jdt.launching.classpathentry.defaultClasspath"> <memento exportedEntriesOnly="false" project="com.sap.sailing.gwt.ui"/> </runtimeClasspathEntry> "/> |
| 102 | 104 | <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry path="3" projectName="com.sap.sse.common" type="1"/> "/> |
| 103 | 105 | <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.landscape.aws.common/src" path="3" type="2"/> "/> |
| 106 | + <listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry internalArchive="/com.sap.sse.branding/src" path="3" type="2"/> "/> |
|
| 104 | 107 | </listAttribute> |
| 105 | 108 | <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="com.gwtplugins.gwt.eclipse.core.moduleClasspathProvider"/> |
| 106 | 109 | <booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/> |
| 110 | + <stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17/"/> |
|
| 107 | 111 | <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/> |
| 108 | 112 | <stringAttribute key="org.eclipse.jdt.launching.MODULE_NAME" value="com.sap.sse.security.ui"/> |
| 109 | - <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-incremental -workDir "${project_loc:com.sap.sse.security.ui}/.tmp/gwt-work" -war "${project_loc:com.sap.sse.security.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -logLevel INFO -codeServerPort 9877 -startupUrl /security/ui/Login.html -startupUrl /security/ui/EditProfile.html -startupUrl /security/ui/EmailValidation.html -startupUrl /security/ui/UserManagement.html -startupUrl /security/ui/Register.html -startupUrl /security/ui/Login.html com.sap.sse.security.ui.EditProfile com.sap.sse.security.ui.EmailValidation com.sap.sse.security.ui.OAuthLogin com.sap.sse.security.ui.UserManagementEntryPoint com.sap.sse.security.ui.Register com.sap.sse.security.ui.Login"/> |
|
| 113 | + <stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-incremental -workDir "${project_loc:com.sap.sse.security.ui}/.tmp/gwt-work" -war "${project_loc:com.sap.sse.security.ui}" -noserver -remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -bindAddress 0.0.0.0 -logLevel INFO -codeServerPort 9877 -startupUrl /security/ui/Login.html -startupUrl /security/ui/EditProfile.html -startupUrl /security/ui/EmailValidation.html -startupUrl /security/ui/UserManagement.html -startupUrl /security/ui/Register.html -startupUrl /security/ui/Login.html com.sap.sse.security.ui.EditProfile com.sap.sse.security.ui.EmailValidation com.sap.sse.security.ui.OAuthLogin com.sap.sse.security.ui.UserManagementEntryPoint com.sap.sse.security.ui.Register com.sap.sse.security.ui.Login"/> |
|
| 110 | 114 | <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="com.sap.sse.security.ui"/> |
| 111 | 115 | <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-XX:+UseG1GC -XX:-UseStringDeduplication -Dgwt.watchFileChanges=false -Xmx2048m -Dgwt-usearchives=false -Dgwt.persistentunitcache=false"/> |
| 112 | 116 | <stringAttribute key="org.eclipse.jdt.launching.WORKING_DIRECTORY" value="${project_loc:com.sap.sailing.gwt.ui}/.tmp/gwt-work"/> |
java/com.sap.sse.security.ui/pom.xml
| ... | ... | @@ -77,9 +77,19 @@ |
| 77 | 77 | <!-- GWT version detected from dependencyManagement --> |
| 78 | 78 | <execution> |
| 79 | 79 | <configuration> |
| 80 | + <!-- for debugger attachment: --> |
|
| 81 | + <!-- |
|
| 82 | + <extraJvmArgs> |
|
| 83 | + -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:8003 |
|
| 84 | + </extraJvmArgs> |
|
| 85 | + <extraJvmArgsCompiler> |
|
| 86 | + -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:8003 |
|
| 87 | + </extraJvmArgsCompiler> |
|
| 88 | + <logLevel>DEBUG</logLevel> |
|
| 89 | + --> |
|
| 80 | 90 | <!-- <userAgents>chrome</userAgents> --> |
| 81 | 91 | <modules> |
| 82 | - <module>com.sap.sse.security.ui.UserManagement</module> |
|
| 92 | + <module>com.sap.sse.security.ui.UserManagement</module> |
|
| 83 | 93 | <module>com.sap.sse.security.ui.UserManagementEntryPoint</module> |
| 84 | 94 | <module>com.sap.sse.security.ui.Login</module> |
| 85 | 95 | <module>com.sap.sse.security.ui.OAuthLogin</module> |
java/com.sap.sse.security.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sse/common/impl/MillisecondsDurationImpl_CustomFieldSerializer.java
| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | +package com.google.gwt.user.client.rpc.core.com.sap.sse.common.impl; |
|
| 2 | + |
|
| 3 | +import com.google.gwt.user.client.rpc.CustomFieldSerializer; |
|
| 4 | +import com.google.gwt.user.client.rpc.SerializationException; |
|
| 5 | +import com.google.gwt.user.client.rpc.SerializationStreamReader; |
|
| 6 | +import com.google.gwt.user.client.rpc.SerializationStreamWriter; |
|
| 7 | +import com.sap.sse.common.impl.MillisecondsDurationImpl; |
|
| 8 | + |
|
| 9 | +public class MillisecondsDurationImpl_CustomFieldSerializer extends CustomFieldSerializer<MillisecondsDurationImpl> { |
|
| 10 | + |
|
| 11 | + @Override |
|
| 12 | + public void serializeInstance(SerializationStreamWriter streamWriter, MillisecondsDurationImpl instance) |
|
| 13 | + throws SerializationException { |
|
| 14 | + serialize(streamWriter, instance); |
|
| 15 | + } |
|
| 16 | + |
|
| 17 | + public static void serialize(SerializationStreamWriter streamWriter, MillisecondsDurationImpl instance) |
|
| 18 | + throws SerializationException { |
|
| 19 | + streamWriter.writeLong(instance.asMillis()); |
|
| 20 | + } |
|
| 21 | + |
|
| 22 | + @Override |
|
| 23 | + public boolean hasCustomInstantiateInstance() { |
|
| 24 | + return true; |
|
| 25 | + } |
|
| 26 | + |
|
| 27 | + @Override |
|
| 28 | + public MillisecondsDurationImpl instantiateInstance(SerializationStreamReader streamReader) |
|
| 29 | + throws SerializationException { |
|
| 30 | + return instantiate(streamReader); |
|
| 31 | + } |
|
| 32 | + |
|
| 33 | + public static MillisecondsDurationImpl instantiate(SerializationStreamReader streamReader) |
|
| 34 | + throws SerializationException { |
|
| 35 | + return new MillisecondsDurationImpl(streamReader.readLong()); |
|
| 36 | + } |
|
| 37 | + |
|
| 38 | + @Override |
|
| 39 | + public void deserializeInstance(SerializationStreamReader streamReader, MillisecondsDurationImpl instance) |
|
| 40 | + throws SerializationException { |
|
| 41 | + deserialize(streamReader, instance); |
|
| 42 | + } |
|
| 43 | + |
|
| 44 | + public static void deserialize(SerializationStreamReader streamReader, MillisecondsDurationImpl instance) { |
|
| 45 | + // Done by instantiateInstance |
|
| 46 | + } |
|
| 47 | + |
|
| 48 | +} |
java/com.sap.sse.security.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sse/common/impl/SecondsDurationImpl_CustomFieldSerializer.java
| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | +package com.google.gwt.user.client.rpc.core.com.sap.sse.common.impl; |
|
| 2 | + |
|
| 3 | +import com.google.gwt.user.client.rpc.CustomFieldSerializer; |
|
| 4 | +import com.google.gwt.user.client.rpc.SerializationException; |
|
| 5 | +import com.google.gwt.user.client.rpc.SerializationStreamReader; |
|
| 6 | +import com.google.gwt.user.client.rpc.SerializationStreamWriter; |
|
| 7 | +import com.sap.sse.common.impl.SecondsDurationImpl; |
|
| 8 | + |
|
| 9 | +public class SecondsDurationImpl_CustomFieldSerializer extends CustomFieldSerializer<SecondsDurationImpl> { |
|
| 10 | + |
|
| 11 | + @Override |
|
| 12 | + public void serializeInstance(SerializationStreamWriter streamWriter, SecondsDurationImpl instance) |
|
| 13 | + throws SerializationException { |
|
| 14 | + serialize(streamWriter, instance); |
|
| 15 | + } |
|
| 16 | + |
|
| 17 | + public static void serialize(SerializationStreamWriter streamWriter, SecondsDurationImpl instance) |
|
| 18 | + throws SerializationException { |
|
| 19 | + streamWriter.writeDouble(instance.asSeconds()); |
|
| 20 | + } |
|
| 21 | + |
|
| 22 | + @Override |
|
| 23 | + public boolean hasCustomInstantiateInstance() { |
|
| 24 | + return true; |
|
| 25 | + } |
|
| 26 | + |
|
| 27 | + @Override |
|
| 28 | + public SecondsDurationImpl instantiateInstance(SerializationStreamReader streamReader) |
|
| 29 | + throws SerializationException { |
|
| 30 | + return instantiate(streamReader); |
|
| 31 | + } |
|
| 32 | + |
|
| 33 | + public static SecondsDurationImpl instantiate(SerializationStreamReader streamReader) |
|
| 34 | + throws SerializationException { |
|
| 35 | + return new SecondsDurationImpl(streamReader.readDouble()); |
|
| 36 | + } |
|
| 37 | + |
|
| 38 | + @Override |
|
| 39 | + public void deserializeInstance(SerializationStreamReader streamReader, SecondsDurationImpl instance) |
|
| 40 | + throws SerializationException { |
|
| 41 | + deserialize(streamReader, instance); |
|
| 42 | + } |
|
| 43 | + |
|
| 44 | + public static void deserialize(SerializationStreamReader streamReader, SecondsDurationImpl instance) { |
|
| 45 | + // Done by instantiateInstance |
|
| 46 | + } |
|
| 47 | + |
|
| 48 | +} |
java/com.sap.sse.security.ui/src/main/java/com/google/gwt/user/client/rpc/core/com/sap/sse/security/ui/shared/IpToTimedLockDTO_CustomFieldSerializer.java
| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | +package com.google.gwt.user.client.rpc.core.com.sap.sse.security.ui.shared; |
|
| 2 | + |
|
| 3 | +import com.google.gwt.user.client.rpc.CustomFieldSerializer; |
|
| 4 | +import com.google.gwt.user.client.rpc.SerializationException; |
|
| 5 | +import com.google.gwt.user.client.rpc.SerializationStreamReader; |
|
| 6 | +import com.google.gwt.user.client.rpc.SerializationStreamWriter; |
|
| 7 | +import com.sap.sse.common.TimedLock; |
|
| 8 | +import com.sap.sse.security.ui.shared.IpToTimedLockDTO; |
|
| 9 | + |
|
| 10 | +public class IpToTimedLockDTO_CustomFieldSerializer extends CustomFieldSerializer<IpToTimedLockDTO> { |
|
| 11 | + @Override |
|
| 12 | + public void serializeInstance(SerializationStreamWriter streamWriter, IpToTimedLockDTO instance) |
|
| 13 | + throws SerializationException { |
|
| 14 | + serialize(streamWriter, instance); |
|
| 15 | + } |
|
| 16 | + |
|
| 17 | + public static void serialize(SerializationStreamWriter streamWriter, IpToTimedLockDTO instance) |
|
| 18 | + throws SerializationException { |
|
| 19 | + streamWriter.writeString(instance.getIp()); |
|
| 20 | + streamWriter.writeObject(instance.getTimedLock()); |
|
| 21 | + } |
|
| 22 | + |
|
| 23 | + @Override |
|
| 24 | + public boolean hasCustomInstantiateInstance() { |
|
| 25 | + return true; |
|
| 26 | + } |
|
| 27 | + |
|
| 28 | + @Override |
|
| 29 | + public IpToTimedLockDTO instantiateInstance(SerializationStreamReader streamReader) |
|
| 30 | + throws SerializationException { |
|
| 31 | + return instantiate(streamReader); |
|
| 32 | + } |
|
| 33 | + |
|
| 34 | + public static IpToTimedLockDTO instantiate(SerializationStreamReader streamReader) |
|
| 35 | + throws SerializationException { |
|
| 36 | + return new IpToTimedLockDTO(streamReader.readString(), (TimedLock) streamReader.readObject()); |
|
| 37 | + } |
|
| 38 | + |
|
| 39 | + @Override |
|
| 40 | + public void deserializeInstance(SerializationStreamReader streamReader, IpToTimedLockDTO instance) |
|
| 41 | + throws SerializationException { |
|
| 42 | + deserialize(streamReader, instance); |
|
| 43 | + } |
|
| 44 | + |
|
| 45 | + public static void deserialize(SerializationStreamReader streamReader, IpToTimedLockDTO instance) { |
|
| 46 | + // Done by instantiateInstance |
|
| 47 | + } |
|
| 48 | +} |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/SerializationDummy.java
| ... | ... | @@ -1,12 +1,14 @@ |
| 1 | 1 | package com.sap.sse.security.ui.client; |
| 2 | 2 | |
| 3 | 3 | import com.google.gwt.user.client.rpc.IsSerializable; |
| 4 | +import com.sap.sse.common.TimedLock; |
|
| 4 | 5 | import com.sap.sse.landscape.aws.common.shared.SecuredAwsLandscapeType; |
| 5 | 6 | import com.sap.sse.security.shared.HasPermissions; |
| 6 | 7 | import com.sap.sse.security.shared.TypeRelativeObjectIdentifier; |
| 7 | 8 | |
| 8 | 9 | public class SerializationDummy implements IsSerializable { |
| 9 | - public TypeRelativeObjectIdentifier typeRelativeObjectIdentifier; |
|
| 10 | - public HasPermissions hasPermissions; |
|
| 11 | - public SecuredAwsLandscapeType securedAwsLandscapeType; |
|
| 10 | + TypeRelativeObjectIdentifier typeRelativeObjectIdentifier; |
|
| 11 | + HasPermissions hasPermissions; |
|
| 12 | + SecuredAwsLandscapeType securedAwsLandscapeType; |
|
| 13 | + TimedLock timedLock; |
|
| 12 | 14 | } |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementService.java
| ... | ... | @@ -24,6 +24,7 @@ import com.sap.sse.security.shared.dto.StrippedUserGroupDTO; |
| 24 | 24 | import com.sap.sse.security.shared.dto.UserDTO; |
| 25 | 25 | import com.sap.sse.security.shared.dto.UserGroupDTO; |
| 26 | 26 | import com.sap.sse.security.ui.oauth.client.CredentialDTO; |
| 27 | +import com.sap.sse.security.ui.shared.IpToTimedLockDTO; |
|
| 27 | 28 | import com.sap.sse.security.ui.shared.SecurityServiceSharingDTO; |
| 28 | 29 | import com.sap.sse.security.ui.shared.SuccessInfo; |
| 29 | 30 | |
| ... | ... | @@ -33,7 +34,7 @@ public interface UserManagementService extends RemoteService { |
| 33 | 34 | throws UnauthorizedException, org.apache.shiro.authz.UnauthorizedException; |
| 34 | 35 | |
| 35 | 36 | Collection<UserGroupDTO> getUserGroups() throws org.apache.shiro.authz.UnauthorizedException; |
| 36 | - |
|
| 37 | + |
|
| 37 | 38 | UserGroupDTO getUserGroupByName(String userGroupName) |
| 38 | 39 | throws UnauthorizedException, org.apache.shiro.authz.UnauthorizedException; |
| 39 | 40 | |
| ... | ... | @@ -94,4 +95,8 @@ public interface UserManagementService extends RemoteService { |
| 94 | 95 | Pair<Boolean, ArrayList<String>> getCORSFilterConfiguration(); |
| 95 | 96 | |
| 96 | 97 | String getBrandingConfigurationId(); |
| 98 | + |
|
| 99 | + ArrayList<IpToTimedLockDTO> getClientIPBasedTimedLocksForUserCreation() throws UnauthorizedException; |
|
| 100 | + |
|
| 101 | + ArrayList<IpToTimedLockDTO> getClientIPBasedTimedLocksForBearerTokenAbuse() throws UnauthorizedException; |
|
| 97 | 102 | } |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementServiceAsync.java
| ... | ... | @@ -22,6 +22,7 @@ import com.sap.sse.security.shared.dto.StrippedUserGroupDTO; |
| 22 | 22 | import com.sap.sse.security.shared.dto.UserDTO; |
| 23 | 23 | import com.sap.sse.security.shared.dto.UserGroupDTO; |
| 24 | 24 | import com.sap.sse.security.ui.oauth.client.CredentialDTO; |
| 25 | +import com.sap.sse.security.ui.shared.IpToTimedLockDTO; |
|
| 25 | 26 | import com.sap.sse.security.ui.shared.SecurityServiceSharingDTO; |
| 26 | 27 | import com.sap.sse.security.ui.shared.SuccessInfo; |
| 27 | 28 | |
| ... | ... | @@ -107,4 +108,8 @@ public interface UserManagementServiceAsync { |
| 107 | 108 | void getCORSFilterConfiguration(AsyncCallback<Pair<Boolean, ArrayList<String>>> callback); |
| 108 | 109 | |
| 109 | 110 | void getBrandingConfigurationId(AsyncCallback<String> callback); |
| 111 | + |
|
| 112 | + void getClientIPBasedTimedLocksForUserCreation(AsyncCallback<ArrayList<IpToTimedLockDTO>> callback); |
|
| 113 | + |
|
| 114 | + void getClientIPBasedTimedLocksForBearerTokenAbuse(AsyncCallback<ArrayList<IpToTimedLockDTO>> callback); |
|
| 110 | 115 | } |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementWriteService.java
| ... | ... | @@ -78,6 +78,11 @@ public interface UserManagementWriteService extends UserManagementService { |
| 78 | 78 | throws UserManagementException, org.apache.shiro.authz.UnauthorizedException; |
| 79 | 79 | |
| 80 | 80 | SuccessInfo deleteUser(String username) throws UnauthorizedException, org.apache.shiro.authz.UnauthorizedException; |
| 81 | + |
|
| 82 | + SuccessInfo unlockUser(String username) throws UnauthorizedException, org.apache.shiro.authz.UnauthorizedException; |
|
| 83 | + |
|
| 84 | + Set<SuccessInfo> unlockUsers(Set<String> usernames) |
|
| 85 | + throws UnauthorizedException, org.apache.shiro.authz.UnauthorizedException; |
|
| 81 | 86 | |
| 82 | 87 | Set<SuccessInfo> deleteUsers(Set<String> usernames) |
| 83 | 88 | throws UnauthorizedException, org.apache.shiro.authz.UnauthorizedException; |
| ... | ... | @@ -136,4 +141,9 @@ public interface UserManagementWriteService extends UserManagementService { |
| 136 | 141 | |
| 137 | 142 | AccessControlListDTO overrideAccessControlList(QualifiedObjectIdentifier idOfAccessControlledObject, |
| 138 | 143 | AccessControlListDTO acl) throws UnauthorizedException, org.apache.shiro.authz.UnauthorizedException; |
| 144 | + |
|
| 145 | + void releaseUserCreationLockOnIp(String ip) throws UnauthorizedException; |
|
| 146 | + |
|
| 147 | + void releaseBearerTokenLockOnIp(String ip) throws UnauthorizedException; |
|
| 148 | + |
|
| 139 | 149 | } |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/UserManagementWriteServiceAsync.java
| ... | ... | @@ -61,6 +61,10 @@ public interface UserManagementWriteServiceAsync extends UserManagementServiceAs |
| 61 | 61 | void updateRoleDefinition(RoleDefinitionDTO roleWithNewProperties, AsyncCallback<Void> callback); |
| 62 | 62 | |
| 63 | 63 | void deleteUser(String username, AsyncCallback<SuccessInfo> callback); |
| 64 | + |
|
| 65 | + void unlockUser(String username, AsyncCallback<SuccessInfo> callback); |
|
| 66 | + |
|
| 67 | + void unlockUsers(Set<String> username, AsyncCallback<Set<SuccessInfo>> callback); |
|
| 64 | 68 | |
| 65 | 69 | void deleteUsers(Set<String> usernames, AsyncCallback<Set<SuccessInfo>> callback); |
| 66 | 70 | |
| ... | ... | @@ -121,4 +125,8 @@ public interface UserManagementWriteServiceAsync extends UserManagementServiceAs |
| 121 | 125 | void setCORSFilterConfigurationAllowedOrigins(ArrayList<String> allowedOrigins, AsyncCallback<Void> callback); |
| 122 | 126 | |
| 123 | 127 | void fileTakedownNotice(TakedownNoticeRequestContext takedownNoticeRequestContext, AsyncCallback<Void> callback); |
| 128 | + |
|
| 129 | + void releaseUserCreationLockOnIp(String ip, AsyncCallback<Void> asyncCallback); |
|
| 130 | + |
|
| 131 | + void releaseBearerTokenLockOnIp(String ip, AsyncCallback<Void> asyncCallback); |
|
| 124 | 132 | } |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/AccessControlledButtonPanel.java
| ... | ... | @@ -179,6 +179,28 @@ public class AccessControlledButtonPanel extends Composite { |
| 179 | 179 | return resolveButtonVisibility(permissionCheck, new Button(text, wrap(permissionCheck, callback))); |
| 180 | 180 | } |
| 181 | 181 | |
| 182 | + /** |
|
| 183 | + * Adds an action button, appended with selection count, whose visibility depends on the provided {@link Supplier |
|
| 184 | + * permission check}. |
|
| 185 | + * |
|
| 186 | + * @param text |
|
| 187 | + * the {@link String text} to show on the button |
|
| 188 | + * @param permissionCheck |
|
| 189 | + * the {@link Supplier permission check} to decide if the action button is visible or not |
|
| 190 | + * @param callback |
|
| 191 | + * the {@link Command callback} to execute on button click, if permission is granted |
|
| 192 | + * @return the created {@link Button} instance |
|
| 193 | + */ |
|
| 194 | + public <T extends Named> Button addCountingAction(final String text, final SetSelectionModel<T> selectionModel, |
|
| 195 | + final Supplier<Boolean> permissionCheck, final Command callback) { |
|
| 196 | + if (selectionModel == null) { |
|
| 197 | + throw new IllegalArgumentException("Selection model for a remove action must not be null"); |
|
| 198 | + } |
|
| 199 | + final SelectedElementsCountingButton<T> button = new SelectedElementsCountingButton<T>(text, |
|
| 200 | + selectionModel, wrap(permissionCheck, callback)); |
|
| 201 | + return resolveButtonVisibility(permissionCheck, button); |
|
| 202 | + } |
|
| 203 | + |
|
| 182 | 204 | private Button resolveButtonVisibility(final Supplier<Boolean> permissionCheck, final Button button) { |
| 183 | 205 | this.buttonToPermissions.put(button, permissionCheck); |
| 184 | 206 | button.getElement().getStyle().setMarginRight(5, Unit.PX); |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/component/DefaultActionsImagesBarCell.java
| ... | ... | @@ -5,6 +5,7 @@ import java.util.Arrays; |
| 5 | 5 | import com.sap.sse.gwt.client.IconResources; |
| 6 | 6 | import com.sap.sse.gwt.client.celltable.ImagesBarCell; |
| 7 | 7 | import com.sap.sse.security.shared.HasPermissions.DefaultActions; |
| 8 | +import com.sap.sse.security.shared.impl.SecuredSecurityTypes.UserActions; |
|
| 8 | 9 | import com.sap.sse.security.ui.client.i18n.StringMessages; |
| 9 | 10 | |
| 10 | 11 | public class DefaultActionsImagesBarCell extends ImagesBarCell { |
| ... | ... | @@ -14,6 +15,7 @@ public class DefaultActionsImagesBarCell extends ImagesBarCell { |
| 14 | 15 | public static final String ACTION_CHANGE_OWNERSHIP = DefaultActions.CHANGE_OWNERSHIP.name(); |
| 15 | 16 | public static final String ACTION_MIGRATE_GROUP_OWNERSHIP_HIERARCHY = "MIGRATE_GROUP_OWNERSHIP_HIERARCHY"; |
| 16 | 17 | public static final String ACTION_CHANGE_ACL = DefaultActions.CHANGE_ACL.name(); |
| 18 | + public static final String ACTION_MANAGE_LOCK = UserActions.MANAGE_LOCK.name(); |
|
| 17 | 19 | |
| 18 | 20 | protected final StringMessages stringMessages; |
| 19 | 21 | |
| ... | ... | @@ -24,7 +26,7 @@ public class DefaultActionsImagesBarCell extends ImagesBarCell { |
| 24 | 26 | @Override |
| 25 | 27 | protected Iterable<ImageSpec> getImageSpecs() { |
| 26 | 28 | return Arrays.asList(getUpdateImageSpec(), getDeleteImageSpec(), getChangeOwnershipImageSpec(), |
| 27 | - getChangeACLImageSpec()); |
|
| 29 | + getChangeACLImageSpec(), getResetLockImageSpec()); |
|
| 28 | 30 | } |
| 29 | 31 | |
| 30 | 32 | /** |
| ... | ... | @@ -65,4 +67,12 @@ public class DefaultActionsImagesBarCell extends ImagesBarCell { |
| 65 | 67 | IconResources.INSTANCE.changeACLIcon()); |
| 66 | 68 | } |
| 67 | 69 | |
| 70 | + /** |
|
| 71 | + * @return {@link ImageSpec} for {@link DefaultActions#CHANGE_ACL reset lock} action |
|
| 72 | + */ |
|
| 73 | + protected ImageSpec getResetLockImageSpec() { |
|
| 74 | + return new ImageSpec(ACTION_MANAGE_LOCK, stringMessages.resetLock(), |
|
| 75 | + IconResources.INSTANCE.resetLockIcon()); |
|
| 76 | + } |
|
| 77 | + |
|
| 68 | 78 | } |
| ... | ... | \ No newline at end of file |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.java
| ... | ... | @@ -150,7 +150,11 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages { |
| 150 | 150 | String groups(); |
| 151 | 151 | String group(); |
| 152 | 152 | String errorDeletingUser(String username, String message); |
| 153 | - String doYouReallyWantToRemoveUser(String name); |
|
| 153 | + String doYouReallyWantToUnlockUser(String name); |
|
| 154 | + String doYouReallyWantToUnlockNUsers(int n); |
|
| 155 | + String unlockSucceededForUser(String username); |
|
| 156 | + String unlockFailedForUser(String username); |
|
| 157 | + String userIsAlreadyUnlocked(); |
|
| 154 | 158 | String errorTryingToUpdateUser(String username, String message); |
| 155 | 159 | String ownership(); |
| 156 | 160 | String editObjectOwnership(); |
| ... | ... | @@ -161,6 +165,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages { |
| 161 | 165 | String userNotFound(String username); |
| 162 | 166 | String usergroupNotFound(String userGroupName); |
| 163 | 167 | String actionChangeACL(); |
| 168 | + String resetLock(); |
|
| 164 | 169 | String editACLForObject(String objectName); |
| 165 | 170 | String acl(); |
| 166 | 171 | String errorUpdatingAcl(String name); |
| ... | ... | @@ -226,4 +231,6 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages { |
| 226 | 231 | String lockedUntil(); |
| 227 | 232 | String passwordAuthenticationCurrentlyLockedForUser(); |
| 228 | 233 | String clientCurrentlyLockedForUserCreation(); |
| 234 | + String unlockedSuccessfully(); |
|
| 235 | + String failedToUnlock(); |
|
| 229 | 236 | } |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages.properties
| ... | ... | @@ -156,7 +156,11 @@ validated=Validated |
| 156 | 156 | groups=Groups |
| 157 | 157 | group=Group |
| 158 | 158 | errorDeletingUser=Error deleting user {0}: {1} |
| 159 | -doYouReallyWantToRemoveUser=Really remove user {0}? |
|
| 159 | +doYouReallyWantToUnlockUser=Really allow locked user {0} to access SAP Sailing Analytics again? |
|
| 160 | +doYouReallyWantToUnlockNUsers=Really allow {0} users to access SAP Sailing Analytics again? |
|
| 161 | +unlockSucceededForUser=Unlock succeeded for user {0}. |
|
| 162 | +unlockFailedForUser=Unlock failed for user {0}. |
|
| 163 | +userIsAlreadyUnlocked=User is already unlocked. |
|
| 160 | 164 | errorTryingToUpdateUser=Error trying to update user {0}: {1} |
| 161 | 165 | ownership=Ownership |
| 162 | 166 | editObjectOwnership=Edit object ownership |
| ... | ... | @@ -167,6 +171,7 @@ pleaseWaitUntilUserGroupNameIsResolved=Please wait until user group name is reso |
| 167 | 171 | userNotFound=User {0} not found |
| 168 | 172 | usergroupNotFound=User group {0} not found |
| 169 | 173 | actionChangeACL=Change ACL |
| 174 | +resetLock=Reset Lock |
|
| 170 | 175 | editACLForObject=Edit ACL for ''{0}'' |
| 171 | 176 | acl=ACL |
| 172 | 177 | errorUpdatingAcl=Error updating ACL: {0}. |
| ... | ... | @@ -232,4 +237,6 @@ paymentUnfinished=Waiting for payment to process. |
| 232 | 237 | paymentFinished=Payment successful. Plan roles have been granted. |
| 233 | 238 | lockedUntil=Locked until |
| 234 | 239 | passwordAuthenticationCurrentlyLockedForUser=Password authentication is currently locked for this user due to too many failed login attempts. Please try again later. |
| 235 | -clientCurrentlyLockedForUserCreation=Client is currently locked for user creation after too many user creations by the same client. Please try again later. |
|
| ... | ... | \ No newline at end of file |
| 0 | +clientCurrentlyLockedForUserCreation=Client is currently locked for user creation after too many user creations by the same client. Please try again later. |
|
| 1 | +unlockedSuccessfully=Unlocked successfully |
|
| 2 | +failedToUnlock=Failed to unlock |
|
| ... | ... | \ No newline at end of file |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/i18n/StringMessages_de.properties
| ... | ... | @@ -100,6 +100,7 @@ error=Es ist ein Fehler aufgetreten |
| 100 | 100 | refresh=Aktualisieren |
| 101 | 101 | preferredLanguage=Bevorzugte Sprache |
| 102 | 102 | cannotResetInvalidURL="Fehlerhafte Reseturl ..." |
| 103 | +cannotUploadVideosAndImagesTogether=Videos und Bilder können nicht gleichzeitig hochgeladen werden, bitte laden Sie sie separat hoch. |
|
| 103 | 104 | sharedSettingsLink=Link mit Settings |
| 104 | 105 | makeDefault=Als Voreinstellung |
| 105 | 106 | makeDefaultInProgress=In Bearbeitung... |
| ... | ... | @@ -154,7 +155,11 @@ validated=Geprüft |
| 154 | 155 | groups=Gruppen |
| 155 | 156 | group=Gruppe |
| 156 | 157 | errorDeletingUser=Fehler beim Löschen des Benutzers {0}: {1} |
| 157 | -doYouReallyWantToRemoveUser=Benutzer {0} wirklich löschen? |
|
| 158 | +doYouReallyWantToUnlockUser=Soll dem gesperrten Benutzer {0} der Zugriff auf SAP Sailing Analytics wirklich wieder gewährt werden? |
|
| 159 | +doYouReallyWantToUnlockNUsers=Soll {0} Benutzern wirklich wieder Zugriff auf SAP Sailing Analytics gewährt werden? |
|
| 160 | +unlockSucceededForUser=Entsperrung für Benutzer {0} erfolgreich. |
|
| 161 | +unlockFailedForUser=Entsperrung für Benutzer {0} fehlgeschlagen. |
|
| 162 | +userIsAlreadyUnlocked=Der Benutzer ist bereits entsperrt. |
|
| 158 | 163 | errorTryingToUpdateUser=Fehler beim Aktualisieren des Benutzers {0}: {1} |
| 159 | 164 | ownership=Besitzer |
| 160 | 165 | editObjectOwnership=Objekt-Besitzer bearbeiten |
| ... | ... | @@ -165,6 +170,7 @@ pleaseWaitUntilUserGroupNameIsResolved=Bitte warten, bis der Benutzergruppen-Nam |
| 165 | 170 | userNotFound=Benutzer {0} nicht gefunden |
| 166 | 171 | usergroupNotFound=Benutzergruppe {0} nicht gefunden |
| 167 | 172 | actionChangeACL=ACL ändern |
| 173 | +resetLock=Sperre zurücksetzen |
|
| 168 | 174 | editACLForObject=ACL für ''{0}'' ändern |
| 169 | 175 | acl=ACL |
| 170 | 176 | errorUpdatingAcl=Fehler beim Aktualisieren der ACL: {0}. |
| ... | ... | @@ -196,6 +202,7 @@ nullUserGroup=<Anonyme Usergruppe> |
| 196 | 202 | editRolesAndPermissionsForUser=Rollen und Berechtigungen für Benutzer {0} editieren |
| 197 | 203 | permissionType=Berechtigungstyp |
| 198 | 204 | couldNotLoadMarkTemplates=Markvorlagen konnten nicht geladen werden. |
| 205 | +transitive=Transitiv |
|
| 199 | 206 | failGeneratingHostedPageObject=Fehler beim Erzeugen der eingebetteten Seiten-Objekte, bitte nochmals versuchen |
| 200 | 207 | errorOpenCheckout=Fehler beim Öffnen des Bezahlformulars: {0} |
| 201 | 208 | errorSaveSubscription=Fehler beim Abspeichern des Abonnements: {0} |
| ... | ... | @@ -211,6 +218,7 @@ premiumFeatureListDescription=Vergleichen Sie alle Funktionen des FREE- oder PRE |
| 211 | 218 | selectSubscriptionPlan=Bitte wählen sie einen Abonnementplan aus. |
| 212 | 219 | features=Enthalten |
| 213 | 220 | premiumFeature=Premium-Feature |
| 221 | +premium=Prämie |
|
| 214 | 222 | price=Preis |
| 215 | 223 | pleaseSubscribeToUse=Erlaubnis verweigert! Möchten sie ein Abonement abschließen? |
| 216 | 224 | pleaseSubscribeToUseSpecific=Sie sind nicht berechtigt, die Funktion "{0}" zu verwenden! Möchten sie ein Abonement abschließen? |
| ... | ... | @@ -228,4 +236,6 @@ paymentUnfinished=Warte auf Zahlungsbestätigung. |
| 228 | 236 | paymentFinished=Zahlung erfolgreich. Planrollen wurden verliehen. |
| 229 | 237 | lockedUntil=Gesperrt bis |
| 230 | 238 | passwordAuthenticationCurrentlyLockedForUser=Passwort-Authentifizierung ist für diesen Benutzer derzeit aufgrund zu vieler fehlgeschlagener Versuche gesperrt. Bitter später erneut versuchen. |
| 231 | -clientCurrentlyLockedForUserCreation=Benutzererstellung für den aktuellen Client ist derzeit wegen zu vieler neuer Nutzer vom selben Client gesperrt. Bitte später erneut versuchen. |
|
| ... | ... | \ No newline at end of file |
| 0 | +clientCurrentlyLockedForUserCreation=Benutzererstellung für den aktuellen Client ist derzeit wegen zu vieler neuer Nutzer vom selben Client gesperrt. Bitte später erneut versuchen. |
|
| 1 | +unlockedSuccessfully=Erfolgreich entsperrt. |
|
| 2 | +failedToUnlock=Entsperren fehlgeschlagen |
|
| ... | ... | \ No newline at end of file |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserManagementPanel.java
| ... | ... | @@ -26,6 +26,7 @@ import com.sap.sse.gwt.client.celltable.RefreshableMultiSelectionModel; |
| 26 | 26 | import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback; |
| 27 | 27 | import com.sap.sse.gwt.client.panels.LabeledAbstractFilterablePanel; |
| 28 | 28 | import com.sap.sse.security.shared.dto.UserDTO; |
| 29 | +import com.sap.sse.security.shared.impl.SecuredSecurityTypes.UserActions; |
|
| 29 | 30 | import com.sap.sse.security.ui.client.UserManagementWriteServiceAsync; |
| 30 | 31 | import com.sap.sse.security.ui.client.UserService; |
| 31 | 32 | import com.sap.sse.security.ui.client.component.AccessControlledButtonPanel; |
| ... | ... | @@ -102,6 +103,12 @@ public class UserManagementPanel<TR extends CellTableWithCheckboxResources> exte |
| 102 | 103 | } |
| 103 | 104 | }); |
| 104 | 105 | removeButton.ensureDebugId("DeleteUserButton"); |
| 106 | + final boolean hasManageLockPermissionOnAnyUser = userService.hasCurrentUserAnyPermission(USER.getPermission(UserActions.MANAGE_LOCK), null); |
|
| 107 | + if (hasManageLockPermissionOnAnyUser) { |
|
| 108 | + final Button unlockButton = buttonPanel.addCountingAction("Unlock", userSelectionModel, () -> true, |
|
| 109 | + () -> onCountingUnlockButtonClick(stringMessages, userManagementWriteService, errorReporter)); |
|
| 110 | + unlockButton.ensureDebugId("UnlockUserButton"); |
|
| 111 | + } |
|
| 105 | 112 | ScrollPanel scrollPanel = new ScrollPanel(userList.asWidget()); |
| 106 | 113 | LabeledAbstractFilterablePanel<UserDTO> filterBox = userList.getFilterField(); |
| 107 | 114 | filterBox.getElement().setPropertyString("placeholder", stringMessages.filterUsers()); |
| ... | ... | @@ -137,6 +144,67 @@ public class UserManagementPanel<TR extends CellTableWithCheckboxResources> exte |
| 137 | 144 | west.add(detailsPanel); |
| 138 | 145 | } |
| 139 | 146 | |
| 147 | + private void onCountingUnlockButtonClick(final StringMessages stringMessages, |
|
| 148 | + final UserManagementWriteServiceAsync userManagementWriteService, final ErrorReporter errorReporter) { |
|
| 149 | + final Set<UserDTO> selectedUsers = userSelectionModel.getSelectedSet(); |
|
| 150 | + final Set<String> selectedUsernames = new HashSet<String>(); |
|
| 151 | + selectedUsers.forEach((u) -> selectedUsernames.add(u.getName())); |
|
| 152 | + final boolean didConfirm = Window.confirm(stringMessages.doYouReallyWantToUnlockNUsers(selectedUsers.size())); |
|
| 153 | + if (didConfirm) { |
|
| 154 | + // run api, collect results |
|
| 155 | + final Set<String> successUserNames = new HashSet<String>(); |
|
| 156 | + final Set<String> failureUserNames = new HashSet<String>(); |
|
| 157 | + userManagementWriteService.unlockUsers(selectedUsernames, new AsyncCallback<Set<SuccessInfo>>() { |
|
| 158 | + @Override |
|
| 159 | + public void onSuccess(Set<SuccessInfo> result) { |
|
| 160 | + for (SuccessInfo si : result) { |
|
| 161 | + final String username = si.getExtra(); |
|
| 162 | + if (si.isSuccessful()) { |
|
| 163 | + successUserNames.add(username); |
|
| 164 | + } else { |
|
| 165 | + failureUserNames.add(username); |
|
| 166 | + } |
|
| 167 | + } |
|
| 168 | + // update locked until entries for successful unlocks |
|
| 169 | + final LabeledAbstractFilterablePanel<UserDTO> filterField = userList.getFilterField(); |
|
| 170 | + final List<UserDTO> allUsersWithUpdatedEntries = new ArrayList<UserDTO>(); |
|
| 171 | + for (UserDTO user : filterField.getAll()) { |
|
| 172 | + final boolean didSucceed = successUserNames.contains(user.getName()); |
|
| 173 | + if (didSucceed) { |
|
| 174 | + allUsersWithUpdatedEntries.add(user.copyWithTimePoint(null)); |
|
| 175 | + } else { |
|
| 176 | + allUsersWithUpdatedEntries.add(user); |
|
| 177 | + } |
|
| 178 | + } |
|
| 179 | + filterField.updateAll(allUsersWithUpdatedEntries); |
|
| 180 | + // create alert dialog |
|
| 181 | + String text = ""; |
|
| 182 | + if (successUserNames.size() != 0) { |
|
| 183 | + text += stringMessages.unlockedSuccessfully() + ":\n"; |
|
| 184 | + for (String name : successUserNames) { |
|
| 185 | + text += " • " + name + "\n"; |
|
| 186 | + } |
|
| 187 | + text += "\n"; |
|
| 188 | + } |
|
| 189 | + if (failureUserNames.size() != 0) { |
|
| 190 | + text += stringMessages.failedToUnlock() + ":\n"; |
|
| 191 | + for (String name : failureUserNames) { |
|
| 192 | + text += " • " + name + "\n"; |
|
| 193 | + } |
|
| 194 | + } |
|
| 195 | + if(!text.equals("")) { |
|
| 196 | + Window.alert(text); |
|
| 197 | + } |
|
| 198 | + } |
|
| 199 | + |
|
| 200 | + @Override |
|
| 201 | + public void onFailure(Throwable caught) { |
|
| 202 | + errorReporter.reportError(stringMessages.failedToUnlock() + ": " + caught.getMessage()); |
|
| 203 | + } |
|
| 204 | + }); |
|
| 205 | + } |
|
| 206 | + } |
|
| 207 | + |
|
| 140 | 208 | /** shows the edit dialog if the user exists */ |
| 141 | 209 | private void showRolesAndPermissionsEditDialog(UserService userService, |
| 142 | 210 | final CellTableWithCheckboxResources tableResources, final ErrorReporter errorReporter) { |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/client/usermanagement/UserTableWrapper.java
| ... | ... | @@ -14,6 +14,7 @@ import java.util.Comparator; |
| 14 | 14 | import java.util.HashMap; |
| 15 | 15 | import java.util.Iterator; |
| 16 | 16 | import java.util.List; |
| 17 | +import java.util.function.Consumer; |
|
| 17 | 18 | |
| 18 | 19 | import com.google.gwt.cell.client.SafeHtmlCell; |
| 19 | 20 | import com.google.gwt.core.client.Callback; |
| ... | ... | @@ -31,6 +32,8 @@ import com.sap.sse.common.Util; |
| 31 | 32 | import com.sap.sse.common.util.NaturalComparator; |
| 32 | 33 | import com.sap.sse.gwt.client.DateAndTimeFormatterUtil; |
| 33 | 34 | import com.sap.sse.gwt.client.ErrorReporter; |
| 35 | +import com.sap.sse.gwt.client.Notification; |
|
| 36 | +import com.sap.sse.gwt.client.Notification.NotificationType; |
|
| 34 | 37 | import com.sap.sse.gwt.client.celltable.AbstractSortableTextColumn; |
| 35 | 38 | import com.sap.sse.gwt.client.celltable.CellTableWithCheckboxResources; |
| 36 | 39 | import com.sap.sse.gwt.client.celltable.EntityIdentityComparator; |
| ... | ... | @@ -45,6 +48,7 @@ import com.sap.sse.security.shared.dto.RoleWithSecurityDTO; |
| 45 | 48 | import com.sap.sse.security.shared.dto.StrippedUserGroupDTO; |
| 46 | 49 | import com.sap.sse.security.shared.dto.UserDTO; |
| 47 | 50 | import com.sap.sse.security.shared.impl.SecuredSecurityTypes; |
| 51 | +import com.sap.sse.security.shared.impl.SecuredSecurityTypes.UserActions; |
|
| 48 | 52 | import com.sap.sse.security.ui.client.EntryPointLinkFactory; |
| 49 | 53 | import com.sap.sse.security.ui.client.UserManagementServiceAsync; |
| 50 | 54 | import com.sap.sse.security.ui.client.UserManagementWriteServiceAsync; |
| ... | ... | @@ -162,12 +166,53 @@ extends TableWrapper<UserDTO, S, StringMessages, TR> { |
| 162 | 166 | user->user.getLockedUntil() != null && user.getLockedUntil().after(TimePoint.now()) ? |
| 163 | 167 | DateAndTimeFormatterUtil.dateTimeMedium.render(user.getLockedUntil().asDate()) : "", |
| 164 | 168 | userColumnListHandler); |
| 169 | + final AccessControlledActionsColumn<UserDTO, DefaultActionsImagesBarCell> userActionColumn = composeUserActionColumn( |
|
| 170 | + stringMessages, errorReporter); |
|
| 171 | + filterField = new LabeledAbstractFilterablePanel<UserDTO>(new Label(stringMessages.filterUsers()), |
|
| 172 | + new ArrayList<UserDTO>(), dataProvider, stringMessages) { |
|
| 173 | + @Override |
|
| 174 | + public Iterable<String> getSearchableStrings(UserDTO t) { |
|
| 175 | + List<String> strings = new ArrayList<>(); |
|
| 176 | + strings.add(t.getName()); |
|
| 177 | + strings.add(t.getFullName()); |
|
| 178 | + strings.add(t.getEmail()); |
|
| 179 | + strings.add(t.getCompany()); |
|
| 180 | + Util.addAll(Util.map(t.getRoles(), RoleWithSecurityDTO::getName), strings); |
|
| 181 | + Util.addAll(Util.map(t.getUserGroups(), StrippedUserGroupDTO::getName), strings); |
|
| 182 | + return strings; |
|
| 183 | + } |
|
| 184 | + |
|
| 185 | + @Override |
|
| 186 | + public AbstractCellTable<UserDTO> getCellTable() { |
|
| 187 | + return table; |
|
| 188 | + } |
|
| 189 | + }; |
|
| 190 | + registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider()); |
|
| 191 | + filterField.setUpdatePermissionFilterForCheckbox(user -> userService.hasPermission(user, DefaultActions.UPDATE)); |
|
| 192 | + mainPanel.insert(filterField, 0); |
|
| 193 | + table.addColumnSortHandler(userColumnListHandler); |
|
| 194 | + table.addColumn(usernameColumn, getStringMessages().username()); |
|
| 195 | + table.addColumn(fullNameColumn, stringMessages.name()); |
|
| 196 | + table.addColumn(emailColumn, stringMessages.email()); |
|
| 197 | + table.addColumn(emailValidatedColumn, stringMessages.validated()); |
|
| 198 | + table.addColumn(companyColumn, stringMessages.company()); |
|
| 199 | + table.addColumn(groupsColumn, stringMessages.groups()); |
|
| 200 | + table.addColumn(rolesColumn, stringMessages.roles()); |
|
| 201 | + table.addColumn(permissionsColumn, stringMessages.permissions()); |
|
| 202 | + table.addColumn(lockedUntilColumn, stringMessages.lockedUntil()); |
|
| 203 | + SecuredDTOOwnerColumn.configureOwnerColumns(table, userColumnListHandler, stringMessages); |
|
| 204 | + table.addColumn(userActionColumn, stringMessages.actions()); |
|
| 205 | + table.ensureDebugId("UsersTable"); |
|
| 206 | + } |
|
| 207 | + |
|
| 208 | + private AccessControlledActionsColumn<UserDTO, DefaultActionsImagesBarCell> composeUserActionColumn( |
|
| 209 | + StringMessages stringMessages, ErrorReporter errorReporter) { |
|
| 165 | 210 | final HasPermissions type = SecuredSecurityTypes.USER; |
| 166 | 211 | final AccessControlledActionsColumn<UserDTO, DefaultActionsImagesBarCell> userActionColumn = create( |
| 167 | 212 | new DefaultActionsImagesBarCell(stringMessages), userService); |
| 168 | 213 | userActionColumn.addAction(ACTION_UPDATE, UPDATE, user -> editUser(user)); |
| 169 | 214 | userActionColumn.addAction(ACTION_DELETE, DELETE, user -> { |
| 170 | - if (Window.confirm(stringMessages.doYouReallyWantToRemoveUser(user.getName()))) { |
|
| 215 | + if (Window.confirm(stringMessages.doYouReallyWantToDeleteUser(user.getName()))) { |
|
| 171 | 216 | getUserManagementWriteService().deleteUser(user.getName(), new AsyncCallback<SuccessInfo>() { |
| 172 | 217 | @Override |
| 173 | 218 | public void onFailure(Throwable caught) { |
| ... | ... | @@ -192,47 +237,53 @@ extends TableWrapper<UserDTO, S, StringMessages, TR> { |
| 192 | 237 | final EditOwnershipDialog.DialogConfig<UserDTO> configOwnership = EditOwnershipDialog.create( |
| 193 | 238 | userService.getUserManagementWriteService(), type, |
| 194 | 239 | user -> refreshUserList((Callback<Iterable<UserDTO>, Throwable>) null), stringMessages); |
| 240 | + userActionColumn.addAction(ACTION_CHANGE_OWNERSHIP, CHANGE_OWNERSHIP, configOwnership::openOwnershipDialog); |
|
| 195 | 241 | final EditACLDialog.DialogConfig<UserDTO> configACL = EditACLDialog.create( |
| 196 | 242 | userService.getUserManagementWriteService(), type, |
| 197 | 243 | user -> user.getAccessControlList(), stringMessages); |
| 198 | - userActionColumn.addAction(ACTION_CHANGE_OWNERSHIP, CHANGE_OWNERSHIP, configOwnership::openOwnershipDialog); |
|
| 199 | 244 | userActionColumn.addAction(DefaultActionsImagesBarCell.ACTION_CHANGE_ACL, DefaultActions.CHANGE_ACL, |
| 200 | 245 | u -> configACL.openDialog(u)); |
| 201 | - filterField = new LabeledAbstractFilterablePanel<UserDTO>(new Label(stringMessages.filterUsers()), |
|
| 202 | - new ArrayList<UserDTO>(), dataProvider, stringMessages) { |
|
| 203 | - @Override |
|
| 204 | - public Iterable<String> getSearchableStrings(UserDTO t) { |
|
| 205 | - List<String> strings = new ArrayList<>(); |
|
| 206 | - strings.add(t.getName()); |
|
| 207 | - strings.add(t.getFullName()); |
|
| 208 | - strings.add(t.getEmail()); |
|
| 209 | - strings.add(t.getCompany()); |
|
| 210 | - Util.addAll(Util.map(t.getRoles(), RoleWithSecurityDTO::getName), strings); |
|
| 211 | - Util.addAll(Util.map(t.getUserGroups(), StrippedUserGroupDTO::getName), strings); |
|
| 212 | - return strings; |
|
| 213 | - } |
|
| 246 | + userActionColumn.addAction( |
|
| 247 | + DefaultActionsImagesBarCell.ACTION_MANAGE_LOCK, |
|
| 248 | + UserActions.MANAGE_LOCK, |
|
| 249 | + onManageLockPressed(stringMessages, errorReporter) |
|
| 250 | + ); |
|
| 251 | + return userActionColumn; |
|
| 252 | + } |
|
| 214 | 253 | |
| 215 | - @Override |
|
| 216 | - public AbstractCellTable<UserDTO> getCellTable() { |
|
| 217 | - return table; |
|
| 254 | + private Consumer<UserDTO> onManageLockPressed(StringMessages stringMessages, ErrorReporter errorReporter) { |
|
| 255 | + return selectedUser -> { |
|
| 256 | + final boolean isLocked = selectedUser.getLockedUntil().after(TimePoint.now()); |
|
| 257 | + if (isLocked) { |
|
| 258 | + final String userName = selectedUser.getName(); |
|
| 259 | + final boolean didConfirm = Window.confirm(stringMessages.doYouReallyWantToUnlockUser(userName)); |
|
| 260 | + if (didConfirm) { |
|
| 261 | + getUserManagementWriteService().unlockUser(userName, new AsyncCallback<SuccessInfo>() { |
|
| 262 | + @Override |
|
| 263 | + public void onSuccess(SuccessInfo result) { |
|
| 264 | + Notification.notify(stringMessages.unlockSucceededForUser(userName), NotificationType.SUCCESS); |
|
| 265 | + final List<UserDTO> usersWithUpdatedEntry = new ArrayList<UserDTO>(); |
|
| 266 | + for (UserDTO user : getAllUsers()) { |
|
| 267 | + if (user.getFullName() == selectedUser.getFullName()) { |
|
| 268 | + usersWithUpdatedEntry.add(user.copyWithTimePoint(null)); |
|
| 269 | + } else { |
|
| 270 | + usersWithUpdatedEntry.add(user); |
|
| 271 | + } |
|
| 272 | + } |
|
| 273 | + filterField.updateAll(usersWithUpdatedEntry); |
|
| 274 | + } |
|
| 275 | + |
|
| 276 | + @Override |
|
| 277 | + public void onFailure(Throwable caught) { |
|
| 278 | + Notification.notify(stringMessages.unlockFailedForUser(userName), NotificationType.ERROR); |
|
| 279 | + errorReporter.reportError(caught.getMessage()); |
|
| 280 | + } |
|
| 281 | + }); |
|
| 282 | + } |
|
| 283 | + } else { |
|
| 284 | + Notification.notify(stringMessages.userIsAlreadyUnlocked(), NotificationType.INFO); |
|
| 218 | 285 | } |
| 219 | 286 | }; |
| 220 | - registerSelectionModelOnNewDataProvider(filterField.getAllListDataProvider()); |
|
| 221 | - filterField.setUpdatePermissionFilterForCheckbox(user -> userService.hasPermission(user, DefaultActions.UPDATE)); |
|
| 222 | - mainPanel.insert(filterField, 0); |
|
| 223 | - table.addColumnSortHandler(userColumnListHandler); |
|
| 224 | - table.addColumn(usernameColumn, getStringMessages().username()); |
|
| 225 | - table.addColumn(fullNameColumn, stringMessages.name()); |
|
| 226 | - table.addColumn(emailColumn, stringMessages.email()); |
|
| 227 | - table.addColumn(emailValidatedColumn, stringMessages.validated()); |
|
| 228 | - table.addColumn(companyColumn, stringMessages.company()); |
|
| 229 | - table.addColumn(groupsColumn, stringMessages.groups()); |
|
| 230 | - table.addColumn(rolesColumn, stringMessages.roles()); |
|
| 231 | - table.addColumn(permissionsColumn, stringMessages.permissions()); |
|
| 232 | - table.addColumn(lockedUntilColumn, stringMessages.lockedUntil()); |
|
| 233 | - SecuredDTOOwnerColumn.configureOwnerColumns(table, userColumnListHandler, stringMessages); |
|
| 234 | - table.addColumn(userActionColumn, stringMessages.actions()); |
|
| 235 | - table.ensureDebugId("UsersTable"); |
|
| 236 | 287 | } |
| 237 | 288 | |
| 238 | 289 | public Iterable<UserDTO> getAllUsers() { |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/SecurityDTOFactory.java
| ... | ... | @@ -96,7 +96,7 @@ public class SecurityDTOFactory { |
| 96 | 96 | /* default tenant filled in later */ null, |
| 97 | 97 | getSecuredPermissions(filteredPermissions, user, securityService), |
| 98 | 98 | createStrippedUserGroupDTOsFromUserGroups(securityService.getUserGroupsOfUser(user), |
| 99 | - fromOriginalToStrippedDownUser, fromOriginalToStrippedDownUserGroup), user.getLockingAndBanning().getLockedUntil()); |
|
| 99 | + fromOriginalToStrippedDownUser, fromOriginalToStrippedDownUserGroup), user.getTimedLock().getLockedUntil()); |
|
| 100 | 100 | userDTO.setDefaultTenantForCurrentServer(createStrippedUserGroupDTOFromUserGroup( |
| 101 | 101 | securityService.getDefaultTenantForCurrentUser(), |
| 102 | 102 | fromOriginalToStrippedDownUserGroup)); |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementServiceImpl.java
| ... | ... | @@ -26,6 +26,7 @@ import com.google.gwt.user.server.rpc.RemoteServiceServlet; |
| 26 | 26 | import com.sap.sse.ServerInfo; |
| 27 | 27 | import com.sap.sse.branding.BrandingConfigurationService; |
| 28 | 28 | import com.sap.sse.branding.shared.BrandingConfiguration; |
| 29 | +import com.sap.sse.common.TimedLock; |
|
| 29 | 30 | import com.sap.sse.common.Util; |
| 30 | 31 | import com.sap.sse.common.Util.Pair; |
| 31 | 32 | import com.sap.sse.common.Util.Triple; |
| ... | ... | @@ -36,6 +37,7 @@ import com.sap.sse.security.interfaces.Credential; |
| 36 | 37 | import com.sap.sse.security.shared.AccessControlListAnnotation; |
| 37 | 38 | import com.sap.sse.security.shared.HasPermissions; |
| 38 | 39 | import com.sap.sse.security.shared.HasPermissions.DefaultActions; |
| 40 | +import com.sap.sse.security.shared.IPAddress; |
|
| 39 | 41 | import com.sap.sse.security.shared.QualifiedObjectIdentifier; |
| 40 | 42 | import com.sap.sse.security.shared.TypeRelativeObjectIdentifier; |
| 41 | 43 | import com.sap.sse.security.shared.UnauthorizedException; |
| ... | ... | @@ -59,6 +61,7 @@ import com.sap.sse.security.shared.impl.UserGroup; |
| 59 | 61 | import com.sap.sse.security.ui.client.SerializationDummy; |
| 60 | 62 | import com.sap.sse.security.ui.client.UserManagementService; |
| 61 | 63 | import com.sap.sse.security.ui.oauth.client.CredentialDTO; |
| 64 | +import com.sap.sse.security.ui.shared.IpToTimedLockDTO; |
|
| 62 | 65 | import com.sap.sse.security.ui.shared.SecurityServiceSharingDTO; |
| 63 | 66 | import com.sap.sse.security.ui.shared.SuccessInfo; |
| 64 | 67 | import com.sap.sse.util.ServiceTrackerFactory; |
| ... | ... | @@ -435,4 +438,25 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U |
| 435 | 438 | private BrandingConfigurationService getBrandingConfigurationService() { |
| 436 | 439 | return brandingConfigurationServiceTracker.getService(); |
| 437 | 440 | } |
| 441 | + |
|
| 442 | + @Override |
|
| 443 | + public ArrayList<IpToTimedLockDTO> getClientIPBasedTimedLocksForUserCreation() throws UnauthorizedException { |
|
| 444 | + final HashMap<String, TimedLock> ipToLockMap = getSecurityService().getClientIPBasedTimedLocksForUserCreation(); |
|
| 445 | + return filterIpToTimedLockTableByCurrentUserReadPermission(ipToLockMap); |
|
| 446 | + } |
|
| 447 | + |
|
| 448 | + private ArrayList<IpToTimedLockDTO> filterIpToTimedLockTableByCurrentUserReadPermission( |
|
| 449 | + final HashMap<String, TimedLock> ipToLockMap) { |
|
| 450 | + final SecurityService securityService = getSecurityService(); |
|
| 451 | + return Util.mapToArrayList( |
|
| 452 | + Util.filter(ipToLockMap.entrySet(), |
|
| 453 | + e->securityService.hasCurrentUserReadPermission(new IPAddress(e.getKey()))), |
|
| 454 | + e->new IpToTimedLockDTO(e.getKey(), e.getValue())); |
|
| 455 | + } |
|
| 456 | + |
|
| 457 | + @Override |
|
| 458 | + public ArrayList<IpToTimedLockDTO> getClientIPBasedTimedLocksForBearerTokenAbuse() throws UnauthorizedException { |
|
| 459 | + final HashMap<String, TimedLock> ipToLockMap = getSecurityService().getClientIPBasedTimedLocksForBearerTokenAbuse(); |
|
| 460 | + return filterIpToTimedLockTableByCurrentUserReadPermission(ipToLockMap); |
|
| 461 | + } |
|
| 438 | 462 | } |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/server/UserManagementWriteServiceImpl.java
| ... | ... | @@ -23,6 +23,7 @@ import com.sap.sse.common.media.TakedownNoticeRequestContext; |
| 23 | 23 | import com.sap.sse.security.Action; |
| 24 | 24 | import com.sap.sse.security.SecurityService; |
| 25 | 25 | import com.sap.sse.security.shared.HasPermissions.DefaultActions; |
| 26 | +import com.sap.sse.security.shared.IPAddress; |
|
| 26 | 27 | import com.sap.sse.security.shared.PermissionChecker; |
| 27 | 28 | import com.sap.sse.security.shared.QualifiedObjectIdentifier; |
| 28 | 29 | import com.sap.sse.security.shared.RoleDefinition; |
| ... | ... | @@ -374,6 +375,38 @@ public class UserManagementWriteServiceImpl extends UserManagementServiceImpl im |
| 374 | 375 | return new SuccessInfo(false, "Could not delete user.", /* redirectURL */ null, null); |
| 375 | 376 | } |
| 376 | 377 | } |
| 378 | + |
|
| 379 | + @Override |
|
| 380 | + public SuccessInfo unlockUser(String username) throws UnauthorizedException { |
|
| 381 | + User user = getSecurityService().getUserByName(username); |
|
| 382 | + if (user != null) { |
|
| 383 | + if (!getSecurityService().hasCurrentUserExplicitPermissions(user, UserActions.MANAGE_LOCK)) { |
|
| 384 | + logger.info("You are not permitted to manage locking on user " + username); |
|
| 385 | + return new SuccessInfo(false, "You are not permitted to manage locking on user " + username, |
|
| 386 | + /* redirectURL */ null, null, username); |
|
| 387 | + } |
|
| 388 | + try { |
|
| 389 | + getSecurityService().resetUserTimedLock(username); |
|
| 390 | + logger.info("Reset lock on user: " + username + "."); |
|
| 391 | + return new SuccessInfo(true, "Reset lock on user: " + username + ".", /* redirectURL */ null, null, username); |
|
| 392 | + } catch (UserManagementException e) { |
|
| 393 | + logger.info("Could not reset lock on user: " + username + "."); |
|
| 394 | + return new SuccessInfo(false, "Could not reset lock on user " + username, /* redirectURL */ null, null, username); |
|
| 395 | + } |
|
| 396 | + } else { |
|
| 397 | + logger.info("Could not reset lock on user: " + username + "."); |
|
| 398 | + return new SuccessInfo(false, "Could not reset lock on user " + username, /* redirectURL */ null, null, username); |
|
| 399 | + } |
|
| 400 | + } |
|
| 401 | + |
|
| 402 | + @Override |
|
| 403 | + public Set<SuccessInfo> unlockUsers(Set<String> usernames) throws UnauthorizedException { |
|
| 404 | + final Set<SuccessInfo> result = new HashSet<>(); |
|
| 405 | + for (String username : usernames) { |
|
| 406 | + result.add(unlockUser(username)); |
|
| 407 | + } |
|
| 408 | + return result; |
|
| 409 | + } |
|
| 377 | 410 | |
| 378 | 411 | @Override |
| 379 | 412 | public Set<SuccessInfo> deleteUsers(Set<String> usernames) throws UnauthorizedException { |
| ... | ... | @@ -709,4 +742,24 @@ public class UserManagementWriteServiceImpl extends UserManagementServiceImpl im |
| 709 | 742 | public void fileTakedownNotice(TakedownNoticeRequestContext takedownNoticeRequestContext) throws MailException { |
| 710 | 743 | getSecurityService().fileTakedownNotice(takedownNoticeRequestContext); |
| 711 | 744 | } |
| 745 | + |
|
| 746 | + @Override |
|
| 747 | + public void releaseUserCreationLockOnIp(String ip) throws UnauthorizedException { |
|
| 748 | + final SecurityService securityService = getSecurityService(); |
|
| 749 | + final WildcardPermission deletePermission = SecuredSecurityTypes.LOCKED_IP |
|
| 750 | + .getPermissionForObject(DefaultActions.DELETE, new IPAddress(ip)); |
|
| 751 | + // throws exception if not permitted |
|
| 752 | + SecurityUtils.getSubject().checkPermission(deletePermission.toString()); |
|
| 753 | + securityService.releaseUserCreationLockOnIp(ip); |
|
| 754 | + } |
|
| 755 | + |
|
| 756 | + @Override |
|
| 757 | + public void releaseBearerTokenLockOnIp(String ip) throws UnauthorizedException { |
|
| 758 | + final SecurityService securityService = getSecurityService(); |
|
| 759 | + final WildcardPermission deletePermission = SecuredSecurityTypes.LOCKED_IP |
|
| 760 | + .getPermissionForObject(DefaultActions.DELETE, new IPAddress(ip)); |
|
| 761 | + // throws exception if not permitted |
|
| 762 | + SecurityUtils.getSubject().checkPermission(deletePermission.toString()); |
|
| 763 | + securityService.releaseBearerTokenLockOnIp(ip); |
|
| 764 | + } |
|
| 712 | 765 | } |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/shared/IpToTimedLockDTO.java
| ... | ... | @@ -0,0 +1,28 @@ |
| 1 | +package com.sap.sse.security.ui.shared; |
|
| 2 | + |
|
| 3 | +import com.sap.sse.common.TimedLock; |
|
| 4 | +import com.sap.sse.common.Named; |
|
| 5 | + |
|
| 6 | +public class IpToTimedLockDTO implements Named { |
|
| 7 | + private static final long serialVersionUID = 7877190394556881643L; |
|
| 8 | + private final String ip; |
|
| 9 | + private final TimedLock timedLock; |
|
| 10 | + |
|
| 11 | + public IpToTimedLockDTO(final String ip, final TimedLock timedLock) { |
|
| 12 | + this.ip = ip; |
|
| 13 | + this.timedLock = timedLock; |
|
| 14 | + } |
|
| 15 | + |
|
| 16 | + @Override |
|
| 17 | + public String getName() { |
|
| 18 | + return "IpToTimedLockDTO"; |
|
| 19 | + } |
|
| 20 | + |
|
| 21 | + public String getIp() { |
|
| 22 | + return ip; |
|
| 23 | + } |
|
| 24 | + |
|
| 25 | + public TimedLock getTimedLock() { |
|
| 26 | + return timedLock; |
|
| 27 | + } |
|
| 28 | +} |
java/com.sap.sse.security.ui/src/main/java/com/sap/sse/security/ui/shared/SuccessInfo.java
| ... | ... | @@ -15,6 +15,7 @@ public class SuccessInfo implements IsSerializable { |
| 15 | 15 | private String message; |
| 16 | 16 | private Triple<UserDTO, UserDTO, ServerInfoDTO> userDTO; |
| 17 | 17 | private String redirectURL; |
| 18 | + private String extra; |
|
| 18 | 19 | |
| 19 | 20 | SuccessInfo() {} // for serializtion only |
| 20 | 21 | |
| ... | ... | @@ -25,6 +26,15 @@ public class SuccessInfo implements IsSerializable { |
| 25 | 26 | this.redirectURL = redirectURL; |
| 26 | 27 | this.userDTO = userDTO; |
| 27 | 28 | } |
| 29 | + |
|
| 30 | + public SuccessInfo(boolean successful, String message, String redirectURL, Triple<UserDTO, UserDTO, ServerInfoDTO> userDTO, String extra) { |
|
| 31 | + super(); |
|
| 32 | + this.successful = successful; |
|
| 33 | + this.message = message; |
|
| 34 | + this.redirectURL = redirectURL; |
|
| 35 | + this.userDTO = userDTO; |
|
| 36 | + this.extra = extra; |
|
| 37 | + } |
|
| 28 | 38 | |
| 29 | 39 | public boolean isSuccessful() { |
| 30 | 40 | return successful; |
| ... | ... | @@ -37,9 +47,12 @@ public class SuccessInfo implements IsSerializable { |
| 37 | 47 | public Triple<UserDTO, UserDTO, ServerInfoDTO> getUserDTO() { |
| 38 | 48 | return userDTO; |
| 39 | 49 | } |
| 40 | - |
|
| 50 | + |
|
| 41 | 51 | public String getRedirectURL() { |
| 42 | 52 | return redirectURL; |
| 43 | 53 | } |
| 44 | - |
|
| 54 | + |
|
| 55 | + public String getExtra() { |
|
| 56 | + return extra; |
|
| 57 | + } |
|
| 45 | 58 | } |
java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/SSESecuritySerializers.gwt.xml
| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| 2 | 2 | <!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.7.0//EN" "http://gwtproject.org/doctype/2.7.0/gwt-module.dtd"> |
| 3 | 3 | <module> |
| 4 | + <inherits name="com.sap.sse.SSECommon" /> |
|
| 4 | 5 | <source path='shared'/> |
| 5 | 6 | </module> |
java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/Login.gwt.xml
| ... | ... | @@ -7,6 +7,8 @@ |
| 7 | 7 | <inherits name="com.sap.sse.security.ui.SecurityLocalesAllPermutations" /> |
| 8 | 8 | <inherits name="com.sap.sse.security.ui.LoginPanel"/> |
| 9 | 9 | <inherits name="com.sap.sse.landscape.aws.common.SSELandscapeAWSCommon" /> |
| 10 | + <inherits name="com.sap.sse.gwt.SSESharedGWT" /> |
|
| 11 | + <inherits name="com.sap.sse.branding.SSEBranding" /> |
|
| 10 | 12 | |
| 11 | 13 | <!-- Specify the app entry point class. --> |
| 12 | 14 | <entry-point class='com.sap.sse.security.ui.login.LoginEntryPoint'/> |
java/com.sap.sse.security.ui/src/main/resources/com/sap/sse/security/ui/Register.gwt.xml
| ... | ... | @@ -11,6 +11,8 @@ |
| 11 | 11 | <inherits name="com.sap.sse.Security" /> |
| 12 | 12 | <inherits name="com.sap.sse.security.ui.SecurityLocalesAllPermutations" /> |
| 13 | 13 | <inherits name="com.sap.sse.security.SSESecuritySerializers" /> |
| 14 | + <inherits name="com.sap.sse.gwt.SSESharedGWT" /> |
|
| 15 | + <inherits name="com.sap.sse.branding.SSEBranding" /> |
|
| 14 | 16 | <inherits name="com.sap.sse.landscape.aws.common.SSELandscapeAWSCommon" /> |
| 15 | 17 | |
| 16 | 18 | <super-source path="jre" /> |
java/com.sap.sse.security.ui/src/main/resources/shiro.ini
| ... | ... | @@ -24,7 +24,7 @@ securityManager.sessionManager.sessionDAO = $sessionDAO |
| 24 | 24 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 25 | 25 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 26 | 26 | securityManager.cacheManager = $cacheManager |
| 27 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 27 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 28 | 28 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 29 | 29 | |
| 30 | 30 | subjectDAO = com.sap.sse.security.NoSessionStorageForUnauthenticatedSessionsSessionDAO |
java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java
| ... | ... | @@ -14,6 +14,7 @@ import java.util.concurrent.ConcurrentHashMap; |
| 14 | 14 | import java.util.logging.Level; |
| 15 | 15 | import java.util.logging.Logger; |
| 16 | 16 | |
| 17 | +import com.sap.sse.common.TimedLock; |
|
| 17 | 18 | import com.sap.sse.common.Util; |
| 18 | 19 | import com.sap.sse.common.Util.Pair; |
| 19 | 20 | import com.sap.sse.concurrent.LockUtil; |
| ... | ... | @@ -34,7 +35,6 @@ import com.sap.sse.security.shared.UserManagementException; |
| 34 | 35 | import com.sap.sse.security.shared.UserRole; |
| 35 | 36 | import com.sap.sse.security.shared.UserStoreManagementException; |
| 36 | 37 | import com.sap.sse.security.shared.WildcardPermission; |
| 37 | -import com.sap.sse.security.shared.impl.LockingAndBanning; |
|
| 38 | 38 | import com.sap.sse.security.shared.impl.Ownership; |
| 39 | 39 | import com.sap.sse.security.shared.impl.Role; |
| 40 | 40 | import com.sap.sse.security.shared.impl.User; |
| ... | ... | @@ -854,12 +854,12 @@ public class UserStoreImpl implements UserStore { |
| 854 | 854 | } |
| 855 | 855 | |
| 856 | 856 | @Override |
| 857 | - public User createUser(String name, String email, LockingAndBanning lockingAndBanning, Account... accounts) |
|
| 857 | + public User createUser(String name, String email, TimedLock timedLock, Account... accounts) |
|
| 858 | 858 | throws UserManagementException { |
| 859 | 859 | return LockUtil.executeWithWriteLockAndResultExpectException(usersLock, () -> { |
| 860 | 860 | checkUsernameUniqueness(name); |
| 861 | 861 | final Map<String, UserGroup> tenantsForServer = new ConcurrentHashMap<>(); |
| 862 | - final User user = new UserImpl(name, email, tenantsForServer, /* user group provider */ this, lockingAndBanning, accounts); |
|
| 862 | + final User user = new UserImpl(name, email, tenantsForServer, /* user group provider */ this, timedLock, accounts); |
|
| 863 | 863 | logger.info("Creating user: " + user + " with e-mail " + email); |
| 864 | 864 | addAndStoreUserInternal(user); |
| 865 | 865 | return user; |
java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/DomainObjectFactoryImpl.java
| ... | ... | @@ -20,7 +20,9 @@ import com.mongodb.client.MongoCollection; |
| 20 | 20 | import com.mongodb.client.MongoDatabase; |
| 21 | 21 | import com.sap.sse.common.Duration; |
| 22 | 22 | import com.sap.sse.common.TimePoint; |
| 23 | +import com.sap.sse.common.TimedLock; |
|
| 23 | 24 | import com.sap.sse.common.Util; |
| 25 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 24 | 26 | import com.sap.sse.security.interfaces.Social; |
| 25 | 27 | import com.sap.sse.security.interfaces.UserImpl; |
| 26 | 28 | import com.sap.sse.security.interfaces.UserStore; |
| ... | ... | @@ -37,8 +39,6 @@ import com.sap.sse.security.shared.UserManagementException; |
| 37 | 39 | import com.sap.sse.security.shared.UsernamePasswordAccount; |
| 38 | 40 | import com.sap.sse.security.shared.WildcardPermission; |
| 39 | 41 | import com.sap.sse.security.shared.impl.AccessControlList; |
| 40 | -import com.sap.sse.security.shared.impl.LockingAndBanning; |
|
| 41 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 42 | 42 | import com.sap.sse.security.shared.impl.Ownership; |
| 43 | 43 | import com.sap.sse.security.shared.impl.QualifiedObjectIdentifierImpl; |
| 44 | 44 | import com.sap.sse.security.shared.impl.Role; |
| ... | ... | @@ -289,9 +289,9 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { |
| 289 | 289 | final String validationSecret = (String) userDBObject.get(FieldNames.User.VALIDATION_SECRET.name()); |
| 290 | 290 | final Long lockedUntilMillis = userDBObject.getLong(FieldNames.User.LOCKED_UNTIL_MILLIS.name()); |
| 291 | 291 | final Long nextLockingDurationMillis = userDBObject.getLong(FieldNames.User.NEXT_LOCKING_DURATION_MILLIS.name()); |
| 292 | - final LockingAndBanning lockingAndBanning = new LockingAndBanningImpl( |
|
| 292 | + final TimedLock timedLock = new TimedLockImpl( |
|
| 293 | 293 | lockedUntilMillis == null ? TimePoint.BeginningOfTime : TimePoint.of(lockedUntilMillis), |
| 294 | - nextLockingDurationMillis == null ? LockingAndBanningImpl.DEFAULT_INITIAL_LOCKING_DELAY : Duration.ofMillis(nextLockingDurationMillis)); |
|
| 294 | + nextLockingDurationMillis == null ? TimedLockImpl.DEFAULT_INITIAL_LOCKING_DELAY : Duration.ofMillis(nextLockingDurationMillis)); |
|
| 295 | 295 | final Set<Role> roles = new HashSet<>(); |
| 296 | 296 | final Set<String> permissions = new HashSet<>(); |
| 297 | 297 | final List<?> rolesO = (List<?>) userDBObject.get(FieldNames.User.ROLE_IDS.name()); |
| ... | ... | @@ -358,7 +358,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory { |
| 358 | 358 | Map<AccountType, Account> accounts = createAccountMapFromdDBObject(accountsMap); |
| 359 | 359 | User result = new UserImpl(username, email, fullName, company, locale, |
| 360 | 360 | emailValidated == null ? false : emailValidated, passwordResetSecret, validationSecret, defaultTenant, |
| 361 | - accounts.values(), userGroupProvider, lockingAndBanning); |
|
| 361 | + accounts.values(), userGroupProvider, timedLock); |
|
| 362 | 362 | for (final Role role : roles) { |
| 363 | 363 | result.addRole(role); |
| 364 | 364 | } |
java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/MongoObjectFactoryImpl.java
| ... | ... | @@ -16,6 +16,7 @@ import com.mongodb.client.MongoCollection; |
| 16 | 16 | import com.mongodb.client.MongoDatabase; |
| 17 | 17 | import com.mongodb.client.model.IndexOptions; |
| 18 | 18 | import com.mongodb.client.model.ReplaceOptions; |
| 19 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 19 | 20 | import com.sap.sse.security.interfaces.Social; |
| 20 | 21 | import com.sap.sse.security.shared.AccessControlListAnnotation; |
| 21 | 22 | import com.sap.sse.security.shared.Account; |
| ... | ... | @@ -27,7 +28,6 @@ import com.sap.sse.security.shared.SocialUserAccount; |
| 27 | 28 | import com.sap.sse.security.shared.UsernamePasswordAccount; |
| 28 | 29 | import com.sap.sse.security.shared.WildcardPermission; |
| 29 | 30 | import com.sap.sse.security.shared.impl.AccessControlList; |
| 30 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 31 | 31 | import com.sap.sse.security.shared.impl.Ownership; |
| 32 | 32 | import com.sap.sse.security.shared.impl.Role; |
| 33 | 33 | import com.sap.sse.security.shared.impl.User; |
| ... | ... | @@ -216,13 +216,13 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory { |
| 216 | 216 | dbUser.put(FieldNames.User.PASSWORD_RESET_SECRET.name(), user.getPasswordResetSecret()); |
| 217 | 217 | dbUser.put(FieldNames.User.VALIDATION_SECRET.name(), user.getValidationSecret()); |
| 218 | 218 | dbUser.put(FieldNames.User.ACCOUNTS.name(), createAccountMapObject(user.getAllAccounts())); |
| 219 | - if (user.getLockingAndBanning() instanceof LockingAndBanningImpl) { |
|
| 220 | - final LockingAndBanningImpl lockingAndBanning = ((LockingAndBanningImpl) user.getLockingAndBanning()); |
|
| 221 | - dbUser.put(FieldNames.User.LOCKED_UNTIL_MILLIS.name(), lockingAndBanning.getLockedUntil().asMillis()); |
|
| 222 | - dbUser.put(FieldNames.User.NEXT_LOCKING_DURATION_MILLIS.name(), lockingAndBanning.getNextLockingDelay().asMillis()); |
|
| 219 | + if (user.getTimedLock() instanceof TimedLockImpl) { |
|
| 220 | + final TimedLockImpl timedLock = ((TimedLockImpl) user.getTimedLock()); |
|
| 221 | + dbUser.put(FieldNames.User.LOCKED_UNTIL_MILLIS.name(), timedLock.getLockedUntil().asMillis()); |
|
| 222 | + dbUser.put(FieldNames.User.NEXT_LOCKING_DURATION_MILLIS.name(), timedLock.getNextLockingDelay().asMillis()); |
|
| 223 | 223 | } else { |
| 224 | - logger.warning("Expected user locking/banning to be of type "+LockingAndBanningImpl.class.getSimpleName() |
|
| 225 | - +" but was of type "+user.getLockingAndBanning().getClass().getSimpleName()+"; not storing to DB"); |
|
| 224 | + logger.warning("Expected user locking/banning to be of type "+TimedLockImpl.class.getSimpleName() |
|
| 225 | + +" but was of type "+user.getTimedLock().getClass().getSimpleName()+"; not storing to DB"); |
|
| 226 | 226 | } |
| 227 | 227 | BasicDBList dbRoles = new BasicDBList(); |
| 228 | 228 | for (Role role : user.getRoles()) { |
java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/impl/UserProxy.java
| ... | ... | @@ -4,13 +4,13 @@ import java.io.Serializable; |
| 4 | 4 | import java.util.Locale; |
| 5 | 5 | import java.util.Map; |
| 6 | 6 | |
| 7 | +import com.sap.sse.common.TimedLock; |
|
| 7 | 8 | import com.sap.sse.security.shared.Account; |
| 8 | 9 | import com.sap.sse.security.shared.Account.AccountType; |
| 9 | 10 | import com.sap.sse.security.shared.HasPermissions; |
| 10 | 11 | import com.sap.sse.security.shared.QualifiedObjectIdentifier; |
| 11 | 12 | import com.sap.sse.security.shared.UserGroupProvider; |
| 12 | 13 | import com.sap.sse.security.shared.WildcardPermission; |
| 13 | -import com.sap.sse.security.shared.impl.LockingAndBanning; |
|
| 14 | 14 | import com.sap.sse.security.shared.impl.Role; |
| 15 | 15 | import com.sap.sse.security.shared.impl.User; |
| 16 | 16 | import com.sap.sse.security.shared.impl.UserGroup; |
| ... | ... | @@ -242,7 +242,7 @@ public class UserProxy implements User { |
| 242 | 242 | } |
| 243 | 243 | |
| 244 | 244 | @Override |
| 245 | - public LockingAndBanning getLockingAndBanning() { |
|
| 245 | + public TimedLock getTimedLock() { |
|
| 246 | 246 | throw new UnsupportedOperationException(); |
| 247 | 247 | } |
| 248 | 248 | } |
java/com.sap.sse.security/resources/shiro.ini
| ... | ... | @@ -26,7 +26,7 @@ securityManager.subjectDAO = $subjectDAO |
| 26 | 26 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 27 | 27 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 28 | 28 | securityManager.cacheManager = $cacheManager |
| 29 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 29 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 30 | 30 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 31 | 31 | |
| 32 | 32 | # Support for anonymous user permissions |
java/com.sap.sse.security/src/com/sap/sse/security/AtLeastOneSuccessfulStrategyWithLockingAndBanning.java
| ... | ... | @@ -1,103 +0,0 @@ |
| 1 | -package com.sap.sse.security; |
|
| 2 | - |
|
| 3 | -import java.util.concurrent.ExecutionException; |
|
| 4 | -import java.util.concurrent.Future; |
|
| 5 | -import java.util.logging.Level; |
|
| 6 | -import java.util.logging.Logger; |
|
| 7 | - |
|
| 8 | -import org.apache.shiro.authc.AuthenticationException; |
|
| 9 | -import org.apache.shiro.authc.AuthenticationInfo; |
|
| 10 | -import org.apache.shiro.authc.AuthenticationToken; |
|
| 11 | -import org.apache.shiro.authc.IncorrectCredentialsException; |
|
| 12 | -import org.apache.shiro.authc.LockedAccountException; |
|
| 13 | -import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy; |
|
| 14 | -import org.apache.shiro.realm.Realm; |
|
| 15 | - |
|
| 16 | -import com.sap.sse.security.impl.Activator; |
|
| 17 | -import com.sap.sse.security.shared.impl.LockingAndBanning; |
|
| 18 | -import com.sap.sse.security.shared.impl.User; |
|
| 19 | -import com.sap.sse.util.ServiceTrackerFactory; |
|
| 20 | - |
|
| 21 | -public class AtLeastOneSuccessfulStrategyWithLockingAndBanning extends AtLeastOneSuccessfulStrategy { |
|
| 22 | - private static final Logger logger = Logger.getLogger(AtLeastOneSuccessfulStrategyWithLockingAndBanning.class.getName()); |
|
| 23 | - |
|
| 24 | - private final Future<SecurityService> securityService; |
|
| 25 | - |
|
| 26 | - public AtLeastOneSuccessfulStrategyWithLockingAndBanning() { |
|
| 27 | - if (Activator.getContext() != null) { |
|
| 28 | - securityService = ServiceTrackerFactory.createServiceFuture(Activator.getContext(), SecurityService.class); |
|
| 29 | - } else { |
|
| 30 | - securityService = null; |
|
| 31 | - } |
|
| 32 | - } |
|
| 33 | - |
|
| 34 | - private SecurityService getSecurityService() { |
|
| 35 | - SecurityService result; |
|
| 36 | - try { |
|
| 37 | - result = securityService == null ? null : securityService.get(); |
|
| 38 | - } catch (InterruptedException | ExecutionException e) { |
|
| 39 | - logger.log(Level.SEVERE, "Error retrieving security service", e); |
|
| 40 | - result = null; |
|
| 41 | - } |
|
| 42 | - return result; |
|
| 43 | - } |
|
| 44 | - |
|
| 45 | - @Override |
|
| 46 | - public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, |
|
| 47 | - AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException { |
|
| 48 | - if (token != null && token.getPrincipal() != null && realm instanceof UsernamePasswordRealm) { |
|
| 49 | - final UsernamePasswordRealm upRealm = (UsernamePasswordRealm) realm; |
|
| 50 | - final String username = token.getPrincipal().toString(); |
|
| 51 | - final User user = upRealm.getUserStore().getUserByName(username); |
|
| 52 | - if (user != null) { |
|
| 53 | - if (t != null) { |
|
| 54 | - if (t instanceof IncorrectCredentialsException) { |
|
| 55 | - logger.info("failed password authentication for user "+username); |
|
| 56 | - final SecurityService mySecurityService = getSecurityService(); |
|
| 57 | - if (mySecurityService != null) { |
|
| 58 | - final LockingAndBanning lockingAndBanning = mySecurityService.failedPasswordAuthentication(user); |
|
| 59 | - if (lockingAndBanning != null) { |
|
| 60 | - logger.info("User "+username+" locked for password authentication: "+lockingAndBanning); |
|
| 61 | - } |
|
| 62 | - } else { |
|
| 63 | - logger.warning("Account locking due to failed password authentication for user "+username+" not possible; security service not found"); |
|
| 64 | - } |
|
| 65 | - } |
|
| 66 | - } else { |
|
| 67 | - // no exception, so the authentication must have been successful |
|
| 68 | - final SecurityService mySecurityService = getSecurityService(); |
|
| 69 | - if (mySecurityService != null) { |
|
| 70 | - mySecurityService.successfulPasswordAuthentication(user); |
|
| 71 | - } |
|
| 72 | - } |
|
| 73 | - } |
|
| 74 | - } else if (token != null && realm instanceof BearerTokenRealm) { |
|
| 75 | - final BearerAuthenticationToken bearerToken = (BearerAuthenticationToken) token; |
|
| 76 | - if (singleRealmInfo == null || singleRealmInfo.getPrincipals().isEmpty()) { |
|
| 77 | - if (t != null && t instanceof LockedAccountException) { |
|
| 78 | - logger.fine(()->"Bearer token authentication from client IP "+bearerToken.getClientIP()+" with user agent "+bearerToken.getUserAgent()+" currently locked"); |
|
| 79 | - } else { |
|
| 80 | - // authentication failed |
|
| 81 | - logger.info("failed bearer token authentication for client IP "+bearerToken.getClientIP()+" with user agent "+bearerToken.getUserAgent()); |
|
| 82 | - final SecurityService mySecurityService = getSecurityService(); |
|
| 83 | - if (mySecurityService != null) { |
|
| 84 | - final LockingAndBanning lockingAndBanning = mySecurityService.failedBearerTokenAuthentication(bearerToken.getClientIP()); |
|
| 85 | - if (lockingAndBanning != null) { |
|
| 86 | - logger.info("Client IP "+bearerToken.getClientIP()+" locked for bearer token authentication: "+lockingAndBanning); |
|
| 87 | - } |
|
| 88 | - } else { |
|
| 89 | - logger.warning("Client IP locking due to failed bearer token authentication for client IP " |
|
| 90 | - +bearerToken.getClientIP()+" with user agent "+bearerToken.getUserAgent() |
|
| 91 | - +" not possible; security service not found"); |
|
| 92 | - } |
|
| 93 | - } |
|
| 94 | - } else { // valid authentication info means authentication was successful |
|
| 95 | - final SecurityService mySecurityService = getSecurityService(); |
|
| 96 | - if (mySecurityService != null) { |
|
| 97 | - mySecurityService.successfulBearerTokenAuthentication(bearerToken.getClientIP()); |
|
| 98 | - } |
|
| 99 | - } |
|
| 100 | - } |
|
| 101 | - return super.afterAttempt(realm, token, singleRealmInfo, aggregateInfo, t); |
|
| 102 | - } |
|
| 103 | -} |
java/com.sap.sse.security/src/com/sap/sse/security/AtLeastOneSuccessfulStrategyWithTimedLocks.java
| ... | ... | @@ -0,0 +1,103 @@ |
| 1 | +package com.sap.sse.security; |
|
| 2 | + |
|
| 3 | +import java.util.concurrent.ExecutionException; |
|
| 4 | +import java.util.concurrent.Future; |
|
| 5 | +import java.util.logging.Level; |
|
| 6 | +import java.util.logging.Logger; |
|
| 7 | + |
|
| 8 | +import org.apache.shiro.authc.AuthenticationException; |
|
| 9 | +import org.apache.shiro.authc.AuthenticationInfo; |
|
| 10 | +import org.apache.shiro.authc.AuthenticationToken; |
|
| 11 | +import org.apache.shiro.authc.IncorrectCredentialsException; |
|
| 12 | +import org.apache.shiro.authc.LockedAccountException; |
|
| 13 | +import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy; |
|
| 14 | +import org.apache.shiro.realm.Realm; |
|
| 15 | + |
|
| 16 | +import com.sap.sse.common.TimedLock; |
|
| 17 | +import com.sap.sse.security.impl.Activator; |
|
| 18 | +import com.sap.sse.security.shared.impl.User; |
|
| 19 | +import com.sap.sse.util.ServiceTrackerFactory; |
|
| 20 | + |
|
| 21 | +public class AtLeastOneSuccessfulStrategyWithTimedLocks extends AtLeastOneSuccessfulStrategy { |
|
| 22 | + private static final Logger logger = Logger.getLogger(AtLeastOneSuccessfulStrategyWithTimedLocks.class.getName()); |
|
| 23 | + |
|
| 24 | + private final Future<SecurityService> securityService; |
|
| 25 | + |
|
| 26 | + public AtLeastOneSuccessfulStrategyWithTimedLocks() { |
|
| 27 | + if (Activator.getContext() != null) { |
|
| 28 | + securityService = ServiceTrackerFactory.createServiceFuture(Activator.getContext(), SecurityService.class); |
|
| 29 | + } else { |
|
| 30 | + securityService = null; |
|
| 31 | + } |
|
| 32 | + } |
|
| 33 | + |
|
| 34 | + private SecurityService getSecurityService() { |
|
| 35 | + SecurityService result; |
|
| 36 | + try { |
|
| 37 | + result = securityService == null ? null : securityService.get(); |
|
| 38 | + } catch (InterruptedException | ExecutionException e) { |
|
| 39 | + logger.log(Level.SEVERE, "Error retrieving security service", e); |
|
| 40 | + result = null; |
|
| 41 | + } |
|
| 42 | + return result; |
|
| 43 | + } |
|
| 44 | + |
|
| 45 | + @Override |
|
| 46 | + public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo, |
|
| 47 | + AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException { |
|
| 48 | + if (token != null && token.getPrincipal() != null && realm instanceof UsernamePasswordRealm) { |
|
| 49 | + final UsernamePasswordRealm upRealm = (UsernamePasswordRealm) realm; |
|
| 50 | + final String username = token.getPrincipal().toString(); |
|
| 51 | + final User user = upRealm.getUserStore().getUserByName(username); |
|
| 52 | + if (user != null) { |
|
| 53 | + if (t != null) { |
|
| 54 | + if (t instanceof IncorrectCredentialsException) { |
|
| 55 | + logger.info("failed password authentication for user "+username); |
|
| 56 | + final SecurityService mySecurityService = getSecurityService(); |
|
| 57 | + if (mySecurityService != null) { |
|
| 58 | + final TimedLock timedLock = mySecurityService.failedPasswordAuthentication(user); |
|
| 59 | + if (timedLock != null) { |
|
| 60 | + logger.info("User "+username+" locked for password authentication: "+timedLock); |
|
| 61 | + } |
|
| 62 | + } else { |
|
| 63 | + logger.warning("Account locking due to failed password authentication for user "+username+" not possible; security service not found"); |
|
| 64 | + } |
|
| 65 | + } |
|
| 66 | + } else { |
|
| 67 | + // no exception, so the authentication must have been successful |
|
| 68 | + final SecurityService mySecurityService = getSecurityService(); |
|
| 69 | + if (mySecurityService != null) { |
|
| 70 | + mySecurityService.successfulPasswordAuthentication(user); |
|
| 71 | + } |
|
| 72 | + } |
|
| 73 | + } |
|
| 74 | + } else if (token != null && realm instanceof BearerTokenRealm) { |
|
| 75 | + final BearerAuthenticationToken bearerToken = (BearerAuthenticationToken) token; |
|
| 76 | + if (singleRealmInfo == null || singleRealmInfo.getPrincipals().isEmpty()) { |
|
| 77 | + if (t != null && t instanceof LockedAccountException) { |
|
| 78 | + logger.fine(()->"Bearer token authentication from client IP "+bearerToken.getClientIP()+" with user agent "+bearerToken.getUserAgent()+" currently locked"); |
|
| 79 | + } else { |
|
| 80 | + // authentication failed |
|
| 81 | + logger.info("failed bearer token authentication for client IP "+bearerToken.getClientIP()+" with user agent "+bearerToken.getUserAgent()); |
|
| 82 | + final SecurityService mySecurityService = getSecurityService(); |
|
| 83 | + if (mySecurityService != null) { |
|
| 84 | + final TimedLock timedLock = mySecurityService.failedBearerTokenAuthentication(bearerToken.getClientIP()); |
|
| 85 | + if (timedLock != null) { |
|
| 86 | + logger.info("Client IP "+bearerToken.getClientIP()+" locked for bearer token authentication: "+timedLock); |
|
| 87 | + } |
|
| 88 | + } else { |
|
| 89 | + logger.warning("Client IP locking due to failed bearer token authentication for client IP " |
|
| 90 | + +bearerToken.getClientIP()+" with user agent "+bearerToken.getUserAgent() |
|
| 91 | + +" not possible; security service not found"); |
|
| 92 | + } |
|
| 93 | + } |
|
| 94 | + } else { // valid authentication info means authentication was successful |
|
| 95 | + final SecurityService mySecurityService = getSecurityService(); |
|
| 96 | + if (mySecurityService != null) { |
|
| 97 | + mySecurityService.successfulBearerTokenAuthentication(bearerToken.getClientIP()); |
|
| 98 | + } |
|
| 99 | + } |
|
| 100 | + } |
|
| 101 | + return super.afterAttempt(realm, token, singleRealmInfo, aggregateInfo, t); |
|
| 102 | + } |
|
| 103 | +} |
java/com.sap.sse.security/src/com/sap/sse/security/OAuthRealm.java
| ... | ... | @@ -33,6 +33,7 @@ import org.scribe.model.Verb; |
| 33 | 33 | import org.scribe.model.Verifier; |
| 34 | 34 | import org.scribe.oauth.OAuthService; |
| 35 | 35 | |
| 36 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 36 | 37 | import com.sap.sse.security.interfaces.Credential; |
| 37 | 38 | import com.sap.sse.security.interfaces.OAuthToken; |
| 38 | 39 | import com.sap.sse.security.interfaces.Social; |
| ... | ... | @@ -40,7 +41,6 @@ import com.sap.sse.security.interfaces.SocialSettingsKeys; |
| 40 | 41 | import com.sap.sse.security.shared.SocialUserAccount; |
| 41 | 42 | import com.sap.sse.security.shared.UserGroupManagementException; |
| 42 | 43 | import com.sap.sse.security.shared.UserManagementException; |
| 43 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 44 | 44 | import com.sap.sse.security.shared.impl.User; |
| 45 | 45 | import com.sap.sse.security.shared.impl.UserGroup; |
| 46 | 46 | |
| ... | ... | @@ -189,7 +189,7 @@ public class OAuthRealm extends AbstractCompositeAuthorizingRealm { |
| 189 | 189 | try { |
| 190 | 190 | UserGroup tenant = getUserStore().createUserGroup(UUID.randomUUID(), socialname + SecurityService.TENANT_SUFFIX); |
| 191 | 191 | getAccessControlStore().setOwnership(tenant.getIdentifier(), user, tenant, tenant.getName()); |
| 192 | - user = getUserStore().createUser(socialname, socialUser.getProperty(Social.EMAIL.name()), new LockingAndBanningImpl(), socialUser); |
|
| 192 | + user = getUserStore().createUser(socialname, socialUser.getProperty(Social.EMAIL.name()), new TimedLockImpl(), socialUser); |
|
| 193 | 193 | tenant.add(user); |
| 194 | 194 | getUserStore().updateUserGroup(tenant); |
| 195 | 195 | } catch (UserManagementException | UserGroupManagementException e) { |
java/com.sap.sse.security/src/com/sap/sse/security/SecurityService.java
| ... | ... | @@ -2,6 +2,7 @@ package com.sap.sse.security; |
| 2 | 2 | |
| 3 | 3 | import java.io.Serializable; |
| 4 | 4 | import java.math.BigDecimal; |
| 5 | +import java.util.HashMap; |
|
| 5 | 6 | import java.util.List; |
| 6 | 7 | import java.util.Locale; |
| 7 | 8 | import java.util.Map; |
| ... | ... | @@ -22,6 +23,7 @@ import org.apache.shiro.subject.Subject; |
| 22 | 23 | import org.osgi.framework.BundleContext; |
| 23 | 24 | |
| 24 | 25 | import com.sap.sse.common.Duration; |
| 26 | +import com.sap.sse.common.TimedLock; |
|
| 25 | 27 | import com.sap.sse.common.Util; |
| 26 | 28 | import com.sap.sse.common.Util.Pair; |
| 27 | 29 | import com.sap.sse.common.http.HttpHeaderUtil; |
| ... | ... | @@ -53,7 +55,6 @@ import com.sap.sse.security.shared.UserManagementException; |
| 53 | 55 | import com.sap.sse.security.shared.WildcardPermission; |
| 54 | 56 | import com.sap.sse.security.shared.WithQualifiedObjectIdentifier; |
| 55 | 57 | import com.sap.sse.security.shared.impl.AccessControlList; |
| 56 | -import com.sap.sse.security.shared.impl.LockingAndBanning; |
|
| 57 | 58 | import com.sap.sse.security.shared.impl.Ownership; |
| 58 | 59 | import com.sap.sse.security.shared.impl.Role; |
| 59 | 60 | import com.sap.sse.security.shared.impl.SecuredSecurityTypes; |
| ... | ... | @@ -178,6 +179,16 @@ public interface SecurityService extends ReplicableWithObjectInputStream<Replica |
| 178 | 179 | |
| 179 | 180 | void deleteUserGroup(UserGroup userGroup) throws UserGroupManagementException; |
| 180 | 181 | |
| 182 | + /** |
|
| 183 | + * Releases the lock applied on IP due to user creation abuse. |
|
| 184 | + */ |
|
| 185 | + void releaseUserCreationLockOnIp(String ip); |
|
| 186 | + |
|
| 187 | + /** |
|
| 188 | + * Releases the lock applied on IP due to user creation abuse. |
|
| 189 | + */ |
|
| 190 | + void releaseBearerTokenLockOnIp(String ip); |
|
| 191 | + |
|
| 181 | 192 | Iterable<User> getUserList(); |
| 182 | 193 | |
| 183 | 194 | User getUserByName(String username); |
| ... | ... | @@ -221,6 +232,8 @@ public interface SecurityService extends ReplicableWithObjectInputStream<Replica |
| 221 | 232 | void updateSimpleUserEmail(String username, String newEmail, String validationBaseURL) throws UserManagementException; |
| 222 | 233 | |
| 223 | 234 | void updateUserProperties(String username, String fullName, String company, Locale locale) throws UserManagementException; |
| 235 | + |
|
| 236 | + void resetUserTimedLock(String username) throws UserManagementException; |
|
| 224 | 237 | |
| 225 | 238 | void deleteUser(String username) throws UserManagementException; |
| 226 | 239 | |
| ... | ... | @@ -873,7 +886,7 @@ public interface SecurityService extends ReplicableWithObjectInputStream<Replica |
| 873 | 886 | |
| 874 | 887 | Pair<Boolean, Set<String>> getCORSFilterConfiguration(String serverName); |
| 875 | 888 | |
| 876 | - LockingAndBanning failedPasswordAuthentication(User user); |
|
| 889 | + TimedLock failedPasswordAuthentication(User user); |
|
| 877 | 890 | |
| 878 | 891 | void successfulPasswordAuthentication(User user); |
| 879 | 892 | |
| ... | ... | @@ -890,7 +903,7 @@ public interface SecurityService extends ReplicableWithObjectInputStream<Replica |
| 890 | 903 | * {@code userAgent}, the locking record including its last locking duration is expunged from the internal data |
| 891 | 904 | * structures, avoiding garbage piling up. |
| 892 | 905 | */ |
| 893 | - LockingAndBanning failedBearerTokenAuthentication(String clientIP); |
|
| 906 | + TimedLock failedBearerTokenAuthentication(String clientIP); |
|
| 894 | 907 | |
| 895 | 908 | /** |
| 896 | 909 | * Call this when the combination of {@code clientIP} and {@code userAgent} was not |
| ... | ... | @@ -905,12 +918,15 @@ public interface SecurityService extends ReplicableWithObjectInputStream<Replica |
| 905 | 918 | * Used in conjunction with {@link #failedBearerTokenAuthentication(String)} and |
| 906 | 919 | * {@link #successfulBearerTokenAuthentication(String)}. If and only if a locking state for the combination |
| 907 | 920 | * of {@code clientIP} and {@code userAgent} is known and still locked, {@code true} is returned. Unlocking |
| 908 | - * will bappen by calling {@link #successfulBearerTokenAuthentication(String)} with an equal combination |
|
| 909 | - * of {@code clientIP} and {@code userAgent}. Invoking {@link #failedBearerTokenAuthentication(String)} |
|
| 910 | - * will establish (if not yet locked) or extend the locking duration for the combination. |
|
| 921 | + * will happen by calling {@link #successfulBearerTokenAuthentication(String)} with an equal combination of |
|
| 922 | + * {@code clientIP} and {@code userAgent} or by calling {@link releaseBearerTokenLockOnIp(String)}. Invoking |
|
| 923 | + * {@link #failedBearerTokenAuthentication(String)} will establish (if not yet locked) or extend the locking |
|
| 924 | + * duration for the combination. |
|
| 911 | 925 | */ |
| 912 | 926 | boolean isClientIPLockedForBearerTokenAuthentication(String clientIP); |
| 913 | 927 | |
| 928 | + boolean isUserCreationLockedForClientIP(String clientIP); |
|
| 929 | + |
|
| 914 | 930 | void fileTakedownNotice(TakedownNoticeRequestContext takedownNoticeRequestContext) throws MailException; |
| 915 | 931 | |
| 916 | 932 | /** |
| ... | ... | @@ -928,4 +944,8 @@ public interface SecurityService extends ReplicableWithObjectInputStream<Replica |
| 928 | 944 | */ |
| 929 | 945 | Iterable<User> getUsersToInformAboutReplicaSet(String serverName, |
| 930 | 946 | Optional<com.sap.sse.security.shared.HasPermissions.Action> alsoSendToAllUsersWithThisPermissionOnReplicaSet); |
| 947 | + |
|
| 948 | + HashMap<String, TimedLock> getClientIPBasedTimedLocksForUserCreation(); |
|
| 949 | + |
|
| 950 | + HashMap<String, TimedLock> getClientIPBasedTimedLocksForBearerTokenAbuse(); |
|
| 931 | 951 | } |
java/com.sap.sse.security/src/com/sap/sse/security/UsernamePasswordRealm.java
| ... | ... | @@ -50,8 +50,8 @@ public class UsernamePasswordRealm extends AbstractCompositeAuthorizingRealm { |
| 50 | 50 | logger.warning("Rejecting authentication attempt for non-existing user "+username); |
| 51 | 51 | return null; |
| 52 | 52 | } |
| 53 | - if (user.getLockingAndBanning().isAuthenticationLocked()) { |
|
| 54 | - logger.warning("Rejected attempt to authenticate user "+username+" because it is locked: "+user.getLockingAndBanning()); |
|
| 53 | + if (user.getTimedLock().isLocked()) { |
|
| 54 | + logger.warning("Rejected attempt to authenticate user "+username+" because it is locked: "+user.getTimedLock()); |
|
| 55 | 55 | throw new LockedAccountException("Password authentication for user "+username+" is currently locked"); |
| 56 | 56 | } |
| 57 | 57 | final UsernamePasswordAccount upa = (UsernamePasswordAccount) user.getAccount(AccountType.USERNAME_PASSWORD); |
java/com.sap.sse.security/src/com/sap/sse/security/impl/ReplicableSecurityService.java
| ... | ... | @@ -8,6 +8,7 @@ import java.util.UUID; |
| 8 | 8 | |
| 9 | 9 | import org.apache.shiro.session.Session; |
| 10 | 10 | |
| 11 | +import com.sap.sse.common.TimedLock; |
|
| 11 | 12 | import com.sap.sse.security.SecurityService; |
| 12 | 13 | import com.sap.sse.security.shared.Account; |
| 13 | 14 | import com.sap.sse.security.shared.QualifiedObjectIdentifier; |
| ... | ... | @@ -15,7 +16,6 @@ import com.sap.sse.security.shared.RoleDefinition; |
| 15 | 16 | import com.sap.sse.security.shared.UserGroupManagementException; |
| 16 | 17 | import com.sap.sse.security.shared.UserManagementException; |
| 17 | 18 | import com.sap.sse.security.shared.WildcardPermission; |
| 18 | -import com.sap.sse.security.shared.impl.LockingAndBanning; |
|
| 19 | 19 | import com.sap.sse.security.shared.impl.Ownership; |
| 20 | 20 | import com.sap.sse.security.shared.impl.User; |
| 21 | 21 | import com.sap.sse.security.shared.subscription.Subscription; |
| ... | ... | @@ -69,6 +69,8 @@ public interface ReplicableSecurityService extends SecurityService { |
| 69 | 69 | |
| 70 | 70 | Void internalUpdateUserProperties(String username, String fullName, String company, Locale locale); |
| 71 | 71 | |
| 72 | + Void internalResetUserTimedLock(String username); |
|
| 73 | + |
|
| 72 | 74 | Boolean internalValidateEmail(String username, String validationSecret); |
| 73 | 75 | |
| 74 | 76 | Void internalSetPreference(String username, String key, String value); |
| ... | ... | @@ -122,13 +124,17 @@ public interface ReplicableSecurityService extends SecurityService { |
| 122 | 124 | |
| 123 | 125 | Void internalSetCORSFilterConfigurationAllowedOrigins(String serverName, String... allowedOrigins); |
| 124 | 126 | |
| 125 | - LockingAndBanning internalFailedPasswordAuthentication(String username); |
|
| 127 | + TimedLock internalFailedPasswordAuthentication(String username); |
|
| 126 | 128 | |
| 127 | 129 | Boolean internalSuccessfulPasswordAuthentication(String username); |
| 128 | 130 | |
| 129 | 131 | Boolean internalSuccessfulBearerTokenAuthentication(String clientIP); |
| 130 | 132 | |
| 131 | - LockingAndBanning internalFailedBearerTokenAuthentication(String clientIP); |
|
| 133 | + TimedLock internalFailedBearerTokenAuthentication(String clientIP); |
|
| 134 | + |
|
| 135 | + TimedLock internalRecordUserCreationFromClientIP(String clientIP); |
|
| 136 | + |
|
| 137 | + void internalReleaseUserCreationLockOnIp(String ip); |
|
| 132 | 138 | |
| 133 | - LockingAndBanning internalRecordUserCreationFromClientIP(String clientIP); |
|
| 139 | + void internalReleaseBearerTokenLockOnIp(String ip); |
|
| 134 | 140 | } |
java/com.sap.sse.security/src/com/sap/sse/security/impl/SecurityServiceImpl.java
| ... | ... | @@ -95,9 +95,11 @@ import com.sap.sse.ServerInfo; |
| 95 | 95 | import com.sap.sse.branding.BrandingConfigurationService; |
| 96 | 96 | import com.sap.sse.common.Duration; |
| 97 | 97 | import com.sap.sse.common.TimePoint; |
| 98 | +import com.sap.sse.common.TimedLock; |
|
| 98 | 99 | import com.sap.sse.common.Util; |
| 99 | 100 | import com.sap.sse.common.Util.Pair; |
| 100 | 101 | import com.sap.sse.common.http.HttpHeaderUtil; |
| 102 | +import com.sap.sse.common.impl.TimedLockImpl; |
|
| 101 | 103 | import com.sap.sse.common.mail.MailException; |
| 102 | 104 | import com.sap.sse.common.media.TakedownNoticeRequestContext; |
| 103 | 105 | import com.sap.sse.concurrent.LockUtil; |
| ... | ... | @@ -140,12 +142,15 @@ import com.sap.sse.security.operations.DeleteRoleDefinitionOperation; |
| 140 | 142 | import com.sap.sse.security.operations.DeleteUserGroupOperation; |
| 141 | 143 | import com.sap.sse.security.operations.DeleteUserOperation; |
| 142 | 144 | import com.sap.sse.security.operations.PutRoleDefinitionToUserGroupOperation; |
| 145 | +import com.sap.sse.security.operations.ReleaseBearerTokenLockOnIpOperation; |
|
| 146 | +import com.sap.sse.security.operations.ReleaseUserCreationLockOnIpOperation; |
|
| 143 | 147 | import com.sap.sse.security.operations.RemoveAccessTokenOperation; |
| 144 | 148 | import com.sap.sse.security.operations.RemovePermissionForUserOperation; |
| 145 | 149 | import com.sap.sse.security.operations.RemoveRoleDefinitionFromUserGroupOperation; |
| 146 | 150 | import com.sap.sse.security.operations.RemoveRoleFromUserOperation; |
| 147 | 151 | import com.sap.sse.security.operations.RemoveUserFromUserGroupOperation; |
| 148 | 152 | import com.sap.sse.security.operations.ResetPasswordOperation; |
| 153 | +import com.sap.sse.security.operations.ResetUserLockOperation; |
|
| 149 | 154 | import com.sap.sse.security.operations.SecurityOperation; |
| 150 | 155 | import com.sap.sse.security.operations.SetAccessTokenOperation; |
| 151 | 156 | import com.sap.sse.security.operations.SetDefaultTenantForServerForUserOperation; |
| ... | ... | @@ -186,8 +191,6 @@ import com.sap.sse.security.shared.UsernamePasswordAccount; |
| 186 | 191 | import com.sap.sse.security.shared.WildcardPermission; |
| 187 | 192 | import com.sap.sse.security.shared.WithQualifiedObjectIdentifier; |
| 188 | 193 | import com.sap.sse.security.shared.impl.AccessControlList; |
| 189 | -import com.sap.sse.security.shared.impl.LockingAndBanning; |
|
| 190 | -import com.sap.sse.security.shared.impl.LockingAndBanningImpl; |
|
| 191 | 194 | import com.sap.sse.security.shared.impl.Ownership; |
| 192 | 195 | import com.sap.sse.security.shared.impl.PermissionAndRoleAssociation; |
| 193 | 196 | import com.sap.sse.security.shared.impl.Role; |
| ... | ... | @@ -281,7 +284,7 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 281 | 284 | * @see #successfulBearerTokenAuthentication(String) |
| 282 | 285 | * @see #isClientIPLockedForBearerTokenAuthentication(String) |
| 283 | 286 | */ |
| 284 | - private final ConcurrentMap<String, LockingAndBanning> clientIPBasedLockingAndBanningForBearerTokenAuthentication; |
|
| 287 | + private final ConcurrentMap<String, TimedLock> clientIPBasedTimedLocksForBearerTokenAuthentication; |
|
| 285 | 288 | private final static String CLIENT_IP_NULL_ESCAPE = UUID.randomUUID().toString(); |
| 286 | 289 | |
| 287 | 290 | /** |
| ... | ... | @@ -293,7 +296,7 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 293 | 296 | * When entering values into this map, the method entering it is responsible for also scheduling a background |
| 294 | 297 | * task that a while after lock expiry the record is expunged again from the map to avoid garbage piling up. |
| 295 | 298 | */ |
| 296 | - private final ConcurrentMap<String, LockingAndBanning> clientIPBasedLockingAndBanningForUserCreation; |
|
| 299 | + private final ConcurrentMap<String, TimedLock> clientIPBasedTimedLocksForUserCreation; |
|
| 297 | 300 | |
| 298 | 301 | private final Zxcvbn passwordValidator; |
| 299 | 302 | |
| ... | ... | @@ -347,8 +350,8 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 347 | 350 | throw new IllegalArgumentException("No HasPermissionsProvider defined"); |
| 348 | 351 | } |
| 349 | 352 | logger.info("Initializing Security Service with user store " + userStore); |
| 350 | - this.clientIPBasedLockingAndBanningForBearerTokenAuthentication = new ConcurrentHashMap<>(); |
|
| 351 | - this.clientIPBasedLockingAndBanningForUserCreation = new ConcurrentHashMap<>(); |
|
| 353 | + this.clientIPBasedTimedLocksForBearerTokenAuthentication = new ConcurrentHashMap<>(); |
|
| 354 | + this.clientIPBasedTimedLocksForUserCreation = new ConcurrentHashMap<>(); |
|
| 352 | 355 | this.permissionChangeListeners = new PermissionChangeListeners(this); |
| 353 | 356 | this.sharedAcrossSubdomainsOf = sharedAcrossSubdomainsOf; |
| 354 | 357 | this.subscriptionPlanProvider = subscriptionPlanProvider; |
| ... | ... | @@ -1000,6 +1003,18 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 1000 | 1003 | } |
| 1001 | 1004 | |
| 1002 | 1005 | @Override |
| 1006 | + public void releaseUserCreationLockOnIp(String ip) { |
|
| 1007 | + logger.info("Releasing timed lock for user creation at IP "+ip); |
|
| 1008 | + apply(new ReleaseUserCreationLockOnIpOperation(ip)); |
|
| 1009 | + } |
|
| 1010 | + |
|
| 1011 | + @Override |
|
| 1012 | + public void releaseBearerTokenLockOnIp(String ip) { |
|
| 1013 | + logger.info("Releasing timed lock for bearer token abuse at IP "+ip); |
|
| 1014 | + apply(new ReleaseBearerTokenLockOnIpOperation(ip)); |
|
| 1015 | + } |
|
| 1016 | + |
|
| 1017 | + @Override |
|
| 1003 | 1018 | public Void internalDeleteUserGroup(UUID groupId) throws UserGroupManagementException { |
| 1004 | 1019 | final UserGroup userGroup = getUserGroup(groupId); |
| 1005 | 1020 | if (userGroup == null) { |
| ... | ... | @@ -1105,6 +1120,16 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 1105 | 1120 | } |
| 1106 | 1121 | |
| 1107 | 1122 | @Override |
| 1123 | + public HashMap<String,TimedLock> getClientIPBasedTimedLocksForUserCreation() { |
|
| 1124 | + return new HashMap<String, TimedLock>(clientIPBasedTimedLocksForUserCreation); |
|
| 1125 | + } |
|
| 1126 | + |
|
| 1127 | + @Override |
|
| 1128 | + public HashMap<String,TimedLock> getClientIPBasedTimedLocksForBearerTokenAbuse() { |
|
| 1129 | + return new HashMap<String, TimedLock>(clientIPBasedTimedLocksForBearerTokenAuthentication); |
|
| 1130 | + } |
|
| 1131 | + |
|
| 1132 | + @Override |
|
| 1108 | 1133 | public User createSimpleUser(final String username, final String email, String password, String fullName, |
| 1109 | 1134 | String company, Locale locale, final String validationBaseURL, UserGroup groupOwningUser, |
| 1110 | 1135 | String requestClientIP, boolean enforceStrongPassword) throws UserManagementException, MailException, UserGroupManagementException { |
| ... | ... | @@ -1160,22 +1185,29 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 1160 | 1185 | // synchronize to ensure that no two threads can enter values into the map concurrently; |
| 1161 | 1186 | // still the use of a ConcurrentMap is justified because there may be concurrent write access |
| 1162 | 1187 | // through replication |
| 1163 | - synchronized (clientIPBasedLockingAndBanningForUserCreation) { |
|
| 1164 | - final LockingAndBanning lockingAndBanning = clientIPBasedLockingAndBanningForUserCreation.get(clientIP); |
|
| 1165 | - if (lockingAndBanning == null || !lockingAndBanning.isAuthenticationLocked()) { |
|
| 1188 | + synchronized (clientIPBasedTimedLocksForUserCreation) { |
|
| 1189 | + final TimedLock timedLock = clientIPBasedTimedLocksForUserCreation.get(clientIP); |
|
| 1190 | + if (timedLock == null || !timedLock.isLocked()) { |
|
| 1166 | 1191 | apply(s->s.internalRecordUserCreationFromClientIP(clientIP)); |
| 1167 | 1192 | } else { |
| 1168 | - throw new UserManagementException(UserManagementException.CLIENT_CURRENTLY_LOCKED_FOR_USER_CREATION); |
|
| 1193 | + timedLock.extendLockDuration(); |
|
| 1194 | + throw new UserManagementException("Client IP "+clientIP+" locked for user creation: "+timedLock); |
|
| 1169 | 1195 | } |
| 1170 | 1196 | } |
| 1171 | 1197 | } |
| 1172 | 1198 | |
| 1173 | 1199 | @Override |
| 1174 | - public LockingAndBanning internalRecordUserCreationFromClientIP(String clientIP) { |
|
| 1175 | - final LockingAndBanning result = new LockingAndBanningImpl(TimePoint.now().plus(DEFAULT_CLIENT_IP_BASED_USER_CREATION_LOCKING_DURATION), |
|
| 1200 | + public boolean isUserCreationLockedForClientIP(String clientIP) { |
|
| 1201 | + final TimedLock timedLock = clientIPBasedTimedLocksForUserCreation.get(escapeNullClientIP(clientIP)); |
|
| 1202 | + return timedLock != null && timedLock.isLocked(); |
|
| 1203 | + } |
|
| 1204 | + |
|
| 1205 | + @Override |
|
| 1206 | + public TimedLock internalRecordUserCreationFromClientIP(String clientIP) { |
|
| 1207 | + final TimedLock result = new TimedLockImpl(TimePoint.now().plus(DEFAULT_CLIENT_IP_BASED_USER_CREATION_LOCKING_DURATION), |
|
| 1176 | 1208 | DEFAULT_CLIENT_IP_BASED_USER_CREATION_LOCKING_DURATION); |
| 1177 | - clientIPBasedLockingAndBanningForUserCreation.put(clientIP, result); |
|
| 1178 | - scheduleCleanUpTask(clientIP, result, clientIPBasedLockingAndBanningForUserCreation, |
|
| 1209 | + clientIPBasedTimedLocksForUserCreation.put(clientIP, result); |
|
| 1210 | + scheduleCleanUpTask(clientIP, result, clientIPBasedTimedLocksForUserCreation, |
|
| 1179 | 1211 | "client IPs locked for user creation"); |
| 1180 | 1212 | return result; |
| 1181 | 1213 | } |
| ... | ... | @@ -1215,7 +1247,7 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 1215 | 1247 | |
| 1216 | 1248 | @Override |
| 1217 | 1249 | public User internalCreateUser(String username, String email, Account... accounts) throws UserManagementException { |
| 1218 | - final User result = store.createUser(username, email, new LockingAndBanningImpl(), accounts); |
|
| 1250 | + final User result = store.createUser(username, email, new TimedLockImpl(), accounts); |
|
| 1219 | 1251 | return result; |
| 1220 | 1252 | } |
| 1221 | 1253 | |
| ... | ... | @@ -1275,12 +1307,29 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 1275 | 1307 | } |
| 1276 | 1308 | |
| 1277 | 1309 | @Override |
| 1310 | + public void resetUserTimedLock(String username) throws UserManagementException { |
|
| 1311 | + final User user = store.getUserByName(username); |
|
| 1312 | + if (user == null) { |
|
| 1313 | + throw new UserManagementException(UserManagementException.USER_DOES_NOT_EXIST); |
|
| 1314 | + } |
|
| 1315 | + apply(new ResetUserLockOperation(username, user.getTimedLock())); |
|
| 1316 | + } |
|
| 1317 | + |
|
| 1318 | + @Override |
|
| 1319 | + public Void internalResetUserTimedLock(String username) { |
|
| 1320 | + final User user = store.getUserByName(username); |
|
| 1321 | + user.getTimedLock().resetLock(); |
|
| 1322 | + store.updateUser(user); |
|
| 1323 | + return null; |
|
| 1324 | + } |
|
| 1325 | + |
|
| 1326 | + @Override |
|
| 1278 | 1327 | public boolean checkPassword(String username, String password) throws UserManagementException { |
| 1279 | 1328 | final User user = store.getUserByName(username); |
| 1280 | 1329 | if (user == null) { |
| 1281 | 1330 | throw new UserManagementException(UserManagementException.USER_DOES_NOT_EXIST); |
| 1282 | 1331 | } |
| 1283 | - if (user.getLockingAndBanning().isAuthenticationLocked()) { |
|
| 1332 | + if (user.getTimedLock().isLocked()) { |
|
| 1284 | 1333 | throw new UserManagementException(UserManagementException.PASSWORD_AUTHENTICATION_CURRENTLY_LOCKED_FOR_USER); |
| 1285 | 1334 | } |
| 1286 | 1335 | final UsernamePasswordAccount account = (UsernamePasswordAccount) user.getAccount(AccountType.USERNAME_PASSWORD); |
| ... | ... | @@ -1296,23 +1345,23 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 1296 | 1345 | } |
| 1297 | 1346 | |
| 1298 | 1347 | @Override |
| 1299 | - public LockingAndBanning failedPasswordAuthentication(User user) { |
|
| 1348 | + public TimedLock failedPasswordAuthentication(User user) { |
|
| 1300 | 1349 | return apply(s->s.internalFailedPasswordAuthentication(user.getName())); |
| 1301 | 1350 | } |
| 1302 | 1351 | |
| 1303 | 1352 | @Override |
| 1304 | - public LockingAndBanning internalFailedPasswordAuthentication(String username) { |
|
| 1353 | + public TimedLock internalFailedPasswordAuthentication(String username) { |
|
| 1305 | 1354 | final User user = getUserByName(username); |
| 1306 | - final LockingAndBanning lockingAndBanning; |
|
| 1355 | + final TimedLock timedLock; |
|
| 1307 | 1356 | if (user != null) { |
| 1308 | - lockingAndBanning = user.getLockingAndBanning(); |
|
| 1309 | - lockingAndBanning.failedPasswordAuthentication(); |
|
| 1357 | + timedLock = user.getTimedLock(); |
|
| 1358 | + timedLock.extendLockDuration(); |
|
| 1310 | 1359 | store.updateUser(user); |
| 1311 | - logger.info("failed password authentication for user "+username+"; locking: "+lockingAndBanning); |
|
| 1360 | + logger.info("failed password authentication for user "+username+"; locking: "+timedLock); |
|
| 1312 | 1361 | } else { |
| 1313 | - lockingAndBanning = null; |
|
| 1362 | + timedLock = null; |
|
| 1314 | 1363 | } |
| 1315 | - return lockingAndBanning; |
|
| 1364 | + return timedLock; |
|
| 1316 | 1365 | } |
| 1317 | 1366 | |
| 1318 | 1367 | @Override |
| ... | ... | @@ -1328,7 +1377,7 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 1328 | 1377 | final boolean changed; |
| 1329 | 1378 | final User user = getUserByName(username); |
| 1330 | 1379 | if (user != null) { |
| 1331 | - changed = user.getLockingAndBanning().successfulPasswordAuthentication(); |
|
| 1380 | + changed = user.getTimedLock().resetLock(); |
|
| 1332 | 1381 | if (changed) { |
| 1333 | 1382 | store.updateUser(user); |
| 1334 | 1383 | } |
| ... | ... | @@ -1339,8 +1388,8 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 1339 | 1388 | } |
| 1340 | 1389 | |
| 1341 | 1390 | @Override |
| 1342 | - public LockingAndBanning failedBearerTokenAuthentication(String clientIP) { |
|
| 1343 | - final LockingAndBanning result; |
|
| 1391 | + public TimedLock failedBearerTokenAuthentication(String clientIP) { |
|
| 1392 | + final TimedLock result; |
|
| 1344 | 1393 | final ReplicationService replicationService = getReplicationService(); |
| 1345 | 1394 | if (replicationService == null || !replicationService.isReplicationStarting()) { |
| 1346 | 1395 | result = apply(s->s.internalFailedBearerTokenAuthentication(clientIP)); |
| ... | ... | @@ -1352,22 +1401,22 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 1352 | 1401 | } |
| 1353 | 1402 | |
| 1354 | 1403 | @Override |
| 1355 | - public LockingAndBanning internalFailedBearerTokenAuthentication(String clientIP) { |
|
| 1356 | - final LockingAndBanning lockingAndBanning = clientIPBasedLockingAndBanningForBearerTokenAuthentication.computeIfAbsent(escapeNullClientIP(clientIP), key->new LockingAndBanningImpl()); |
|
| 1357 | - lockingAndBanning.failedPasswordAuthentication(); |
|
| 1358 | - logger.info("failed bearer token authentication from client IP "+clientIP+"; locking: "+lockingAndBanning); |
|
| 1359 | - scheduleCleanUpTask(clientIP, lockingAndBanning, clientIPBasedLockingAndBanningForBearerTokenAuthentication, |
|
| 1404 | + public TimedLock internalFailedBearerTokenAuthentication(String clientIP) { |
|
| 1405 | + final TimedLock timedLock = clientIPBasedTimedLocksForBearerTokenAuthentication.computeIfAbsent(escapeNullClientIP(clientIP), key->new TimedLockImpl()); |
|
| 1406 | + timedLock.extendLockDuration(); |
|
| 1407 | + logger.info("failed bearer token authentication from client IP "+clientIP+"; locking: "+timedLock); |
|
| 1408 | + scheduleCleanUpTask(clientIP, timedLock, clientIPBasedTimedLocksForBearerTokenAuthentication, |
|
| 1360 | 1409 | "client IPs locked for bearer token authentication"); |
| 1361 | - return lockingAndBanning; |
|
| 1410 | + return timedLock; |
|
| 1362 | 1411 | } |
| 1363 | 1412 | |
| 1364 | 1413 | /** |
| 1365 | - * Schedule a clean-up task to avoid leaking memory for the LockingAndBanning objects; schedule it in two times the |
|
| 1366 | - * locking expiry of {@code lockingAndBanning}, but at least one hour, because if no authentication failure occurs |
|
| 1367 | - * for that IP/user agent combination, we will entirely remove the {@link LockingAndBanning} from the map, |
|
| 1414 | + * Schedule a clean-up task to avoid leaking memory for the TimedLock objects; schedule it in two times the |
|
| 1415 | + * locking expiry of {@code timedLock}, but at least one hour, because if no authentication failure occurs |
|
| 1416 | + * for that IP/user agent combination, we will entirely remove the {@link TimedLock} from the map, |
|
| 1368 | 1417 | * effectively resetting that IP to a short default locking duration again; this way, if during the double |
| 1369 | 1418 | * expiration time another failed attempt is registered, we can still grow the locking duration because we have kept |
| 1370 | - * the {@link LockingAndBanning} object available for a bit longer. Furthermore, for authentication requests, the |
|
| 1419 | + * the {@link TimedLock} object available for a bit longer. Furthermore, for authentication requests, the |
|
| 1371 | 1420 | * responsible {@link Realm} will let authentication requests get to here only if not locked, so if we were to |
| 1372 | 1421 | * expunge entries immediately as they unlock, the locking duration could never grow.<p> |
| 1373 | 1422 | * |
| ... | ... | @@ -1375,16 +1424,16 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 1375 | 1424 | * expiry duration. |
| 1376 | 1425 | */ |
| 1377 | 1426 | private void scheduleCleanUpTask(final String clientIPOrNull, |
| 1378 | - final LockingAndBanning lockingAndBanning, |
|
| 1379 | - final ConcurrentMap<String, LockingAndBanning> mapToRemoveFrom, |
|
| 1427 | + final TimedLock timedLock, |
|
| 1428 | + final ConcurrentMap<String, TimedLock> mapToRemoveFrom, |
|
| 1380 | 1429 | final String nameOfMapForLog) { |
| 1381 | 1430 | final long millisUntilLockingExpiry = Math.max( |
| 1382 | - 2*ApproximateTime.approximateNow().until(lockingAndBanning.getLockedUntil()).asMillis(), |
|
| 1431 | + 2*ApproximateTime.approximateNow().until(timedLock.getLockedUntil()).asMillis(), |
|
| 1383 | 1432 | Duration.ONE_HOUR.asMillis()); |
| 1384 | 1433 | ThreadPoolUtil.INSTANCE.getDefaultBackgroundTaskThreadPoolExecutor().schedule( |
| 1385 | 1434 | ()->{ |
| 1386 | - final LockingAndBanning lab = mapToRemoveFrom.get(escapeNullClientIP(clientIPOrNull)); |
|
| 1387 | - if (lab != null && !lab.isAuthenticationLocked()) { |
|
| 1435 | + final TimedLock lab = mapToRemoveFrom.get(escapeNullClientIP(clientIPOrNull)); |
|
| 1436 | + if (lab != null && !lab.isLocked()) { |
|
| 1388 | 1437 | mapToRemoveFrom.remove(escapeNullClientIP(clientIPOrNull)); |
| 1389 | 1438 | logger.info("Removed "+clientIPOrNull+" from "+nameOfMapForLog+"; " |
| 1390 | 1439 | +mapToRemoveFrom.size() |
| ... | ... | @@ -1409,9 +1458,9 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 1409 | 1458 | @Override |
| 1410 | 1459 | public Boolean internalSuccessfulBearerTokenAuthentication(String clientIP) { |
| 1411 | 1460 | final boolean changed; |
| 1412 | - final LockingAndBanning lockingAndBanning = clientIPBasedLockingAndBanningForBearerTokenAuthentication.remove(escapeNullClientIP(clientIP)); |
|
| 1413 | - if (lockingAndBanning != null) { |
|
| 1414 | - logger.info("Unlocked bearer token authentication from "+clientIP+"; last locking state was "+lockingAndBanning); |
|
| 1461 | + final TimedLock timedLock = clientIPBasedTimedLocksForBearerTokenAuthentication.remove(escapeNullClientIP(clientIP)); |
|
| 1462 | + if (timedLock != null) { |
|
| 1463 | + logger.info("Unlocked bearer token authentication from "+clientIP+"; last locking state was "+timedLock); |
|
| 1415 | 1464 | changed = true; |
| 1416 | 1465 | } else { |
| 1417 | 1466 | changed = false; |
| ... | ... | @@ -1421,8 +1470,8 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 1421 | 1470 | |
| 1422 | 1471 | @Override |
| 1423 | 1472 | public boolean isClientIPLockedForBearerTokenAuthentication(String clientIP) { |
| 1424 | - final LockingAndBanning lockingAndBanning = clientIPBasedLockingAndBanningForBearerTokenAuthentication.get(escapeNullClientIP(clientIP)); |
|
| 1425 | - return lockingAndBanning != null && lockingAndBanning.isAuthenticationLocked(); |
|
| 1473 | + final TimedLock timedLock = clientIPBasedTimedLocksForBearerTokenAuthentication.get(escapeNullClientIP(clientIP)); |
|
| 1474 | + return timedLock != null && timedLock.isLocked(); |
|
| 1426 | 1475 | } |
| 1427 | 1476 | |
| 1428 | 1477 | @Override |
| ... | ... | @@ -2521,8 +2570,8 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 2521 | 2570 | store.clear(); |
| 2522 | 2571 | accessControlStore.clear(); |
| 2523 | 2572 | corsFilterConfigurationsByReplicaSetName.clear(); |
| 2524 | - clientIPBasedLockingAndBanningForBearerTokenAuthentication.clear(); |
|
| 2525 | - clientIPBasedLockingAndBanningForUserCreation.clear(); |
|
| 2573 | + clientIPBasedTimedLocksForBearerTokenAuthentication.clear(); |
|
| 2574 | + clientIPBasedTimedLocksForUserCreation.clear(); |
|
| 2526 | 2575 | } |
| 2527 | 2576 | |
| 2528 | 2577 | @Override |
| ... | ... | @@ -2604,13 +2653,13 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 2604 | 2653 | final SecurityServiceInitialLoadExtensionsDTO initialLoadExtensions = (SecurityServiceInitialLoadExtensionsDTO) is.readObject(); |
| 2605 | 2654 | final ConcurrentMap<String, Pair<Boolean, Set<String>>> newCORSFilterConfigurations = initialLoadExtensions.getCorsFilterConfigurationsByReplicaSetName(); |
| 2606 | 2655 | corsFilterConfigurationsByReplicaSetName.putAll(newCORSFilterConfigurations); |
| 2607 | - if (initialLoadExtensions.getClientIPBasedLockingAndBanningForBearerTokenAuthentication() != null) { |
|
| 2656 | + if (initialLoadExtensions.getClientIPBasedTimedLocksForBearerTokenAuthentication() != null) { |
|
| 2608 | 2657 | // checking for null for backward compatibility; an older primary/master may not have known this field yet |
| 2609 | - clientIPBasedLockingAndBanningForBearerTokenAuthentication.putAll(initialLoadExtensions.getClientIPBasedLockingAndBanningForBearerTokenAuthentication()); |
|
| 2658 | + clientIPBasedTimedLocksForBearerTokenAuthentication.putAll(initialLoadExtensions.getClientIPBasedTimedLocksForBearerTokenAuthentication()); |
|
| 2610 | 2659 | } |
| 2611 | - if (initialLoadExtensions.getClientIPBasedLockingAndBanningForUserCreation() != null) { |
|
| 2660 | + if (initialLoadExtensions.getClientIPBasedTimedLocksForUserCreation() != null) { |
|
| 2612 | 2661 | // checking for null for backward compatibility; an older primary/master may not have known this field yet |
| 2613 | - clientIPBasedLockingAndBanningForUserCreation.putAll(initialLoadExtensions.getClientIPBasedLockingAndBanningForUserCreation()); |
|
| 2662 | + clientIPBasedTimedLocksForUserCreation.putAll(initialLoadExtensions.getClientIPBasedTimedLocksForUserCreation()); |
|
| 2614 | 2663 | } |
| 2615 | 2664 | logger.info("Triggering SecurityInitializationCustomizers upon replication ..."); |
| 2616 | 2665 | customizers.forEach(c -> c.customizeSecurityService(this)); |
| ... | ... | @@ -2626,8 +2675,8 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 2626 | 2675 | objectOutputStream.writeObject(baseUrlForCrossDomainStorage); |
| 2627 | 2676 | objectOutputStream.writeObject(new SecurityServiceInitialLoadExtensionsDTO( |
| 2628 | 2677 | corsFilterConfigurationsByReplicaSetName, |
| 2629 | - clientIPBasedLockingAndBanningForBearerTokenAuthentication, |
|
| 2630 | - clientIPBasedLockingAndBanningForUserCreation)); |
|
| 2678 | + clientIPBasedTimedLocksForBearerTokenAuthentication, |
|
| 2679 | + clientIPBasedTimedLocksForUserCreation)); |
|
| 2631 | 2680 | } |
| 2632 | 2681 | |
| 2633 | 2682 | @Override |
| ... | ... | @@ -2934,8 +2983,8 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 2934 | 2983 | // See com.sap.sse.security.impl.Activator.clearState(), moved due to required reinitialisation sequence for |
| 2935 | 2984 | // permission-vertical |
| 2936 | 2985 | public void clearState() throws Exception { |
| 2937 | - clientIPBasedLockingAndBanningForBearerTokenAuthentication.clear(); |
|
| 2938 | - clientIPBasedLockingAndBanningForUserCreation.clear(); |
|
| 2986 | + clientIPBasedTimedLocksForBearerTokenAuthentication.clear(); |
|
| 2987 | + clientIPBasedTimedLocksForUserCreation.clear(); |
|
| 2939 | 2988 | } |
| 2940 | 2989 | |
| 2941 | 2990 | @Override |
| ... | ... | @@ -3499,4 +3548,18 @@ implements ReplicableSecurityService, ClearStateTestSupport { |
| 3499 | 3548 | .forEach(usersToSendMailTo::add)); |
| 3500 | 3549 | return usersToSendMailTo; |
| 3501 | 3550 | } |
| 3551 | + |
|
| 3552 | + @Override |
|
| 3553 | + public void internalReleaseUserCreationLockOnIp(String ip) { |
|
| 3554 | + if(clientIPBasedTimedLocksForUserCreation.containsKey(ip)) { |
|
| 3555 | + clientIPBasedTimedLocksForUserCreation.remove(ip); |
|
| 3556 | + } |
|
| 3557 | + } |
|
| 3558 | + |
|
| 3559 | + @Override |
|
| 3560 | + public void internalReleaseBearerTokenLockOnIp(String ip) { |
|
| 3561 | + if(clientIPBasedTimedLocksForBearerTokenAuthentication.containsKey(ip)) { |
|
| 3562 | + clientIPBasedTimedLocksForBearerTokenAuthentication.remove(ip); |
|
| 3563 | + } |
|
| 3564 | + } |
|
| 3502 | 3565 | } |
java/com.sap.sse.security/src/com/sap/sse/security/impl/SecurityServiceInitialLoadExtensionsDTO.java
| ... | ... | @@ -6,17 +6,17 @@ import java.io.Serializable; |
| 6 | 6 | import java.util.Set; |
| 7 | 7 | import java.util.concurrent.ConcurrentMap; |
| 8 | 8 | |
| 9 | +import com.sap.sse.common.TimedLock; |
|
| 9 | 10 | import com.sap.sse.common.Util.Pair; |
| 10 | 11 | import com.sap.sse.replication.Replicable; |
| 11 | 12 | import com.sap.sse.security.SecurityService; |
| 12 | -import com.sap.sse.security.shared.impl.LockingAndBanning; |
|
| 13 | 13 | |
| 14 | 14 | /** |
| 15 | 15 | * Starting with the CORS filter configurations, this and future extensions of the {@link SecurityService}'s |
| 16 | 16 | * initial load format can be added to this DTO type. The benefit, compared to adding new content with |
| 17 | 17 | * explicit {@link ObjectOutputStream#writeObject(Object)} and {@link ObjectInputStream#readObject()} calls, |
| 18 | 18 | * is that there is a certain built-in backward compatibility when a replica with a new version and additional |
| 19 | - * fields expected in the initial load tries to replica from an older version where those fields don't exist |
|
| 19 | + * fields expected in the initial load tries to replicate from an older version where those fields don't exist |
|
| 20 | 20 | * yet in this type. Then, those additional fields will come out as {@code null} on the replica, and the replica |
| 21 | 21 | * at least has a chance to continue with a useful initialization of those data structures instead of having |
| 22 | 22 | * the replication of {@link SecurityService} and all subsequent {@link Replicable}s fail due to incompatible |
| ... | ... | @@ -30,29 +30,30 @@ public class SecurityServiceInitialLoadExtensionsDTO implements Serializable { |
| 30 | 30 | |
| 31 | 31 | private final ConcurrentMap<String, Pair<Boolean, Set<String>>> corsFilterConfigurationsByReplicaSetName; |
| 32 | 32 | |
| 33 | - private final ConcurrentMap<String, LockingAndBanning> clientIPBasedLockingAndBanningForBearerTokenAuthentication; |
|
| 33 | + private final ConcurrentMap<String, TimedLock> clientIPBasedTimedLocksForBearerTokenAuthentication; |
|
| 34 | 34 | |
| 35 | - private final ConcurrentMap<String, LockingAndBanning> clientIPBasedLockingAndBanningForUserCreation; |
|
| 35 | + private final ConcurrentMap<String, TimedLock> clientIPBasedTimedLocksForUserCreation; |
|
| 36 | 36 | |
| 37 | 37 | public SecurityServiceInitialLoadExtensionsDTO( |
| 38 | 38 | ConcurrentMap<String, Pair<Boolean, Set<String>>> corsFilterConfigurationsByReplicaSetName, |
| 39 | - ConcurrentMap<String, LockingAndBanning> clientIPBasedLockingAndBanningForBearerTokenAuthentication, |
|
| 40 | - ConcurrentMap<String, LockingAndBanning> clientIPBasedLockingAndBanningForUserCreation) { |
|
| 39 | + ConcurrentMap<String, TimedLock> clientIPBasedTimedLockForBearerTokenAuthentication, |
|
| 40 | + ConcurrentMap<String, TimedLock> clientIPBasedTimedLocksForUserCreation) { |
|
| 41 | 41 | super(); |
| 42 | 42 | this.corsFilterConfigurationsByReplicaSetName = corsFilterConfigurationsByReplicaSetName; |
| 43 | - this.clientIPBasedLockingAndBanningForBearerTokenAuthentication = clientIPBasedLockingAndBanningForBearerTokenAuthentication; |
|
| 44 | - this.clientIPBasedLockingAndBanningForUserCreation = clientIPBasedLockingAndBanningForUserCreation; |
|
| 43 | + this.clientIPBasedTimedLocksForBearerTokenAuthentication = clientIPBasedTimedLockForBearerTokenAuthentication; |
|
| 44 | + this.clientIPBasedTimedLocksForUserCreation = clientIPBasedTimedLocksForUserCreation; |
|
| 45 | 45 | } |
| 46 | + |
|
| 46 | 47 | |
| 47 | 48 | ConcurrentMap<String, Pair<Boolean, Set<String>>> getCorsFilterConfigurationsByReplicaSetName() { |
| 48 | 49 | return corsFilterConfigurationsByReplicaSetName; |
| 49 | 50 | } |
| 50 | 51 | |
| 51 | - ConcurrentMap<String, LockingAndBanning> getClientIPBasedLockingAndBanningForBearerTokenAuthentication() { |
|
| 52 | - return clientIPBasedLockingAndBanningForBearerTokenAuthentication; |
|
| 52 | + ConcurrentMap<String, TimedLock> getClientIPBasedTimedLocksForBearerTokenAuthentication() { |
|
| 53 | + return clientIPBasedTimedLocksForBearerTokenAuthentication; |
|
| 53 | 54 | } |
| 54 | 55 | |
| 55 | - ConcurrentMap<String, LockingAndBanning> getClientIPBasedLockingAndBanningForUserCreation() { |
|
| 56 | - return clientIPBasedLockingAndBanningForUserCreation; |
|
| 56 | + ConcurrentMap<String, TimedLock> getClientIPBasedTimedLocksForUserCreation() { |
|
| 57 | + return clientIPBasedTimedLocksForUserCreation; |
|
| 57 | 58 | } |
| 58 | 59 | } |
java/com.sap.sse.security/src/com/sap/sse/security/operations/ReleaseBearerTokenLockOnIpOperation.java
| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | +package com.sap.sse.security.operations; |
|
| 2 | + |
|
| 3 | +import com.sap.sse.security.impl.ReplicableSecurityService; |
|
| 4 | + |
|
| 5 | +public class ReleaseBearerTokenLockOnIpOperation implements SecurityOperation<Void> { |
|
| 6 | + private static final long serialVersionUID = 5839571828359473821L; |
|
| 7 | + protected final String ip; |
|
| 8 | + |
|
| 9 | + public ReleaseBearerTokenLockOnIpOperation(final String ip) { |
|
| 10 | + this.ip = ip; |
|
| 11 | + } |
|
| 12 | + |
|
| 13 | + @Override |
|
| 14 | + public Void internalApplyTo(ReplicableSecurityService toState) throws Exception { |
|
| 15 | + toState.internalReleaseBearerTokenLockOnIp(ip); |
|
| 16 | + return null; |
|
| 17 | + } |
|
| 18 | +} |
java/com.sap.sse.security/src/com/sap/sse/security/operations/ReleaseUserCreationLockOnIpOperation.java
| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | +package com.sap.sse.security.operations; |
|
| 2 | + |
|
| 3 | +import com.sap.sse.security.impl.ReplicableSecurityService; |
|
| 4 | + |
|
| 5 | +public class ReleaseUserCreationLockOnIpOperation implements SecurityOperation<Void> { |
|
| 6 | + private static final long serialVersionUID = 8729427754960969395L; |
|
| 7 | + protected final String ip; |
|
| 8 | + |
|
| 9 | + public ReleaseUserCreationLockOnIpOperation(final String ip) { |
|
| 10 | + this.ip = ip; |
|
| 11 | + } |
|
| 12 | + |
|
| 13 | + @Override |
|
| 14 | + public Void internalApplyTo(ReplicableSecurityService toState) throws Exception { |
|
| 15 | + toState.internalReleaseUserCreationLockOnIp(ip); |
|
| 16 | + return null; |
|
| 17 | + } |
|
| 18 | +} |
java/com.sap.sse.security/src/com/sap/sse/security/operations/ResetUserLockOperation.java
| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | +package com.sap.sse.security.operations; |
|
| 2 | + |
|
| 3 | +import com.sap.sse.common.TimedLock; |
|
| 4 | +import com.sap.sse.security.impl.ReplicableSecurityService; |
|
| 5 | + |
|
| 6 | +public class ResetUserLockOperation implements SecurityOperation<Void> { |
|
| 7 | + private static final long serialVersionUID = -6267523788529623080L; |
|
| 8 | + protected final TimedLock timedLock; |
|
| 9 | + protected final String username; |
|
| 10 | + |
|
| 11 | + public ResetUserLockOperation(String username, TimedLock timedLock) { |
|
| 12 | + this.username = username; |
|
| 13 | + this.timedLock = timedLock; |
|
| 14 | + } |
|
| 15 | + |
|
| 16 | + @Override |
|
| 17 | + public Void internalApplyTo(ReplicableSecurityService toState) throws Exception { |
|
| 18 | + toState.internalResetUserTimedLock(username); |
|
| 19 | + return null; |
|
| 20 | + } |
|
| 21 | + |
|
| 22 | +} |
java/com.sap.sse.threadmanager/resources/shiro.ini
| ... | ... | @@ -26,7 +26,7 @@ securityManager.subjectDAO = $subjectDAO |
| 26 | 26 | securityManager.sessionManager.globalSessionTimeout = 31536000000 |
| 27 | 27 | cacheManager = com.sap.sse.security.SessionCacheManager |
| 28 | 28 | securityManager.cacheManager = $cacheManager |
| 29 | -authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning |
|
| 29 | +authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithTimedLocks |
|
| 30 | 30 | securityManager.authenticator.authenticationStrategy = $authenticationStrategy |
| 31 | 31 | |
| 32 | 32 | # Support for anonymous user permissions |
java/pom.xml
| ... | ... | @@ -38,10 +38,10 @@ |
| 38 | 38 | --> |
| 39 | 39 | <tycho-version>4.0.12</tycho-version> |
| 40 | 40 | <toolchains-version>3.2.0</toolchains-version> |
| 41 | - <gwt.version>2.12.2</gwt.version> |
|
| 41 | + <gwt.version>2.12.3</gwt.version> |
|
| 42 | 42 | <!-- gwt-maven-plugin is typically in sync with the GWT version. But sometimes versions need extra time after a new GWT release. --> |
| 43 | - <gwt.plugin.version>2.12.2</gwt.plugin.version> |
|
| 44 | - <gwt.minVersion>2.12.2</gwt.minVersion> |
|
| 43 | + <gwt.plugin.version>2.12.3</gwt.plugin.version> |
|
| 44 | + <gwt.minVersion>2.12.3</gwt.minVersion> |
|
| 45 | 45 | <gwt.workers>2</gwt.workers> |
| 46 | 46 | <p2-target>race-analysis-p2-remote</p2-target><!--can be overidden through p2-target.local profile --> |
| 47 | 47 | <!-- QUESTION: Which properties or settings are system dependent and differ across different machines/environments? QUESTION: |
scripts/assume_unchanged_for_mac.sh
| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | +#!/bin/bash |
|
| 2 | + |
|
| 3 | +# Description: |
|
| 4 | +# This script finds all *.prefs and *.launch files tracked by Git |
|
| 5 | +# and sets them to "assume-unchanged", so local changes won't show |
|
| 6 | +# up in 'git status' or be accidentally committed. |
|
| 7 | + |
|
| 8 | +# Find and apply the assume-unchanged flag |
|
| 9 | +echo "Scanning for tracked *.prefs and *.launch files..." |
|
| 10 | + |
|
| 11 | +files=$(git ls-files | grep -E '\.prefs$|\.launch$') |
|
| 12 | + |
|
| 13 | +if [ -z "$files" ]; then |
|
| 14 | + echo "No .prefs or .launch files found in the tracked file list." |
|
| 15 | + exit 0 |
|
| 16 | +fi |
|
| 17 | + |
|
| 18 | +echo "$files" | while read -r file; do |
|
| 19 | + git update-index --assume-unchanged "$file" |
|
| 20 | + echo "Marked as assume-unchanged: $file" |
|
| 21 | +done |
|
| 22 | + |
|
| 23 | +echo "" |
|
| 24 | +echo "Git will now ignore local changes to these files (but they will still update from upstream if you clear this flag before pulling)." |
|
| 25 | + |
wiki/info/landscape/development-environment.md
| ... | ... | @@ -18,7 +18,7 @@ Everything else should follow the pattern |
| 18 | 18 | - when the workflow has finished, it triggers your Hudson job which collects the [build and test results](https://hudson.sapsailing.com/job/bug12345) |
| 19 | 19 | - be verbose and document your changes, progress, hold-ups and problems on your Bugzilla issue |
| 20 | 20 | - when build is "green," suggest your branch for review; so far we do this informally by assigning the Bugzilla issue to the reviewer and in a comment asking for review; in the future, we may want to use Github Pull Requests for this |
| 21 | -- after your branch has been merged into ``main``, disable your Hudson build job for your branch |
|
| 21 | +- after your branch has been merged into ``main``, disable your Hudson build job for your branch, comment about the merge in Bugzilla and resolve the Bugzilla item, usually as "FIXED". |
|
| 22 | 22 | - the ``main`` branch will then build a new release that you can roll out into the production landscape |
| 23 | 23 | - in case of changes to i18n-related message properties files, merge ``main`` into ``translation`` which triggers the translation process; the completed translations will arrive as pushes to the ``translations`` branch, triggering another ``release`` workflow, and---if successful---an automated merge into ``main`` with the corresponding build/release process happens, based on the [translation Hudson job](https://hudson.sapsailing.com/job/translation/configure)'s special logic |
| 24 | 24 | - a successful ``main`` build (still on Java 8) will lead to an automatic merge into one or more branches for newer Java releases (such as ``docker-24``) with the corresponding build/release process |