///////////////////////////////////////////////////////////////////////////// // // Project ProjectForge Community Edition // www.projectforge.org // // Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de) // // ProjectForge is dual-licensed. // // This community edition is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as published // by the Free Software Foundation; version 3 of the License. // // This community edition 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 this program; if not, see http://www.gnu.org/licenses/. // ///////////////////////////////////////////////////////////////////////////// package org.projectforge.web.rest; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import org.projectforge.AppVersion; import org.projectforge.Version; import org.projectforge.registry.Registry; import org.projectforge.rest.JsonUtils; import org.projectforge.rest.RestPaths; import org.projectforge.rest.objects.ServerInfo; import org.projectforge.rest.objects.UserObject; import org.projectforge.user.PFUserContext; import org.projectforge.user.PFUserDO; import org.projectforge.user.UserDao; import org.projectforge.web.rest.converter.PFUserDOConverter; /** * REST interface for authentication (tests) and getting the authentication token on initial contact. * * <h2>Concept</h2> It's recommended to avoid storing the user's username and password on the client (e. g. on the mobile phone) due to * security reasons. Please store the user's id and authentication-token instead: * <ol> * <li>On first start of your client (user-token isn't known yet), please call {@link #getToken()} for getting the user data (id, * authentication-token and optional information) by sending the username and password the user typed in.</li> * <li> * You may now store the user's id and authentication-token for the user's convenience on your client (e. g. mobile app).</li> * <li> * Every time the user starts the client / app you should call {@link #initialContact(String)} for checking the server version. May-be the * server version is too old or your client version is too old. This call is optional but good practice.</li> * <li> * Every further rest call is done by authentication via user-id and authentication-token. The user-id is required for logging purposes e. g. for failed logins or brute-force attacks. * </li> * </ol> * * @author Kai Reinhard (k.reinhard@micromata.de) * */ @Path(RestPaths.AUTHENTICATE) public class AuthenticationRest { private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(AuthenticationRest.class); private final UserDao userDao; public AuthenticationRest() { this.userDao = Registry.instance().getDao(UserDao.class); } /** * Authentication via http header authenticationUsername and authenticationPassword.<br/> * For getting the user's authentication token. This token can be stored in the client (e. g. mobile app). The user's password shouldn't * be stored in the client for security reasons. The authentication token is renewable through the ProjectForge's web app (my account). * @return {@link UserObject} */ @GET @Path(RestPaths.AUTHENTICATE_GET_TOKEN_METHOD) @Produces(MediaType.APPLICATION_JSON) public Response getToken() { final PFUserDO user = PFUserContext.getUser(); if (user == null) { log.error("No user given for rest call."); throw new IllegalArgumentException("No user given for the rest call: authenticate/getToken."); } final UserObject userObject = PFUserDOConverter.getUserObject(user); final String authenticationToken = userDao.getAuthenticationToken(user.getId()); userObject.setAuthenticationToken(authenticationToken); final String json = JsonUtils.toJson(userObject); return Response.ok(json).build(); } /** * Authentication via http header authenticationUserId and authenticationToken. * @param clientVersionString * @return {@link ServerInfo} */ @GET @Path(RestPaths.AUTHENTICATE_INITIAL_CONTACT_METHOD) @Produces(MediaType.APPLICATION_JSON) public Response initialContact(@QueryParam("clientVersion") final String clientVersionString) { final PFUserDO user = PFUserContext.getUser(); if (user == null) { log.error("No user given for rest call."); throw new IllegalArgumentException("No user given for the rest call: authenticate/getToken."); } final UserObject userObject = PFUserDOConverter.getUserObject(user); final ServerInfo info = new ServerInfo(AppVersion.VERSION.toString()); info.setUser(userObject); Version clientVersion = null; if (clientVersionString != null) { clientVersion = new Version(clientVersionString); } if (clientVersion == null) { info.setStatus(ServerInfo.STATUS_UNKNOWN); } else if (clientVersion.compareTo(new Version("5.0")) < 0) { info.setStatus(ServerInfo.STATUS_CLIENT_TO_OLD); } else if (clientVersion.compareTo(AppVersion.VERSION) > 0) { info.setStatus(ServerInfo.STATUS_CLIENT_NEWER_THAN_SERVER); } else { info.setStatus(ServerInfo.STATUS_OK); } final String json = JsonUtils.toJson(info); return Response.ok(json).build(); } }