13 changed files with 593 additions and 31 deletions
@ -0,0 +1,192 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2019 the original author or authors. |
||||||
|
* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* https://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.springframework.security.config.annotation.rsocket; |
||||||
|
|
||||||
|
import io.rsocket.RSocketFactory; |
||||||
|
import io.rsocket.exceptions.ApplicationErrorException; |
||||||
|
import io.rsocket.frame.decoder.PayloadDecoder; |
||||||
|
import io.rsocket.transport.netty.server.CloseableChannel; |
||||||
|
import io.rsocket.transport.netty.server.TcpServerTransport; |
||||||
|
import org.junit.After; |
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import org.junit.runner.RunWith; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.messaging.handler.annotation.MessageMapping; |
||||||
|
import org.springframework.messaging.rsocket.RSocketRequester; |
||||||
|
import org.springframework.messaging.rsocket.RSocketStrategies; |
||||||
|
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler; |
||||||
|
import org.springframework.security.config.Customizer; |
||||||
|
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; |
||||||
|
import org.springframework.security.core.userdetails.User; |
||||||
|
import org.springframework.security.core.userdetails.UserDetails; |
||||||
|
import org.springframework.security.rsocket.core.PayloadSocketAcceptorInterceptor; |
||||||
|
import org.springframework.security.rsocket.core.SecuritySocketAcceptorInterceptor; |
||||||
|
import org.springframework.security.rsocket.metadata.SimpleAuthenticationEncoder; |
||||||
|
import org.springframework.security.rsocket.metadata.UsernamePasswordMetadata; |
||||||
|
import org.springframework.stereotype.Controller; |
||||||
|
import org.springframework.test.context.ContextConfiguration; |
||||||
|
import org.springframework.test.context.junit4.SpringRunner; |
||||||
|
import org.springframework.util.MimeType; |
||||||
|
import org.springframework.util.MimeTypeUtils; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import static io.rsocket.metadata.WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION; |
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
import static org.assertj.core.api.Assertions.assertThatCode; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Rob Winch |
||||||
|
*/ |
||||||
|
@ContextConfiguration |
||||||
|
@RunWith(SpringRunner.class) |
||||||
|
public class SimpleAuthenticationITests { |
||||||
|
@Autowired |
||||||
|
RSocketMessageHandler handler; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
SecuritySocketAcceptorInterceptor interceptor; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ServerController controller; |
||||||
|
|
||||||
|
private CloseableChannel server; |
||||||
|
|
||||||
|
private RSocketRequester requester; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void setup() { |
||||||
|
this.server = RSocketFactory.receive() |
||||||
|
.frameDecoder(PayloadDecoder.ZERO_COPY) |
||||||
|
.addSocketAcceptorPlugin(this.interceptor) |
||||||
|
.acceptor(this.handler.responder()) |
||||||
|
.transport(TcpServerTransport.create("localhost", 0)) |
||||||
|
.start() |
||||||
|
.block(); |
||||||
|
} |
||||||
|
|
||||||
|
@After |
||||||
|
public void dispose() { |
||||||
|
this.requester.rsocket().dispose(); |
||||||
|
this.server.dispose(); |
||||||
|
this.controller.payloads.clear(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void retrieveMonoWhenSecureThenDenied() throws Exception { |
||||||
|
this.requester = RSocketRequester.builder() |
||||||
|
.rsocketStrategies(this.handler.getRSocketStrategies()) |
||||||
|
.connectTcp("localhost", this.server.address().getPort()) |
||||||
|
.block(); |
||||||
|
|
||||||
|
String data = "rob"; |
||||||
|
assertThatCode(() -> this.requester.route("secure.retrieve-mono") |
||||||
|
.data(data) |
||||||
|
.retrieveMono(String.class) |
||||||
|
.block() |
||||||
|
) |
||||||
|
.isInstanceOf(ApplicationErrorException.class); |
||||||
|
assertThat(this.controller.payloads).isEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void retrieveMonoWhenAuthorizedThenGranted() { |
||||||
|
MimeType authenticationMimeType = MimeTypeUtils.parseMimeType(MESSAGE_RSOCKET_AUTHENTICATION.getString()); |
||||||
|
|
||||||
|
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("rob", "password"); |
||||||
|
this.requester = RSocketRequester.builder() |
||||||
|
.setupMetadata(credentials, authenticationMimeType) |
||||||
|
.rsocketStrategies(this.handler.getRSocketStrategies()) |
||||||
|
.connectTcp("localhost", this.server.address().getPort()) |
||||||
|
.block(); |
||||||
|
String data = "rob"; |
||||||
|
String hiRob = this.requester.route("secure.retrieve-mono") |
||||||
|
.metadata(credentials, authenticationMimeType) |
||||||
|
.data(data) |
||||||
|
.retrieveMono(String.class) |
||||||
|
.block(); |
||||||
|
|
||||||
|
assertThat(hiRob).isEqualTo("Hi rob"); |
||||||
|
assertThat(this.controller.payloads).containsOnly(data); |
||||||
|
} |
||||||
|
|
||||||
|
@Configuration |
||||||
|
@EnableRSocketSecurity |
||||||
|
static class Config { |
||||||
|
|
||||||
|
@Bean |
||||||
|
public ServerController controller() { |
||||||
|
return new ServerController(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public RSocketMessageHandler messageHandler() { |
||||||
|
RSocketMessageHandler handler = new RSocketMessageHandler(); |
||||||
|
handler.setRSocketStrategies(rsocketStrategies()); |
||||||
|
return handler; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public RSocketStrategies rsocketStrategies() { |
||||||
|
return RSocketStrategies.builder() |
||||||
|
.encoder(new SimpleAuthenticationEncoder()) |
||||||
|
.build(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) { |
||||||
|
rsocket |
||||||
|
.authorizePayload(authorize -> |
||||||
|
authorize |
||||||
|
.anyRequest().authenticated() |
||||||
|
.anyExchange().permitAll() |
||||||
|
) |
||||||
|
.simpleAuthentication(Customizer.withDefaults()); |
||||||
|
return rsocket.build(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
MapReactiveUserDetailsService uds() { |
||||||
|
UserDetails rob = User.withDefaultPasswordEncoder() |
||||||
|
.username("rob") |
||||||
|
.password("password") |
||||||
|
.roles("USER", "ADMIN") |
||||||
|
.build(); |
||||||
|
return new MapReactiveUserDetailsService(rob); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Controller |
||||||
|
static class ServerController { |
||||||
|
private List<String> payloads = new ArrayList<>(); |
||||||
|
|
||||||
|
@MessageMapping("**") |
||||||
|
String retrieveMono(String payload) { |
||||||
|
add(payload); |
||||||
|
return "Hi " + payload; |
||||||
|
} |
||||||
|
|
||||||
|
private void add(String p) { |
||||||
|
this.payloads.add(p); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,102 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2019 the original author or authors. |
||||||
|
* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* https://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.springframework.security.rsocket.authentication; |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf; |
||||||
|
import io.netty.buffer.ByteBufAllocator; |
||||||
|
import io.rsocket.metadata.WellKnownMimeType; |
||||||
|
import io.rsocket.metadata.security.AuthMetadataFlyweight; |
||||||
|
import io.rsocket.metadata.security.WellKnownAuthType; |
||||||
|
import org.springframework.core.codec.ByteArrayDecoder; |
||||||
|
import org.springframework.messaging.rsocket.DefaultMetadataExtractor; |
||||||
|
import org.springframework.messaging.rsocket.MetadataExtractor; |
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
||||||
|
import org.springframework.security.core.Authentication; |
||||||
|
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken; |
||||||
|
import org.springframework.security.rsocket.api.PayloadExchange; |
||||||
|
import org.springframework.util.MimeType; |
||||||
|
import org.springframework.util.MimeTypeUtils; |
||||||
|
import reactor.core.publisher.Mono; |
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* Converts from the {@link PayloadExchange} for |
||||||
|
* <a href="https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Authentication.md">Authentication Extension</a>. |
||||||
|
* For |
||||||
|
* <a href="https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md">Simple</a> |
||||||
|
* a {@link UsernamePasswordAuthenticationToken} is returned. For |
||||||
|
* <a href="https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Bearer.md">Bearer</a> |
||||||
|
* a {@link BearerTokenAuthenticationToken} is returned. |
||||||
|
* |
||||||
|
* @author Rob Winch |
||||||
|
* @since 5.3 |
||||||
|
*/ |
||||||
|
public class AuthenticationPayloadExchangeConverter implements PayloadExchangeAuthenticationConverter { |
||||||
|
private static final MimeType COMPOSITE_METADATA_MIME_TYPE = MimeTypeUtils.parseMimeType( |
||||||
|
WellKnownMimeType.MESSAGE_RSOCKET_COMPOSITE_METADATA.getString()); |
||||||
|
|
||||||
|
private static final MimeType AUTHENTICATION_MIME_TYPE = MimeTypeUtils.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString()); |
||||||
|
|
||||||
|
private MetadataExtractor metadataExtractor = createDefaultExtractor(); |
||||||
|
|
||||||
|
@Override |
||||||
|
public Mono<Authentication> convert(PayloadExchange exchange) { |
||||||
|
return Mono.fromCallable(() -> this.metadataExtractor |
||||||
|
.extract(exchange.getPayload(), this.COMPOSITE_METADATA_MIME_TYPE)) |
||||||
|
.flatMap(metadata -> Mono.justOrEmpty(authentication(metadata))); |
||||||
|
} |
||||||
|
|
||||||
|
private Authentication authentication(Map<String, Object> metadata) { |
||||||
|
byte[] authenticationMetadata = (byte[]) metadata.get("authentication"); |
||||||
|
if (authenticationMetadata == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
ByteBuf rawAuthentication = ByteBufAllocator.DEFAULT.buffer().writeBytes(authenticationMetadata); |
||||||
|
if (!AuthMetadataFlyweight.isWellKnownAuthType(rawAuthentication)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
WellKnownAuthType wellKnownAuthType = AuthMetadataFlyweight.decodeWellKnownAuthType(rawAuthentication); |
||||||
|
if (WellKnownAuthType.SIMPLE.equals(wellKnownAuthType)) { |
||||||
|
return simple(rawAuthentication); |
||||||
|
} else if (WellKnownAuthType.BEARER.equals(wellKnownAuthType)) { |
||||||
|
return bearer(rawAuthentication); |
||||||
|
} |
||||||
|
throw new IllegalArgumentException("Unknown Mime Type " + wellKnownAuthType); |
||||||
|
} |
||||||
|
|
||||||
|
private Authentication simple(ByteBuf rawAuthentication) { |
||||||
|
ByteBuf rawUsername = AuthMetadataFlyweight.decodeUsername(rawAuthentication); |
||||||
|
String username = rawUsername.toString(StandardCharsets.UTF_8); |
||||||
|
ByteBuf rawPassword = AuthMetadataFlyweight.decodePassword(rawAuthentication); |
||||||
|
String password = rawPassword.toString(StandardCharsets.UTF_8); |
||||||
|
return new UsernamePasswordAuthenticationToken(username, password); |
||||||
|
} |
||||||
|
|
||||||
|
private Authentication bearer(ByteBuf rawAuthentication) { |
||||||
|
char[] rawToken = AuthMetadataFlyweight.decodeBearerTokenAsCharArray(rawAuthentication); |
||||||
|
String token = new String(rawToken); |
||||||
|
return new BearerTokenAuthenticationToken(token); |
||||||
|
} |
||||||
|
|
||||||
|
private static MetadataExtractor createDefaultExtractor() { |
||||||
|
DefaultMetadataExtractor result = new DefaultMetadataExtractor(new ByteArrayDecoder()); |
||||||
|
result.metadataToExtract(AUTHENTICATION_MIME_TYPE, byte[].class, "authentication"); |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,78 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2019 the original author or authors. |
||||||
|
* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* https://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.springframework.security.rsocket.metadata; |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf; |
||||||
|
import io.netty.buffer.ByteBufAllocator; |
||||||
|
import io.rsocket.metadata.security.AuthMetadataFlyweight; |
||||||
|
import org.reactivestreams.Publisher; |
||||||
|
import org.springframework.core.ResolvableType; |
||||||
|
import org.springframework.core.codec.AbstractEncoder; |
||||||
|
import org.springframework.core.io.buffer.DataBuffer; |
||||||
|
import org.springframework.core.io.buffer.DataBufferFactory; |
||||||
|
import org.springframework.core.io.buffer.NettyDataBufferFactory; |
||||||
|
import org.springframework.util.MimeType; |
||||||
|
import org.springframework.util.MimeTypeUtils; |
||||||
|
import reactor.core.publisher.Flux; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* Encodes <a href="https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Bearer.md">Bearer Authentication</a>. |
||||||
|
* |
||||||
|
* @author Rob Winch |
||||||
|
* @since 5.3 |
||||||
|
*/ |
||||||
|
public class BearerTokenAuthenticationEncoder extends |
||||||
|
AbstractEncoder<BearerTokenMetadata> { |
||||||
|
|
||||||
|
private static final MimeType AUTHENTICATION_MIME_TYPE = MimeTypeUtils.parseMimeType("message/x.rsocket.authentication.v0"); |
||||||
|
|
||||||
|
private NettyDataBufferFactory defaultBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT); |
||||||
|
|
||||||
|
public BearerTokenAuthenticationEncoder() { |
||||||
|
super(AUTHENTICATION_MIME_TYPE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Flux<DataBuffer> encode( |
||||||
|
Publisher<? extends BearerTokenMetadata> inputStream, |
||||||
|
DataBufferFactory bufferFactory, ResolvableType elementType, |
||||||
|
MimeType mimeType, Map<String, Object> hints) { |
||||||
|
return Flux.from(inputStream).map(credentials -> |
||||||
|
encodeValue(credentials, bufferFactory, elementType, mimeType, hints)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public DataBuffer encodeValue(BearerTokenMetadata credentials, |
||||||
|
DataBufferFactory bufferFactory, ResolvableType valueType, MimeType mimeType, |
||||||
|
Map<String, Object> hints) { |
||||||
|
String token = credentials.getToken(); |
||||||
|
NettyDataBufferFactory factory = nettyFactory(bufferFactory); |
||||||
|
ByteBufAllocator allocator = factory.getByteBufAllocator(); |
||||||
|
ByteBuf simpleAuthentication = AuthMetadataFlyweight |
||||||
|
.encodeBearerMetadata(allocator, token.toCharArray()); |
||||||
|
return factory.wrap(simpleAuthentication); |
||||||
|
} |
||||||
|
|
||||||
|
private NettyDataBufferFactory nettyFactory(DataBufferFactory bufferFactory) { |
||||||
|
if (bufferFactory instanceof NettyDataBufferFactory) { |
||||||
|
return (NettyDataBufferFactory) bufferFactory; |
||||||
|
} |
||||||
|
return this.defaultBufferFactory; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,81 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2019 the original author or authors. |
||||||
|
* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* https://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.springframework.security.rsocket.metadata; |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf; |
||||||
|
import io.netty.buffer.ByteBufAllocator; |
||||||
|
import io.rsocket.metadata.security.AuthMetadataFlyweight; |
||||||
|
import org.reactivestreams.Publisher; |
||||||
|
import org.springframework.core.ResolvableType; |
||||||
|
import org.springframework.core.codec.AbstractEncoder; |
||||||
|
import org.springframework.core.io.buffer.DataBuffer; |
||||||
|
import org.springframework.core.io.buffer.DataBufferFactory; |
||||||
|
import org.springframework.core.io.buffer.NettyDataBufferFactory; |
||||||
|
import org.springframework.util.MimeType; |
||||||
|
import org.springframework.util.MimeTypeUtils; |
||||||
|
import reactor.core.publisher.Flux; |
||||||
|
|
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* Encodes |
||||||
|
* <a href="https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md">Simple</a> |
||||||
|
* Authentication. |
||||||
|
* |
||||||
|
* @author Rob Winch |
||||||
|
* @since 5.3 |
||||||
|
*/ |
||||||
|
public class SimpleAuthenticationEncoder extends |
||||||
|
AbstractEncoder<UsernamePasswordMetadata> { |
||||||
|
|
||||||
|
private static final MimeType AUTHENTICATION_MIME_TYPE = MimeTypeUtils.parseMimeType("message/x.rsocket.authentication.v0"); |
||||||
|
|
||||||
|
private NettyDataBufferFactory defaultBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT); |
||||||
|
|
||||||
|
public SimpleAuthenticationEncoder() { |
||||||
|
super(AUTHENTICATION_MIME_TYPE); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Flux<DataBuffer> encode( |
||||||
|
Publisher<? extends UsernamePasswordMetadata> inputStream, |
||||||
|
DataBufferFactory bufferFactory, ResolvableType elementType, |
||||||
|
MimeType mimeType, Map<String, Object> hints) { |
||||||
|
return Flux.from(inputStream).map(credentials -> |
||||||
|
encodeValue(credentials, bufferFactory, elementType, mimeType, hints)); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public DataBuffer encodeValue(UsernamePasswordMetadata credentials, |
||||||
|
DataBufferFactory bufferFactory, ResolvableType valueType, MimeType mimeType, |
||||||
|
Map<String, Object> hints) { |
||||||
|
String username = credentials.getUsername(); |
||||||
|
String password = credentials.getPassword(); |
||||||
|
NettyDataBufferFactory factory = nettyFactory(bufferFactory); |
||||||
|
ByteBufAllocator allocator = factory.getByteBufAllocator(); |
||||||
|
ByteBuf simpleAuthentication = AuthMetadataFlyweight |
||||||
|
.encodeSimpleMetadata(allocator, username.toCharArray(), password.toCharArray()); |
||||||
|
return factory.wrap(simpleAuthentication); |
||||||
|
} |
||||||
|
|
||||||
|
private NettyDataBufferFactory nettyFactory(DataBufferFactory bufferFactory) { |
||||||
|
if (bufferFactory instanceof NettyDataBufferFactory) { |
||||||
|
return (NettyDataBufferFactory) bufferFactory; |
||||||
|
} |
||||||
|
return this.defaultBufferFactory; |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue