-
Notifications
You must be signed in to change notification settings - Fork 398
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Store forum token instead of password #6487
Conversation
context.setValue(tokenSetting, tokenInfo.getToken().toCharArray()); | ||
|
||
context.setValue(usernameSetting, usernameField.getText().toCharArray()); | ||
// TODO error reporting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO found
Code Climate has analyzed commit ab9c619 and detected 1 issue on this pull request. Here's the issue category breakdown:
View more on Code Climate. |
...a/games/strategy/engine/framework/startup/ui/posted/game/pbf/ForumPosterEditorViewModel.java
Outdated
Show resolved
Hide resolved
new JPasswordField(credentialToString(passwordSetting::getValue), 20); | ||
new JTextFieldBuilder() | ||
.columns(20) | ||
.text(usernameSetting.getValue().map(String::new).orElse("")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will properly clear any char arrays in the final form as well, even though I'm not sure if actually encrypting everything is that important now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The concept of storing a token is good; I like how this is coming along.
Off-topic, this makes me wonder if we can do the same for email. Handling any form of email password just really worries me. So far there is not much reason to attack TripleA or the players, if you can get someone email then suddenly there is a real financial reward for doing so.
...a/games/strategy/engine/framework/startup/ui/posted/game/pbf/ForumPosterEditorViewModel.java
Outdated
Show resolved
Hide resolved
game-core/src/main/java/games/strategy/engine/posted/game/pbf/NodeBbTokenGenerator.java
Show resolved
Hide resolved
game-core/src/main/java/games/strategy/engine/posted/game/pbf/NodeBbTokenGenerator.java
Show resolved
Hide resolved
game-core/src/main/java/games/strategy/engine/posted/game/pbf/NodeBbTokenGenerator.java
Show resolved
Hide resolved
game-core/src/main/java/games/strategy/engine/posted/game/pbf/NodeBbTokenGenerator.java
Show resolved
Hide resolved
game-core/src/main/java/games/strategy/triplea/settings/SelectionComponentFactory.java
Show resolved
Hide resolved
game-core/src/main/java/games/strategy/triplea/settings/SelectionComponentFactory.java
Show resolved
Hide resolved
game-core/src/main/java/games/strategy/triplea/settings/SelectionComponentFactory.java
Outdated
Show resolved
Hide resolved
} | ||
|
||
@Override | ||
public void reset() { | ||
usernameField.setText(credentialToString(usernameSetting::getValue)); | ||
passwordField.setText(credentialToString(passwordSetting::getValue)); | ||
usernameField.setText(usernameSetting.getValue().map(String::new).orElse("")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think username
should be a char[]
, IMO it's just not sensitive enough. Does it make sense changing username
to be a String value before, after or in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes and no.
It would make sense changing it to a normal string, but for usernames that are actually stored already it would fill the username field with a cryptic string for the first time, so we'd have to change the name of the setting to something different.
Regardless I think we should offer a button that performs a "factory reset" on the preferences store so users have a way to clear out settings that might no longer be there at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IF we change datatype of a client setting, we only need to change the name of the setting. Having something clear out old settings would be nice, but I think certainly nice and not required.
For certain services that offern an API like google, the answer is probably yes, but in general the answer is probably no, because every email provider handles things differently |
This pull request has been automatically marked as stale because it has not had recent activity. We are eager to see this work completed, please update and re-open as soon as possible. |
This pull request has been automatically marked as stale because it has not had recent activity. We are eager to see this work completed, please update and re-open as soon as possible. |
@RoiEXLab any thoughts when you might be able to wrap this up? |
Coding can probably be done in a matter of half an hour or something. If you think you have a good solution for all of those questions I'd be happy to implement them on the weekend or something, but I don't want to spend 2 hours just trying things until I get to a point that somehow works |
IMO setting a long 'dummy' password value is reasonable (ballpark 15~20 characters). I think in the case of saved passwords we are already pre-filling a dummy value in the password field to show that it has been set (so that is not without precedent).
I'm not sure I have enough context to really suggest a solution to this. The 'unregister' is with client settings, or with the forum? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I think this PR should be in a fine spot now.
A couple of questions remain open though: What about dummy passwords, as mentioned above and how important is clearing the char array token if we end up converting it into a String anyways?
For convenience I used the String constructor and toCharArray() everywhere
import org.triplea.java.Postconditions; | ||
import org.triplea.java.StringUtils; | ||
import org.triplea.java.ViewModelListener; | ||
|
||
class ForumPosterEditorViewModel { | ||
private static final int DUMMY_PASSWORD_LENGTH = 4; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We no longer store passwords, so we have to go for something. Thoughts regarding the recent events? @DanVanAtta
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh.. the UX should be changed then probably. Perhaps a button to log in to the forum, clicking that asks for username and password, and once done then the user sees a "credentials saved" label somewhere and are given a button to clear their credentials. When entering in their credentials, that would be a good place to have a checkbox for "clear credentials when the application closes".
This way we never need to enter in a dummy password at all, we don't have to worry about a remember password checkbox, and if the credentials are already entered we don't show needless text fields on the UI.
|
||
private Map<?, ?> queryUserInfo(final CloseableHttpClient client, final String username) | ||
throws IOException { | ||
final String encodedUsername = URLEncoder.encode(username, StandardCharsets.UTF_8); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note this fix for #6737 I added
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@RoiEXLab we should probably put the bug fix to its own PR:
- when this gets squashed, a bug fix being mixed in with a feature update will be somewhat confusing
- the bugfix needs to go out with the next release, which could be as soon as tonight or tomorrow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nice to see a test case for this as well considering it was a bug. Tests are good for preventing future regressions, ensuring bugs are fixed well, and for giving feedback if the code is designed well, which should drive generally better code design (or at least prevent completely ad-hoc and chaotic design).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A quick comment or two for you to work on if you get the time @RoiEXLab
I'll need a few more days and iterations to properly review this.
@@ -41,13 +41,15 @@ | |||
private final JTextField usernameField = new JTextField(); | |||
private final JLabel passwordLabel = new JLabel("Forum Password"); | |||
private final JPasswordField passwordField = new JPasswordField(); | |||
private final JLabel otpLabel = new JLabel("2FA OTP-Code (optional)"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
otp
is not that well known of an acronym. What is it spelled out?
Can we add a help text or box next to this as well to explain what this is for a user? We do want people to use this after all. If we look at the 1.9 PBF menu, we can see that the game explained pretty much all the options quite well. This meant any user could learn how to use PBF, even if it was kinda clunky.
2FA OTP-code is a bit cryptic to even me. I think we'll need to help users a bit more, and/or explain when/why they'd want to use this. I'm a bit curious myself when we would want to use OTP code and not just use passwords.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OTP is short for "One-Time-Password".
This Field is only required for people that have 2FA enabled in the Forum. Up until recently the "write-api" for NodeBB didn't check if 2FA was enabled and just ignored it. Because @panther2 pointed this out I created an issue which lead to a fix. Currently people with 2FA enabled can't use PbF at all and this extra field should fix this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also perhaps worth mentioning: The OTP isn't a replacement for the password, it is a necessary addition
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, that is good context. Do you have a plan for how to convey that information to users? Specifically, what the field is, when it is needed, and if then not already clear - perhaps where to get their OTP when it is needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really, but I think this is a problem that isn't limited to TripleA. How can we explain or even advertise 2FA for users?
For most people this just adds another inconvenient step to the login process, and I'd assume most people already using 2FA know what to look out for, they don't need any extra explanation, they just want a field to enter their newly generated code.
If you have any good explanation, please let me know. I'd also like to know how to explain such an "abstract" concept in such a limited screen space 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To clarify: Obviously we could implement a wall of text, but I bet most people aren't going to read it if it's more than a couple of lines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A help button that says this field is used if "2FA is enabled. That this value can be found in forum settings. Doesn't have to be anything to complicated. Leaving it as 'OTP' though is going to be cryptic.
@@ -63,6 +65,10 @@ | |||
super(new GridBagLayout()); | |||
this.viewModel = viewModel; | |||
viewModel.setView(this); | |||
// If password is already stored we already remember | |||
if (viewModel.isForumPasswordValid()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, view should not be doing logic if it has a view model. The view model should be the one that owns the full logic of when 'rememberPassword' is selected.
Would recommend to fix by moving the logic to view model, EG:
rememberPassword.setSelected(viewModel.isRememberPasswordSelected());
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest this is more like a hack.
If the user already has a token stored, it makes no sense to have "Remember Password" unchecked, which would cause the credentials to be removed on close by default.
On the other hand if no token is stored it "defaults" to the ClientSetting that stores the last state. That's why the code is the way it is.
I think "Remember Password" shouldn't be a client setting at all. The checkbox should be selected by default if and only if the token is already stored and leave it up to the user to alter this behaviour.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 'remember password' is a setting as we are currently supporting passwords, and if you select the box then you want it checked, and if you unselect it then it'll be annoying to have to unselect it every time. Those users are probably very worried about their password and if they forget to unselect the value then they'll be unhappy with the software for allowing the error.
It sounds like if 'remember password' does not apply with tokens then it should be hidden.
Either way, any if
statements should be removed from the view and moved to the model. The view should not know how to compute the UI state, it should ask the model what its appropriate state should be and render that.
import org.snakeyaml.engine.v2.api.LoadSettings; | ||
|
||
@AllArgsConstructor | ||
public class NodeBbTokenGenerator { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could use a javadoc on this class IMO to explain it's general usage and how it works.
@DanVanAtta I added documentation and updated the PR description. Let me know what you think so far. I only had a brief look at #6925 so far but I think most of the few remaining open questions can be dicussed there |
@RoiEXLab I want the URI decode bug fix for 2.1, sooner. To get there we should create a test for it, but to test it we should be extracting the HTTP client portion so that we can get at the logic that needs to be tested. I am thinking we probably should first convert the HTTP client to feign so it's uniform and testable, then do this work. On another front, I also think the completable future portions can be removed as we are simply calling So, if we convert the return value from the http client to be a result and result code, we can remove the completable futures and an exception would be an IOException only (which we would perhaps want reported and/or retried). I digress though, one main point is if we don't convert to Feign now and test now, I don't think we'll do either one ever. |
Here is an overview of what got changed by this pull request: Issues
======
- Added 3
Complexity increasing per file
==============================
- game-core/src/main/java/games/strategy/engine/posted/game/pbf/NodeBbTokenGenerator.java 7
- game-core/src/main/java/games/strategy/engine/framework/startup/ui/posted/game/pbf/ForumPosterEditor.java 1
See the complete overview on Codacy |
final int userId = getUserId(client, username); | ||
return new TokenInfo(getToken(client, userId, password, otp), userId); | ||
} catch (final IOException e) { | ||
throw new RuntimeException("Failed to retrieve login token", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Codacy found an issue: Avoid throwing raw exception types.
try (CloseableHttpClient client = HttpClients.custom().disableCookieManagement().build()) { | ||
deleteToken(client, userId, token); | ||
} catch (final IOException e) { | ||
throw new RuntimeException("Failed to revoke login token", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Codacy found an issue: Avoid throwing raw exception types.
Arrays.withSensitiveArrayAndReturn(() -> forumPostingParameters.username, String::new); | ||
this.password = | ||
Arrays.withSensitiveArrayAndReturn(() -> forumPostingParameters.password, String::new); | ||
this.token = new String(forumPostingParameters.token); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Codacy found an issue: Avoid instantiating String objects; this is usually unnecessary.
Going to merge this now. Explanation can be found in #6925 Ultimate goal is to migrate this to feign to allow for less logic and nicer tests |
This is what I was able to come up with from #6452
This PR is a WIP, but I wanted to hear your thoughts on the UI decisions.
Basically the user never really gets to see the token and we only store the username for display purposes, so the user can tell their settings have some sort of credentials stored.
We also store a uid to be able to properly revoke the token again.
Whenever a user clicks "save" now in engine preferences, we make a request to the proper forum and create a new token. There's no UI mechanism in NodeBB for this outside of the admin panel. Tokens are revoked if
This has 2 benefits:
Open question: How should we implement this on the "on screen"/not-engine-preferences login fields? Same UI like the engine preferences or just a pre-filled token field?
Functional Changes
[] New map or map update
[] New Feature
[x] Feature update or enhancement
[] Feature Removal
[] Code Cleanup or refactor
[] Configuration Change
[] Problem fix:
[] Other:
Testing
I verified basic posting works with this new approach.
Release Note
Feature|Support for 2FA for PbFEnhancement|PbF now stores login tokens instead of passwords
Fix|Usernames with spaces work for PbF