Skip to content

Commit c196da1

Browse files
authored
Merge pull request #21 from ozkanpakdil/authorization-tab
Implement authorization settings management with save and load functi…
2 parents 96438ce + c14d8c0 commit c196da1

File tree

10 files changed

+680
-8
lines changed

10 files changed

+680
-8
lines changed
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
package io.github.ozkanpakdil.swaggerific.data;
2+
3+
import io.github.ozkanpakdil.swaggerific.ui.edit.AuthorizationController;
4+
import io.github.ozkanpakdil.swaggerific.ui.edit.AuthorizationController.AuthType;
5+
import io.github.ozkanpakdil.swaggerific.security.CredentialEncryption;
6+
7+
import java.io.IOException;
8+
import java.io.ObjectInputStream;
9+
import java.io.ObjectOutputStream;
10+
import java.io.Serial;
11+
import java.io.Serializable;
12+
import java.util.HashMap;
13+
import java.util.Map;
14+
15+
/**
16+
* Class for storing authorization settings by URL.
17+
* This class is serializable and can be saved to a file.
18+
*/
19+
public class AuthorizationSettings implements Serializable {
20+
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AuthorizationSettings.class);
21+
22+
@Serial
23+
private static final long serialVersionUID = -2338626292552177485L;
24+
25+
// Map of URL to authorization settings
26+
private Map<String, AuthSetting> settingsByUrl = new HashMap<>();
27+
28+
/**
29+
* Inner class to store authorization settings for a specific URL.
30+
*/
31+
public static class AuthSetting implements Serializable {
32+
@Serial
33+
private static final long serialVersionUID = -1234567890123456789L;
34+
35+
private AuthType authType;
36+
private transient String apiKeyName;
37+
private transient String apiKeyValue;
38+
private transient String username;
39+
private transient String password;
40+
private transient String bearerToken;
41+
42+
// Encrypted versions of sensitive fields for serialization
43+
private String encryptedApiKeyValue;
44+
private String encryptedUsername;
45+
private String encryptedPassword;
46+
private String encryptedBearerToken;
47+
48+
@Serial
49+
private void writeObject(ObjectOutputStream out) throws IOException {
50+
// Encrypt sensitive data before serialization
51+
this.encryptedApiKeyValue = CredentialEncryption.encrypt(apiKeyValue);
52+
this.encryptedUsername = CredentialEncryption.encrypt(username);
53+
this.encryptedPassword = CredentialEncryption.encrypt(password);
54+
this.encryptedBearerToken = CredentialEncryption.encrypt(bearerToken);
55+
56+
out.defaultWriteObject();
57+
out.writeObject(apiKeyName); // apiKeyName is not sensitive, but still needs manual writing due to transient
58+
}
59+
60+
@Serial
61+
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
62+
in.defaultReadObject();
63+
64+
// Read non-sensitive transient field
65+
this.apiKeyName = (String) in.readObject();
66+
67+
// Decrypt sensitive data after deserialization
68+
this.apiKeyValue = CredentialEncryption.decrypt(encryptedApiKeyValue);
69+
this.username = CredentialEncryption.decrypt(encryptedUsername);
70+
this.password = CredentialEncryption.decrypt(encryptedPassword);
71+
this.bearerToken = CredentialEncryption.decrypt(encryptedBearerToken);
72+
}
73+
74+
public AuthSetting() {
75+
this.authType = AuthType.NO_AUTH;
76+
}
77+
78+
public AuthSetting(AuthType authType) {
79+
this.authType = authType;
80+
}
81+
82+
public AuthType getAuthType() {
83+
return authType;
84+
}
85+
86+
public void setAuthType(AuthType authType) {
87+
this.authType = authType;
88+
}
89+
90+
public String getApiKeyName() {
91+
return apiKeyName;
92+
}
93+
94+
public void setApiKeyName(String apiKeyName) {
95+
this.apiKeyName = apiKeyName;
96+
}
97+
98+
public String getApiKeyValue() {
99+
return apiKeyValue;
100+
}
101+
102+
public void setApiKeyValue(String apiKeyValue) {
103+
this.apiKeyValue = apiKeyValue;
104+
}
105+
106+
public String getUsername() {
107+
return username;
108+
}
109+
110+
public void setUsername(String username) {
111+
this.username = username;
112+
}
113+
114+
public String getPassword() {
115+
return password;
116+
}
117+
118+
public void setPassword(String password) {
119+
this.password = password;
120+
}
121+
122+
public String getBearerToken() {
123+
return bearerToken;
124+
}
125+
126+
public void setBearerToken(String bearerToken) {
127+
this.bearerToken = bearerToken;
128+
}
129+
}
130+
131+
/**
132+
* Gets the authorization settings for a specific URL.
133+
*
134+
* @param url the URL
135+
* @return the authorization settings, or null if not found
136+
*/
137+
public AuthSetting getSettingsForUrl(String url) {
138+
return settingsByUrl.get(url);
139+
}
140+
141+
/**
142+
* Saves the authorization settings for a specific URL.
143+
*
144+
* @param url the URL
145+
* @param authController the authorization controller
146+
*/
147+
public void saveSettingsForUrl(String url, AuthorizationController authController) {
148+
if (url == null || url.isEmpty() || authController == null) {
149+
return;
150+
}
151+
152+
AuthSetting setting = new AuthSetting(authController.getCurrentAuthType());
153+
154+
// Save settings based on auth type
155+
switch (authController.getCurrentAuthType()) {
156+
case API_KEY:
157+
setting.setApiKeyName(authController.getApiKeyNameField().getText());
158+
setting.setApiKeyValue(authController.getApiKeyField().getText());
159+
break;
160+
case BASIC_AUTH:
161+
setting.setUsername(authController.getUsernameField().getText());
162+
setting.setPassword(authController.getPasswordField().getText());
163+
break;
164+
case BEARER_TOKEN:
165+
setting.setBearerToken(authController.getTokenField().getText());
166+
break;
167+
case NO_AUTH:
168+
default:
169+
// No additional settings needed
170+
break;
171+
}
172+
173+
settingsByUrl.put(url, setting);
174+
log.debug("Saved authorization settings for URL: {}", url);
175+
}
176+
177+
/**
178+
* Applies the saved authorization settings to an authorization controller.
179+
*
180+
* @param url the URL
181+
* @param authController the authorization controller
182+
* @return true if settings were applied, false otherwise
183+
*/
184+
public boolean applySettingsToController(String url, AuthorizationController authController) {
185+
if (url == null || url.isEmpty() || authController == null) {
186+
return false;
187+
}
188+
189+
AuthSetting setting = settingsByUrl.get(url);
190+
if (setting == null) {
191+
return false;
192+
}
193+
194+
// Set auth type first
195+
authController.setCurrentAuthType(setting.getAuthType());
196+
197+
// Apply settings based on auth type
198+
switch (setting.getAuthType()) {
199+
case API_KEY:
200+
authController.getApiKeyNameField().setText(setting.getApiKeyName());
201+
authController.getApiKeyField().setText(setting.getApiKeyValue());
202+
break;
203+
case BASIC_AUTH:
204+
authController.getUsernameField().setText(setting.getUsername());
205+
authController.getPasswordField().setText(setting.getPassword());
206+
break;
207+
case BEARER_TOKEN:
208+
authController.getTokenField().setText(setting.getBearerToken());
209+
break;
210+
case NO_AUTH:
211+
default:
212+
// No additional settings needed
213+
break;
214+
}
215+
216+
log.info("Applied authorization settings for URL: {}", url);
217+
return true;
218+
}
219+
220+
/**
221+
* Clears all authorization settings.
222+
*/
223+
public void clear() {
224+
settingsByUrl.clear();
225+
}
226+
227+
/**
228+
* Gets the number of saved authorization settings.
229+
*
230+
* @return the number of saved authorization settings
231+
*/
232+
public int size() {
233+
return settingsByUrl.size();
234+
}
235+
236+
@Serial
237+
private void writeObject(ObjectOutputStream out) throws IOException {
238+
out.defaultWriteObject();
239+
}
240+
241+
@Serial
242+
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
243+
in.defaultReadObject();
244+
}
245+
}
246+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package io.github.ozkanpakdil.swaggerific.security;
2+
3+
import javax.crypto.Cipher;
4+
import javax.crypto.SecretKey;
5+
import javax.crypto.SecretKeyFactory;
6+
import javax.crypto.spec.PBEKeySpec;
7+
import javax.crypto.spec.SecretKeySpec;
8+
import java.nio.charset.StandardCharsets;
9+
import java.security.spec.KeySpec;
10+
import java.util.Base64;
11+
12+
public class CredentialEncryption {
13+
private static final String ALGORITHM = "AES";
14+
private static final byte[] SALT = "SwaggerificSalt".getBytes(StandardCharsets.UTF_8);
15+
private static SecretKey secretKey;
16+
17+
static {
18+
try {
19+
// Generate a key based on system-specific properties
20+
String systemSpecific = System.getProperty("user.name") +
21+
System.getProperty("os.name") +
22+
System.getProperty("user.home");
23+
24+
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
25+
KeySpec spec = new PBEKeySpec(systemSpecific.toCharArray(), SALT, 65536, 256);
26+
SecretKey tmp = factory.generateSecret(spec);
27+
secretKey = new SecretKeySpec(tmp.getEncoded(), ALGORITHM);
28+
} catch (Exception e) {
29+
throw new RuntimeException("Failed to initialize encryption", e);
30+
}
31+
}
32+
33+
public static String encrypt(String value) {
34+
if (value == null) return null;
35+
try {
36+
Cipher cipher = Cipher.getInstance(ALGORITHM);
37+
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
38+
return Base64.getEncoder().encodeToString(cipher.doFinal(value.getBytes()));
39+
} catch (Exception e) {
40+
throw new RuntimeException("Encryption failed", e);
41+
}
42+
}
43+
44+
public static String decrypt(String encrypted) {
45+
if (encrypted == null) return null;
46+
try {
47+
Cipher cipher = Cipher.getInstance(ALGORITHM);
48+
cipher.init(Cipher.DECRYPT_MODE, secretKey);
49+
return new String(cipher.doFinal(Base64.getDecoder().decode(encrypted)));
50+
} catch (Exception e) {
51+
throw new RuntimeException("Decryption failed", e);
52+
}
53+
}
54+
}

src/main/java/io/github/ozkanpakdil/swaggerific/tools/HttpUtility.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,14 +162,16 @@ public HttpResponse sendRequest(String targetUri, PathItem.HttpMethod httpMethod
162162
try {
163163
URI uri = buildUri(targetUri, queryParams, pathParams);
164164

165+
log.info("Headers before creating request: {}", headers);
166+
165167
HttpRequest request = new HttpRequest.Builder()
166168
.uri(uri)
167169
.method(httpMethod.name())
168170
.headers(headers)
169171
.body(body)
170172
.build();
171173

172-
log.info("Sending {} request to {}", httpMethod.name(), uri);
174+
log.info("Sending {} request to {} with headers: {}", httpMethod.name(), uri, request.headers());
173175
return httpService.sendRequest(request);
174176
} catch (Exception e) {
175177
log.error("Error preparing request: {}", e.getMessage(), e);

src/main/java/io/github/ozkanpakdil/swaggerific/tools/http/HttpServiceImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,14 @@ public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
202202
@Override
203203
public HttpResponse sendRequest(HttpRequest request) {
204204
try {
205+
log.info("HttpServiceImpl received request with headers: {}", request.headers());
206+
205207
String[] headerArray = new String[request.headers().size() * 2];
206208
int i = 0;
207209
for (Map.Entry<String, String> entry : request.headers().entrySet()) {
208210
headerArray[i++] = entry.getKey();
209211
headerArray[i++] = entry.getValue();
212+
log.info("Adding header: {} = {}", entry.getKey(), entry.getValue());
210213
}
211214

212215
java.net.http.HttpRequest.Builder requestBuilder = java.net.http.HttpRequest.newBuilder()
@@ -216,6 +219,7 @@ public HttpResponse sendRequest(HttpRequest request) {
216219

217220
if (headerArray.length > 0) {
218221
requestBuilder.headers(headerArray);
222+
log.info("Added {} headers to the request", headerArray.length / 2);
219223
}
220224

221225
java.net.http.HttpRequest httpRequest = requestBuilder.build();

0 commit comments

Comments
 (0)