Skip to content

Commit bafbd64

Browse files
ludochgae-java-bot
authored andcommitted
Refactors the App Engine Jetty runtime by extracting several nested classes from AppEngineAuthentication.java.
PiperOrigin-RevId: 874366115 Change-Id: I29ad2e55d9a14e3b5250ab58a910bf1010d952af
1 parent 57b5f19 commit bafbd64

10 files changed

Lines changed: 499 additions & 357 deletions

File tree

shared_sdk_jetty12/src/main/java/com/google/apphosting/runtime/jetty/AppEngineAuthentication.java

Lines changed: 4 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,16 @@
2222
import com.google.apphosting.api.ApiProxy;
2323
import com.google.common.flogger.GoogleLogger;
2424
import java.io.IOException;
25-
import java.security.Principal;
2625
import java.util.Arrays;
2726
import java.util.HashSet;
2827
import java.util.function.Function;
29-
import javax.security.auth.Subject;
3028
import javax.servlet.ServletRequest;
3129
import javax.servlet.ServletResponse;
3230
import javax.servlet.http.HttpServletRequest;
3331
import javax.servlet.http.HttpServletResponse;
3432
import javax.servlet.http.HttpSession;
3533
import org.eclipse.jetty.ee8.nested.Authentication;
36-
import org.eclipse.jetty.ee8.security.Authenticator;
3734
import org.eclipse.jetty.ee8.security.ConstraintSecurityHandler;
38-
import org.eclipse.jetty.ee8.security.SecurityHandler;
3935
import org.eclipse.jetty.ee8.security.ServerAuthException;
4036
import org.eclipse.jetty.ee8.security.UserAuthentication;
4137
import org.eclipse.jetty.ee8.security.authentication.DeferredAuthentication;
@@ -77,9 +73,10 @@ public class AppEngineAuthentication {
7773
* Any authenticated user is a member of the {@code "*"} role, and any administrators are members
7874
* of the {@code "admin"} role. Any other roles will be logged and ignored.
7975
*/
80-
private static final String USER_ROLE = "*";
8176

82-
private static final String ADMIN_ROLE = "admin";
77+
static final String USER_ROLE = "*";
78+
79+
static final String ADMIN_ROLE = "admin";
8380

8481
/**
8582
* Inject custom {@link LoginService} and {@link Authenticator} implementations into the specified
@@ -245,170 +242,5 @@ private static String getFullURL(HttpServletRequest request) {
245242
return buffer.toString();
246243
}
247244

248-
/**
249-
* {@code AppEngineLoginService} is a custom Jetty {@link LoginService} that is aware of the two
250-
* special role names implemented by Google App Engine. Any authenticated user is a member of the
251-
* {@code "*"} role, and any administrators are members of the {@code "admin"} role. Any other
252-
* roles will be logged and ignored.
253-
*/
254-
private static class AppEngineLoginService implements LoginService {
255-
private IdentityService identityService;
256-
257-
/**
258-
* @return Get the name of the login service (aka Realm name)
259-
*/
260-
@Override
261-
public String getName() {
262-
return REALM_NAME;
263-
}
264-
265-
@Override
266-
public UserIdentity login(
267-
String s, Object o, Request request, Function<Boolean, Session> function) {
268-
return loadUser();
269-
}
270-
271-
/**
272-
* Creates a new AppEngineUserIdentity based on information retrieved from the Users API.
273-
*
274-
* @return A AppEngineUserIdentity if a user is logged in, or null otherwise.
275-
*/
276-
private AppEngineUserIdentity loadUser() {
277-
UserService userService = UserServiceFactory.getUserService();
278-
User engineUser = userService.getCurrentUser();
279-
if (engineUser == null) {
280-
return null;
281-
}
282-
return new AppEngineUserIdentity(new AppEnginePrincipal(engineUser));
283-
}
284-
285-
@Override
286-
public IdentityService getIdentityService() {
287-
return identityService;
288-
}
289-
290-
@Override
291-
public void logout(UserIdentity user) {
292-
// Jetty calls this on every request -- even if user is null!
293-
if (user != null) {
294-
logger.atFine().log("Ignoring logout call for: %s", user);
295-
}
296-
}
297-
298-
@Override
299-
public void setIdentityService(IdentityService identityService) {
300-
this.identityService = identityService;
301-
}
302-
303-
@Override
304-
public boolean validate(UserIdentity user) {
305-
logger.atInfo().log("validate(%s) throwing UnsupportedOperationException.", user);
306-
throw new UnsupportedOperationException();
307-
}
308-
}
309-
310-
/**
311-
* {@code AppEnginePrincipal} is an implementation of {@link Principal} that represents a
312-
* logged-in Google App Engine user.
313-
*/
314-
public static class AppEnginePrincipal implements Principal {
315-
private final User user;
316-
317-
public AppEnginePrincipal(User user) {
318-
this.user = user;
319-
}
320-
321-
public User getUser() {
322-
return user;
323-
}
324-
325-
@Override
326-
public String getName() {
327-
if ((user.getFederatedIdentity() != null) && (!user.getFederatedIdentity().isEmpty())) {
328-
return user.getFederatedIdentity();
329-
}
330-
return user.getEmail();
331-
}
332-
333-
@Override
334-
public boolean equals(Object other) {
335-
if (other instanceof AppEnginePrincipal) {
336-
return user.equals(((AppEnginePrincipal) other).user);
337-
} else {
338-
return false;
339-
}
340-
}
341-
342-
@Override
343-
public String toString() {
344-
return user.toString();
345-
}
346-
347-
@Override
348-
public int hashCode() {
349-
return user.hashCode();
350-
}
351-
}
352-
353-
/**
354-
* {@code AppEngineUserIdentity} is an implementation of {@link UserIdentity} that represents a
355-
* logged-in Google App Engine user.
356-
*/
357-
public static class AppEngineUserIdentity implements UserIdentity {
358-
359-
private final AppEnginePrincipal userPrincipal;
360-
361-
public AppEngineUserIdentity(AppEnginePrincipal userPrincipal) {
362-
this.userPrincipal = userPrincipal;
363-
}
364-
365-
/*
366-
* Only used by jaas and jaspi.
367-
*/
368-
@Override
369-
public Subject getSubject() {
370-
logger.atInfo().log("getSubject() throwing UnsupportedOperationException.");
371-
throw new UnsupportedOperationException();
372-
}
373-
374-
@Override
375-
public Principal getUserPrincipal() {
376-
return userPrincipal;
377-
}
378-
379-
@Override
380-
public boolean isUserInRole(String role) {
381-
UserService userService = UserServiceFactory.getUserService();
382-
logger.atFine().log("Checking if principal %s is in role %s", userPrincipal, role);
383-
if (userPrincipal == null) {
384-
logger.atInfo().log("isUserInRole() called with null principal.");
385-
return false;
386-
}
387-
388-
if (USER_ROLE.equals(role)) {
389-
return true;
390-
}
391-
392-
if (ADMIN_ROLE.equals(role)) {
393-
User user = userPrincipal.getUser();
394-
if (user.equals(userService.getCurrentUser())) {
395-
return userService.isUserAdmin();
396-
} else {
397-
// TODO: I'm not sure this will happen in
398-
// practice. If it does, we may need to pass an
399-
// application's admin list down somehow.
400-
logger.atSevere().log("Cannot tell if non-logged-in user %s is an admin.", user);
401-
return false;
402-
}
403-
} else {
404-
logger.atWarning().log("Unknown role: %s.", role);
405-
return false;
406-
}
407-
}
408-
409-
@Override
410-
public String toString() {
411-
return AppEngineUserIdentity.class.getSimpleName() + "('" + userPrincipal + "')";
412-
}
413-
}
245+
private AppEngineAuthentication() {}
414246
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright 2021 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.apphosting.runtime.jetty;
18+
19+
import com.google.appengine.api.users.User;
20+
import com.google.appengine.api.users.UserService;
21+
import com.google.appengine.api.users.UserServiceFactory;
22+
import com.google.common.flogger.GoogleLogger;
23+
import java.util.function.Function;
24+
import org.eclipse.jetty.security.IdentityService;
25+
import org.eclipse.jetty.security.LoginService;
26+
import org.eclipse.jetty.security.UserIdentity;
27+
import org.eclipse.jetty.server.Request;
28+
import org.eclipse.jetty.server.Session;
29+
30+
/**
31+
* {@code AppEngineLoginService} is a custom Jetty {@link LoginService} that is aware of the two
32+
* special role names implemented by Google App Engine. Any authenticated user is a member of the
33+
* {@code "*"} role, and any administrators are members of the {@code "admin"} role. Any other
34+
* roles will be logged and ignored.
35+
*/
36+
public class AppEngineLoginService implements LoginService {
37+
private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();
38+
39+
private static final String REALM_NAME = "Google App Engine";
40+
41+
private IdentityService identityService;
42+
43+
/**
44+
* @return Get the name of the login service (aka Realm name)
45+
*/
46+
@Override
47+
public String getName() {
48+
return REALM_NAME;
49+
}
50+
51+
@Override
52+
public UserIdentity login(
53+
String s, Object o, Request request, Function<Boolean, Session> function) {
54+
return loadUser();
55+
}
56+
57+
/**
58+
* Creates a new AppEngineUserIdentity based on information retrieved from the Users API.
59+
*
60+
* @return A AppEngineUserIdentity if a user is logged in, or null otherwise.
61+
*/
62+
private AppEngineUserIdentity loadUser() {
63+
UserService userService = UserServiceFactory.getUserService();
64+
User engineUser = userService.getCurrentUser();
65+
if (engineUser == null) {
66+
return null;
67+
}
68+
return new AppEngineUserIdentity(new AppEnginePrincipal(engineUser));
69+
}
70+
71+
@Override
72+
public IdentityService getIdentityService() {
73+
return identityService;
74+
}
75+
76+
@Override
77+
public void logout(UserIdentity user) {
78+
// Jetty calls this on every request -- even if user is null!
79+
if (user != null) {
80+
logger.atFine().log("Ignoring logout call for: %s", user);
81+
}
82+
}
83+
84+
@Override
85+
public void setIdentityService(IdentityService identityService) {
86+
this.identityService = identityService;
87+
}
88+
89+
@Override
90+
public boolean validate(UserIdentity user) {
91+
logger.atInfo().log("validate(%s) throwing UnsupportedOperationException.", user);
92+
throw new UnsupportedOperationException();
93+
}
94+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2021 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.apphosting.runtime.jetty;
18+
19+
import com.google.appengine.api.users.User;
20+
import java.security.Principal;
21+
22+
/**
23+
* {@code AppEnginePrincipal} is an implementation of {@link Principal} that represents a logged-in
24+
* Google App Engine user.
25+
*/
26+
public final class AppEnginePrincipal implements Principal {
27+
private final User user;
28+
29+
AppEnginePrincipal(User user) {
30+
this.user = user;
31+
}
32+
33+
public User getUser() {
34+
return user;
35+
}
36+
37+
@Override
38+
public String getName() {
39+
if ((user.getFederatedIdentity() != null) && !user.getFederatedIdentity().isEmpty()) {
40+
return user.getFederatedIdentity();
41+
}
42+
return user.getEmail();
43+
}
44+
45+
@Override
46+
public boolean equals(Object other) {
47+
if (other instanceof AppEnginePrincipal appEnginePrincipal) {
48+
return user.equals(appEnginePrincipal.user);
49+
} else {
50+
return false;
51+
}
52+
}
53+
54+
@Override
55+
public String toString() {
56+
return user.toString();
57+
}
58+
59+
@Override
60+
public int hashCode() {
61+
return user.hashCode();
62+
}
63+
}

0 commit comments

Comments
 (0)