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 &quot;${project_loc:com.sap.sailing.dashboards.gwt}&quot; -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -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 &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -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 &quot;${project_loc:com.sap.sailing.gwt.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -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="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8&quot; javaProject=&quot;com.sap.sse.gwt&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
... ...
@@ -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 &quot;${project_loc:com.sap.sse.gwt}/.tmp/gwt-work&quot; -war &quot;${project_loc:com.sap.sse.gwt}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -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 &quot;${project_loc:com.sap.sse.gwt}/.tmp/gwt-work&quot; -war &quot;${project_loc:com.sap.sse.gwt}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -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="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8&quot; javaProject=&quot;com.sap.sailing.gwt.ui&quot; path=&quot;1&quot; type=&quot;4&quot;/&gt;&#10;"/>
... ...
@@ -101,12 +103,14 @@
101 103
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry id=&quot;org.eclipse.jdt.launching.classpathentry.defaultClasspath&quot;&gt;&#10; &lt;memento exportedEntriesOnly=&quot;false&quot; project=&quot;com.sap.sailing.gwt.ui&quot;/&gt;&#10;&lt;/runtimeClasspathEntry&gt;&#10;"/>
102 104
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;com.sap.sse.common&quot; type=&quot;1&quot;/&gt;&#10;"/>
103 105
<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.landscape.aws.common/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
106
+ <listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/com.sap.sse.branding/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#10;"/>
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 &quot;${project_loc:com.sap.sse.security.ui}/.tmp/gwt-work&quot; -war &quot;${project_loc:com.sap.sse.security.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -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 &quot;${project_loc:com.sap.sse.security.ui}/.tmp/gwt-work&quot; -war &quot;${project_loc:com.sap.sse.security.ui}&quot; -noserver -remoteUI &quot;${gwt_remote_ui_server_port}:${unique_id}&quot; -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