001/** 002 * GRANITE DATA SERVICES 003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S. 004 * 005 * This file is part of the Granite Data Services Platform. 006 * 007 * *** 008 * 009 * Community License: GPL 3.0 010 * 011 * This file is free software: you can redistribute it and/or modify 012 * it under the terms of the GNU General Public License as published 013 * by the Free Software Foundation, either version 3 of the License, 014 * or (at your option) any later version. 015 * 016 * This file is distributed in the hope that it will be useful, but 017 * WITHOUT ANY WARRANTY; without even the implied warranty of 018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 019 * GNU General Public License for more details. 020 * 021 * You should have received a copy of the GNU General Public License 022 * along with this program. If not, see <http://www.gnu.org/licenses/>. 023 * 024 * *** 025 * 026 * Available Commercial License: GraniteDS SLA 1.0 027 * 028 * This is the appropriate option if you are creating proprietary 029 * applications and you are not prepared to distribute and share the 030 * source code of your application under the GPL v3 license. 031 * 032 * Please visit http://www.granitedataservices.com/license for more 033 * details. 034 */ 035package org.granite.client.tide; 036 037import java.beans.PropertyChangeListener; 038import java.beans.PropertyChangeSupport; 039import java.nio.charset.Charset; 040import java.util.Observable; 041import java.util.Observer; 042import java.util.concurrent.Future; 043 044import org.granite.client.messaging.messages.responses.FaultMessage; 045import org.granite.client.messaging.messages.responses.FaultMessage.Code; 046import org.granite.client.tide.impl.ComponentImpl; 047import org.granite.client.tide.server.ExceptionHandler; 048import org.granite.client.tide.server.ServerSession; 049import org.granite.client.tide.server.SimpleTideResponder; 050import org.granite.client.tide.server.TideFaultEvent; 051import org.granite.client.tide.server.TideResponder; 052import org.granite.client.tide.server.TideResultEvent; 053 054 055public abstract class BaseIdentity extends ComponentImpl implements Identity, ExceptionHandler { 056 057 private boolean loggedIn; 058 private String username; 059 private PropertyChangeSupport pcs = new PropertyChangeSupport(this); 060 061 public boolean isLoggedIn() { 062 return loggedIn; 063 } 064 065 public void setLoggedIn(boolean loggedIn) { 066 if (loggedIn == this.loggedIn) 067 return; 068 069 this.loggedIn = loggedIn; 070 if (loggedIn) 071 getServerSession().afterLogin(); 072 else 073 setUsername(null); 074 075 pcs.firePropertyChange("loggedIn", !loggedIn, loggedIn); 076 } 077 078 public String getUsername() { 079 return username; 080 } 081 082 protected void setUsername(String username) { 083 String oldUsername = this.username; 084 this.username = username; 085 086 if ((username == null && oldUsername != null) || (username != null && !username.equals(oldUsername))) 087 pcs.firePropertyChange("username", oldUsername, username); 088 } 089 090 091 public BaseIdentity(final ServerSession serverSession) { 092 super(serverSession); 093 094 loggedIn = false; 095 } 096 097 /** 098 * Triggers a remote call to check is user is currently logged in 099 * Can be used at application startup to handle browser refresh cases 100 * 101 * @param tideResponder a responder for the remote call 102 * @return future result returning the username if logged in or null 103 */ 104 public Future<String> checkLoggedIn(final TideResponder<String> tideResponder) { 105 return super.call("isLoggedIn", new SimpleTideResponder<String>() { 106 @Override 107 public void result(TideResultEvent<String> event) { 108 if (event.getResult() != null) { 109 setUsername(event.getResult()); 110 setLoggedIn(true); 111 } 112 else if (isLoggedIn()) { 113 setLoggedIn(false); 114 115 // Session expired, directly mark the channel as logged out 116 getServerSession().sessionExpired(); 117 } 118 119 if (tideResponder != null) 120 tideResponder.result(event); 121 } 122 123 @Override 124 public void fault(TideFaultEvent event) { 125 if (event.getFault().getCode() == Code.ACCESS_DENIED) { 126 // Not in role for the destination 127 setLoggedIn(false); 128 129 getServerSession().logout(null); 130 } 131 132 if (tideResponder != null) 133 tideResponder.fault(event); 134 } 135 }); 136 } 137 138 139 public void login(final String username, String password, final TideResponder<String> tideResponder) { 140 getServerSession().login(username, password); 141 142 clearSecurityCache(); 143 144 try { 145 // Force synchronous operation to prevent issues with Spring session fixation protection 146 // so next remote calls use the correct session id 147 checkLoggedIn(tideResponder).get(); 148 } 149 catch (Exception e) { 150 } 151 } 152 153 public void login(final String username, String password, Charset charset, final TideResponder<String> tideResponder) { 154 getServerSession().login(username, password, charset); 155 156 clearSecurityCache(); 157 158 try { 159 // Force synchronous operation to prevent issues with Spring session fixation protection 160 // so next remote calls use the correct session id 161 checkLoggedIn(tideResponder).get(); 162 } 163 catch (Exception e) { 164 } 165 } 166 167 168 public void logout(final TideResponder<Void> tideResponder) { 169 final Observer observer = new Observer() { 170 @SuppressWarnings("unchecked") 171 @Override 172 public void update(Observable logout, Object event) { 173 setLoggedIn(false); 174 175 if (tideResponder != null) { 176 if (event instanceof TideResultEvent) 177 tideResponder.result((TideResultEvent<Void>)event); 178 else if (event instanceof TideFaultEvent) 179 tideResponder.fault((TideFaultEvent)event); 180 } 181 } 182 }; 183 184 getServerSession().logout(observer); 185 } 186 187 188 @Override 189 public boolean accepts(FaultMessage emsg) { 190 return emsg.getCode() == Code.NOT_LOGGED_IN; 191 } 192 193 @Override 194 public void handle(Context context, FaultMessage emsg, TideFaultEvent faultEvent) { 195 if (isLoggedIn()) { 196 setLoggedIn(false); 197 198 // Session expired, directly mark the channel as logged out 199 getServerSession().sessionExpired(); 200 } 201 } 202 203 204 public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) { 205 pcs.addPropertyChangeListener(propertyName, listener); 206 } 207 208 public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) { 209 pcs.removePropertyChangeListener(propertyName, listener); 210 } 211 212 public void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { 213 pcs.firePropertyChange(propertyName, oldValue, newValue); 214 } 215 216 /** 217 * Clear the security cache 218 */ 219 public void clearSecurityCache() { 220 } 221}