| Conditions | 17 |
| Total Lines | 100 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like org.apereo.cas.authentication.DefaultAuthenticationContextValidator.validate(Authentication,String,RegisteredService) often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | package org.apereo.cas.authentication; |
||
| 61 | @Override |
||
| 62 | public Pair<Boolean, Optional<MultifactorAuthenticationProvider>> validate(final Authentication authentication, |
||
| 63 | final String requestedContext, |
||
| 64 | final RegisteredService service) { |
||
| 65 | final Map<String, Object> attrs = authentication.getAttributes(); |
||
| 66 | final Object ctxAttr = attrs.get(this.authenticationContextAttribute); |
||
| 67 | final Collection<Object> contexts = CollectionUtils.toCollection(ctxAttr); |
||
| 68 | LOGGER.debug("Attempting to match requested authentication context [{}] against [{}]", requestedContext, contexts); |
||
| 69 | |||
| 70 | final Map<String, MultifactorAuthenticationProvider> providerMap = |
||
| 71 | MultifactorAuthenticationUtils.getAvailableMultifactorAuthenticationProviders(this.applicationContext); |
||
| 72 | if (providerMap == null) { |
||
| 73 | LOGGER.debug("No multifactor authentication providers are configured"); |
||
| 74 | return Pair.of(Boolean.FALSE, Optional.empty()); |
||
| 75 | } |
||
| 76 | final Optional<MultifactorAuthenticationProvider> requestedProvider = locateRequestedProvider(providerMap.values(), requestedContext); |
||
| 77 | |||
| 78 | if (!requestedProvider.isPresent()) { |
||
| 79 | LOGGER.debug("Requested authentication provider cannot be recognized."); |
||
| 80 | return Pair.of(Boolean.FALSE, Optional.empty()); |
||
| 81 | } |
||
| 82 | |||
| 83 | if (contexts.stream().filter(ctx -> ctx.toString().equals(requestedContext)).count() > 0) { |
||
| 84 | LOGGER.debug("Requested authentication context [{}] is satisfied", requestedContext); |
||
| 85 | return Pair.of(Boolean.TRUE, requestedProvider); |
||
| 86 | } |
||
| 87 | |||
| 88 | |||
| 89 | if (StringUtils.isNotBlank(this.mfaTrustedAuthnAttributeName) |
||
| 90 | && attrs.containsKey(this.mfaTrustedAuthnAttributeName)) { |
||
| 91 | LOGGER.debug("Requested authentication context [{}] is satisfied since device is already trusted", requestedContext); |
||
| 92 | return Pair.of(Boolean.TRUE, requestedProvider); |
||
| 93 | } |
||
| 94 | |||
| 95 | if (attrs.containsKey(MultifactorAuthenticationProviderBypass.AUTHENTICATION_ATTRIBUTE_BYPASS_MFA) |
||
| 96 | && attrs.containsKey(MultifactorAuthenticationProviderBypass.AUTHENTICATION_ATTRIBUTE_BYPASS_MFA_PROVIDER)) { |
||
| 97 | |||
| 98 | final boolean isBypass = Boolean.class.cast(attrs.get(MultifactorAuthenticationProviderBypass.AUTHENTICATION_ATTRIBUTE_BYPASS_MFA)); |
||
| 99 | final String bypassedId = attrs.get(MultifactorAuthenticationProviderBypass.AUTHENTICATION_ATTRIBUTE_BYPASS_MFA_PROVIDER).toString(); |
||
| 100 | |||
| 101 | LOGGER.debug("Found multifactor authentication bypass attributes for provider [{}]", bypassedId); |
||
| 102 | |||
| 103 | if (isBypass && StringUtils.equals(bypassedId, requestedContext)) { |
||
| 104 | LOGGER.debug("Requested authentication context [{}] is satisfied given mfa was bypassed for the authentication attempt", |
||
| 105 | requestedContext); |
||
| 106 | return Pair.of(Boolean.TRUE, requestedProvider); |
||
| 107 | } |
||
| 108 | |||
| 109 | LOGGER.debug("Either multifactor authentication was not bypassed or the requested context [{}] does not match the bypassed provider [{}]", |
||
| 110 | requestedProvider, bypassedId); |
||
| 111 | } |
||
| 112 | |||
| 113 | final Collection<MultifactorAuthenticationProvider> satisfiedProviders = |
||
| 114 | getSatisfiedAuthenticationProviders(authentication, providerMap.values()); |
||
| 115 | |||
| 116 | if (satisfiedProviders == null) { |
||
| 117 | LOGGER.warn("No satisfied multifactor authentication providers are recorded in the current authentication context."); |
||
| 118 | return Pair.of(Boolean.FALSE, requestedProvider); |
||
| 119 | } |
||
| 120 | |||
| 121 | if (!satisfiedProviders.isEmpty()) { |
||
| 122 | final MultifactorAuthenticationProvider[] providers = satisfiedProviders.toArray(new MultifactorAuthenticationProvider[]{}); |
||
| 123 | OrderComparator.sortIfNecessary(providers); |
||
| 124 | final Optional<MultifactorAuthenticationProvider> result = Arrays.stream(providers) |
||
| 125 | .filter(provider -> { |
||
| 126 | final MultifactorAuthenticationProvider p = requestedProvider.get(); |
||
| 127 | return provider.equals(p) || provider.getOrder() >= p.getOrder(); |
||
| 128 | }) |
||
| 129 | .findFirst(); |
||
| 130 | |||
| 131 | if (result.isPresent()) { |
||
| 132 | LOGGER.debug("Current provider [{}] already satisfies the authentication requirements of [{}]; proceed with flow normally.", |
||
| 133 | result.get(), requestedProvider); |
||
| 134 | return Pair.of(Boolean.TRUE, requestedProvider); |
||
| 135 | } |
||
| 136 | } |
||
| 137 | |||
| 138 | LOGGER.debug("No multifactor providers could be located to satisfy the requested context for [{}]", requestedProvider); |
||
| 139 | |||
| 140 | final RegisteredServiceMultifactorPolicy.FailureModes mode = getMultifactorFailureModeForService(service); |
||
| 141 | if (mode == RegisteredServiceMultifactorPolicy.FailureModes.PHANTOM) { |
||
| 142 | if (!requestedProvider.get().isAvailable(service)) { |
||
| 143 | LOGGER.debug("Service [{}] is configured to use a [{}] failure mode for multifactor authentication policy. " |
||
| 144 | + "Since provider [{}] is unavailable at the moment, CAS will knowingly allow [{}] as a satisfied criteria " |
||
| 145 | + "of the present authentication context", service.getServiceId(), |
||
| 146 | mode, requestedProvider, requestedContext); |
||
| 147 | return Pair.of(Boolean.TRUE, requestedProvider); |
||
| 148 | } |
||
| 149 | } |
||
| 150 | if (mode == RegisteredServiceMultifactorPolicy.FailureModes.OPEN) { |
||
| 151 | if (!requestedProvider.get().isAvailable(service)) { |
||
| 152 | LOGGER.debug("Service [{}] is configured to use a [{}] failure mode for multifactor authentication policy and " |
||
| 153 | + "since provider [{}] is unavailable at the moment, CAS will consider the authentication satisfied " |
||
| 154 | + "without the presence of [{}]", service.getServiceId(), |
||
| 155 | mode, requestedProvider, requestedContext); |
||
| 156 | return Pair.of(Boolean.TRUE, satisfiedProviders.stream().findFirst()); |
||
| 157 | } |
||
| 158 | } |
||
| 159 | |||
| 160 | return Pair.of(Boolean.FALSE, requestedProvider); |
||
| 161 | } |
||
| 199 |