All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.infinispan.server.security.http.localuser.LocalUserAuthenticationMechanism Maven / Gradle / Ivy

The newest version!
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2015 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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 org.infinispan.server.security.http.localuser;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.wildfly.common.Assert.checkNotNullParam;
import static org.wildfly.security.http.HttpConstants.AUTHORIZATION;
import static org.wildfly.security.http.HttpConstants.UNAUTHORIZED;
import static org.wildfly.security.http.HttpConstants.WWW_AUTHENTICATE;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.List;
import java.util.Random;

import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.wildfly.common.iteration.ByteIterator;
import org.wildfly.common.iteration.CodePointIterator;
import org.wildfly.security.http.HttpAuthenticationException;
import org.wildfly.security.http.HttpServerRequest;
import org.wildfly.security.http.HttpServerResponse;
import org.wildfly.security.mechanism.http.UsernamePasswordAuthenticationMechanism;

/**
 * Implementation of the HTTP Local authentication mechanism
 *
 * @author Tristan Tarrant <[email protected]>
 * @since 10.0
 */
final class LocalUserAuthenticationMechanism extends UsernamePasswordAuthenticationMechanism {
   public static final String LOCALUSER_NAME = "LOCALUSER";

   static final String SILENT = "silent";

   public static final String LOCAL_USER_USE_SECURE_RANDOM = "wildfly.http.local-user.use-secure-random";
   public static final String LOCAL_USER_CHALLENGE_PATH = "wildfly.http.local-user.challenge-path";
   public static final String DEFAULT_USER = "wildfly.http.local-user.default-user";
   private static final String CHALLENGE_PREFIX = "Localuser ";
   private static final int PREFIX_LENGTH = CHALLENGE_PREFIX.length();
   private static final byte UTF8NUL = 0x00;

   private final boolean useSecureRandom;

   /**
    * If silent is true then this mechanism will only take effect if there is an Authorization header.
    * 

* This allows you to combine basic auth with form auth, so human users will use form based auth, but allows * programmatic clients to login using basic auth. */ private final boolean silent; private final File basePath; /** * Construct a new instance of {@code BasicAuthenticationMechanism}. * * @param callbackHandler the {@link CallbackHandler} to use to verify the supplied credentials and to notify to * establish the current identity. */ LocalUserAuthenticationMechanism(final CallbackHandler callbackHandler, final boolean silent) { super(checkNotNullParam("callbackHandler", callbackHandler)); this.silent = silent; this.useSecureRandom = true; this.basePath = new File(System.getProperty("java.io.tmpdir")); } /** * @see org.wildfly.security.http.HttpServerAuthenticationMechanism#getMechanismName() */ @Override public String getMechanismName() { return LOCALUSER_NAME; } /** * @throws HttpAuthenticationException * @see org.wildfly.security.http.HttpServerAuthenticationMechanism#evaluateRequest(HttpServerRequest) */ @Override public void evaluateRequest(final HttpServerRequest request) throws HttpAuthenticationException { List authorizationValues = request.getRequestHeaderValues(AUTHORIZATION); if (authorizationValues != null) { for (String current : authorizationValues) { if (current.startsWith(CHALLENGE_PREFIX)) { byte[] decodedValue = ByteIterator.ofBytes(current.substring(PREFIX_LENGTH).getBytes(UTF_8)).asUtf8String().base64Decode().drain(); if (decodedValue.length == 0) { // Initial response, create the file final Random random = getRandom(); File challengeFile; try { challengeFile = File.createTempFile("local", ".challenge", basePath); } catch (IOException e) { throw new RuntimeException(e); } final FileOutputStream fos; try { fos = new FileOutputStream(challengeFile); } catch (FileNotFoundException e) { throw new RuntimeException(e); } boolean ok = false; final byte[] bytes; try { bytes = new byte[8]; random.nextBytes(bytes); try { fos.write(bytes); fos.close(); ok = true; } catch (IOException e) { throw new RuntimeException(e); } } finally { if (!ok) { deleteChallenge(null); } try { fos.close(); } catch (Throwable ignored) { } } //challengeBytes = bytes; final String path = challengeFile.getAbsolutePath(); final byte[] response = CodePointIterator.ofString(path).asUtf8(true).drain(); } else { try { request.authenticationComplete(); if (true) { succeed(); request.authenticationComplete(); return; } else { fail(); request.authenticationFailed("auth failed", response -> prepareResponse(request, response)); return; } } catch (IOException | UnsupportedCallbackException e) { throw new HttpAuthenticationException(e); } } } } } } private void prepareResponse(final HttpServerRequest request, HttpServerResponse response) { if (silent) { //if silent we only send a challenge if the request contained auth headers //otherwise we assume another method will send the challenge String authHeader = request.getFirstRequestHeaderValue(AUTHORIZATION); if (authHeader == null) { return; //CHALLENGE NOT SENT } } StringBuilder sb = new StringBuilder(CHALLENGE_PREFIX); response.addResponseHeader(WWW_AUTHENTICATE, sb.toString()); response.setStatusCode(UNAUTHORIZED); } private void deleteChallenge(File challengeFile) { if (challengeFile != null) { challengeFile.delete(); challengeFile = null; } } private Random getRandom() { if (useSecureRandom) { return new SecureRandom(); } else { return new Random(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy