// access_token 처리, refresh_token 처리 // grant_type이 password 와 client_credentials 인 경우는 if 문 블럭만 작성하였음. 추후 작성해야 함. @RequestMapping(value = "token") public String accessToken(RequestAccessTokenVO ratVO, Model model, HttpServletRequest request) throws OAuth2Exception { String json = ""; // grant type이 무엇이냐에 따라 각기 다른 처리 // password, client_credential은 미구현.. 추후 구현 요망됨. System.out.println("### token flow 1"); System.out.println("### grant_type : " + ratVO.getGrant_type()); if (ratVO.getGrant_type().equals(OAuth2Constant.GRANT_TYPE_AUTHORIZATION_CODE)) { ResponseAccessTokenVO resVO = accessTokenServerFlow(ratVO, request); json = OAuth2Util.getJSONFromObject(resVO); } else if (ratVO.getGrant_type().equals(OAuth2Constant.GRANT_TYPE_PASSWORD)) { // 차후 구현할 것 throw new OAuth2Exception(500, OAuth2ErrorConstant.UNSUPPORTED_RESPONSE_TYPE); } else if (ratVO.getGrant_type().equals(OAuth2Constant.GRANT_TYPE_CLIENT_CREDENTIALS)) { // 차후 구현할 것 throw new OAuth2Exception(500, OAuth2ErrorConstant.UNSUPPORTED_RESPONSE_TYPE); } else if (ratVO.getGrant_type().equals(OAuth2Constant.GRANT_TYPE_REFRESH_TOKEN)) { // refresh token 사용 여부에 따라 값이 달라짐. if (OAuth2Constant.USE_REFRESH_TOKEN) { ResponseAccessTokenVO resVO = refreshTokenFlow(ratVO, request); json = OAuth2Util.getJSONFromObject(resVO); } else { throw new OAuth2Exception(500, OAuth2ErrorConstant.UNSUPPORTED_RESPONSE_TYPE); } } else { throw new OAuth2Exception(500, OAuth2ErrorConstant.UNSUPPORTED_RESPONSE_TYPE); } model.addAttribute("json", json); return "json/json"; }
// grant_type이 authorization_code일 때 private ResponseAccessTokenVO refreshTokenFlow( RequestAccessTokenVO ratVO, HttpServletRequest request) throws OAuth2Exception { // 1. 전달된 refresh Token과 // GET 방식일 때는 Client ID와 Client Secret은 Authorization Header를 통해 전달되어야 함. if (request.getMethod().equalsIgnoreCase("GET")) { String authHeader = (String) request.getHeader("Authorization"); if (authHeader == null || authHeader.equals("")) { throw new OAuth2Exception(400, OAuth2ErrorConstant.INVALID_PARAMETER); } // Basic 인증 헤더 파싱 OAuth2Util.parseBasicAuthHeader(authHeader, ratVO); } // 2. ClientID, Secret 모두 전달되었는지 여부 --> 존재 여부 확인 if (ratVO.getClient_id() == null || ratVO.getClient_secret() == null) { throw new OAuth2Exception(400, OAuth2ErrorConstant.INVALID_PARAMETER); } // 3. clientID 와 client_secret의 일치여부 ClientVO cVOTemp = new ClientVO(); cVOTemp.setClient_id(ratVO.getClient_id()); ClientVO cVO = null; try { cVO = dao.getClientOne(cVOTemp); } catch (Exception e) { throw new OAuth2Exception(500, OAuth2ErrorConstant.SERVER_ERROR); } if (cVO == null) { throw new OAuth2Exception(500, OAuth2ErrorConstant.UNAUTHORIZED_CLIENT); } if (ratVO.getClient_secret() != null && !cVO.getClient_secret().equals(ratVO.getClient_secret())) { throw new OAuth2Exception(500, OAuth2ErrorConstant.UNAUTHORIZED_CLIENT); } // 4. refresh token의 일치 여부 if (ratVO.getRefresh_token() == null) { throw new OAuth2Exception(400, OAuth2ErrorConstant.INVALID_PARAMETER); } TokenVO tVOTemp = new TokenVO(); tVOTemp.setRefresh_token(ratVO.getRefresh_token()); TokenVO tVO = null; try { tVO = dao.selectRefreshToken(tVOTemp); } catch (Exception e) { e.printStackTrace(); throw new OAuth2Exception(500, OAuth2ErrorConstant.SERVER_ERROR); } if (tVO == null) { throw new OAuth2Exception(400, OAuth2ErrorConstant.INVALID_TOKEN); } // 5. TokenVO의 accessToken 갱신 --> DB 업데이트 --> // --> refreshToken 값 없이 ResponseAccessTokenVO객체 생성 --> JSON 포맷으로 응답 tVO.setAccess_token(OAuth2Util.generateToken()); tVO.setCreated_at(OAuth2Util.getCurrentTimeStamp()); try { dao.updateAccessToken(tVO); } catch (Exception e) { e.printStackTrace(); throw new OAuth2Exception(500, OAuth2ErrorConstant.SERVER_ERROR); } ResponseAccessTokenVO resVO = new ResponseAccessTokenVO( tVO.getAccess_token(), tVO.getToken_type(), tVO.getExpires_in(), null, ratVO.getState(), tVO.getCreated_at()); return resVO; }
// grant_type이 authorization_code일 때 private ResponseAccessTokenVO accessTokenServerFlow( RequestAccessTokenVO ratVO, HttpServletRequest request) throws OAuth2Exception { // GET 방식일 때는 Client ID와 Client Secret은 Authorization Header를 통해 전달되어야 함. System.out.println("### token flow 2"); if (request.getMethod().equalsIgnoreCase("GET")) { String authHeader = (String) request.getHeader("Authorization"); if (authHeader == null || authHeader.equals("")) { throw new OAuth2Exception(400, OAuth2ErrorConstant.INVALID_PARAMETER); } // Basic 인증 헤더 파싱 OAuth2Util.parseBasicAuthHeader(authHeader, ratVO); } // 1. ClientID, Secret 모두 전달되었는지 여부 --> 존재 여부 확인 System.out.println("### token flow 3"); if (ratVO.getClient_id() == null || ratVO.getClient_secret() == null) { throw new OAuth2Exception(400, OAuth2ErrorConstant.INVALID_PARAMETER); } ClientVO cVOTemp = new ClientVO(); cVOTemp.setClient_id(ratVO.getClient_id()); cVOTemp.setClient_secret(ratVO.getClient_secret()); ClientVO cVO = null; try { cVO = dao.getClientOne(cVOTemp); } catch (Exception e) { e.printStackTrace(); throw new OAuth2Exception(500, OAuth2ErrorConstant.SERVER_ERROR); } // 1.2 client 존재 여부 확인 System.out.println("### token flow 4"); if (cVO == null) { throw new OAuth2Exception(401, OAuth2ErrorConstant.UNAUTHORIZED_CLIENT); } // 2. redirect_uri 일치 여부 확인 System.out.println("### token flow 5"); if (!ratVO.getRedirect_uri().equals(cVO.getRedirect_uri())) { throw new OAuth2Exception(400, OAuth2ErrorConstant.NOT_MATCH_REDIRECT_URI); } // 3. code값 일치 여부 확인 System.out.println("### token flow 6"); if (ratVO.getCode() == null) { throw new OAuth2Exception(400, OAuth2ErrorConstant.INVALID_PARAMETER); } TokenVO tVOTemp = new TokenVO(); tVOTemp.setCode(ratVO.getCode()); TokenVO tVO = null; try { tVO = dao.selectTokenByCode(tVOTemp); } catch (Exception e) { e.printStackTrace(); throw new OAuth2Exception(500, OAuth2ErrorConstant.SERVER_ERROR); } if (tVO == null) { throw new OAuth2Exception(400, OAuth2ErrorConstant.INVALID_CODE); } // 4. expire되었는지 여부 확인, refresh token 사용 여부에 따라 결정함. if (OAuth2Constant.USE_REFRESH_TOKEN) { System.out.println("### token flow 7"); long expires = tVO.getCreated_at() + tVO.getExpires_in(); if (System.currentTimeMillis() > expires) { // 토큰 생성되고 한참 뒤에 code로 access token을 요청하는 것은 금지 throw new OAuth2Exception(400, OAuth2ErrorConstant.EXPIRED_TOKEN); } } // 5. 전달받은 state값 그대로 전달(CSRF 공격 방지용) // 6. ResponseAccessToken객체 생성 --> json 포맷 응답 System.out.println("### token flow 9"); ResponseAccessTokenVO resVO = new ResponseAccessTokenVO(); resVO.setIssued_at(tVO.getCreated_at()); resVO.setState(ratVO.getState()); resVO.setToken_type(tVO.getToken_type()); if (OAuth2Constant.USE_REFRESH_TOKEN) { resVO.setAccess_token(tVO.getAccess_token()); resVO.setExpires_in(tVO.getExpires_in()); resVO.setRefresh_token(tVO.getRefresh_token()); } else { // 6.1. password를 확보하기 위해 UserVO 객체 획득 // ResponsToken을 생성하고 나면 token 테이블의 레코드 삭제 UserVO uVOTemp = new UserVO(); uVOTemp.setUserid(tVO.getUserid()); UserVO uVO = null; try { uVO = dao.getUserInfo(uVOTemp); } catch (Exception e) { e.printStackTrace(); throw new OAuth2Exception(500, OAuth2ErrorConstant.SERVER_ERROR); } if (uVO == null) { throw new OAuth2Exception(500, OAuth2ErrorConstant.INVALID_USER); } // token 테이블 레코드 삭제 try { dao.deleteToken(tVO); } catch (Exception e) { e.printStackTrace(); throw new OAuth2Exception(500, OAuth2ErrorConstant.SERVER_ERROR); } resVO.setAccess_token( this.tokenService.generateAccessToken( cVO.getClient_id(), cVO.getClient_secret(), uVO.getUserid(), uVO.getPassword())); } return resVO; }