source: josm/trunk/src/org/openstreetmap/josm/gui/JosmUserIdentityManager.java@ 11117

Last change on this file since 11117 was 10217, checked in by Don-vip, 8 years ago

findbugs - SF_SWITCH_NO_DEFAULT + various sonar fixes

  • Property svn:eol-style set to native
File size: 11.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.text.MessageFormat;
7
8import org.openstreetmap.josm.Main;
9import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
10import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
11import org.openstreetmap.josm.data.osm.User;
12import org.openstreetmap.josm.data.osm.UserInfo;
13import org.openstreetmap.josm.data.preferences.StringSetting;
14import org.openstreetmap.josm.gui.preferences.server.OAuthAccessTokenHolder;
15import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
16import org.openstreetmap.josm.io.OnlineResource;
17import org.openstreetmap.josm.io.OsmApi;
18import org.openstreetmap.josm.io.OsmServerUserInfoReader;
19import org.openstreetmap.josm.io.OsmTransferException;
20import org.openstreetmap.josm.io.auth.CredentialsManager;
21import org.openstreetmap.josm.tools.CheckParameterUtil;
22
23/**
24 * JosmUserIdentityManager is a global object which keeps track of what JOSM knows about
25 * the identity of the current user.
26 *
27 * JOSM can be operated anonymously provided the current user never invokes an operation
28 * on the OSM server which required authentication. In this case JOSM neither knows
29 * the user name of the OSM account of the current user nor its unique id. Perhaps the
30 * user doesn't have one.
31 *
32 * If the current user supplies a user name and a password in the JOSM preferences JOSM
33 * can partially identify the user.
34 *
35 * The current user is fully identified if JOSM knows both the user name and the unique
36 * id of the users OSM account. The latter is retrieved from the OSM server with a
37 * <tt>GET /api/0.6/user/details</tt> request, submitted with the user name and password
38 * of the current user.
39 *
40 * The global JosmUserIdentityManager listens to {@link PreferenceChangeEvent}s and keeps track
41 * of what the current JOSM instance knows about the current user. Other subsystems can
42 * let the global JosmUserIdentityManager know in case they fully identify the current user, see
43 * {@link #setFullyIdentified}.
44 *
45 * The information kept by the JosmUserIdentityManager can be used to
46 * <ul>
47 * <li>safely query changesets owned by the current user based on its user id, not on its user name</li>
48 * <li>safely search for objects last touched by the current user based on its user id, not on its user name</li>
49 * </ul>
50 *
51 */
52public final class JosmUserIdentityManager implements PreferenceChangedListener {
53
54 private static JosmUserIdentityManager instance;
55
56 /**
57 * Replies the unique instance of the JOSM user identity manager
58 *
59 * @return the unique instance of the JOSM user identity manager
60 */
61 public static synchronized JosmUserIdentityManager getInstance() {
62 if (instance == null) {
63 instance = new JosmUserIdentityManager();
64 if (OsmApi.isUsingOAuth() && OAuthAccessTokenHolder.getInstance().containsAccessToken() &&
65 !Main.isOffline(OnlineResource.OSM_API)) {
66 try {
67 instance.initFromOAuth();
68 } catch (RuntimeException e) {
69 Main.error(e);
70 // Fall back to preferences if OAuth identification fails for any reason
71 instance.initFromPreferences();
72 }
73 } else {
74 instance.initFromPreferences();
75 }
76 Main.pref.addPreferenceChangeListener(instance);
77 }
78 return instance;
79 }
80
81 private String userName;
82 private UserInfo userInfo;
83 private boolean accessTokenKeyChanged;
84 private boolean accessTokenSecretChanged;
85
86 private JosmUserIdentityManager() {
87 }
88
89 /**
90 * Remembers the fact that the current JOSM user is anonymous.
91 */
92 public void setAnonymous() {
93 userName = null;
94 userInfo = null;
95 }
96
97 /**
98 * Remebers the fact that the current JOSM user is partially identified
99 * by the user name of its OSM account.
100 *
101 * @param userName the user name. Must not be null. Must not be empty (whitespace only).
102 * @throws IllegalArgumentException if userName is null
103 * @throws IllegalArgumentException if userName is empty
104 */
105 public void setPartiallyIdentified(String userName) {
106 CheckParameterUtil.ensureParameterNotNull(userName, "userName");
107 if (userName.trim().isEmpty())
108 throw new IllegalArgumentException(
109 MessageFormat.format("Expected non-empty value for parameter ''{0}'', got ''{1}''", "userName", userName));
110 this.userName = userName;
111 userInfo = null;
112 }
113
114 /**
115 * Remembers the fact that the current JOSM user is fully identified with a
116 * verified pair of user name and user id.
117 *
118 * @param username the user name. Must not be null. Must not be empty.
119 * @param userinfo additional information about the user, retrieved from the OSM server and including the user id
120 * @throws IllegalArgumentException if userName is null
121 * @throws IllegalArgumentException if userName is empty
122 * @throws IllegalArgumentException if userinfo is null
123 */
124 public void setFullyIdentified(String username, UserInfo userinfo) {
125 CheckParameterUtil.ensureParameterNotNull(username, "username");
126 if (username.trim().isEmpty())
127 throw new IllegalArgumentException(tr("Expected non-empty value for parameter ''{0}'', got ''{1}''", "userName", userName));
128 CheckParameterUtil.ensureParameterNotNull(userinfo, "userinfo");
129 this.userName = username;
130 this.userInfo = userinfo;
131 }
132
133 /**
134 * Replies true if the current JOSM user is anonymous.
135 *
136 * @return {@code true} if the current user is anonymous.
137 */
138 public boolean isAnonymous() {
139 return userName == null && userInfo == null;
140 }
141
142 /**
143 * Replies true if the current JOSM user is partially identified.
144 *
145 * @return true if the current JOSM user is partially identified.
146 */
147 public boolean isPartiallyIdentified() {
148 return userName != null && userInfo == null;
149 }
150
151 /**
152 * Replies true if the current JOSM user is fully identified.
153 *
154 * @return true if the current JOSM user is fully identified.
155 */
156 public boolean isFullyIdentified() {
157 return userName != null && userInfo != null;
158 }
159
160 /**
161 * Replies the user name of the current JOSM user. null, if {@link #isAnonymous()} is true.
162 *
163 * @return the user name of the current JOSM user
164 */
165 public String getUserName() {
166 return userName;
167 }
168
169 /**
170 * Replies the user id of the current JOSM user. 0, if {@link #isAnonymous()} or
171 * {@link #isPartiallyIdentified()} is true.
172 *
173 * @return the user id of the current JOSM user
174 */
175 public int getUserId() {
176 if (userInfo == null) return 0;
177 return userInfo.getId();
178 }
179
180 /**
181 * Replies verified additional information about the current user if the user is
182 * {@link #isFullyIdentified()}.
183 *
184 * @return verified additional information about the current user
185 */
186 public UserInfo getUserInfo() {
187 return userInfo;
188 }
189
190 /**
191 * Returns the identity as a {@link User} object
192 *
193 * @return the identity as user, or {@link User#getAnonymous()} if {@link #isAnonymous()}
194 */
195 public User asUser() {
196 return isAnonymous() ? User.getAnonymous() : User.createOsmUser(userInfo != null ? userInfo.getId() : 0, userName);
197 }
198
199 /**
200 * Initializes the user identity manager from Basic Authentication values in the {@link org.openstreetmap.josm.data.Preferences}
201 * This method should be called if {@code osm-server.auth-method} is set to {@code basic}.
202 * @see #initFromOAuth
203 */
204 public void initFromPreferences() {
205 String userName = CredentialsManager.getInstance().getUsername();
206 if (isAnonymous()) {
207 if (userName != null && !userName.trim().isEmpty()) {
208 setPartiallyIdentified(userName);
209 }
210 } else {
211 if (userName != null && !userName.equals(this.userName)) {
212 setPartiallyIdentified(userName);
213 }
214 // else: same name in the preferences as JOSM already knows about.
215 // keep the state, be it partially or fully identified
216 }
217 }
218
219 /**
220 * Initializes the user identity manager from OAuth request of user details.
221 * This method should be called if {@code osm-server.auth-method} is set to {@code oauth}.
222 * @see #initFromPreferences
223 * @since 5434
224 */
225 public void initFromOAuth() {
226 try {
227 UserInfo info = new OsmServerUserInfoReader().fetchUserInfo(NullProgressMonitor.INSTANCE);
228 setFullyIdentified(info.getDisplayName(), info);
229 } catch (IllegalArgumentException | OsmTransferException e) {
230 Main.error(e);
231 }
232 }
233
234 /**
235 * Replies true if the user with name <code>username</code> is the current user
236 *
237 * @param username the user name
238 * @return true if the user with name <code>username</code> is the current user
239 */
240 public boolean isCurrentUser(String username) {
241 return username != null && this.userName != null && this.userName.equals(username);
242 }
243
244 /**
245 * Replies true if the current user is {@link #isFullyIdentified() fully identified} and the {@link #getUserId() user ids} match,
246 * or if the current user is not {@link #isFullyIdentified() fully identified} and the {@link #userName user names} match.
247 *
248 * @param user the user to test
249 * @return true if given user is the current user
250 */
251 public boolean isCurrentUser(User user) {
252 if (user == null) {
253 return false;
254 } else if (isFullyIdentified()) {
255 return getUserId() == user.getId();
256 } else {
257 return isCurrentUser(user.getName());
258 }
259 }
260
261 /* ------------------------------------------------------------------- */
262 /* interface PreferenceChangeListener */
263 /* ------------------------------------------------------------------- */
264 @Override
265 public void preferenceChanged(PreferenceChangeEvent evt) {
266 switch (evt.getKey()) {
267 case "osm-server.username":
268 String newUserName = null;
269 if (evt.getNewValue() instanceof StringSetting) {
270 newUserName = ((StringSetting) evt.getNewValue()).getValue();
271 }
272 if (newUserName == null || newUserName.trim().isEmpty()) {
273 setAnonymous();
274 } else {
275 if (!newUserName.equals(userName)) {
276 setPartiallyIdentified(newUserName);
277 }
278 }
279 return;
280 case "osm-server.url":
281 String newUrl = null;
282 if (evt.getNewValue() instanceof StringSetting) {
283 newUrl = ((StringSetting) evt.getNewValue()).getValue();
284 }
285 if (newUrl == null || newUrl.trim().isEmpty()) {
286 setAnonymous();
287 } else if (isFullyIdentified()) {
288 setPartiallyIdentified(getUserName());
289 }
290 break;
291 case "oauth.access-token.key":
292 accessTokenKeyChanged = true;
293 break;
294 case "oauth.access-token.secret":
295 accessTokenSecretChanged = true;
296 break;
297 default: // Do nothing
298 }
299
300 if (accessTokenKeyChanged && accessTokenSecretChanged) {
301 accessTokenKeyChanged = false;
302 accessTokenSecretChanged = false;
303 if (OsmApi.isUsingOAuth()) {
304 getInstance().initFromOAuth();
305 }
306 }
307 }
308}
Note: See TracBrowser for help on using the repository browser.