aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/traccar/api')
-rw-r--r--src/main/java/org/traccar/api/resource/ServerResource.java7
-rw-r--r--src/main/java/org/traccar/api/resource/SessionResource.java26
-rw-r--r--src/main/java/org/traccar/api/security/LoginService.java17
-rw-r--r--src/main/java/org/traccar/api/security/OpenIDProvider.java245
4 files changed, 27 insertions, 268 deletions
diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java
index 4b7ee9189..9b4d82a66 100644
--- a/src/main/java/org/traccar/api/resource/ServerResource.java
+++ b/src/main/java/org/traccar/api/resource/ServerResource.java
@@ -16,6 +16,7 @@
package org.traccar.api.resource;
import org.traccar.api.BaseResource;
+import org.traccar.database.OpenIdProvider;
import org.traccar.helper.model.UserUtil;
import org.traccar.mail.MailManager;
import org.traccar.geocoder.Geocoder;
@@ -57,6 +58,10 @@ public class ServerResource extends BaseResource {
@Inject
@Nullable
+ private OpenIdProvider openIdProvider;
+
+ @Inject
+ @Nullable
private Geocoder geocoder;
@PermitAll
@@ -65,6 +70,8 @@ public class ServerResource extends BaseResource {
Server server = storage.getObject(Server.class, new Request(new Columns.All()));
server.setEmailEnabled(mailManager.getEmailEnabled());
server.setGeocoderEnabled(geocoder != null);
+ server.setOpenIdEnabled(openIdProvider != null);
+ server.setOpenIdForce(openIdProvider != null && openIdProvider.force);
User user = permissionsService.getUser(getUserId());
if (user != null) {
if (user.getAdministrator()) {
diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java
index 515d7374a..3de20b8c7 100644
--- a/src/main/java/org/traccar/api/resource/SessionResource.java
+++ b/src/main/java/org/traccar/api/resource/SessionResource.java
@@ -17,8 +17,8 @@ package org.traccar.api.resource;
import org.traccar.api.BaseResource;
import org.traccar.api.security.LoginService;
-import org.traccar.api.security.OpenIDProvider;
import org.traccar.api.signature.TokenManager;
+import org.traccar.database.OpenIdProvider;
import org.traccar.helper.DataConverter;
import org.traccar.helper.LogAction;
import org.traccar.helper.ServletHelper;
@@ -28,6 +28,7 @@ import org.traccar.storage.query.Columns;
import org.traccar.storage.query.Condition;
import org.traccar.storage.query.Request;
+import com.nimbusds.oauth2.sdk.ParseException;
import javax.annotation.security.PermitAll;
import javax.inject.Inject;
import javax.servlet.http.Cookie;
@@ -65,7 +66,7 @@ public class SessionResource extends BaseResource {
private LoginService loginService;
@Inject
- private OpenIDProvider openIdProvider;
+ private OpenIdProvider openIdProvider;
@Inject
private TokenManager tokenManager;
@@ -169,28 +170,17 @@ public class SessionResource extends BaseResource {
@Path("openid/auth")
@GET
public Response openIdAuth() throws IOException {
- if (openIdProvider == null) {
- throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
- }
-
- return Response.seeOther(
- openIdProvider.createAuthRequest()
- ).build();
+ return Response.seeOther(openIdProvider.createAuthUri()).build();
}
@PermitAll
@Path("openid/callback")
@GET
- public Response requestToken() throws IOException, StorageException {
- if (openIdProvider == null) {
- throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build());
- }
-
- // Get full request URI
- StringBuilder requestURL = new StringBuilder(request.getRequestURL().toString());
+ public Response requestToken() throws IOException, StorageException, ParseException {
+ StringBuilder requestUrl = new StringBuilder(request.getRequestURL().toString());
String queryString = request.getQueryString();
- String requestURI = requestURL.append('?').append(queryString).toString();
+ String requestUri = requestUrl.append('?').append(queryString).toString();
- return openIdProvider.handleCallback(URI.create(requestURI), request);
+ return openIdProvider.handleCallback(URI.create(requestUri), request);
}
}
diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java
index 3d4f42b20..7b51667c8 100644
--- a/src/main/java/org/traccar/api/security/LoginService.java
+++ b/src/main/java/org/traccar/api/security/LoginService.java
@@ -89,17 +89,24 @@ public class LoginService {
return null;
}
- public User lookup(String email) throws StorageException {
+ public User login(String email, String name, Boolean administrator) throws StorageException {
User user = storage.getObject(User.class, new Request(
- new Columns.All(),
- new Condition.Equals("email", email)));
+ new Columns.All(),
+ new Condition.Equals("email", email)));
if (user != null) {
checkUserEnabled(user);
return user;
+ } else {
+ user = new User();
+ user.setName(name);
+ user.setEmail(email);
+ user.setFixedEmail(true);
+ user.setAdministrator(administrator);
+ user.setId(storage.addObject(user, new Request(new Columns.Exclude("id"))));
+ checkUserEnabled(user);
+ return user;
}
-
- return null;
}
private void checkUserEnabled(User user) throws SecurityException {
diff --git a/src/main/java/org/traccar/api/security/OpenIDProvider.java b/src/main/java/org/traccar/api/security/OpenIDProvider.java
deleted file mode 100644
index 1e18fde43..000000000
--- a/src/main/java/org/traccar/api/security/OpenIDProvider.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.traccar.api.security;
-
-import org.traccar.config.Config;
-import org.traccar.config.Keys;
-import org.traccar.api.resource.SessionResource;
-import org.traccar.model.User;
-import org.traccar.storage.Storage;
-import org.traccar.storage.StorageException;
-import org.traccar.storage.query.Request;
-import org.traccar.storage.query.Columns;
-import org.traccar.helper.LogAction;
-import org.traccar.helper.ServletHelper;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Date;
-import java.util.List;
-import java.io.IOException;
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Response;
-import com.google.inject.Inject;
-
-import com.nimbusds.oauth2.sdk.http.HTTPResponse;
-import com.nimbusds.oauth2.sdk.AuthorizationCode;
-import com.nimbusds.oauth2.sdk.ResponseType;
-import com.nimbusds.oauth2.sdk.Scope;
-import com.nimbusds.oauth2.sdk.AuthorizationGrant;
-import com.nimbusds.oauth2.sdk.TokenRequest;
-import com.nimbusds.oauth2.sdk.TokenResponse;
-import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
-import com.nimbusds.oauth2.sdk.AuthorizationErrorResponse;
-import com.nimbusds.oauth2.sdk.ParseException;
-import com.nimbusds.oauth2.sdk.AuthorizationResponse;
-import com.nimbusds.oauth2.sdk.auth.Secret;
-import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic;
-import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
-import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
-import com.nimbusds.oauth2.sdk.id.State;
-import com.nimbusds.oauth2.sdk.id.ClientID;
-import com.nimbusds.openid.connect.sdk.OIDCTokenResponse;
-import com.nimbusds.openid.connect.sdk.Nonce;
-import com.nimbusds.openid.connect.sdk.OIDCTokenResponseParser;
-import com.nimbusds.openid.connect.sdk.UserInfoResponse;
-import com.nimbusds.openid.connect.sdk.UserInfoRequest;
-import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
-
-import com.nimbusds.openid.connect.sdk.claims.UserInfo;
-
-public class OpenIDProvider {
- public final Boolean force;
- private final ClientID clientId;
- private final Secret clientSecret;
- private URI callbackUrl;
- private URI authUrl;
- private URI tokenUrl;
- private URI userInfoUrl;
- private URI baseUrl;
- private final String adminGroup;
-
- private Config config;
- private LoginService loginService;
- private Storage storage;
-
- @Inject
- public OpenIDProvider(Config config, LoginService loginService, Storage storage) {
- force = config.getBoolean(Keys.OIDC_FORCE);
- clientId = new ClientID(config.getString(Keys.OIDC_CLIENTID));
- clientSecret = new Secret(config.getString(Keys.OIDC_CLIENTSECRET));
-
- this.config = config;
- this.storage = storage;
- this.loginService = loginService;
-
- try {
- callbackUrl = new URI(config.getString(Keys.WEB_URL, "") + "/api/session/openid/callback");
- authUrl = new URI(config.getString(Keys.OIDC_AUTHURL, ""));
- tokenUrl = new URI(config.getString(Keys.OIDC_TOKENURL, ""));
- userInfoUrl = new URI(config.getString(Keys.OIDC_USERINFOURL, ""));
- baseUrl = new URI(config.getString(Keys.WEB_URL, ""));
- } catch (URISyntaxException e) {
- }
-
- adminGroup = config.getString(Keys.OIDC_ADMINGROUP);
- }
-
- public URI createAuthRequest() {
- AuthenticationRequest request = new AuthenticationRequest.Builder(
- new ResponseType("code"),
- new Scope("openid", "profile", "email", "groups"),
- this.clientId,
- this.callbackUrl)
- .endpointURI(this.authUrl)
- .state(new State())
- .nonce(new Nonce())
- .build();
-
- return request.toURI();
- }
-
- private OIDCTokenResponse getToken(AuthorizationCode code) {
- // Credentials to authenticate us to the token endpoint
- ClientAuthentication clientAuth = new ClientSecretBasic(this.clientId, this.clientSecret);
- AuthorizationGrant codeGrant = new AuthorizationCodeGrant(code, this.callbackUrl);
-
- TokenRequest request = new TokenRequest(this.tokenUrl, clientAuth, codeGrant);
- TokenResponse tokenResponse;
-
- try {
- HTTPResponse tokenReq = request.toHTTPRequest().send();
- tokenResponse = OIDCTokenResponseParser.parse(tokenReq);
- if (!tokenResponse.indicatesSuccess()) {
- return null;
- }
-
- return (OIDCTokenResponse) tokenResponse.toSuccessResponse();
- } catch (IOException e) {
- return null;
- } catch (ParseException e) {
- return null;
- }
- }
-
- private AuthorizationCode parseCallback(URI requri) throws WebApplicationException {
- AuthorizationResponse response;
-
- try {
- response = AuthorizationResponse.parse(requri);
- } catch (ParseException e) {
- return null;
- }
-
- if (!response.indicatesSuccess()) {
- AuthorizationErrorResponse error = response.toErrorResponse();
- throw new WebApplicationException(Response.status(403).entity(error.getErrorObject().getDescription()).build());
- }
-
- return response.toSuccessResponse().getAuthorizationCode();
- }
-
- private UserInfo getUserInfo(BearerAccessToken token) {
- UserInfoResponse userInfoResponse;
-
- try {
- HTTPResponse httpResponse = new UserInfoRequest(this.userInfoUrl, token)
- .toHTTPRequest()
- .send();
-
- userInfoResponse = UserInfoResponse.parse(httpResponse);
- } catch (IOException e) {
- return null;
- } catch (ParseException e) {
- return null;
- }
-
- if (!userInfoResponse.indicatesSuccess()) {
- // User info request failed - usually from expiring
- return null;
- }
-
- return userInfoResponse.toSuccessResponse().getUserInfo();
- }
-
- private User createUser(String name, String email, Boolean administrator) throws StorageException {
- User user = new User();
-
- user.setName(name);
- user.setEmail(email);
- user.setFixedEmail(true);
- user.setDeviceLimit(this.config.getInteger(Keys.USERS_DEFAULT_DEVICE_LIMIT));
-
- int expirationDays = this.config.getInteger(Keys.USERS_DEFAULT_EXPIRATION_DAYS);
-
- if (expirationDays > 0) {
- user.setExpirationTime(new Date(System.currentTimeMillis() + expirationDays * 86400000L));
- }
-
- if (administrator) {
- user.setAdministrator(true);
- }
-
- user.setId(this.storage.addObject(user, new Request(new Columns.Exclude("id"))));
-
- return user;
- }
-
- public Response handleCallback(URI requri, HttpServletRequest request) throws StorageException, WebApplicationException {
- // Parse callback
- AuthorizationCode authCode = this.parseCallback(requri);
-
- if (authCode == null) {
- return Response.status(403).entity( "Invalid OpenID Connect callback.").build();
- }
-
- // Get token from IDP
- OIDCTokenResponse tokens = this.getToken(authCode);
-
- if (tokens == null) {
- return Response.status(403).entity("Unable to authenticate with the OpenID Connect provider. Please try again.").build();
- }
-
- BearerAccessToken bearerToken = tokens.getOIDCTokens().getBearerAccessToken();
-
- // Get user info from IDP
- UserInfo idpUser = this.getUserInfo(bearerToken);
-
- if (idpUser == null) {
- return Response.status(500).entity("Failed to access OpenID Connect user info endpoint. Please contact your administrator.").build();
- }
-
- String email = idpUser.getEmailAddress();
- String name = idpUser.getName();
-
- // Check if user exists
- User user = this.loginService.lookup(email);
-
- // If user does not exist, create one
- if (user == null) {
- List<String> groups = idpUser.getStringListClaim("groups");
- Boolean administrator = groups.contains(this.adminGroup);
- user = this.createUser(name, email, administrator);
- }
-
- // Set user session and redirect to homepage
- request.getSession().setAttribute(SessionResource.USER_ID_KEY, user.getId());
- LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request));
- return Response.seeOther(
- baseUrl).build();
- }
-}