/* This file is part of Cyclos (www.cyclos.org). A project of the Social Trade Organisation (www.socialtrade.org). Cyclos 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; either version 2 of the License, or (at your option) any later version. Cyclos 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 Cyclos; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package nl.strohalm.cyclos.webservices.access; import javax.jws.WebService; import nl.strohalm.cyclos.entities.access.Channel; import nl.strohalm.cyclos.entities.access.Channel.Credentials; import nl.strohalm.cyclos.entities.access.PrincipalType; import nl.strohalm.cyclos.entities.members.Element; import nl.strohalm.cyclos.entities.members.Member; import nl.strohalm.cyclos.exceptions.PermissionDeniedException; import nl.strohalm.cyclos.services.access.AccessServiceLocal; import nl.strohalm.cyclos.services.access.exceptions.BlockedCredentialsException; import nl.strohalm.cyclos.services.access.exceptions.CredentialsAlreadyUsedException; import nl.strohalm.cyclos.services.access.exceptions.InvalidCredentialsException; import nl.strohalm.cyclos.services.elements.ElementServiceLocal; import nl.strohalm.cyclos.services.settings.SettingsServiceLocal; import nl.strohalm.cyclos.utils.validation.ValidationError; import nl.strohalm.cyclos.utils.validation.ValidationException; import nl.strohalm.cyclos.webservices.PrincipalParameters; import nl.strohalm.cyclos.webservices.WebServiceContext; import nl.strohalm.cyclos.webservices.utils.ChannelHelper; import nl.strohalm.cyclos.webservices.utils.MemberHelper; import nl.strohalm.cyclos.webservices.utils.WebServiceHelper; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; /** * Implementation for AccessWebService * * @author luis */ @WebService(name = "access", serviceName = "access") public class AccessWebServiceImpl implements AccessWebService { private SettingsServiceLocal settingsServiceLocal; private ChannelHelper channelHelper; private ElementServiceLocal elementServiceLocal; private AccessServiceLocal accessServiceLocal; private MemberHelper memberHelper; private WebServiceHelper webServiceHelper; @Override public ChangeCredentialsStatus changeCredentials(final ChangeCredentialsParameters params) { // Get and validate the parameters final String principal = params == null ? null : StringUtils.trimToNull(params.getPrincipal()); final String oldCredentials = params == null ? null : StringUtils.trimToNull(params.getOldCredentials()); final String newCredentials = params == null ? null : StringUtils.trimToNull(params.getNewCredentials()); if (principal == null || oldCredentials == null || newCredentials == null) { throw new ValidationException(); } final Channel channel = WebServiceContext.getChannel(); // Only login password and pin can be changed from here final Credentials credentials = channel.getCredentials(); if (credentials != Credentials.LOGIN_PASSWORD && credentials != Credentials.PIN) { throw new PermissionDeniedException(); } final PrincipalType principalType = channelHelper.resolvePrincipalType(params.getPrincipalType()); // Load the member Member member; try { member = elementServiceLocal.loadByPrincipal(principalType, principal, Element.Relationships.GROUP, Element.Relationships.USER); } catch (final Exception e) { webServiceHelper.error(e); return ChangeCredentialsStatus.MEMBER_NOT_FOUND; } // Check the current credentials try { accessServiceLocal.checkCredentials(channel, member.getMemberUser(), oldCredentials, WebServiceContext.getRequest().getRemoteAddr(), WebServiceContext.getMember()); } catch (final InvalidCredentialsException e) { webServiceHelper.error(e); return ChangeCredentialsStatus.INVALID_CREDENTIALS; } catch (final BlockedCredentialsException e) { webServiceHelper.error(e); return ChangeCredentialsStatus.BLOCKED_CREDENTIALS; } // The login password is numeric depending on settings. Others, are always numeric boolean numericPassword; if (credentials == Credentials.LOGIN_PASSWORD) { numericPassword = settingsServiceLocal.getAccessSettings().isNumericPassword(); } else { numericPassword = true; } if (numericPassword && !StringUtils.isNumeric(newCredentials)) { return ChangeCredentialsStatus.INVALID_CHARACTERS; } // Change the password try { accessServiceLocal.changeCredentials(member.getMemberUser(), newCredentials); } catch (final ValidationException e) { if (CollectionUtils.isNotEmpty(e.getGeneralErrors())) { // Actually, the only possible general error is that it is the same as another credential. // In this case, we return CREDENTIALS_ALREADY_USED return ChangeCredentialsStatus.CREDENTIALS_ALREADY_USED; } // There is a property error. Let's scrap it to determine which is it try { final ValidationError error = e.getErrorsByProperty().values().iterator().next().iterator().next(); final String key = error.getKey(); if (key.endsWith("obvious")) { // The password is too simple return ChangeCredentialsStatus.TOO_SIMPLE; } else { // Either must be numeric / must contain letters and numbers / must contain letters, numbers and special throw new Exception(); } } catch (final Exception e1) { // If there is some kind of unexpected validation result, just return as invalid webServiceHelper.error(e1); return ChangeCredentialsStatus.INVALID_CHARACTERS; } } catch (final CredentialsAlreadyUsedException e) { webServiceHelper.error(e); return ChangeCredentialsStatus.CREDENTIALS_ALREADY_USED; } return ChangeCredentialsStatus.SUCCESS; } @Override public CredentialsStatus checkCredentials(final CheckCredentialsParameters params) { if (WebServiceContext.getMember() != null) { // Only allow this method on unrestricted clients throw new PermissionDeniedException(); } try { final Channel channel = WebServiceContext.getChannel(); final PrincipalType principalType = channelHelper.resolvePrincipalType(params.getPrincipalType()); final Member member = memberHelper.loadByPrincipal(principalType, params.getPrincipal()); String credentials = params.getCredentials(); if (channel.getCredentials() == Credentials.TRANSACTION_PASSWORD) { credentials = credentials.toUpperCase(); } final String remoteAddr = WebServiceContext.getRequest().getRemoteAddr(); accessServiceLocal.checkCredentials(channel, member.getMemberUser(), credentials, remoteAddr, null); return CredentialsStatus.VALID; } catch (final BlockedCredentialsException e) { webServiceHelper.error(e); return CredentialsStatus.BLOCKED; } catch (final Exception e) { webServiceHelper.error(e); return CredentialsStatus.INVALID; } } @Override public boolean isChannelEnabledForMember(final PrincipalParameters params) { Member member = WebServiceContext.getMember(); if (member != null) { throw new PermissionDeniedException(); } final PrincipalType principalType = channelHelper.resolvePrincipalType(params.getPrincipalType()); member = elementServiceLocal.loadByPrincipal(principalType, params.getPrincipal()); return memberHelper.isChannelEnabledForMember(member); } public void setAccessServiceLocal(final AccessServiceLocal accessService) { accessServiceLocal = accessService; } public void setChannelHelper(final ChannelHelper channelHelper) { this.channelHelper = channelHelper; } public void setElementServiceLocal(final ElementServiceLocal elementService) { elementServiceLocal = elementService; } public void setMemberHelper(final MemberHelper memberHelper) { this.memberHelper = memberHelper; } public void setSettingsServiceLocal(final SettingsServiceLocal settingsService) { settingsServiceLocal = settingsService; } public void setWebServiceHelper(final WebServiceHelper webServiceHelper) { this.webServiceHelper = webServiceHelper; } }