| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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 org.apache.shiro.cas; |
| |
| import org.apache.shiro.authc.AuthenticationException; |
| import org.apache.shiro.authc.AuthenticationInfo; |
| import org.apache.shiro.authc.AuthenticationToken; |
| import org.apache.shiro.authc.SimpleAuthenticationInfo; |
| import org.apache.shiro.authz.AuthorizationInfo; |
| import org.apache.shiro.authz.SimpleAuthorizationInfo; |
| import org.apache.shiro.realm.AuthorizingRealm; |
| import org.apache.shiro.subject.PrincipalCollection; |
| import org.apache.shiro.subject.SimplePrincipalCollection; |
| import org.apache.shiro.util.CollectionUtils; |
| import org.apache.shiro.util.StringUtils; |
| import org.jasig.cas.client.authentication.AttributePrincipal; |
| import org.jasig.cas.client.validation.*; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| |
| /** |
| * This realm implementation acts as a CAS client to a CAS server for authentication and basic authorization. |
| * <p/> |
| * This realm functions by inspecting a submitted {@link org.apache.shiro.cas.CasToken CasToken} (which essentially |
| * wraps a CAS service ticket) and validates it against the CAS server using a configured CAS |
| * {@link org.jasig.cas.client.validation.TicketValidator TicketValidator}. |
| * <p/> |
| * The {@link #getValidationProtocol() validationProtocol} is {@code CAS} by default, which indicates that a |
| * a {@link org.jasig.cas.client.validation.Cas20ServiceTicketValidator Cas20ServiceTicketValidator} |
| * will be used for ticket validation. You can alternatively set |
| * or {@link org.jasig.cas.client.validation.Saml11TicketValidator Saml11TicketValidator} of CAS client. It is based on |
| * {@link AuthorizingRealm AuthorizingRealm} for both authentication and authorization. User id and attributes are retrieved from the CAS |
| * service ticket validation response during authentication phase. Roles and permissions are computed during authorization phase (according |
| * to the attributes previously retrieved). |
| * |
| * @since 1.2 |
| * @see <a href="https://github.com/bujiio/buji-pac4j">buji-pac4j</a> |
| * @deprecated replaced with Shiro integration in <a href="https://github.com/bujiio/buji-pac4j">buji-pac4j</a>. |
| */ |
| @Deprecated |
| public class CasRealm extends AuthorizingRealm { |
| |
| // default name of the CAS attribute for remember me authentication (CAS 3.4.10+) |
| public static final String DEFAULT_REMEMBER_ME_ATTRIBUTE_NAME = "longTermAuthenticationRequestTokenUsed"; |
| public static final String DEFAULT_VALIDATION_PROTOCOL = "CAS"; |
| |
| private static Logger log = LoggerFactory.getLogger(CasRealm.class); |
| |
| // this is the url of the CAS server (example : http://host:port/cas) |
| private String casServerUrlPrefix; |
| |
| // this is the CAS service url of the application (example : http://host:port/mycontextpath/shiro-cas) |
| private String casService; |
| |
| /* CAS protocol to use for ticket validation : CAS (default) or SAML : |
| - CAS protocol can be used with CAS server version < 3.1 : in this case, no user attributes can be retrieved from the CAS ticket validation response (except if there are some customizations on CAS server side) |
| - SAML protocol can be used with CAS server version >= 3.1 : in this case, user attributes can be extracted from the CAS ticket validation response |
| */ |
| private String validationProtocol = DEFAULT_VALIDATION_PROTOCOL; |
| |
| // default name of the CAS attribute for remember me authentication (CAS 3.4.10+) |
| private String rememberMeAttributeName = DEFAULT_REMEMBER_ME_ATTRIBUTE_NAME; |
| |
| // this class from the CAS client is used to validate a service ticket on CAS server |
| private TicketValidator ticketValidator; |
| |
| // default roles to applied to authenticated user |
| private String defaultRoles; |
| |
| // default permissions to applied to authenticated user |
| private String defaultPermissions; |
| |
| // names of attributes containing roles |
| private String roleAttributeNames; |
| |
| // names of attributes containing permissions |
| private String permissionAttributeNames; |
| |
| public CasRealm() { |
| setAuthenticationTokenClass(CasToken.class); |
| } |
| |
| @Override |
| protected void onInit() { |
| super.onInit(); |
| ensureTicketValidator(); |
| } |
| |
| protected TicketValidator ensureTicketValidator() { |
| if (this.ticketValidator == null) { |
| this.ticketValidator = createTicketValidator(); |
| } |
| return this.ticketValidator; |
| } |
| |
| protected TicketValidator createTicketValidator() { |
| String urlPrefix = getCasServerUrlPrefix(); |
| if ("saml".equalsIgnoreCase(getValidationProtocol())) { |
| return new Saml11TicketValidator(urlPrefix); |
| } |
| return new Cas20ServiceTicketValidator(urlPrefix); |
| } |
| |
| /** |
| * Authenticates a user and retrieves its information. |
| * |
| * @param token the authentication token |
| * @throws AuthenticationException if there is an error during authentication. |
| */ |
| @Override |
| @SuppressWarnings("unchecked") |
| protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { |
| CasToken casToken = (CasToken) token; |
| if (token == null) { |
| return null; |
| } |
| |
| String ticket = (String)casToken.getCredentials(); |
| if (!StringUtils.hasText(ticket)) { |
| return null; |
| } |
| |
| TicketValidator ticketValidator = ensureTicketValidator(); |
| |
| try { |
| // contact CAS server to validate service ticket |
| Assertion casAssertion = ticketValidator.validate(ticket, getCasService()); |
| // get principal, user id and attributes |
| AttributePrincipal casPrincipal = casAssertion.getPrincipal(); |
| String userId = casPrincipal.getName(); |
| log.debug("Validate ticket : {} in CAS server : {} to retrieve user : {}", new Object[]{ |
| ticket, getCasServerUrlPrefix(), userId |
| }); |
| |
| Map<String, Object> attributes = casPrincipal.getAttributes(); |
| // refresh authentication token (user id + remember me) |
| casToken.setUserId(userId); |
| String rememberMeAttributeName = getRememberMeAttributeName(); |
| String rememberMeStringValue = (String)attributes.get(rememberMeAttributeName); |
| boolean isRemembered = rememberMeStringValue != null && Boolean.parseBoolean(rememberMeStringValue); |
| if (isRemembered) { |
| casToken.setRememberMe(true); |
| } |
| // create simple authentication info |
| List<Object> principals = CollectionUtils.asList(userId, attributes); |
| PrincipalCollection principalCollection = new SimplePrincipalCollection(principals, getName()); |
| return new SimpleAuthenticationInfo(principalCollection, ticket); |
| } catch (TicketValidationException e) { |
| throw new CasAuthenticationException("Unable to validate ticket [" + ticket + "]", e); |
| } |
| } |
| |
| /** |
| * Retrieves the AuthorizationInfo for the given principals (the CAS previously authenticated user : id + attributes). |
| * |
| * @param principals the primary identifying principals of the AuthorizationInfo that should be retrieved. |
| * @return the AuthorizationInfo associated with this principals. |
| */ |
| @Override |
| @SuppressWarnings("unchecked") |
| protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { |
| // retrieve user information |
| SimplePrincipalCollection principalCollection = (SimplePrincipalCollection) principals; |
| List<Object> listPrincipals = principalCollection.asList(); |
| Map<String, String> attributes = (Map<String, String>) listPrincipals.get(1); |
| // create simple authorization info |
| SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); |
| // add default roles |
| addRoles(simpleAuthorizationInfo, split(defaultRoles)); |
| // add default permissions |
| addPermissions(simpleAuthorizationInfo, split(defaultPermissions)); |
| // get roles from attributes |
| List<String> attributeNames = split(roleAttributeNames); |
| for (String attributeName : attributeNames) { |
| String value = attributes.get(attributeName); |
| addRoles(simpleAuthorizationInfo, split(value)); |
| } |
| // get permissions from attributes |
| attributeNames = split(permissionAttributeNames); |
| for (String attributeName : attributeNames) { |
| String value = attributes.get(attributeName); |
| addPermissions(simpleAuthorizationInfo, split(value)); |
| } |
| return simpleAuthorizationInfo; |
| } |
| |
| /** |
| * Split a string into a list of not empty and trimmed strings, delimiter is a comma. |
| * |
| * @param s the input string |
| * @return the list of not empty and trimmed strings |
| */ |
| private List<String> split(String s) { |
| List<String> list = new ArrayList<String>(); |
| String[] elements = StringUtils.split(s, ','); |
| if (elements != null && elements.length > 0) { |
| for (String element : elements) { |
| if (StringUtils.hasText(element)) { |
| list.add(element.trim()); |
| } |
| } |
| } |
| return list; |
| } |
| |
| /** |
| * Add roles to the simple authorization info. |
| * |
| * @param simpleAuthorizationInfo |
| * @param roles the list of roles to add |
| */ |
| private void addRoles(SimpleAuthorizationInfo simpleAuthorizationInfo, List<String> roles) { |
| for (String role : roles) { |
| simpleAuthorizationInfo.addRole(role); |
| } |
| } |
| |
| /** |
| * Add permissions to the simple authorization info. |
| * |
| * @param simpleAuthorizationInfo |
| * @param permissions the list of permissions to add |
| */ |
| private void addPermissions(SimpleAuthorizationInfo simpleAuthorizationInfo, List<String> permissions) { |
| for (String permission : permissions) { |
| simpleAuthorizationInfo.addStringPermission(permission); |
| } |
| } |
| |
| public String getCasServerUrlPrefix() { |
| return casServerUrlPrefix; |
| } |
| |
| public void setCasServerUrlPrefix(String casServerUrlPrefix) { |
| this.casServerUrlPrefix = casServerUrlPrefix; |
| } |
| |
| public String getCasService() { |
| return casService; |
| } |
| |
| public void setCasService(String casService) { |
| this.casService = casService; |
| } |
| |
| public String getValidationProtocol() { |
| return validationProtocol; |
| } |
| |
| public void setValidationProtocol(String validationProtocol) { |
| this.validationProtocol = validationProtocol; |
| } |
| |
| public String getRememberMeAttributeName() { |
| return rememberMeAttributeName; |
| } |
| |
| public void setRememberMeAttributeName(String rememberMeAttributeName) { |
| this.rememberMeAttributeName = rememberMeAttributeName; |
| } |
| |
| public String getDefaultRoles() { |
| return defaultRoles; |
| } |
| |
| public void setDefaultRoles(String defaultRoles) { |
| this.defaultRoles = defaultRoles; |
| } |
| |
| public String getDefaultPermissions() { |
| return defaultPermissions; |
| } |
| |
| public void setDefaultPermissions(String defaultPermissions) { |
| this.defaultPermissions = defaultPermissions; |
| } |
| |
| public String getRoleAttributeNames() { |
| return roleAttributeNames; |
| } |
| |
| public void setRoleAttributeNames(String roleAttributeNames) { |
| this.roleAttributeNames = roleAttributeNames; |
| } |
| |
| public String getPermissionAttributeNames() { |
| return permissionAttributeNames; |
| } |
| |
| public void setPermissionAttributeNames(String permissionAttributeNames) { |
| this.permissionAttributeNames = permissionAttributeNames; |
| } |
| } |