Skip to content
This repository was archived by the owner on Sep 29, 2024. It is now read-only.

Commit 7a0cdbe

Browse files
authored
Backend/Frontend: Added Sign in via Google (#825)
* feat: first attempt for oauth loggin via google * Fix: Added missing classes * Feat: Added misery * Feat: Added sonarlint gitignore * Fix: Save some commits * Feat: Added Endpoint for Google Login * Feat: Updated google endpoint * Feat: Implemented Frontend Redirect * Fixed Redirect: * Fix: Fixed saving user images * Fix: some smol mistakes * Fix: Changed to actual url * Fix: fixed miniscule mistakes
1 parent b380004 commit 7a0cdbe

File tree

16 files changed

+254
-22
lines changed

16 files changed

+254
-22
lines changed

pom.xml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,18 @@
162162
<artifactId>freemarker</artifactId>
163163
<version>2.3.33</version>
164164
</dependency>
165+
<!-- Google OAuth -->
166+
<dependency>
167+
<groupId>com.google.api-client</groupId>
168+
<artifactId>google-api-client</artifactId>
169+
<version>2.6.0</version>
170+
</dependency>
171+
172+
<dependency>
173+
<groupId>com.google.http-client</groupId>
174+
<artifactId>google-http-client-jackson2</artifactId>
175+
<version>1.44.2</version>
176+
</dependency>
165177

166178
<!--
167179
<dependency>
@@ -170,7 +182,7 @@
170182
<version>2.3.1</version>
171183
</dependency>
172184
-->
173-
185+
174186
<!-- Logging -->
175187
<dependency>
176188
<groupId>ch.qos.logback</groupId>

src/main/java/de/tinf22b6/dhbwhub/controller/AuthController.java

Lines changed: 73 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,29 @@
11
package de.tinf22b6.dhbwhub.controller;
22

3-
import de.tinf22b6.dhbwhub.model.Account;
4-
import de.tinf22b6.dhbwhub.model.User;
5-
import de.tinf22b6.dhbwhub.payload.request.*;
3+
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
4+
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
5+
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
6+
import com.google.api.client.json.gson.GsonFactory;
7+
import de.tinf22b6.dhbwhub.model.*;
8+
import de.tinf22b6.dhbwhub.payload.request.EmailVerificationRequest;
9+
import de.tinf22b6.dhbwhub.payload.request.LoginRequest;
10+
import de.tinf22b6.dhbwhub.payload.request.SignupRequest;
11+
import de.tinf22b6.dhbwhub.payload.request.TokenValidationRequest;
612
import de.tinf22b6.dhbwhub.payload.response.JwtResponse;
713
import de.tinf22b6.dhbwhub.payload.response.MessageResponse;
814
import de.tinf22b6.dhbwhub.repository.AccountRepository;
15+
import de.tinf22b6.dhbwhub.repository.AdministratorRepository;
916
import de.tinf22b6.dhbwhub.repository.UserRepository;
1017
import de.tinf22b6.dhbwhub.security.jwt.JwtUtils;
1118
import de.tinf22b6.dhbwhub.security.services.UserDetailsImpl;
19+
import de.tinf22b6.dhbwhub.service.AccountServiceImpl;
1220
import de.tinf22b6.dhbwhub.service.EmailService;
1321
import de.tinf22b6.dhbwhub.service.EmailVerificationTokenManager;
22+
import de.tinf22b6.dhbwhub.service.interfaces.PictureService;
1423
import jakarta.mail.MessagingException;
1524
import jakarta.validation.Valid;
1625
import lombok.RequiredArgsConstructor;
26+
import org.springframework.beans.factory.annotation.Value;
1727
import org.springframework.http.HttpStatus;
1828
import org.springframework.http.ResponseEntity;
1929
import org.springframework.security.authentication.AuthenticationManager;
@@ -22,9 +32,13 @@
2232
import org.springframework.security.core.GrantedAuthority;
2333
import org.springframework.security.core.context.SecurityContextHolder;
2434
import org.springframework.security.crypto.password.PasswordEncoder;
25-
import org.springframework.web.bind.annotation.*;
35+
import org.springframework.web.bind.annotation.PostMapping;
36+
import org.springframework.web.bind.annotation.RequestBody;
37+
import org.springframework.web.bind.annotation.RequestMapping;
38+
import org.springframework.web.bind.annotation.RestController;
2639

2740
import java.io.IOException;
41+
import java.util.Collections;
2842
import java.util.HashMap;
2943
import java.util.List;
3044
import java.util.Map;
@@ -37,10 +51,16 @@ public class AuthController {
3751

3852
private final AuthenticationManager authenticationManager;
3953
private final AccountRepository accountRepository;
54+
private final AdministratorRepository administratorRepository;
4055
private final PasswordEncoder passwordEncoder;
4156
private final JwtUtils jwtUtils;
4257
private final UserRepository userRepository;
4358
private final EmailService emailService;
59+
private final PictureService pictureService;
60+
private final AccountServiceImpl accountServiceImpl;
61+
62+
@Value("${spring.security.oauth2.client.registration.google.client-id}")
63+
private String clientId;
4464

4565
// TODO: Save JWT in Database
4666
@PostMapping("login")
@@ -122,5 +142,54 @@ public ResponseEntity<?> tokenValidation (@Valid @RequestBody TokenValidationReq
122142
}
123143
}
124144

145+
@PostMapping("google")
146+
public ResponseEntity<?> googleLogin(@RequestBody Map<String, String> request) {
147+
String idTokenString = request.get("token");
148+
GoogleIdToken idToken = null;
149+
150+
try {
151+
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(GoogleNetHttpTransport.newTrustedTransport(), new GsonFactory())
152+
.setAudience(Collections.singletonList(clientId))
153+
.build();
154+
155+
idToken = verifier.verify(idTokenString);
156+
}catch (Exception e) {
157+
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("There has been a serverside problem");
158+
}
159+
160+
if (idToken == null) return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid ID token");
161+
GoogleIdToken.Payload payload = idToken.getPayload();
162+
String userId = payload.getSubject();
163+
String email = payload.getEmail();
164+
String name = (String) payload.get("name");
165+
String pictureUrl = (String) payload.get("picture");
166+
Picture picture = pictureService.getImageFromUrl(pictureUrl);
167+
168+
Account account = accountServiceImpl.findByEmail(email);
169+
User user = null;
170+
171+
if(account == null) {
172+
account = accountRepository.save(new Account(name, email, null, picture, true));
173+
user = userRepository.save(new User(0, null, null, account));
174+
accountRepository.saveOAuthEntry(new OAuthAccount(account,OAuthAccount.GOOGLE_ENTRY));
175+
} else if (!accountRepository.existsOAuthEntry(account.getId())) {
176+
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Access denied - No such account exists");
177+
} else {
178+
user = userRepository.findByAccountId(account.getId());
179+
}
180+
181+
String jwt = jwtUtils.generateJwtToken(account.getUsername());
182+
UserDetailsImpl userDetails = UserDetailsImpl.build(user, administratorRepository);
125183

184+
List<String> roles = userDetails.getAuthorities().stream()
185+
.map(GrantedAuthority::getAuthority)
186+
.collect(Collectors.toList());
187+
188+
return ResponseEntity.ok(new JwtResponse(jwt,
189+
userDetails.getAccountId(),
190+
userDetails.getUserId(),
191+
userDetails.getUsername(),
192+
userDetails.getEmail(),
193+
roles));
194+
}
126195
}

src/main/java/de/tinf22b6/dhbwhub/model/Account.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ public class Account {
2222
@NotBlank
2323
private final String email;
2424

25-
@NotBlank
2625
private final String password;
2726

2827
@JoinColumn(name = "picture_id")
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package de.tinf22b6.dhbwhub.model;
2+
3+
import jakarta.persistence.*;
4+
import lombok.Getter;
5+
import lombok.NoArgsConstructor;
6+
import lombok.RequiredArgsConstructor;
7+
import lombok.Setter;
8+
9+
@Getter
10+
@Setter
11+
@RequiredArgsConstructor
12+
@NoArgsConstructor(force = true)
13+
@Entity
14+
public class OAuthAccount {
15+
public static String GOOGLE_ENTRY = "GOOGLE";
16+
17+
@Id
18+
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "oauth_account_generator")
19+
@SequenceGenerator(name = "oauth_account_generator", sequenceName = "oauth_account_seq", allocationSize = 1)
20+
@Column(name = "oauth_id")
21+
private Long id;
22+
23+
@JoinColumn(name = "account_id")
24+
@ManyToOne(cascade = CascadeType.PERSIST)
25+
private final Account account;
26+
27+
private final String authType;
28+
}

src/main/java/de/tinf22b6/dhbwhub/repository/AccountRepository.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package de.tinf22b6.dhbwhub.repository;
22

33
import de.tinf22b6.dhbwhub.model.Account;
4+
import de.tinf22b6.dhbwhub.model.OAuthAccount;
45
import de.tinf22b6.dhbwhub.repository.interfaces.SpringAccountRepository;
6+
import de.tinf22b6.dhbwhub.repository.interfaces.SpringOAuthRepository;
57
import org.springframework.beans.factory.annotation.Autowired;
68
import org.springframework.stereotype.Repository;
79

@@ -11,9 +13,12 @@
1113
@Repository
1214
public class AccountRepository {
1315
private final SpringAccountRepository repository;
16+
private final SpringOAuthRepository oAuthRepository;
1417

15-
public AccountRepository(@Autowired SpringAccountRepository repository) {
18+
public AccountRepository(@Autowired SpringAccountRepository repository,
19+
@Autowired SpringOAuthRepository oAuthRepository) {
1620
this.repository = repository;
21+
this.oAuthRepository = oAuthRepository;
1722
}
1823

1924
public List<Account> findAll() {
@@ -44,4 +49,15 @@ public Boolean existsByEmail(String email) {
4449
return repository.existsByEmail(email);
4550
}
4651

52+
public Account findByEmail(String email) {
53+
return repository.findByEmail(email).orElse(null);
54+
}
55+
56+
public Boolean existsOAuthEntry(Long accountId) {
57+
return oAuthRepository.findByAccountId(accountId).orElse(null) != null;
58+
}
59+
60+
public OAuthAccount saveOAuthEntry(OAuthAccount account) {
61+
return oAuthRepository.save(account);
62+
}
4763
}

src/main/java/de/tinf22b6/dhbwhub/repository/interfaces/SpringAccountRepository.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ public interface SpringAccountRepository extends JpaRepository<Account, Long> {
1212

1313
Boolean existsByEmail(String email);
1414

15+
Optional<Account> findByEmail(String email);
1516
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package de.tinf22b6.dhbwhub.repository.interfaces;
2+
3+
import de.tinf22b6.dhbwhub.model.OAuthAccount;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
import java.util.Optional;
7+
8+
public interface SpringOAuthRepository extends JpaRepository<OAuthAccount, Long> {
9+
10+
Optional<OAuthAccount> findByAccountId(Long accountId);
11+
}

src/main/java/de/tinf22b6/dhbwhub/security/WebSecurityConfig.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public class WebSecurityConfig {
2828
private static final String[] PUBLIC_ENDPOINTS = {
2929
"/api/auth/login",
3030
"/api/auth/signup",
31+
"/api/auth/google",
3132
"/api/auth/email-verification",
3233
"/api/auth/token-validation",
3334
"/post/homepage-preview-posts",

src/main/java/de/tinf22b6/dhbwhub/security/jwt/JwtUtils.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,13 @@ public String generateJwtToken(Authentication authentication) {
3030

3131
UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
3232

33+
return generateJwtToken(userPrincipal.getUsername());
34+
}
35+
36+
public String generateJwtToken(String username) {
37+
3338
return Jwts.builder()
34-
.subject((userPrincipal.getUsername()))
39+
.subject(username)
3540
.issuedAt(new Date())
3641
.expiration(new Date((new Date()).getTime() + jwtExpirationMs))
3742
.signWith(key())

src/main/java/de/tinf22b6/dhbwhub/service/AccountServiceImpl.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import de.tinf22b6.dhbwhub.exception.NoSuchEntryException;
44
import de.tinf22b6.dhbwhub.mapper.AccountMapper;
55
import de.tinf22b6.dhbwhub.model.Account;
6+
import de.tinf22b6.dhbwhub.model.OAuthAccount;
67
import de.tinf22b6.dhbwhub.proposal.AccountProposal;
78
import de.tinf22b6.dhbwhub.repository.AccountRepository;
89
import de.tinf22b6.dhbwhub.service.interfaces.AccountService;
@@ -57,8 +58,28 @@ public void delete(Long id) {
5758
repository.delete(id);
5859
}
5960

61+
@Override
62+
public boolean checkIfOAuthAccountExists(Long id) {
63+
return repository.existsOAuthEntry(id);
64+
}
65+
6066
public boolean checkIfEmailExists(String email) {
6167
return getAll().stream().anyMatch(account -> account.getEmail().equals(email));
6268
}
6369

70+
@Override
71+
public Account findByEmail(String email) {
72+
return repository.findByEmail(email);
73+
}
74+
75+
76+
@Override
77+
public boolean existsOAuthEntry(Long accountId) {
78+
return repository.existsOAuthEntry(accountId);
79+
}
80+
81+
@Override
82+
public OAuthAccount saveOAuthEntry(OAuthAccount account) {
83+
return repository.saveOAuthEntry(account);
84+
}
6485
}

src/main/java/de/tinf22b6/dhbwhub/service/PictureServiceImpl.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@
66
import de.tinf22b6.dhbwhub.proposal.PictureProposal;
77
import de.tinf22b6.dhbwhub.repository.PictureRepository;
88
import de.tinf22b6.dhbwhub.service.interfaces.PictureService;
9+
import org.postgresql.shaded.com.ongres.scram.common.bouncycastle.base64.Base64;
910
import org.springframework.beans.factory.annotation.Autowired;
1011
import org.springframework.stereotype.Service;
1112

13+
import javax.imageio.ImageIO;
14+
import java.awt.image.BufferedImage;
15+
import java.io.ByteArrayOutputStream;
16+
import java.net.URL;
1217
import java.util.List;
1318

1419
@Service
@@ -58,6 +63,23 @@ public Picture update(Long id, PictureProposal proposal) {
5863
return repository.save(picture);
5964
}
6065

66+
public Picture getImageFromUrl(String imageUrl) {
67+
String imageBytes = null;
68+
try {
69+
URL url = new URL(imageUrl);
70+
BufferedImage image = ImageIO.read(url);
71+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
72+
ImageIO.write(image, "png", baos);
73+
imageBytes = "data:image/png;base64," + Base64.toBase64String(baos.toByteArray());
74+
}catch (Exception e) {
75+
System.out.println("Something went wrong during the image retrieval");
76+
}
77+
if (imageBytes == null) {
78+
return null;
79+
}
80+
return PictureMapper.mapToModelUser(imageBytes);
81+
}
82+
6183
@Override
6284
public void delete(Long id) {
6385
// Check if picture exists
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
package de.tinf22b6.dhbwhub.service.interfaces;
22

33
import de.tinf22b6.dhbwhub.model.Account;
4+
import de.tinf22b6.dhbwhub.model.OAuthAccount;
45
import de.tinf22b6.dhbwhub.proposal.AccountProposal;
56

67
import java.util.List;
78

89
public interface AccountService {
910
List<Account> getAll();
1011
Account create(AccountProposal proposal);
12+
Account findByEmail(String email);
13+
boolean existsOAuthEntry(Long accountId);
14+
OAuthAccount saveOAuthEntry(OAuthAccount account);
1115
Account get(Long id);
1216
Account update(Long id, AccountProposal proposal);
1317
void delete(Long id);
18+
boolean checkIfOAuthAccountExists(Long id);
1419
}

src/main/java/de/tinf22b6/dhbwhub/service/interfaces/PictureService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ public interface PictureService {
1111
Picture get(Long id);
1212
Picture findByUserId(Long id);
1313
Picture update(Long id, PictureProposal proposal);
14+
Picture getImageFromUrl(String url);
1415
void delete(Long id);
1516
}

0 commit comments

Comments
 (0)