Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ dependencies {
annotationProcessor 'com.querydsl:querydsl-apt:5.0.0:jakarta'
annotationProcessor 'jakarta.persistence:jakarta.persistence-api:3.1.0'
annotationProcessor 'jakarta.annotation:jakarta.annotation-api:2.1.1'

// mongodb
implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'

Expand All @@ -113,6 +113,9 @@ dependencies {

// S3 SDK
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

//AES 암호화
implementation 'javax.xml.bind:jaxb-api:2.3.1'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.ezcode.codetest.application.usermanagement.user.dto.response;

import java.util.Map;

import io.swagger.v3.oas.annotations.media.Schema;

@Schema(description = "Github OAuth2 응답 처리 클래스")
public class GithubOAuth2Response implements OAuth2Response{
private final Map<String, Object> attributes;

public GithubOAuth2Response(Map<String, Object> attributes) {
this.attributes = attributes;
}

@Override
@Schema(description = "OAuth 제공자 이름", example = "github")
public String getProvider() {
return "github";
}

@Override
@Schema(description = "제공자 내부 식별자", example = "109000123456789012345")
public String getProviderId() {
return attributes.get("id").toString();
}

@Override
@Schema(description = "사용자 이메일", example = "[email protected]")
public String getEmail() {
if (attributes.get("email") == null && getProvider().equals("github")) {
return getGithubId()+"@github.com";
} else {
return (String) attributes.get("email");
}
}

@Override
@Schema(description = "사용자 이름", example = "홍길동")
public String getName() {
return attributes.get("name").toString();
}

@Override
@Schema(description = "Github Id", example = "1345932")
public String getGithubId() {
return attributes.get("id").toString();
}

@Override
@Schema(description = "Github URL", example = "https://github.com/id")
public String getGithubUrl(){
return attributes.get("html_url").toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,15 @@ public String getName() {
return attributes.get("name").toString();
}

@Override
public String getGithubId() {
return "";
}

@Override
public String getGithubUrl() {
return "";
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@ public interface OAuth2Response {

//사용자 이름
String getName();

//깃헙 아이디
String getGithubId();

//깃헙 링크
String getGithubUrl();
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ public class UserService {
private final UserDomainService userDomainService;
private final SubmissionDomainService submissionDomainService;
private final RedisTemplate<String, String> redisTemplate;
private final MailService mailService;

@Transactional(readOnly = true)
public UserInfoResponse getUserInfo(AuthUser authUser) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
.httpBasic(AbstractHttpConfigurer::disable)
.logout(AbstractHttpConfigurer::disable)
.oauth2Login((outh2)-> outh2
.userInfoEndpoint((userInfoEndpointConfig ->
userInfoEndpointConfig.userService(customOAuth2UserService)))
.userInfoEndpoint((userInfo -> userInfo
.userService(customOAuth2UserService)))
.successHandler(customSuccessHandler))

// JWT 사용을 위해 세션을 STATELESS로 설정 (세션 정보 저장 x)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@
import java.util.concurrent.TimeUnit;

import org.ezcode.codetest.application.usermanagement.auth.dto.response.OAuthResponse;
import org.ezcode.codetest.common.security.util.AESUtil;
import org.ezcode.codetest.domain.user.exception.AuthException;
import org.ezcode.codetest.domain.user.exception.code.AuthExceptionCode;
import org.ezcode.codetest.domain.user.model.entity.CustomOAuth2User;
import org.ezcode.codetest.domain.user.model.entity.User;
import org.ezcode.codetest.domain.user.service.UserDomainService;
import org.ezcode.codetest.common.security.util.JwtUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponentsBuilder;

import com.fasterxml.jackson.databind.ObjectMapper;

Expand All @@ -27,14 +34,19 @@ public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler
private final UserDomainService userDomainService;
private final RedisTemplate<String, String> redisTemplate;
private final ObjectMapper objectMapper; //json직렬화
private final OAuth2AuthorizedClientService authorizedClientService;
private final AESUtil aesUtil;

public CustomSuccessHandler(JwtUtil jwtUtil, UserDomainService userDomainService,
RedisTemplate<String, String> redisTemplate, ObjectMapper objectMapper) {
RedisTemplate<String, String> redisTemplate, ObjectMapper objectMapper,
OAuth2AuthorizedClientService authorizedClientService, AESUtil aesUtil) {
this.jwtUtil = jwtUtil;
this.userDomainService = userDomainService;
this.redisTemplate = redisTemplate;
this.objectMapper = objectMapper;
}
this.authorizedClientService = authorizedClientService;
this.aesUtil = aesUtil;
}

@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws
Expand All @@ -43,8 +55,27 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
//OAuth2User
CustomOAuth2User customUserDetails = (CustomOAuth2User) authentication.getPrincipal();

User loginUser = userDomainService.getUserByEmail(customUserDetails.getEmail());
log.info("loginUser: {}", loginUser);
User loginUser= userDomainService.getUserByEmail(customUserDetails.getEmail());
log.info("loginUser Name: {}", loginUser.getUsername());

if (customUserDetails.getProvider().equalsIgnoreCase("github")) {
//깃허브 access-token 가져오기
OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
OAuth2AuthorizedClient client = authorizedClientService.loadAuthorizedClient(
oauthToken.getAuthorizedClientRegistrationId(),
oauthToken.getName()
);

//AES 암호화
try {
String encodedGithubToken = aesUtil.encrypt(client.getAccessToken().getTokenValue());
loginUser.setGithubAccessToken(encodedGithubToken);
} catch (Exception e) {
log.error(e.getMessage());
throw new AuthException(AuthExceptionCode.TOKEN_ENCODE_FAIL);
}
userDomainService.updateUserGithubAccessToken(loginUser);
}

String accessToken = jwtUtil.createAccessToken(
loginUser.getId(),
Expand All @@ -64,14 +95,27 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
refreshToken,
jwtUtil.getExpiration(refreshToken),
TimeUnit.MILLISECONDS);
log.info("레디스에 저장완료");

String redirectUri = (String) request.getSession().getAttribute("redirect_uri");

if (redirectUri == null) {
throw new AuthException(AuthExceptionCode.REDIRECT_URI_NOT_FOUND);
}

request.getSession().removeAttribute("redirect_uri"); // uri 사용 후 제거하기

String targetUri = UriComponentsBuilder.fromUriString(redirectUri)
.queryParam("accessToken", accessToken)
.queryParam("refreshToken", refreshToken)
.build().toUriString();

//JSON 문자열로 바꿔서 클라이언트에게 응답 본문으로 전달
OAuthResponse oAuthResponse = new OAuthResponse(accessToken, refreshToken);

response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(oAuthResponse));
log.info("------------- accessToken : {}, refreshToken : {} ------------", accessToken, refreshToken);
}
// response.sendRedirect(targetUri);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.ezcode.codetest.common.security.util;

import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class AESUtil {

private static final String ALGORITHM = "AES";
@Value("${aes.secret.key}")
private String SECRET_KEY; // 반드시 16, 24, 또는 32바이트

public String encrypt(String input) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encryptedBytes = cipher.doFinal(input.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}
Comment on lines +18 to +24
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

치명적인 보안 취약점: ECB 모드 사용

AES ECB 모드는 보안상 안전하지 않습니다. 같은 평문이 같은 암호문을 생성하므로 패턴 분석이 가능합니다. CBC 또는 GCM 모드를 사용해야 합니다.

-public String encrypt(String input) throws Exception {
-    SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
-    Cipher cipher = Cipher.getInstance(ALGORITHM);
-    cipher.init(Cipher.ENCRYPT_MODE, keySpec);
-    byte[] encryptedBytes = cipher.doFinal(input.getBytes());
-    return Base64.getEncoder().encodeToString(encryptedBytes);
+public String encrypt(String input) throws Exception {
+    if (SECRET_KEY.getBytes().length != 16 && SECRET_KEY.getBytes().length != 24 && SECRET_KEY.getBytes().length != 32) {
+        throw new IllegalArgumentException("AES key must be 16, 24, or 32 bytes");
+    }
+    
+    SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
+    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+    cipher.init(Cipher.ENCRYPT_MODE, keySpec);
+    
+    byte[] iv = cipher.getIV();
+    byte[] encryptedBytes = cipher.doFinal(input.getBytes("UTF-8"));
+    
+    // IV와 암호문을 함께 저장
+    byte[] combined = new byte[iv.length + encryptedBytes.length];
+    System.arraycopy(iv, 0, combined, 0, iv.length);
+    System.arraycopy(encryptedBytes, 0, combined, iv.length, encryptedBytes.length);
+    
+    return Base64.getEncoder().encodeToString(combined);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public String encrypt(String input) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
byte[] encryptedBytes = cipher.doFinal(input.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}
public String encrypt(String input) throws Exception {
// Ensure the key is a valid AES length
if (SECRET_KEY.getBytes().length != 16
&& SECRET_KEY.getBytes().length != 24
&& SECRET_KEY.getBytes().length != 32) {
throw new IllegalArgumentException("AES key must be 16, 24, or 32 bytes");
}
SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
// Retrieve the randomly generated IV
byte[] iv = cipher.getIV();
byte[] encryptedBytes = cipher.doFinal(input.getBytes("UTF-8"));
// Prepend IV to ciphertext so it can be used for decryption
byte[] combined = new byte[iv.length + encryptedBytes.length];
System.arraycopy(iv, 0, combined, 0, iv.length);
System.arraycopy(encryptedBytes, 0, combined, iv.length, encryptedBytes.length);
return Base64.getEncoder().encodeToString(combined);
}
🧰 Tools
🪛 ast-grep (0.38.1)

[warning] 19-19: Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES.
Context: Cipher.getInstance(ALGORITHM)
Note: [CWE-326]: Inadequate Encryption Strength [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://find-sec-bugs.github.io/bugs.htm#TDES_USAGE
- https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA

(desede-is-deprecated-java)


[warning] 19-19: Use of AES with ECB mode detected. ECB doesn't provide message confidentiality and is not semantically secure so should not be used. Instead, use a strong, secure cipher: Cipher.getInstance("AES/CBC/PKCS7PADDING"). See https://owasp.org/www-community/Using_the_Java_Cryptographic_Extensions for more information.
Context: Cipher.getInstance(ALGORITHM)
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://owasp.org/Top10/A02_2021-Cryptographic_Failures
- https://googleprojectzero.blogspot.com/2022/10/rc4-is-still-considered-harmful.html

(use-of-aes-ecb-java)

🤖 Prompt for AI Agents
In src/main/java/org/ezcode/codetest/common/security/util/AESUtil.java around
lines 18 to 24, the encryption method uses AES in ECB mode, which is insecure
due to pattern leakage. Change the Cipher instance to use AES in CBC or GCM
mode, initialize it with an IV (initialization vector), and update the
encryption logic to handle the IV properly. Ensure the key and IV are securely
generated and managed.


public String decrypt(String encryptedInput) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedInput);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes);
}
Comment on lines +26 to +33
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

복호화 메서드도 보안 모드로 업데이트 필요

암호화 메서드와 동일하게 CBC 모드를 사용하도록 수정해야 합니다.

-public String decrypt(String encryptedInput) throws Exception {
-    SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
-    Cipher cipher = Cipher.getInstance(ALGORITHM);
-    cipher.init(Cipher.DECRYPT_MODE, keySpec);
-    byte[] encryptedBytes = Base64.getDecoder().decode(encryptedInput);
-    byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
-    return new String(decryptedBytes);
+public String decrypt(String encryptedInput) throws Exception {
+    if (SECRET_KEY.getBytes().length != 16 && SECRET_KEY.getBytes().length != 24 && SECRET_KEY.getBytes().length != 32) {
+        throw new IllegalArgumentException("AES key must be 16, 24, or 32 bytes");
+    }
+    
+    byte[] combined = Base64.getDecoder().decode(encryptedInput);
+    
+    // IV 추출 (처음 16바이트)
+    byte[] iv = new byte[16];
+    byte[] encryptedBytes = new byte[combined.length - 16];
+    System.arraycopy(combined, 0, iv, 0, 16);
+    System.arraycopy(combined, 16, encryptedBytes, 0, encryptedBytes.length);
+    
+    SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
+    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+    IvParameterSpec ivSpec = new IvParameterSpec(iv);
+    cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
+    
+    byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
+    return new String(decryptedBytes, "UTF-8");
 }

필요한 import 추가:

+import javax.crypto.spec.IvParameterSpec;
+import java.nio.charset.StandardCharsets;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public String decrypt(String encryptedInput) throws Exception {
SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] encryptedBytes = Base64.getDecoder().decode(encryptedInput);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes);
}
// Add at top of the file:
+ import javax.crypto.spec.IvParameterSpec;
+ import java.nio.charset.StandardCharsets;
public String decrypt(String encryptedInput) throws Exception {
// Validate key length
int keyLen = SECRET_KEY.getBytes().length;
if (keyLen != 16 && keyLen != 24 && keyLen != 32) {
throw new IllegalArgumentException("AES key must be 16, 24, or 32 bytes");
}
// Decode IV + ciphertext
byte[] combined = Base64.getDecoder().decode(encryptedInput);
// Extract IV (first 16 bytes)
byte[] iv = new byte[16];
byte[] encryptedBytes = new byte[combined.length - 16];
System.arraycopy(combined, 0, iv, 0, 16);
System.arraycopy(combined, 16, encryptedBytes, 0, encryptedBytes.length);
// Initialize cipher in CBC mode with PKCS5 padding
SecretKeySpec keySpec = new SecretKeySpec(SECRET_KEY.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
🧰 Tools
🪛 ast-grep (0.38.1)

[warning] 27-27: Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES.
Context: Cipher.getInstance(ALGORITHM)
Note: [CWE-326]: Inadequate Encryption Strength [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://find-sec-bugs.github.io/bugs.htm#TDES_USAGE
- https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA

(desede-is-deprecated-java)


[warning] 27-27: Use of AES with ECB mode detected. ECB doesn't provide message confidentiality and is not semantically secure so should not be used. Instead, use a strong, secure cipher: Cipher.getInstance("AES/CBC/PKCS7PADDING"). See https://owasp.org/www-community/Using_the_Java_Cryptographic_Extensions for more information.
Context: Cipher.getInstance(ALGORITHM)
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
- https://owasp.org/Top10/A02_2021-Cryptographic_Failures
- https://googleprojectzero.blogspot.com/2022/10/rc4-is-still-considered-harmful.html

(use-of-aes-ecb-java)

🤖 Prompt for AI Agents
In src/main/java/org/ezcode/codetest/common/security/util/AESUtil.java around
lines 26 to 33, the decrypt method uses the default cipher mode instead of CBC
mode like the encrypt method. Update the Cipher.getInstance call to specify
"AES/CBC/PKCS5Padding" to match the encryption mode. Also, initialize the cipher
with an IvParameterSpec for the CBC mode using the same IV as encryption. Add
necessary imports for IvParameterSpec and any other required classes.

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,6 @@ public class JwtFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {

// String requestURI = request.getRequestURI();
//
// //whiteList 등록
// if (shouldNotFilter(requestURI)) {
// filterChain.doFilter(request, response);
// return;
// }

String bearerToken = request.getHeader("Authorization");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
@Component
public class SecurityPath {
public static final String[] PUBLIC_PATH = {
"/login/oauth2/**", //OAuth로그인 접근
"/api/auth/**",
"/api/oauth2/**",
"/login",
"/ezlogin",
"/login/**",
"/oauth2/**",
"/login/oauth",
"/login/oauth2/**", //OAuth로그인 접근
"/actuator/**",
"/chatting",
"/submit-test",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ public enum AuthExceptionCode implements ResponseCode {
ALREADY_EXIST_USER(false, HttpStatus.BAD_REQUEST, "이미 가입된 유저입니다."),
NOT_EMAIL_USER(false, HttpStatus.BAD_REQUEST, "소셜 로그인 회원은 비밀번호 변경을 할 수 없습니다."),
PASSWORD_IS_SAME(false, HttpStatus.BAD_REQUEST, "기존 비밀번호와 같습니다. 새로운 비밀번호는 기존 비밀번호와 달라야합니다."),
ALREADY_WITHDRAW_USER(false, HttpStatus.NOT_FOUND, "탈퇴된 회원입니다.")

;
ALREADY_WITHDRAW_USER(false, HttpStatus.NOT_FOUND, "탈퇴된 회원입니다."),
TOKEN_ENCODE_FAIL(false, HttpStatus.BAD_REQUEST, "토큰 인코딩에 실패했습니다."),
REDIRECT_URI_NOT_FOUND(false, HttpStatus.BAD_REQUEST, "redirect_uri를 찾을 수 없습니다");

private final boolean success;
private final HttpStatus status;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ public String getName() {
}

public String getEmail() {
return oAuth2Response.getEmail();
if (oAuth2Response.getEmail() == null) {
return oAuth2Response.getGithubId()+"@github.com";
} else {
return oAuth2Response.getEmail();
}
}

public String getProvider(){
Expand All @@ -40,4 +44,5 @@ public String getProvider(){
public String getUsername() {
return oAuth2Response.getProvider()+" "+oAuth2Response.getProviderId();
}

}
Loading