001 package org.tynamo.security.federatedaccounts.facebook;
002
003 import java.util.Collection;
004 import java.util.List;
005
006 import org.apache.shiro.authc.AccountException;
007 import org.apache.shiro.authc.AuthenticationException;
008 import org.apache.shiro.authc.AuthenticationInfo;
009 import org.apache.shiro.authc.AuthenticationToken;
010 import org.apache.shiro.authc.IncorrectCredentialsException;
011 import org.apache.shiro.authz.AuthorizationException;
012 import org.apache.shiro.authz.Permission;
013 import org.apache.shiro.cache.MemoryConstrainedCacheManager;
014 import org.apache.shiro.realm.AuthenticatingRealm;
015 import org.apache.shiro.subject.PrincipalCollection;
016 import org.apache.tapestry5.ioc.annotations.Inject;
017 import org.apache.tapestry5.ioc.annotations.Symbol;
018 import org.slf4j.Logger;
019 import org.tynamo.security.federatedaccounts.FederatedAccount;
020 import org.tynamo.security.federatedaccounts.oauth.FacebookAccessToken;
021 import org.tynamo.security.federatedaccounts.services.FederatedAccountService;
022
023 import com.restfb.DefaultFacebookClient;
024 import com.restfb.FacebookClient;
025 import com.restfb.exception.FacebookException;
026 import com.restfb.types.User;
027
028 /**
029 * <p>
030 * A {@link org.apache.shiro.realm.Realm} that authenticates with Facebook.
031 */
032 public class FacebookRealm extends AuthenticatingRealm {
033 public static final String FACEBOOK_CLIENTID = "facebook.clientid";
034 public static final String FACEBOOK_CLIENTSECRET = "facebook.clientsecret";
035 public static final String FACEBOOK_PERMISSIONS = "facebook.permissions";
036 public static final String FACEBOOK_PRINCIPAL = "facebook.principal";
037
038 private Logger logger;
039
040 public static enum PrincipalProperty {
041 id, email, name
042 }
043
044 private PrincipalProperty principalProperty;
045
046 private FederatedAccountService federatedAccountService;
047
048 public FacebookRealm(Logger logger, FederatedAccountService federatedAccountService,
049 @Inject @Symbol(FacebookRealm.FACEBOOK_PRINCIPAL) String principalPropertyName) {
050 super(new MemoryConstrainedCacheManager());
051 this.federatedAccountService = federatedAccountService;
052 this.logger = logger;
053 // Let this throw IllegalArgumentException if value is not supported
054 this.principalProperty = PrincipalProperty.valueOf(principalPropertyName);
055 setName(FederatedAccount.Type.facebook.name());
056 setAuthenticationTokenClass(FacebookAccessToken.class);
057 }
058
059 @Override
060 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
061 FacebookAccessToken token = (FacebookAccessToken) authenticationToken;
062
063 FacebookClient facebookClient = new DefaultFacebookClient(authenticationToken.getPrincipal().toString());
064 User facebookUser;
065 try {
066 facebookUser = facebookClient.fetchObject("me", User.class);
067 } catch (FacebookException e) {
068 logger.error(e.getMessage(), e);
069 throw new IncorrectCredentialsException("Facebook security verification failed, terminating authentication request", e);
070 }
071 // Null username is invalid, throw an exception if so - indicates that user hasn't granted the right
072 // permissions (and/or we haven't asked for it)
073 if (facebookUser == null) throw new AccountException("Null Facebook user is not allowed by this realm.");
074 // long facebookUserId;
075 // try {
076 // facebookUserId = Long.valueOf(facebookUser.getId());
077 // } catch (NumberFormatException e) {
078 // logger.error("Facebook implementation has changed, returned id '" + facebookUser.getId() +
079 // "' cannot be cast to Long");
080 // throw new AccountException("Unknown user id format. Report this problem to support");
081 // }
082
083 String principalValue = null;
084 switch (principalProperty) {
085 case id: principalValue = facebookUser.getId();
086 break;
087 case email: principalValue = facebookUser.getEmail();
088 break;
089 case name: principalValue = facebookUser.getName();
090 break;
091 }
092
093 AuthenticationInfo authenticationInfo = federatedAccountService.federate(FederatedAccount.Type.facebook.name(), principalValue,
094 authenticationToken, facebookUser);
095 // returned principalcollection is immutable
096 // authenticationInfo.getPrincipals().fromRealm(FederatedAccount.Type.facebook.name()).add(authenticationToken);
097 return authenticationInfo;
098 // if (federatedAccount.isAccountLocked()) { throw new LockedAccountException("Facebook federated account ["
099 // + federatedAccount.getUsername() + "] is locked."); }
100 // if (federatedAccount.isCredentialsExpired()) {
101 // String msg = "The credentials for account [" + facebookUser.getId() + "] are expired";
102 // throw new ExpiredCredentialsException(msg);
103 // }
104 // return new SimpleAuthenticationInfo(federatedAccount.getUsername(), token.getCredentials(), getName());
105
106 // return federatedAccount;
107 }
108
109 /**
110 * FIXME The following operations should all be removed - https://issues.apache.org/jira/browse/SHIRO-231 requires
111 * AuthenticatingRealm to implement Authorizer, which is wrong. Remove when upgrading Shiro dependency to 1.2
112 */
113 @Override
114 public boolean isPermitted(PrincipalCollection principals, String permission) {
115 // TODO Auto-generated method stub
116 return false;
117 }
118
119 @Override
120 public boolean isPermitted(PrincipalCollection subjectPrincipal, Permission permission) {
121 // TODO Auto-generated method stub
122 return false;
123 }
124
125 @Override
126 public boolean[] isPermitted(PrincipalCollection subjectPrincipal, String... permissions) {
127 // TODO Auto-generated method stub
128 return null;
129 }
130
131 @Override
132 public boolean[] isPermitted(PrincipalCollection subjectPrincipal, List<Permission> permissions) {
133 // TODO Auto-generated method stub
134 return null;
135 }
136
137 @Override
138 public boolean isPermittedAll(PrincipalCollection subjectPrincipal, String... permissions) {
139 // TODO Auto-generated method stub
140 return false;
141 }
142
143 @Override
144 public boolean isPermittedAll(PrincipalCollection subjectPrincipal, Collection<Permission> permissions) {
145 // TODO Auto-generated method stub
146 return false;
147 }
148
149 @Override
150 public void checkPermission(PrincipalCollection subjectPrincipal, String permission) throws AuthorizationException {
151 // TODO Auto-generated method stub
152
153 }
154
155 @Override
156 public void checkPermission(PrincipalCollection subjectPrincipal, Permission permission) throws AuthorizationException {
157 // TODO Auto-generated method stub
158
159 }
160
161 @Override
162 public void checkPermissions(PrincipalCollection subjectPrincipal, String... permissions) throws AuthorizationException {
163 // TODO Auto-generated method stub
164
165 }
166
167 @Override
168 public void checkPermissions(PrincipalCollection subjectPrincipal, Collection<Permission> permissions) throws AuthorizationException {
169 // TODO Auto-generated method stub
170
171 }
172
173 @Override
174 public boolean hasRole(PrincipalCollection subjectPrincipal, String roleIdentifier) {
175 // TODO Auto-generated method stub
176 return false;
177 }
178
179 @Override
180 public boolean[] hasRoles(PrincipalCollection subjectPrincipal, List<String> roleIdentifiers) {
181 // TODO Auto-generated method stub
182 return null;
183 }
184
185 @Override
186 public boolean hasAllRoles(PrincipalCollection subjectPrincipal, Collection<String> roleIdentifiers) {
187 // TODO Auto-generated method stub
188 return false;
189 }
190
191 @Override
192 public void checkRole(PrincipalCollection subjectPrincipal, String roleIdentifier) throws AuthorizationException {
193 // TODO Auto-generated method stub
194
195 }
196
197 @Override
198 public void checkRoles(PrincipalCollection subjectPrincipal, Collection<String> roleIdentifiers) throws AuthorizationException {
199 // TODO Auto-generated method stub
200
201 }
202
203 @Override
204 public void checkRoles(PrincipalCollection subjectPrincipal, String... roleIdentifiers) throws AuthorizationException {
205 // TODO Auto-generated method stub
206
207 }
208
209 }