-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #113 from medizininformatik-initiative/feat/add-op…
…enid-connect Add OpenID Connect authentication for connecting to OAuth secured FHIR stores
- Loading branch information
Showing
10 changed files
with
2,342 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
.../medizininformatik_initiative/process/feasibility/client/store/OAuth2ClientException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package de.medizininformatik_initiative.process.feasibility.client.store; | ||
|
||
public class OAuth2ClientException extends RuntimeException { | ||
|
||
private static final long serialVersionUID = -5840162115734733430L; | ||
|
||
public OAuth2ClientException(String message) { | ||
super(message); | ||
} | ||
|
||
public OAuth2ClientException(String message, Exception cause) { | ||
super(message, cause); | ||
} | ||
|
||
} |
92 changes: 92 additions & 0 deletions
92
...va/de/medizininformatik_initiative/process/feasibility/client/store/OAuthInterceptor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package de.medizininformatik_initiative.process.feasibility.client.store; | ||
|
||
import ca.uhn.fhir.rest.api.Constants; | ||
import ca.uhn.fhir.rest.client.api.IClientInterceptor; | ||
import ca.uhn.fhir.rest.client.api.IHttpRequest; | ||
import ca.uhn.fhir.rest.client.api.IHttpResponse; | ||
import com.nimbusds.oauth2.sdk.AccessTokenResponse; | ||
import com.nimbusds.oauth2.sdk.ClientCredentialsGrant; | ||
import com.nimbusds.oauth2.sdk.ParseException; | ||
import com.nimbusds.oauth2.sdk.TokenErrorResponse; | ||
import com.nimbusds.oauth2.sdk.TokenRequest; | ||
import com.nimbusds.oauth2.sdk.TokenResponse; | ||
import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic; | ||
import com.nimbusds.oauth2.sdk.auth.Secret; | ||
import com.nimbusds.oauth2.sdk.http.HTTPRequest; | ||
import com.nimbusds.oauth2.sdk.id.ClientID; | ||
import com.nimbusds.oauth2.sdk.token.AccessToken; | ||
import org.joda.time.DateTime; | ||
|
||
import java.io.IOException; | ||
import java.net.InetSocketAddress; | ||
import java.net.Proxy; | ||
import java.net.Proxy.Type; | ||
import java.net.URI; | ||
import java.util.Base64; | ||
import java.util.Optional; | ||
|
||
final class OAuthInterceptor implements IClientInterceptor { | ||
|
||
private static final String HEADER_PROXY_AUTHORIZATION = "Proxy-Authorization"; | ||
private static final int TOKEN_EXPIRY_THRESHOLD = 10000; | ||
private HTTPRequest tokenRequest; | ||
private AccessToken token; | ||
private DateTime tokenExpiry; | ||
|
||
public OAuthInterceptor(String oauthClientId, String oauthClientSecret, String oauthTokenUrl, | ||
Optional<String> proxyHost, Optional<Integer> proxyPort, Optional<String> proxyUsername, | ||
Optional<String> proxyPassword) { | ||
super(); | ||
ClientSecretBasic clientAuth = new ClientSecretBasic(new ClientID(oauthClientId), | ||
new Secret(oauthClientSecret)); | ||
HTTPRequest request = new TokenRequest(URI.create(oauthTokenUrl), clientAuth, new ClientCredentialsGrant()) | ||
.toHTTPRequest(); | ||
|
||
if (proxyHost.isPresent() && proxyPort.isPresent()) { | ||
Proxy proxy = new Proxy(Type.HTTP, | ||
InetSocketAddress.createUnresolved(proxyHost.get(), proxyPort.get())); | ||
request.setProxy(proxy); | ||
|
||
if (proxyUsername.isPresent() && proxyPassword.isPresent()) { | ||
request.setHeader(HEADER_PROXY_AUTHORIZATION, | ||
generateBasicAuthHeader(proxyUsername.get(), proxyPassword.get())); | ||
} | ||
} | ||
tokenRequest = request; | ||
} | ||
|
||
private String generateBasicAuthHeader(String username, String password) { | ||
return Constants.HEADER_AUTHORIZATION_VALPREFIX_BASIC | ||
+ Base64.getEncoder().encodeToString((username + ":" + password).getBytes(Constants.CHARSET_US_ASCII)); | ||
} | ||
|
||
public String getToken() { | ||
if (token == null || tokenExpiry == null || tokenExpiry.isBefore(DateTime.now().plus(TOKEN_EXPIRY_THRESHOLD))) { | ||
try { | ||
TokenResponse response = TokenResponse.parse(tokenRequest.send()); | ||
if (!response.indicatesSuccess()) { | ||
TokenErrorResponse errorResponse = response.toErrorResponse(); | ||
throw new OAuth2ClientException(errorResponse.getErrorObject().getCode() + " - " | ||
+ errorResponse.getErrorObject().getDescription()); | ||
} | ||
AccessTokenResponse successResponse = response.toSuccessResponse(); | ||
|
||
token = successResponse.getTokens().getAccessToken(); | ||
tokenExpiry = DateTime.now().plus(token.getLifetime() * 1000); | ||
} catch (ParseException | IOException e) { | ||
throw new OAuth2ClientException("OAuth2 access token tokenRequest failed", e); | ||
} | ||
} | ||
return token.getValue(); | ||
} | ||
|
||
@Override | ||
public void interceptRequest(IHttpRequest theRequest) { | ||
theRequest.addHeader(Constants.HEADER_AUTHORIZATION, | ||
Constants.HEADER_AUTHORIZATION_VALPREFIX_BEARER + getToken()); | ||
} | ||
|
||
@Override | ||
public void interceptResponse(IHttpResponse theResponse) throws IOException { | ||
} | ||
} |
Oops, something went wrong.