added access token to QR code

Change-Id: I9fb1f44c8e21da4a30df9ce78dd75519c49a5476
This commit is contained in:
Axel Uhl committed 2016-03-02 12:49:51 +01:00
1 parent 4e72f2ff99
commit 1bc8300210
14 files changed
+139 -40

No files matched your search

@@ -1,37 +1,75 @@
package com.sap.sailing.domain.common.impl;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Map;
import java.util.logging.Logger;
import com.sap.sse.common.Util;
import com.google.gwt.dev.util.collect.HashMap;
/**
* This class is used by our backend, in GWT-client code and by the Android app. Therefore we cannot use classes like
* {@link URLEncoder} to help us with the encoding.
*/
public class DeviceConfigurationQRCodeUtils {
public static final String fragmentKey = "identifier";
public static String composeQRContent(String deviceIdentifier, String apkUrl) {
// poor man's uri fragment encoding: ' ' as '%20'
String encodedIdentifier = deviceIdentifier.replaceAll(" ", "%20");
return apkUrl + "#" + fragmentKey + "=" + encodedIdentifier;
private static final Logger logger = Logger.getLogger(DeviceConfigurationQRCodeUtils.class.getName());
public static final String deviceIdentifierKey = "identifier";
public static final String accessTokenKey = "token";
public static class DeviceConfigurationDetails {
private final String apkUrl;
private final String deviceIdentifier;
private final String accessToken;
public DeviceConfigurationDetails(String apkUrl, String deviceIdentifier, String accessToken) {
super();
this.apkUrl = apkUrl;
this.deviceIdentifier = deviceIdentifier;
this.accessToken = accessToken;
}
public String getApkUrl() {
return apkUrl;
}
public String getDeviceIdentifier() {
return deviceIdentifier;
}
public String getAccessToken() {
return accessToken;
}
}
public static Util.Pair<String, String> splitQRContent(String qrCodeContent) {
public static String composeQRContent(String deviceIdentifier, String apkUrl, String accessToken) {
// poor man's uri fragment encoding: ' ' as '%20'
String encodedIdentifier = deviceIdentifier.replaceAll(" ", "%20");
return apkUrl + "#" + deviceIdentifierKey + "=" + encodedIdentifier+"?"+accessTokenKey + "=" + accessToken;
}
public static DeviceConfigurationDetails splitQRContent(String qrCodeContent) {
int fragmentIndex = qrCodeContent.lastIndexOf('#');
if (fragmentIndex == -1 || fragmentIndex == 0 || qrCodeContent.length() == fragmentIndex + 1) {
throw new IllegalArgumentException("There is no server or identifier.");
}
String deviceIdentifier = qrCodeContent.substring(fragmentIndex + 1, qrCodeContent.length());
if (!deviceIdentifier.startsWith(fragmentKey + "=")) {
String fragment = qrCodeContent.substring(fragmentIndex + 1, qrCodeContent.length());
final String[] params = fragment.split("&");
final Map<String, String> paramMap = new HashMap<>();
for (String param : params) {
final String[] keyValue = param.split("=");
if (keyValue.length == 2) {
try {
paramMap.put(keyValue[0], URLDecoder.decode(keyValue[1], "UTF-8"));
} catch (UnsupportedEncodingException e) {
logger.severe("Internal error: Unknown encoding "+e.getMessage());
}
}
}
if (!fragment.startsWith(deviceIdentifierKey + "=")) {
throw new IllegalArgumentException("The identifier is malformed");
}
deviceIdentifier = deviceIdentifier.substring((fragmentKey + "=").length());
deviceIdentifier = deviceIdentifier.replaceAll("%20", " ");
fragment = fragment.substring((deviceIdentifierKey + "=").length());
fragment = fragment.replaceAll("%20", " ");
String apkUrl = qrCodeContent.substring(0, fragmentIndex);
return new Util.Pair<String, String>(deviceIdentifier, apkUrl);
return new DeviceConfigurationDetails(apkUrl, paramMap.get(deviceIdentifierKey), paramMap.get(accessTokenKey));
}
}
@@ -156,7 +156,7 @@ public class AdminConsoleEntryPoint extends AbstractSailingEntryPoint implements
final TabLayoutPanel raceCommitteeTabPanel = panel.addVerticalTab(getStringMessages().raceCommitteeApp(), "RaceCommiteeAppPanel");
final DeviceConfigurationUserPanel deviceConfigurationUserPanel = new DeviceConfigurationUserPanel(sailingService,
getStringMessages(), this);
getUserService(), getStringMessages(), this);
panel.addToTabPanel(raceCommitteeTabPanel, new DefaultRefreshableAdminConsolePanel<DeviceConfigurationUserPanel>(deviceConfigurationUserPanel),
getStringMessages().deviceConfiguration(), Permission.MANAGE_DEVICE_CONFIGURATION);
@@ -14,24 +14,23 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
public class DeviceConfigurationQRIdentifierDialog extends DialogBox {
public static final String rcAppApkPath = "/apps/com.sap.sailing.racecommittee.app.apk";
private static final int qrCodeSize = 320;
private static final int qrCodeSize = 320;
private class DeviceConfigurationQRIdentifierWidget extends BaseQRIdentifierWidget {
private final TextBox identifierBox;
private StringMessages stringMessages;
public DeviceConfigurationQRIdentifierWidget(String identifier, StringMessages stringMessages) {
private final StringMessages stringMessages;
private final String accessToken;
public DeviceConfigurationQRIdentifierWidget(String identifier, String accessToken, StringMessages stringMessages) {
super(qrCodeSize, stringMessages);
this.accessToken = accessToken;
identifierBox = new TextBox();
identifierBox.setValue(identifier);
identifierBox.setReadOnly(true);
identifierBox.setVisibleLength(40);
inputGrid.resize(2, 2);
inputGrid.setWidget(1, 0, new Label("Identifier:"));
inputGrid.setWidget(1, 1, identifierBox);
this.stringMessages = stringMessages;
}
@@ -41,7 +40,7 @@ public class DeviceConfigurationQRIdentifierDialog extends DialogBox {
Window.alert(stringMessages.notCapableOfGeneratingACodeForIdentifier());
} else if (!identifierBox.getValue().isEmpty() && !serverBox.getValue().isEmpty()) {
String apkUrl = getServerUrlWithoutFinalSlash() + rcAppApkPath;
return DeviceConfigurationQRCodeUtils.composeQRContent(identifierBox.getValue(), apkUrl);
return DeviceConfigurationQRCodeUtils.composeQRContent(identifierBox.getValue(), apkUrl, accessToken);
}
return null;
}
@@ -49,8 +48,8 @@ public class DeviceConfigurationQRIdentifierDialog extends DialogBox {
private final DeviceConfigurationQRIdentifierWidget widget;
public DeviceConfigurationQRIdentifierDialog(String identifier, StringMessages stringMessages) {
widget = new DeviceConfigurationQRIdentifierWidget(identifier, stringMessages);
public DeviceConfigurationQRIdentifierDialog(String identifier, StringMessages stringMessages, String accessToken) {
widget = new DeviceConfigurationQRIdentifierWidget(identifier, accessToken, stringMessages);
Button exitButton = new Button(stringMessages.close());
exitButton.addClickHandler(new ClickHandler() {
@Override
@@ -3,6 +3,7 @@ package com.sap.sailing.gwt.ui.adminconsole;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.Grid;
@@ -10,12 +11,18 @@ import com.google.gwt.user.client.ui.HorizontalPanel;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.async.MarkedAsyncCallback;
import com.sap.sse.security.ui.client.UserService;
import com.sap.sse.security.ui.shared.UserDTO;
public class DeviceConfigurationUserDetailComposite extends DeviceConfigurationDetailComposite {
public DeviceConfigurationUserDetailComposite(SailingServiceAsync sailingService, ErrorReporter errorReporter,
StringMessages stringMessages, DeviceConfigurationCloneListener listener) {
private final UserService userService;
public DeviceConfigurationUserDetailComposite(SailingServiceAsync sailingService, UserService userService,
ErrorReporter errorReporter, StringMessages stringMessages, DeviceConfigurationCloneListener listener) {
super(sailingService, errorReporter, stringMessages, listener);
this.userService = userService;
}
protected void setupIdentifier(Grid grid, int gridRow) {
@@ -24,20 +31,40 @@ public class DeviceConfigurationUserDetailComposite extends DeviceConfigurationD
HorizontalPanel panel = new HorizontalPanel();
panel.add(identifierBox);
Button qrCodeButton = new Button("QR-Sync");
Button qrCodeButton = new Button(stringMessages.qrSync());
qrCodeButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
if (identifierBox.getValue() == null || identifierBox.getValue().isEmpty()) {
Window.alert("There is no identifier set.");
Window.alert(stringMessages.thereIsNoIdentifierSet());
} else {
DialogBox dialog = new DeviceConfigurationQRIdentifierDialog(identifierBox.getValue(), stringMessages);
dialog.show();
dialog.center();
UserDTO currentUser = userService.getCurrentUser();
if (currentUser == null) {
createAndShowDialogForAccessToken(/* accessToken */ null);
} else {
userService.getUserManagementService().getAccessToken(currentUser.getName(),
new MarkedAsyncCallback<>(new AsyncCallback<String>() {
@Override
public void onFailure(Throwable caught) {
errorReporter.reportError(stringMessages.couldNotObtainAccessTokenForUser(caught.getMessage()), /* silentMode */ true);
}
@Override
public void onSuccess(String accessToken) {
createAndShowDialogForAccessToken(accessToken);
}
}));
}
}
}
});
panel.add(qrCodeButton);
grid.setWidget(gridRow, 1, panel);
}
private void createAndShowDialogForAccessToken(String accessToken) {
final DialogBox dialog = new DeviceConfigurationQRIdentifierDialog(identifierBox.getValue(), stringMessages, accessToken);
dialog.show();
dialog.center();
}
}
@@ -8,12 +8,16 @@ import com.sap.sse.gwt.client.ErrorReporter;
import com.sap.sse.gwt.client.dialog.DataEntryDialog;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
import com.sap.sse.gwt.client.dialog.DataEntryDialog.Validator;
import com.sap.sse.security.ui.client.UserService;
public class DeviceConfigurationUserPanel extends DeviceConfigurationPanel {
public DeviceConfigurationUserPanel(SailingServiceAsync sailingService, StringMessages stringMessages,
ErrorReporter reporter) {
private final UserService userService;
public DeviceConfigurationUserPanel(SailingServiceAsync sailingService, UserService userService,
StringMessages stringMessages, ErrorReporter reporter) {
super(sailingService, stringMessages, reporter);
this.userService = userService;
}
@Override
@@ -25,7 +29,7 @@ public class DeviceConfigurationUserPanel extends DeviceConfigurationPanel {
@Override
protected DeviceConfigurationDetailComposite createDetailComposite(SailingServiceAsync sailingService,
ErrorReporter errorReporter, StringMessages stringMessages, DeviceConfigurationCloneListener cloneListener) {
return new DeviceConfigurationUserDetailComposite(sailingService, errorReporter, stringMessages, cloneListener);
return new DeviceConfigurationUserDetailComposite(sailingService, userService, errorReporter, stringMessages, cloneListener);
}
@Override
@@ -1484,4 +1484,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages, c
String failedToLinkLeaderboardToLeaderboardGroup(String leaderboardName, String leaderboardGroupName);
String defaultLocale();
String defaultSailorsInfoLinkInfoText();
String qrSync();
String thereIsNoIdentifierSet();
String couldNotObtainAccessTokenForUser(String message);
}
@@ -1452,3 +1452,6 @@ doYouWantToLinkLeaderboardToLeaderboardGroupOfEvent=Link leaderboard {0} to a le
failedToLinkLeaderboardToLeaderboardGroup=Failed to link leaderboard {0} to leaderboard group {1}
defaultLocale=Default
defaultSailorsInfoLinkInfoText=The default link is used unless a language specific overwrite exists. If no default exists, there will be no link for languages that do not explicitly have one set.
qrSync=QR-Sync
thereIsNoIdentifierSet=There is no identifier set.
couldNotObtainAccessTokenForUser=Could not obtain access token for user {0}
@@ -1442,3 +1442,6 @@ doYouWantToLinkLeaderboardToLeaderboardGroupOfEvent=Ergebnisliste {0} zu einer R
failedToLinkLeaderboardToLeaderboardGroup=Ergebnisliste {0} konnte nicht in Ranglisten-Gruppe {1} eingefügt werden
defaultLocale=Standard
defaultSailorsInfoLinkInfoText=Der Standardwert wird verwendet, sofern kein Sprach-abhängiger Selglerinfo-Link hinterlegt wurde. Wenn kein Standardwert angegeben ist, so erscheint kein Selgerinfo-Link bei Sprachen, welche keinen Sprach-spezifischen Link definiert haben.
qrSync=QR-Sync
thereIsNoIdentifierSet=Es ist noch keine Kennung gesetzt.
couldNotObtainAccessTokenForUser=Zugangscode für Benutzer {0} konnte nicht bezogen werden
@@ -1374,3 +1374,6 @@ doYouWantToLinkLeaderboardToLeaderboardGroupOfEvent=Link leaderboard {0} to a le
failedToLinkLeaderboardToLeaderboardGroup=Failed to link leaderboard {0} to leaderboard group {1}
defaultLocale=Default
defaultSailorsInfoLinkInfoText=The default link is used unless a language specific overwrite exists. If no default exists, there will be no link for languages that do not explicitly have one set.
qrSync=QR-Sync
thereIsNoIdentifierSet=There is no identifier set.
couldNotObtainAccessTokenForUser=Could not obtain access token for user {0}
@@ -1389,3 +1389,6 @@ doYouWantToLinkLeaderboardToLeaderboardGroupOfEvent=Link leaderboard {0} to a le
failedToLinkLeaderboardToLeaderboardGroup=Failed to link leaderboard {0} to leaderboard group {1}
defaultLocale=Default
defaultSailorsInfoLinkInfoText=The default link is used unless a language specific overwrite exists. If no default exists, there will be no link for languages that do not explicitly have one set.
qrSync=QR-Sync
thereIsNoIdentifierSet=There is no identifier set.
couldNotObtainAccessTokenForUser=Could not obtain access token for user {0}
@@ -73,6 +73,8 @@ public interface UserManagementService extends RemoteService {
*/
String getPreference(String username, String key);
String getAccessToken(String username);
// ------------------------------------------------ OAuth Interface --------------------------------------------------------------
public String getAuthorizationUrl(CredentialDTO credential) throws OAuthException;
@@ -4,6 +4,7 @@ import java.util.Collection;
import java.util.Map;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.sap.sse.security.shared.DefaultRoles;
import com.sap.sse.security.ui.oauth.client.CredentialDTO;
import com.sap.sse.security.ui.shared.SuccessInfo;
import com.sap.sse.security.ui.shared.UserDTO;
@@ -51,6 +52,13 @@ public interface UserManagementServiceAsync {
void getPreference(String username, String key, AsyncCallback<String> callback);
/**
* Obtains an access token for the user specified by {@code username}. The caller needs to
* have role {@link DefaultRoles#ADMIN} or be authorized as the user identified by {@code username}
* in order to be permitted to retrieve the access token.
*/
void getAccessToken(String username, AsyncCallback<String> markedAsyncCallback);
//------------------------------------------------ OAuth Interface ----------------------------------------------------------------------
void getAuthorizationUrl(CredentialDTO credential, AsyncCallback<String> callback);
@@ -433,4 +433,8 @@ public class UserManagementServiceImpl extends RemoteServiceServlet implements U
return getSecurityService().getPreference(username, key);
}
@Override
public String getAccessToken(String username) {
return getSecurityService().getAccessToken(username);
}
}