-
-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathAuthenticationService.java
More file actions
192 lines (165 loc) · 7.15 KB
/
AuthenticationService.java
File metadata and controls
192 lines (165 loc) · 7.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/* OwlPlug
* Copyright (C) 2021 Arthur <dropsnorz@gmail.com>
*
* This file is part of OwlPlug.
*
* OwlPlug is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3
* as published by the Free Software Foundation.
*
* OwlPlug is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OwlPlug. If not, see <https://www.gnu.org/licenses/>.
*/
package com.owlplug.auth.services;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.store.DataStoreFactory;
import com.google.api.services.oauth2.Oauth2;
import com.google.api.services.oauth2.model.Userinfoplus;
import com.owlplug.auth.JPADataStoreFactory;
import com.owlplug.auth.components.OwlPlugCredentials;
import com.owlplug.auth.events.AccountUpdateEvent;
import com.owlplug.auth.repositories.GoogleCredentialRepository;
import com.owlplug.auth.repositories.UserAccountRepository;
import com.owlplug.auth.model.UserAccount;
import com.owlplug.auth.model.UserAccountProvider;
import com.owlplug.auth.utils.AuthenticationException;
import com.owlplug.core.components.ApplicationDefaults;
import com.owlplug.core.services.BaseService;
import jakarta.transaction.Transactional;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
/**
* OAuth Authentication service. Authenticates users from known providers using
* IP Loopback and requests API call permissions for OwlPlug. This service
* stores users access tokens for next calls. Only one Authentication flow must
* be performed at time as this class is not thread safe and maintain states
* during Authentication.
*
*/
@Service
public class AuthenticationService extends BaseService {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
private ApplicationEventPublisher publisher;
@Autowired
private OwlPlugCredentials owlPlugCredentials;
@Autowired
private GoogleCredentialRepository googleCredentialRepository;
@Autowired
private UserAccountRepository userAccountRepository;
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
private LocalServerReceiver receiver = null;
/**
* Creates a new account by starting the Authentication flow.
*
* @throws AuthenticationException if an error occurs during Authentication
* flow.
*/
public void createAccountAndAuth() throws AuthenticationException {
String clientId = owlPlugCredentials.getGoogleAppId();
String clientSecret = owlPlugCredentials.getGoogleSecret();
ArrayList<String> scopes = new ArrayList<>();
scopes.add("https://www.googleapis.com/auth/userinfo.profile");
try {
NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
DataStoreFactory dataStore = new JPADataStoreFactory(googleCredentialRepository);
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, JSON_FACTORY, clientId,
clientSecret, scopes).setDataStoreFactory(dataStore).setAccessType("offline").setApprovalPrompt("force")
.build();
UserAccount userAccount = new UserAccount();
userAccountRepository.save(userAccount);
receiver = new LocalServerReceiver();
AuthorizationCodeInstalledApp authCodeAccess = new AuthorizationCodeInstalledApp(flow, receiver);
Credential credential = authCodeAccess.authorize(userAccount.getKey());
Oauth2 oauth2 = new Oauth2.Builder(new NetHttpTransport(), new JacksonFactory(), credential)
.setApplicationName("OwlPlug").build();
Userinfoplus userinfo = oauth2.userinfo().get().execute();
userAccount.setName(userinfo.getName());
userAccount.setIconUrl(userinfo.getPicture());
userAccount.setAccountProvider(UserAccountProvider.GOOGLE);
userAccount.setCredential(googleCredentialRepository.findByKey(userAccount.getKey()));
userAccountRepository.save(userAccount);
this.getPreferences().putLong(ApplicationDefaults.SELECTED_ACCOUNT_KEY, userAccount.getId());
publisher.publishEvent(new AccountUpdateEvent());
} catch (GeneralSecurityException | IOException e) {
log.error("Error during authentication", e);
throw new AuthenticationException(e);
} finally {
// Delete accounts without complete setup
userAccountRepository.deleteInvalidAccounts();
}
}
/**
* Retrieve Google Credentials from key.
*
* @param key Google credential unique key
* @return
*/
public GoogleCredential getGoogleCredential(String key) {
String clientId = owlPlugCredentials.getGoogleAppId();
String clientSecret = owlPlugCredentials.getGoogleSecret();
com.owlplug.auth.model.GoogleCredential gc = googleCredentialRepository.findByKey(key);
return new GoogleCredential.Builder().setTransport(new NetHttpTransport()).setJsonFactory(new JacksonFactory())
.setClientSecrets(clientId, clientSecret).build().setRefreshToken(gc.getRefreshToken());
}
/**
* Deletes a user account.
*
* @param userAccount user account to delete
*/
@Transactional
public void deleteAccount(UserAccount userAccount) {
googleCredentialRepository.deleteByKey(userAccount.getKey());
userAccountRepository.delete(userAccount);
publisher.publishEvent(new AccountUpdateEvent());
}
/**
* Returns all registered UserAccounts.
* @return list of user accounts
*/
public Iterable<UserAccount> getAccounts() {
return userAccountRepository.findAll();
}
/**
* Returns a user account matching a given id.
* @param id - user account unique id
* @return related user account
*/
public Optional<UserAccount> getUserAccountById(Long id) {
return userAccountRepository.findById(id);
}
/**
* Force the Authentication flow authReceiver to stop. Called when the user
* cancels authentication.
*/
public void stopAuthReceiver() {
try {
userAccountRepository.deleteInvalidAccounts();
if (receiver != null) {
receiver.stop();
}
} catch (IOException e) {
log.error("Error while stopping local authentication receiver", e);
}
}
}