Authentication Required Vertx - http

The problem is when I write a simple query to this verticle I get this response.
Request:
curl -X GET http://localhost:8080/v1/calculation/DELPHI_METHOD_FORECAST
-H 'Content-Type: application/json'
-d '{"pessimisticMark":5,"optimisticMark":10}'
Response:
<html><head><meta http-equiv='refresh' content='1;url=/login?from=%2Fv1%2Fcalculation%2FDELPHI_METHOD_FORECAST'/><script>window.location.replace('/login?from=%2Fv1%2Fcalculation%2FDELPHI_METHOD_FORECAST');</script></head><body style='background-color:white; color:white;'>
Authentication required
<!--
-->
</body></html>
Verticle:
public class ExpertMarkCalculationController extends AbstractVerticle {
#Override
public void start() {
Router router = Router.router(vertx);
router.put("/v1/calculate/:methodName").handler(this::calculateForecast);
vertx.createHttpServer().requestHandler(router).listen(8080);
}
void calculateForecast(RoutingContext ctx) {
MethodType methodType = MethodType.valueOf(ctx.pathParam("methodName"));
JsonObject jsonMethodData = ctx.getBodyAsJson();
MethodData methodData = MethodDataParser.parseJsonToMethodData(jsonMethodData, methodType);
BasicExpertForecastCalculationService service = MethodMappingHandler.getForecastCalculationService(methodType);
service.process(methodData);
ctx.response().putHeader("content-type", "application/json").
end(MethodDataParser.parseMethodDataToJson(methodData, methodType));
}
}
As you can see there is no security configuration.

Related

Spring Security OAuth2 Credentiais through header

Well, i'm creating a Authorization Server using Spring Security OAuth Project, this is my configurer class:
#Configuration
public class AuthConfig extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
public AuthConfig(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("clientid")
.secret(passwordEncoder().encode("secret"))
.authorizedGrantTypes("authorization_code", "client_credentials", "password")
.scopes("myscope")
.redirectUris("http://localhost:8080/oauth/login/client-app");
}
/**
* Precisamos para uso do Password Flow
*/
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).
tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
#Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
#Bean
TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
jwtAccessTokenConverter.setSigningKey("ABC");
return jwtAccessTokenConverter;
}
}
Well, when I try to retrieve the Access Token i need pass "clientid" and "secret" through headers, like this (works very well returning the JWT Token):
curl clientid:secret#localhost:8080/oauth/token -dgrant_type=client_credentials -dscope=myscope
But if I try this:
curl localhost:8080/oauth/token -dgrant_type=client_credentials -dscope=transferir-valores -dclient_id=clientid -dclient_secret=secret
I got Unauthorized message.
The second request is incorrect and that is why you're getting an unauthorized message.
Check the following excerpt from the specification:
Clients in possession of a client password MAY use the HTTP Basic
authentication scheme as defined in [RFC2617] to authenticate with the
authorization server. The client identifier is encoded using the
"application/x-www-form-urlencoded"
Alternatively, the authorization server MAY support including the client credentials in the request-body.
Including the client credentials in the request-body using the two parameters is NOT RECOMMENDED
It is recommended to send client credentials as basic auth (encode credentials to base64 as add it to headers). Something like this:
curl -X POST \ http://localhost:8443/auth-service/oauth/token \ -H 'Authorization: Basic VEVTVF9TRVJWSUNFOnBhc3N3b3Jk' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d grant_type=client_credentials

Post body raw json to server retrofit 2?

I have a rest web service on a server with postman. How can I send this request to the service?
Body->Raw->JSON(application/json)
[{"NewDigit":"0070297","ReadingStatus":"1","WaterMeterStatus":"1","SCode":"113950","ReportedIssues":"","LNG":"0.0","LAT":"0.0"}]
And this is my Header on the Postman:
Authorization:bearer 123 Content-Type:application/json
and server return this to me:
"OK"
Now I want to implement that with retrofit. This is my interface:
public interface IPostReads {
#Headers( "Content-Type: application/json")
#POST("/readings")
Call<String> savePost(#Header("Authorization") String Authorization, #Body RequestBody body);
}
And this:
public class PostReading {
private PostReading() {}
public static final String BASE_URL = "http://185.113.58.156:9100/";
public static IPostReads getAPIService() {
return RetrofitClient.getClient(BASE_URL).create(IPostReads.class);
}
}
I have the following code for the post request:
String[] parts = params[0].toString().split(";");
ir.behineh.wepapiinterface.PostReadingToServer.IPostReads taskService = ServiceGenerator.createService(ir.behineh.wepapiinterface.PostReadingToServer.IPostReads.class);
Call<String> tasks = taskService.savePost("bearer "+parts[1].toString(),RequestBody.create(MediaType.parse("application/json"),parts[0].toString()));
try {
String x=tasks.execute().body();
Log.d("behzad post output:",x.toString());
} catch (IOException e) {
e.printStackTrace();
}
I get a response with code 200, but the server returns an error. I think there is something wrong in the body parameter.
What happens?
Thanks.
Remove / from #POST("/readings") => #POST("readings") because you already added it on base url at the end.

How can I get dynamic response when using Spring Cloud Contract?

org.springframework.cloud.contract.spec.Contract.make {
request {
method 'GET'
url '/weather'
}
response {
status 200
body([
"weather": value(regex("(SUNNY|WINDY|CLOUDY|RAINY)"))
])
}
I know Groovy DSL is able to generate a random value, Like the code above.
But the Groovy DSL just generate a static stub, and it will always return the same response as I requested.
How can I get a random weather without re-generate the stubs in this case?
You can't, that's because WireMock stub needs a concrete value on the response side. The only thing you could do is to reference the request from the response and then the request can have random input. In general, your tests shouldn't depend on random response.
I know is an old question but I found a workaround solution to achieve that using dynamic values from the given request, you can set a custom headers using $regex then use as output response.
Groovy
request {
method 'GET'
url """/v1/persons/${anyUuid()}"""
headers {
contentType('application/json')
header 'Authorization' : 'Mocked Return Data'
header 'nameMocked' : $(regex('[a-zA-Z0-9]{5, 30}'))
header 'dateMocked' : $(regex('(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[012])/([0-9]{4})'))
header 'typeMocked' : $(regex('CONSUMER|COMMERCIAL'))
}
}
response {
status 200
body(
"""
{
"name": "${fromRequest().header('nameMocked')}",
"date": "${fromRequest().header('dateMocked')}",
"type": "${fromRequest().header('typeMocked')}",
}
"""
)
headers {
contentType('application/json')
}
}
BaseClass
class PersonDto {
private UUID id;
private String name;
private LocalDate date;
private PersonType type;
}
#Slf4j
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = JacksonAutoConfiguration.class)
public abstract class BaseTest {
#Autowired
private ObjectMapper objectMapper;
#Before
public void setup() throws Exception {
YourController yourController = spy(new YourController());
//normal business mocks
doAnswer((Answer<ResponseEntity>) invocation -> {
HttpServletRequest currentRequest = getCurrentRequest();
Map<String, String> map = Collections.list(currentRequest.getHeaderNames()).stream()
.filter(n -> n.endsWith("Mocked"))
.collect(Collectors.toMap(k -> k.replaceFirst("Mocked", ""), currentRequest::getHeader));
return ResponseEntity.ok(objectMapper.convertValue(map, PersonDto.class)); //Convert map to dto
}).when(YourController).getPerson(matches("([a-f0-9]{8}(-[a-f0-9]{4}){4}[a-f0-9]{8})"), eq("Mocked Return Data")); //This should match your request
RestAssuredMockMvc.standaloneSetup(yourController);
}
private HttpServletRequest getCurrentRequest() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
Assert.state(requestAttributes != null, "Could not find current request via RequestContextHolder");
Assert.isInstanceOf(ServletRequestAttributes.class, requestAttributes);
HttpServletRequest servletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
Assert.state(servletRequest != null, "Could not find current HttpServletRequest");
return servletRequest;
}
}
Consumer example
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
#AutoConfigureStubRunner(workOffline = true, ids = "groupId:artifactId:+:stubs:8083")
#DirtiesContext
public class ConsumerContractAT {
#Test
public void callApiGetShouldReturnDynamicMockedData() {
Response response = RestAssured.given()
.header(HttpHeaders.AUTHORIZATION, "Mocked Return Data")
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.header("nameMocked", "Test")
.header("typeMocked", "CONSUMER")
.header("dobMocked", DateTimeFormatter.ofPattern("dd/MM/yyyy").format(LocalDate.of(2019, 10, 10)))
.when()
.get("/v1/persons/{tokeId}", UUID.randomUUID())
.then()
.statusCode(200)
.extract().response();
assertThat(response.jsonPath().getString("typeMocked")).isEqualTo("CONSUMER");
assertThat(response.jsonPath().getString("name")).isEqualTo("Test");
assertThat(response.jsonPath().getString("dob")).isEqualTo("10/10/2019");
response = RestAssured.given()
.header(HttpHeaders.AUTHORIZATION, "Mocked Return Data")
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.header("nameMocked", "Test 2")
.header("typeMocked", "COMMERCIAL")
.header("dobMocked", DateTimeFormatter.ofPattern("dd/MM/yyyy").format(LocalDate.now()))
.when()
.get("/v1/persons/{tokeId}", UUID.randomUUID())
.then()
.statusCode(200)
.extract().response();
assertThat(response.jsonPath().getString("typeMocked")).isEqualTo("COMMERCIAL");
assertThat(response.jsonPath().getString("name")).isEqualTo("Test 2");
assertThat(response.jsonPath().getString("dob")).isEqualTo(DateTimeFormatter.ofPattern("dd/MM/yyyy").format(LocalDate.now()));
}
}

ASP.NET controller gets called repeatedly by firefox if HttpStatusCodeResult has newlines in the description [duplicate]

When I return a StatusDescription with a newline using the HttpStatusCodeResult from ASP.Net MVC 3.0, the connection to my client is forcibly closed. App is hosted in IIS 7.0.
Example controller:
public class FooController : Controller
{
public ActionResult MyAction()
{
return new HttpStatusCodeResult((int)HttpStatusCode.BadRequest, "Foo \n Bar");
}
}
Example client:
using (WebClient client = new WebClient())
{
client.DownloadString("http://localhost/app/Foo/MyAction");
}
Thrown Exception:
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive.
System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
The behavior is consistent when using curl (curl 7.25.0 (i386-pc-win32) libcurl/7.25.0 zlib/1.2.6)
curl http://localhost/app/Foo/MyAction
curl: (56) Recv failure: Connection was reset
Edit
I ended up using this custom ActionResult to get the desired results.
public class BadRequestResult : ActionResult
{
private const int BadRequestCode = (int)HttpStatusCode.BadRequest;
private int count = 0;
public BadRequestResult(string errors)
: this(errors, "")
{
}
public BadRequestResult(string format, params object[] args)
{
if (String.IsNullOrEmpty(format))
{
throw new ArgumentException("format");
}
Errors = String.Format(format, args);
count = Errors.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).Length;
}
public string Errors { get; private set; }
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
HttpResponseBase response = context.HttpContext.Response;
response.TrySkipIisCustomErrors = true;
response.StatusCode = BadRequestCode;
response.StatusDescription = String.Format("Bad Request {0} Error(s)", count);
response.Write(Errors);
response.End();
}
}
You can't have a linebreak in the middle of an HTTP header.
The HTTP protocol specifies the end of a header is a line break.
Since the line break is in the middle of a header, the header is not a valid header and you are getting this error.
Fix: Don't put a line break in the middle of an HTTP header.

Basic Authentication with Retrofit

I am trying to build a client for a REST API using Retrofit. The API uses basic auth and I have been unable to authenticate using Retrofit.
I tested the API using the curl below and it works as expected
curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{some_json}' -u api_key: https://apitest.com/api/v1/customers
Below is the Retrofit client
public interface UserService {
String HOST = "https://apitest.com";
public static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
public static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(HOST)
.addConverterFactory(GsonConverterFactory.create());
/*
* CREATE/UPDATE User
*/
#POST("api/v1/customers")
Call<UserAPIResponse> userUpdate(#Body UserUpdateRequest userUpdateRequest);
static UserService newInstance(String userAPIKey) {
String credentials = userAPIKey + ":";
final String basic = "Basic "+ Base64.encodeBase64(credentials.getBytes());
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", basic);
requestBuilder.header("Accept", "application/json");
requestBuilder.method(original.method(),original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.build();
Retrofit retrofit = builder.client(client).build();
return retrofit.create(BlueshiftUserService.class);
}
When I call updateUser on the UserService
Response<UserAPIResponse> response = UserService.userUpdate(userUpdateRequest).execute();
The response.code is 401 (unauthorized/authentication failed)
The curl command with -u and the same credentials works as expected.
The issue was with the credentials encoding. I wasnt sending it as string.
byte[] encodedAuth= Base64.encodeBase64(credentials.getBytes());
final String basic = "Basic " + new String(encodedAuth);
use these libraries in Gradle file
compile 'com.squareup.retrofit:retrofit:1.9.0'
compile 'com.squareup.okhttp:okhttp:2.3.0'
compile 'com.cookpad.android.rxt4a:rxt4a:0.9.0'
compile 'io.reactivex:rxjava:1.0.12'
and put this classes in your project
public class ServiceGenerator {
private static final String TAG = erviceGenerator.class.getSimpleName();
public static final int READ_TIMEOUT = 10000;
public static final int CONNECT_TIMEOUT = 100000;
// No need to instantiate this class.
private ServiceGenerator(){}
public static <S> S createService(Class<S> serviceClass, String
endpoint) {
// Call basic auth generator method without user and pass
return createService(serviceClass, endpoint, null, null); }
public static <S> S createService(Class<S> serviceClass, String
endpoint, String username, String password) {
OkHttpClient okHttpClient = new OkHttpClient();
okHttpClient.setReadTimeout(READ_TIMEOUT, TimeUnit.SECONDS);
okHttpClient.setConnectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS);
// Set endpoint url and use OkHTTP as HTTP client
RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(endpoint)
.setConverter(new GsonConverter(new Gson()))
.setClient(new OkClient(okHttpClient));
if (username != null && password != null) {
// Concatenate username and password with colon for authentication
final String credentials = username + ":" + password;
builder.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
// Create Base64 encoded string
String string = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
request.addHeader("Authorization", string);
request.addHeader("Accept", "application/json");
}
});
}
RestAdapter adapter = builder.build();
return adapter.create(serviceClass); } }
and this interface
public class TodolyClient {
private static final String TAG = TodolyClient.class.getSimpleName();
public static final String ENDPOINT = "your base URL";
public interface TodolyService {
#GET("/wp-json/wc/v2/products")(your remaining url)
Observable<Object> isAuthenticated();
}
}
and call the below method in your main activity
private void createProject() {
final TodolyClient.TodolyService service =ServiceGenerator.createService(
TodolyClient.TodolyService.class, TodolyClient.ENDPOINT, "your user name",
"your password");
Observable<Object> observable = service.isAuthenticated();
AndroidCompositeSubscription compositeSubscription = new AndroidCompositeSubscription();
observable
.lift(new OperatorAddToCompositeSubscription<Object>(compositeSubscription))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Object>() {
#Override
public void onNext(Object project) {
android.util.Log.d(TAG, "onNext: "+project.toString());
}
#Override
public void onCompleted() {
android.util.Log.d(TAG, "onNext:commm " );
}
#Override
public void onError(Throwable e) {
android.util.Log.d(TAG, "onNext: eeeeeeeee"+e.getMessage());
}
});
}
This is so far the easiest method i have ever tried for "Basic Authentication".
Use the below code to generate the auth header (API/Repository class), You can add any character set for encoding as the third parameter here.
var basic = Credentials.basic("YOUR_USERNAME", "YOUR_PASSWORD")
Pass this as header to the webservice call (API/Repository class)
var retrofitCall = myWebservice.getNewsFeed(basic)
Add the basic header as parameter (Retrofit Webservice interface class)
#GET("newsfeed/daily")
fun getNewsFeed(#Header("Authorization") h1:String):Call<NewsFeedResponse>
Sorry, my code is in Kotlin, but can be easily translated to Java.
References: https://mobikul.com/basic-authentication-retrofit-android/

Resources