/* * Copyright (c) 2019 TOYOTA MOTOR CORPORATION * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package app.market.token.service; import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import app.market.WebServiceConstants; import app.market.model.resource.Resource; import app.market.model.user.User; import app.market.token.dao.RedisGeneratorDao; import app.market.utils.constants.Constants; import app.market.utils.token.TokenModel; import app.market.utils.webservice.WebServiceURI; @Component public class RedisTokenManager extends RedisGeneratorDao { private static Logger logger = LoggerFactory.getLogger( RedisTokenManager.class ); /** * generate token * @param loginId * @param user * @param list * @param isPermanent guestUser not expire * @return */ public TokenModel generateToken(String loginId, User user, List list, boolean isPermanent ) { // user UUID as token String token = UUID.randomUUID().toString().replace( "-", "" ); TokenModel model = new TokenModel( loginId, user, token ); for (Resource res : list) { if ( res.getResType().equals( WebServiceConstants.RESOURSE_TYPE_RES ) ) { model.getResourceList().add( res ); } else if ( res.getResType().equals( WebServiceConstants.RESOURSE_TYPE_API ) ) { model.getApiList().add( res ); } } // save token, set expire time if(isPermanent){ redis.boundValueOps( loginId ).set( model ); }else{ redis.boundValueOps( loginId ).set( model, WebServiceConstants.EXPIRE_TIME_MINUTES, TimeUnit.MINUTES ); } return model; } public String generateRefreshToken(String loginId) { String token = UUID.randomUUID().toString().replace( "-", "" ); redis.boundValueOps( token ).set( loginId, WebServiceConstants.EXPIRE_TIME_HOURS, TimeUnit.HOURS ); return token; } public int checkAuthentication(String authentication, String servletPath, String url, String httpMethod) { int ret = Constants.STATUS_SUCCESS; if(StringUtils.isEmpty(authentication)){ //guest ret = validateAuthentication(authentication, servletPath, url, httpMethod); }else{ ret = validateToken(authentication, servletPath, url, httpMethod); } return ret; } /** * check Authentication when guest * @param authentication * @param servletPath * @param httpMethod * @param url * @return */ private int validateAuthentication(String authentication, String servletPath, String url, String httpMethod) { int ret = Constants.STATUS_FORBIDDEN; String guestId = Constants.GUEST_ID; TokenModel model = null; if (redis.opsForValue().get(guestId) instanceof TokenModel) { model = (TokenModel) redis.opsForValue().get(guestId); } if (model == null) { //ResourceRestController.initGuestResoureList(Constants.GUEST_ID); logger.debug( "validateAuthentication" + this.getClass().getName() + "--method: " + Thread.currentThread().getStackTrace()[1].getMethodName() + "model is null" ); ret = Constants.STATUS_ERROR; } if(checkResoureAuth(model, servletPath, url, httpMethod)) { ret = Constants.STATUS_SUCCESS; }else { ret = Constants.STATUS_FORBIDDEN; } return ret; } /** * check Authentication when not guest * @param authentication * @param servletPath * @param httpMethod * @param url * @return */ private int validateToken(String authentication, String servletPath, String url, String httpMethod) { TokenModel model = getToken( authentication ); if ( model == null ) return Constants.STATUS_UNAUTHORIZED; // Only one account is online as one time if ( !model.getToken().equals( authentication.split( Constants.TOKEN_SEPARATOR )[1] ) ) { return Constants.STATUS_TOO_MANY_CONNECTIONS; } // get cache token TokenModel cacheModel = getCacheModel( model.getLoginId() ); // check cache token if ( cacheModel == null ) return Constants.STATUS_UNAUTHORIZED; String token = cacheModel.getToken(); if ( !token.equals( model.getToken() ) ) return Constants.STATUS_UNAUTHORIZED; if (!checkResoureAuth(cacheModel, servletPath, url, httpMethod)) { return Constants.STATUS_FORBIDDEN; } // check ok, reset expire time redis.boundValueOps( model.getLoginId() ).expire( WebServiceConstants.EXPIRE_TIME_MINUTES, TimeUnit.SECONDS ); return Constants.STATUS_SUCCESS; } /** * * @param list * @param resPath * @return */ private boolean checkResoureAuth(TokenModel model, String resPath, String url, String httpMethod) { boolean ret = false; if (StringUtils.isEmpty(resPath) && !url.contains(WebServiceURI.REST_TOKEN_VALIDATETOKENAUTHORTICATION_LF)) { //URL check int s = url.indexOf(WebServiceConstants.PATTERN_RESOURSE_S); if (s < 0) { return ret; } resPath = url.substring(s + WebServiceConstants.PATTERN_RESOURSE_S.length()-1); if (resPath.endsWith(WebServiceConstants.SEPARATOR)) { resPath = resPath.substring(0, resPath.length() - 1); } int count = (resPath.split(WebServiceConstants.SEPARATOR)).length; List list = model.getApiList(); for (Object obj : list) { Resource r = (Resource) obj; //httpmethod check if (!r.getHttpMethod().equalsIgnoreCase(httpMethod)){ continue; } //url length check if(count != r.getAccessPath().split(WebServiceConstants.SEPARATOR).length) { continue; } String rUrl = r.getAccessPath(); //delete param depart of url int paramS = r.getAccessPath().indexOf(WebServiceConstants.PATTERN_RESOURSE_PARAM_S); if (paramS > 0) { rUrl = r.getAccessPath().substring(0, paramS); } //url check if (resPath.indexOf(rUrl) == 0) { ret = true; break; } } } else if(url.contains(WebServiceURI.REST_TOKEN_VALIDATETOKENAUTHORTICATION_LF)){ // temp code ret = true; } else {//For web selertPath check; List list = model.getResourceList(); for (Object obj : list) { Resource res = (Resource) obj; if (res.getAccessPath().contains(resPath)) { ret = true; break; } } } return ret; } public TokenModel getToken(String authentication) { String loginId =""; if (StringUtils.isEmpty(authentication)) { loginId = Constants.GUEST_ID; } else { String[] param = authentication.split(Constants.TOKEN_SEPARATOR); if (param.length != 2){ return null; } loginId = param[0]; } TokenModel model = null; if (redis.opsForValue().get(loginId) instanceof TokenModel) { model = (TokenModel) redis.opsForValue().get(loginId); } return model; } public TokenModel getCacheModel(String loginId) { try { return (TokenModel) redis.boundValueOps( loginId ).get(); } catch ( Exception e ) { return null; } } public String getRefreshtokenValue(String authentication) { if (StringUtils.isEmpty(authentication)) { return null; } String[] param = authentication.split(Constants.TOKEN_SEPARATOR); if (param.length != 2){ return null; } String loginId = (String) redis.opsForValue().get(param[1]); return loginId; } public void updateTokenInfo(TokenModel model) { redis.boundValueOps( model.getLoginId() ).set( model, WebServiceConstants.EXPIRE_TIME_MINUTES, TimeUnit.MINUTES ); } public void deleteToken(String loginId) { redis.delete( loginId ); } }