2 * //******************************************************************
4 * // Copyright 2016 Samsung Electronics All Rights Reserved.
6 * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
8 * // Licensed under the Apache License, Version 2.0 (the "License");
9 * // you may not use this file except in compliance with the License.
10 * // You may obtain a copy of the License at
12 * // http://www.apache.org/licenses/LICENSE-2.0
14 * // Unless required by applicable law or agreed to in writing, software
15 * // distributed under the License is distributed on an "AS IS" BASIS,
16 * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * // See the License for the specific language governing permissions and
18 * // limitations under the License.
20 * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
22 package org.iotivity.cloud.accountserver.resources.account;
24 import java.io.IOException;
25 import java.nio.file.Files;
26 import java.nio.file.Path;
27 import java.nio.file.Paths;
28 import java.text.DateFormat;
29 import java.text.ParseException;
30 import java.text.SimpleDateFormat;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Date;
34 import java.util.HashMap;
35 import java.util.HashSet;
36 import java.util.UUID;
38 import org.iotivity.cloud.accountserver.Constants;
39 import org.iotivity.cloud.accountserver.db.AccountDBManager;
40 import org.iotivity.cloud.accountserver.db.TokenTable;
41 import org.iotivity.cloud.accountserver.db.UserTable;
42 import org.iotivity.cloud.accountserver.oauth.OAuthProviderFactory;
43 import org.iotivity.cloud.accountserver.resources.acl.group.GroupResource;
44 import org.iotivity.cloud.accountserver.util.TypeCastingManager;
45 import org.iotivity.cloud.base.exception.ServerException.BadRequestException;
46 import org.iotivity.cloud.base.exception.ServerException.InternalServerErrorException;
47 import org.iotivity.cloud.base.exception.ServerException.NotFoundException;
48 import org.iotivity.cloud.base.exception.ServerException.UnAuthorizedException;
49 import org.iotivity.cloud.util.Log;
53 * This class provides a set of APIs to handle requests about account
54 * information of authorized user.
57 public class AccountManager {
59 private OAuthProviderFactory mFactory = null;
60 private TypeCastingManager<UserTable> mUserTableCastingManager = new TypeCastingManager<>();
61 private TypeCastingManager<TokenTable> mTokenTableCastingManager = new TypeCastingManager<>();
63 public HashMap<String, Object> signUp(String did, String authCode,
64 String authProvider, Object options) {
67 authProvider = checkAuthProviderName(authProvider);
68 res = loadAuthProviderLibrary(authProvider);
71 throw new InternalServerErrorException(
72 authProvider + " library is not loaded");
74 String userUuid = null;
76 TokenTable tokenInfo = requestAccessToken(authCode, options);
77 tokenInfo.setDid(did);
78 tokenInfo.setProvider(authProvider);
79 Date currentTime = new Date();
80 DateFormat transFormat = new SimpleDateFormat("yyyyMMddkkmm");
81 tokenInfo.setIssuedtime(transFormat.format(currentTime));
84 UserTable userInfo = requestUserInfo(tokenInfo.getAccesstoken(),
86 userInfo.setProvider(authProvider);
89 userUuid = findUuid(userInfo.getUserid(), authProvider);
91 storeUserTokenInfo(userUuid, userInfo, tokenInfo, did);
94 HashMap<String, Object> response = makeSignUpResponse(tokenInfo);
99 private void storeUserTokenInfo(String userUuid, UserTable userInfo,
100 TokenTable tokenInfo, String did) {
102 if (userUuid == null) {
103 userUuid = generateUuid();
104 userInfo.setUuid(userUuid);
106 AccountDBManager.getInstance().insertRecord(Constants.USER_TABLE,
107 castUserTableToMap(userInfo));
109 // make my private group
110 GroupResource.getInstance().createGroup(userInfo.getUuid(),
111 Constants.REQ_GTYPE_PRIVATE);
113 // add my device to private group
114 GroupResource.getInstance().getGroup(userUuid)
115 .addDevice(new HashSet<String>(Arrays.asList(did)));
116 tokenInfo.setUuid(userUuid);
117 AccountDBManager.getInstance().insertAndReplaceRecord(
118 Constants.TOKEN_TABLE, castTokenTableToMap(tokenInfo));
121 private String checkAuthProviderName(String authProvider) {
123 String authProviderName = null;
125 if (authProvider.equalsIgnoreCase(Constants.GITHUB)) {
126 authProviderName = Constants.GITHUB;
127 } else if (authProvider.equalsIgnoreCase(Constants.SAMSUNG)) {
128 authProviderName = Constants.SAMSUNG;
129 } else if (authProvider.equalsIgnoreCase(Constants.GOOGLE))
130 authProviderName = Constants.GOOGLE;
132 Log.w("Unsupported oauth provider : " + authProvider);
135 return authProviderName;
138 private String findUuid(String userId, String authProvider) {
141 HashMap<String, Object> condition = new HashMap<>();
142 condition.put(Constants.KEYFIELD_USERID, userId);
144 ArrayList<HashMap<String, Object>> recordList = AccountDBManager
145 .getInstance().selectRecord(Constants.USER_TABLE, condition);
147 for (HashMap<String, Object> record : recordList) {
148 String foundProvider = record.get(Constants.KEYFIELD_PROVIDER)
150 if (foundProvider != null
151 && foundProvider.equalsIgnoreCase(authProvider)) {
152 return record.get(Constants.KEYFIELD_UUID).toString();
158 private HashMap<String, Object> castUserTableToMap(UserTable userInfo) {
160 return mUserTableCastingManager.convertObjectToMap(userInfo);
163 private HashMap<String, Object> castTokenTableToMap(TokenTable tokenInfo) {
165 return mTokenTableCastingManager.convertObjectToMap(tokenInfo);
168 private TokenTable castMapToTokenTable(HashMap<String, Object> record) {
169 TokenTable tokenInfo = new TokenTable();
170 return mTokenTableCastingManager.convertMaptoObject(record, tokenInfo);
173 private HashMap<String, Object> makeSignUpResponse(TokenTable tokenInfo) {
175 HashMap<String, Object> response = new HashMap<>();
177 response.put(Constants.RESP_ACCESS_TOKEN, tokenInfo.getAccesstoken());
178 response.put(Constants.RESP_REFRESH_TOKEN, tokenInfo.getRefreshtoken());
179 response.put(Constants.RESP_TOKEN_TYPE, Constants.TOKEN_TYPE_BEARER);
180 response.put(Constants.RESP_EXPIRES_IN, tokenInfo.getExpiredtime());
181 response.put(Constants.RESP_UUID, tokenInfo.getUuid());
183 // It will be modified.
184 response.put(Constants.RESP_REDIRECT_URI, getRegionCIUrl());
185 response.put(Constants.RESP_CERTIFICATE, getRootCert());
186 response.put(Constants.RESP_SERVER_ID, Constants.CLOUD_UUID);
191 private String getRegionCIUrl() {
193 // TODO: add region management
194 return "coap+tcp://127.0.0.1:5683";
197 private byte[] getRootCert() {
199 byte[] byteRootCert = null;
201 Path path = Paths.get(Constants.ROOT_CERT_FILE);
205 byteRootCert = Files.readAllBytes(path);
207 } catch (IOException e) {
210 // throw new InternalServerErrorException(
211 // "root cert file read failed!");
217 private Boolean loadAuthProviderLibrary(String authProvider) {
218 mFactory = new OAuthProviderFactory();
220 return mFactory.load(authProvider);
223 private TokenTable requestAccessToken(String authCode, Object options) {
224 TokenTable tokenInfo = mFactory.requestAccessTokenInfo(authCode,
226 Log.d("access token : " + tokenInfo.getAccesstoken());
227 Log.d("refresh token : " + tokenInfo.getRefreshtoken());
228 Log.d("expired time : " + tokenInfo.getExpiredtime());
233 private UserTable requestUserInfo(String accessToken, Object options) {
234 UserTable userInfo = mFactory.requestGetUserInfo(accessToken, options);
235 Log.d("user id : " + userInfo.getUserid());
240 private String generateUuid() {
241 UUID uuid = UUID.randomUUID();
242 String userUuid = uuid.toString();
243 Log.d("generated uuid : " + userUuid);
247 public HashMap<String, Object> signInOut(String uuid, String did,
248 String accessToken) {
250 // find record about uuid and did
251 HashMap<String, Object> condition = new HashMap<>();
252 condition.put(Constants.KEYFIELD_UUID, uuid);
254 ArrayList<HashMap<String, Object>> recordList = findRecord(
255 AccountDBManager.getInstance()
256 .selectRecord(Constants.TOKEN_TABLE, condition),
257 Constants.KEYFIELD_DID, did);
259 if (recordList.isEmpty()) {
260 throw new UnAuthorizedException("access token doesn't exist");
263 HashMap<String, Object> record = recordList.get(0);
265 TokenTable tokenInfo = castMapToTokenTable(record);
267 if (verifyToken(tokenInfo, accessToken)) {
268 long remainedSeconds = getRemainedSeconds(
269 tokenInfo.getExpiredtime(), tokenInfo.getIssuedtime());
271 return makeSignInResponse(remainedSeconds);
273 throw new UnAuthorizedException("AccessToken is unauthorized");
277 private ArrayList<HashMap<String, Object>> findRecord(
278 ArrayList<HashMap<String, Object>> recordList, String fieldName,
280 ArrayList<HashMap<String, Object>> foundRecord = new ArrayList<>();
282 for (HashMap<String, Object> record : recordList) {
283 Object obj = record.get(fieldName);
284 if (obj != null && obj.equals(value)) {
285 foundRecord.add(record);
291 private HashMap<String, Object> makeSignInResponse(long remainedSeconds) {
292 HashMap<String, Object> response = new HashMap<>();
293 response.put(Constants.RESP_EXPIRES_IN, remainedSeconds);
298 private long getRemainedSeconds(long expiredTime, String issuedTime) {
299 if (expiredTime == Constants.TOKEN_INFINITE) {
300 return Constants.TOKEN_INFINITE;
302 return expiredTime - getElaspedSeconds(issuedTime);
306 private boolean verifyToken(TokenTable tokenInfo, String accessToken) {
308 if (!checkAccessTokenInDB(tokenInfo, accessToken)) {
312 if (tokenInfo.getExpiredtime() != Constants.TOKEN_INFINITE
313 && !checkExpiredTime(tokenInfo)) {
320 private boolean checkRefreshTokenInDB(TokenTable tokenInfo, String token) {
321 if (tokenInfo.getRefreshtoken() == null) {
322 Log.w("Refreshtoken doesn't exist");
324 } else if (!tokenInfo.getRefreshtoken().equals(token)) {
325 Log.w("Refreshtoken is not correct");
331 private boolean checkAccessTokenInDB(TokenTable tokenInfo, String token) {
332 if (tokenInfo.getAccesstoken() == null) {
333 Log.w("AccessToken doesn't exist");
335 } else if (!tokenInfo.getAccesstoken().equals(token)) {
336 Log.w("AccessToken is not correct");
342 private boolean checkExpiredTime(TokenTable tokenInfo) {
344 String issuedTime = tokenInfo.getIssuedtime();
345 long expiredTime = tokenInfo.getExpiredtime();
347 long remainTime = getElaspedSeconds(issuedTime);
349 if (remainTime > expiredTime) {
350 Log.w("access token is expired");
356 private long getElaspedSeconds(String issuedTime) {
358 DateFormat format = new SimpleDateFormat("yyyyMMddkkmm");
359 Date currentTime = new Date();
360 Date issuedTimeDate = null;
363 issuedTimeDate = format.parse(issuedTime);
364 } catch (ParseException e) {
368 long difference = currentTime.getTime() - issuedTimeDate.getTime();
369 long elaspedSeconds = difference / 1000;
370 Log.d("accessToken elasped time: " + elaspedSeconds + "s");
372 return elaspedSeconds;
375 public HashMap<String, Object> refreshToken(String uuid, String did,
376 String grantType, String refreshToken) {
378 // find record about uuid and did
379 HashMap<String, Object> condition = new HashMap<>();
380 condition.put(Constants.KEYFIELD_UUID, uuid);
381 condition.put(Constants.KEYFIELD_DID, did);
383 ArrayList<HashMap<String, Object>> recordList = findRecord(
384 AccountDBManager.getInstance()
385 .selectRecord(Constants.TOKEN_TABLE, condition),
386 Constants.KEYFIELD_DID, did);
388 if (recordList.isEmpty()) {
389 throw new NotFoundException("refresh token doesn't exist");
392 HashMap<String, Object> record = recordList.get(0);
394 TokenTable oldTokenInfo = castMapToTokenTable(record);
395 String provider = oldTokenInfo.getProvider();
397 if (!checkRefreshTokenInDB(oldTokenInfo, refreshToken)) {
398 throw new NotFoundException("refresh token is not correct");
400 // call 3rd party refresh token method
401 TokenTable newTokenInfo = requestRefreshToken(refreshToken, provider);
404 oldTokenInfo.setAccesstoken(newTokenInfo.getAccesstoken());
405 oldTokenInfo.setRefreshtoken(newTokenInfo.getRefreshtoken());
408 AccountDBManager.getInstance().insertAndReplaceRecord(
409 Constants.TOKEN_TABLE, castTokenTableToMap(oldTokenInfo));
412 HashMap<String, Object> response = makeRefreshTokenResponse(
418 private HashMap<String, Object> makeRefreshTokenResponse(
419 TokenTable tokenInfo) {
420 HashMap<String, Object> response = new HashMap<>();
421 response.put(Constants.RESP_ACCESS_TOKEN, tokenInfo.getAccesstoken());
422 response.put(Constants.RESP_REFRESH_TOKEN, tokenInfo.getRefreshtoken());
423 response.put(Constants.RESP_TOKEN_TYPE, Constants.TOKEN_TYPE_BEARER);
424 response.put(Constants.RESP_EXPIRES_IN, tokenInfo.getExpiredtime());
429 private TokenTable requestRefreshToken(String refreshToken,
432 if (mFactory == null) {
435 String authProvider = checkAuthProviderName(provider);
436 res = loadAuthProviderLibrary(authProvider);
439 throw new InternalServerErrorException(
440 authProvider + " library is not loaded");
444 TokenTable tokenInfo = mFactory.requestRefreshTokenInfo(refreshToken);
446 Log.d("access token : " + tokenInfo.getAccesstoken());
447 Log.d("refresh token : " + tokenInfo.getRefreshtoken());
448 Log.d("expired time : " + tokenInfo.getExpiredtime());
453 public HashMap<String, Object> searchUserAboutUuid(String uuid) {
454 // search user info about uuid
455 HashMap<String, Object> condition = new HashMap<>();
456 condition.put(Constants.KEYFIELD_UUID, uuid);
458 ArrayList<HashMap<String, Object>> recordList = AccountDBManager
459 .getInstance().selectRecord(Constants.USER_TABLE, condition);
460 HashMap<String, Object> response = makeSearchUserResponse(recordList);
465 private HashMap<String, Object> makeSearchUserResponse(
466 ArrayList<HashMap<String, Object>> recordList) {
467 HashMap<String, Object> response = new HashMap<>();
468 ArrayList<HashMap<String, Object>> ulist = new ArrayList<>();
470 for (HashMap<String, Object> record : recordList) {
471 HashMap<String, Object> uInfo = new HashMap<>();
472 String uid = record.get(Constants.KEYFIELD_UUID).toString();
473 uInfo.put(Constants.RESP_UUID, uid);
474 record.remove(Constants.KEYFIELD_UUID);
475 uInfo.put(Constants.RESP_USER_INFO, record);
479 response.put(Constants.RESP_USER_LIST, ulist);
480 Log.d("User List " + response.toString());
485 // TODO: It will be changed
486 public HashMap<String, Object> searchUserAboutCriteria(String criteria) {
488 String[] searchType = getSearchType(criteria);
490 // search user info about criteria
491 HashMap<String, Object> condition = new HashMap<>();
492 condition.put(searchType[0], searchType[1]);
494 ArrayList<HashMap<String, Object>> recordList = AccountDBManager
495 .getInstance().selectRecord(Constants.USER_TABLE, condition);
496 HashMap<String, Object> response = makeSearchUserResponse(recordList);
500 // TODO: It will be changed
501 private String[] getSearchType(String criteria) {
502 String[] searchType = criteria.split(":");
503 String searchKey = searchType[0];
504 String searchValue = searchType[1];
506 if (searchKey == null || searchValue == null) {
507 throw new BadRequestException("search key or value is null");
513 public void deleteDevice(String uid, String di) {
515 HashSet<String> diSet = new HashSet<String>();
518 // the group that gid is uid is my group.
519 GroupResource.getInstance().removeGroupDevice(uid, diSet);