/*
*
* * Copyright (c) 2016. David Sowerby
* *
* * 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 uk.q3c.krail.core.shiro;
import com.google.inject.Inject;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.realm.activedirectory.ActiveDirectoryRealm;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.realm.ldap.JndiLdapRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.q3c.krail.core.navigate.sitemap.MasterSitemap;
import javax.annotation.Nonnull;
import java.util.Optional;
public class DefaultRealm extends AuthorizingRealmBase {
private static Logger log = LoggerFactory.getLogger(DefaultRealm.class);
private final LoginAttemptLog loginAttemptLog;
private SubjectIdentifier subjectIdentifier;
@Inject
protected DefaultRealm(LoginAttemptLog loginAttemptLog, CredentialsMatcher matcher, SubjectIdentifier subjectIdentifier, Optional<CacheManager>
cacheManagerOpt) {
super(cacheManagerOpt);
this.loginAttemptLog = loginAttemptLog;
this.subjectIdentifier = subjectIdentifier;
}
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof UsernamePasswordToken;
}
/**
* This Realm implementation is not expected to be used in a real system, not least because anyone can log in as
* long as they have a password of 'password'! AND it exposes user names and password in the debug log <br>
* <br>
* It does however demonstrate the use of {@link LoginAttemptLog} to track login attempts Authorises all users to
* access the private pages of the {@link MasterSitemap}
*
* @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(@Nonnull AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
String password = String.copyValueOf(upToken.getPassword());
log.debug("Username {}, password: {}", username, password);
if ("password".equals(password) && (!(username == null) && (!username.isEmpty()))) {
log.debug("login succeeds");
loginAttemptLog.recordSuccessfulAttempt(upToken);
return new SimpleAuthenticationInfo(username, password, this.getName());
} else {
log.debug("login fails");
if (username != null) {
loginAttemptLog.recordFailedAttempt(upToken);
}
return null;
}
}
@Override
public String getName() {
return "Krail Default Realm";
}
/**
* This Realm implementation is not expected to be used in a real system, not least because anyone can log in as
* long as they have a password of 'password'! <br>
* <br>
* This method would normally retrieve user permissions and /or roles from an underlying datastore of some form.
* There are various implementations already provided by Shiro, including {@link ActiveDirectoryRealm},
* {@link JdbcRealm} and {@link JndiLdapRealm}<br>
* <br>
* You can provide your own Realm implementation by overriding {@link DefaultShiroModule#bindRealms()}<br>
* <br>
* This implementation authorises<ol>
* <li>all authenticated users to access the pages of the 'private' or 'system-admin' branches of the {@link MasterSitemap}</li>
* <li>users to edit their own options in the SimpleUserHierarchy</li>
* </ol>
*
* @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// used by PageController - authorisation to see pages in 'private' branch
String privatePermission = "page:view:private:*";
info.addStringPermission(privatePermission);
// used by PageController - authorisation to see pages in 'system-admin' branch
String sysAdminPermission = "page:view:system-admin:*";
info.addStringPermission(sysAdminPermission);
// used by Option to enable users to edit their own options in SimpleUserHierarchy
String userId = subjectIdentifier.userId();
String editOwnOptionsPermission = "option:edit:SimpleUserHierarchy:" + userId + ":0:*:*";
info.addStringPermission(editOwnOptionsPermission);
// admin can set any options in SimpleUserHierarchy
if ("admin".equals(userId.toLowerCase())) {
String editAnyOption = "option:edit:SimpleUserHierarchy:*:*:*:*";
info.addStringPermission(editAnyOption);
}
return info;
}
/**
* This has been made public to enable testing
*
* @see org.apache.shiro.realm.AuthorizingRealm#getAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection)
*/
@Override
public AuthorizationInfo getAuthorizationInfo(PrincipalCollection principals) {
return super.getAuthorizationInfo(principals);
}
}