Angular 2 api call responds with 404 even though service works when tested - rest

I am trying to call a web service from my Angular 2 app.
private baseUrl: string = 'http://localhost:3000/api';
getPatterns(): Observable<Pattern[]> {
const patterns$ = this.http
.get(`${this.baseUrl}/pattern`, {headers: this.getHeaders()})
.map(this.mapPatterns)
.catch(this.handleError);
return patterns$;
}
private getHeaders() {
const headers = new Headers();
headers.append('Accept', 'application/json');
return headers;
}
This gives me a 404 error for URL: http://localhost:3000/api/pattern even though I get a valid response when I open the URL in browser or try to call it from POSTMAN.
Any help pointing out why this doesn't work would be appreciated.
Thanks!

Vetemi's answer solved the first step of this issue for me. I had built my Angular App following along with the Angular Tour Of Heroes tutorial and removing the dependencies on the In Memory web api service resolved the 404 error. After that I was getting a CORS error, specifically the error read:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
My API is a .Net Core 2.0 API, so I needed to enable CORS which I did following the steps at this link
https://learn.microsoft.com/en-us/aspnet/core/security/cors
This is a trimmed down version of my Startup.cs file
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors(builder => builder.AllowAnyOrigin());
app.UseMvc();
}

In case, you haven't found the problem and for those who have the same problem.
Have you used the in memory database from the tutorial Angular Tour of Heroes? If yes, then this may be the problem. The dependency
"angular-in-memory-web-api": "~0.2.4",
intercepts your http requests. Removing this dependency might help. Solution was found here.

Your header contains nothing, so the response is 404. See the below change
private getHeaders() : Headers {
const headers = new Headers();
headers.append('Accept', 'application/json');
return headers;
}
Reason: Default return type of the methods are void, so when you are returning you need to explicitly have the return type

Related

Redirection issue in Oauth2

I'm developing simple microservices with Oauth2 with keycloak as authorization server.
Following is the code which returns list of albums when hitting the url: - http://localhost:8087/albums
#Controller
public class AlbumController {
#Autowired
OAuth2AuthorizedClientService oauthService;
#Autowired
RestTemplate restTemplate;
#GetMapping("/albums")
public String getAlbums(Model model,#AuthenticationPrincipal OidcUser principal,Authentication auth) {
OidcIdToken token=principal.getIdToken();
String tokenValue=token.getTokenValue();
Authentication authentication=SecurityContextHolder.getContext().getAuthentication();
OAuth2AuthenticationToken oauthToken=(OAuth2AuthenticationToken) authentication;
OAuth2AuthorizedClient client=oauthService.loadAuthorizedClient(oauthToken.getAuthorizedClientRegistrationId(), oauthToken.getName());
String jwtAccessToken=client.getAccessToken().getTokenValue();
String url="http://localhost:9091/albums";
HttpHeaders headers=new HttpHeaders();
headers.add("Authorization", "Bearer "+jwtAccessToken);
HttpEntity<List<AlbumsRest>> entity=new HttpEntity<List<AlbumsRest>>(headers);
ResponseEntity<List<AlbumsRest>> responseEntity=restTemplate.exchange(url, HttpMethod.GET, entity, new ParameterizedTypeReference<List<AlbumsRest>>() {
});
List<AlbumsRest> albums=responseEntity.getBody();
model.addAttribute("Albums", albums);
return "albums";
}
}
Following is my application.properties file :-
server.port=8087
spring.security.oauth2.client.registration.mywebclient.client-id=tcs
spring.security.oauth2.client.registration.mywebclient.client-secret=2KcMN6xsmJH235k6TlLXUXj3iY3sAl8i
spring.security.oauth2.client.registration.mywebclient.scope=openid,profile,roles
spring.security.oauth2.client.registration.mywebclient.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.mywebclient.redirect-uri=http://localhost:8087/login/oauth2/code/mywebclient
spring.security.oauth2.client.provider.mywebclient.authorization-uri=http://localhost:7070/auth/realms/developer/protocol/openid-connect/auth
spring.security.oauth2.client.provider.mywebclient.token-uri=http://localhost:7070/auth/realms/developer/protocol/openid-connect/token
spring.security.oauth2.client.provider.mywebclient.jwk-set-uri=http://localhost:7070/auth/realms/developer/protocol/openid-connect/certs
spring.security.oauth2.client.provider.mywebclient.user-info-uri=http://localhost:7070/auth/realms/developer/protocol/openid-connect/userinfo
spring.security.oauth2.client.provider.mywebclient.user-name-attribute=Utkarsh0911
Whenever I'm hitting the url http://localhost:8087/albums, it performs too many redirections and finally end up on a page with message "This Page isn't working".
this loop usually occurs when the redirect URL is not defined as permitted in the application. Please check here:
https://dzone.com/articles/spring-boot-how-to-solve-oauth2-err-too-many-redir

how to get a valid response from a php web service on GWT

I'm trying to get data from a php web service (that I've put in my localhost - tested and works fine) in the client side of my GWT application.
I've tried to use the following package com.google.gwt.http.client.* it looks like the code works fine but the response is always 0, it's highly likely to be a corss problem but I still can't figure how to solve it even though I've tried to use requestBuilder.setHeader(..);
here's the code I'm working on:
String url = "http://localhost/geoTrackerTest.php?id=15";
RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, URL.encode(url));
requestBuilder.setHeader("Access-Control-Allow-Origin", "http://localhost");
requestBuilder.setHeader("Access-Control-Allow-Methods", "POST, GET, UPDATE, OPTIONS");
requestBuilder.setHeader("Access-Control-Allow-Headers", "x-http-method-override");
try {
Request request = requestBuilder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
GWT.log("Error: "+exception.getMessage());
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
GWT.log("response: "+response.getText());
} else {
GWT.log("response code: "+response.getStatusCode());
}
}
});
} catch (RequestException e) {
GWT.log("Request Exception: "+e.getMessage());
}
I'm still getting 0 as a response.
You will need to set the header in response from server side (not from the GWT client side), then you can make Cross Site Requests from GWT RequestBuilder. Something like this on server side:
Response.setHeader("Access-Control-Allow-Origin","http://localhost");
If you only need to send GET requests, you can use JSONP (http://www.gwtproject.org/javadoc/latest/com/google/gwt/jsonp/client/JsonpRequestBuilder.html) instead to send cross domain requests, without headers setting on server side.

.Net Core: Validate Anti Forgery Token with Ionic front end

I have looked all over and have found similar solutions, but nothing that matches exactly what I'm working on.
We have a .net core MVC website with an API Controller for handling requests from an ionic mobile app which we are also developing.
In most cases, adding [ValidateAntiForgeryToken] to the API controller actions works. I have gone through the process of generating the token, passing it to Ionic, and storing it in the request headers for validation.
Here is the code I am using to fetch and store the token:
static XSRF_TOKEN_KEY: string = "X-XSRF-TOKEN";
static XSRF_TOKEN_NAME_KEY: string = "X-XSRF-TOKEN-NAME";
constructor(){}
static getXsrfToken(http: HTTP) : {tokenName: string, token: string} {
let tokenName: string = window.sessionStorage.getItem(ValidationManager.XSRF_TOKEN_NAME_KEY);
let token: string = window.sessionStorage.getItem(ValidationManager.XSRF_TOKEN_KEY);
if(!tokenName || !token){
this.fetchXsrfToken(http);
tokenName= window.sessionStorage.getItem(ValidationManager.XSRF_TOKEN_NAME_KEY);
token = window.sessionStorage.getItem(ValidationManager.XSRF_TOKEN_KEY);
}
return {
tokenName: tokenName,
token: token
};
}
private static setXsrfToken({ token, tokenName }: { token: string, tokenName: string }) {
window.sessionStorage.setItem(ValidationManager.XSRF_TOKEN_KEY, token);
window.sessionStorage.setItem(ValidationManager.XSRF_TOKEN_NAME_KEY, tokenName);
}
private static fetchXsrfToken(http: HTTP) {
let token: string = window.sessionStorage.getItem(ValidationManager.XSRF_TOKEN_KEY);
let tokenName: string = window.sessionStorage.getItem(ValidationManager.XSRF_TOKEN_NAME_KEY);
if (!token || !tokenName) {
let apiUrl: string = AppConfig.apiUrl + "/GetAntiforgeryToken";
http.get(apiUrl, {}, {})
.then(r => this.setXsrfToken(JSON.parse(r.data)))
.catch(r => console.error("Could not fetch XSRFTOKEN", r));
} else {
this.setXsrfToken({ token: token, tokenName: tokenName });
}
}
Here is the action in my controller that serves anti forgery tokens:
[HttpGet]
public override IActionResult GetAntiforgeryToken()
{
var tokens = _antiforgery.GetAndStoreTokens(HttpContext);
return new ObjectResult(new
{
token = tokens.RequestToken,
tokenName = tokens.HeaderName
});
}
I set the headers of the http plugin by calling this function from the view's associated typescript file:
initializeHttp() {
let token = ValidationManager.getXsrfToken(this.http);
this.http.setHeader(token.tokenName, token.token);
console.log("Http Initialized: ", token);
}
then any request I make with the http plugin is validated properly in the controller's action:
this.http.post(apiUrl, {}, {}).then(response => {
that.navCtrl.setRoot(HomePage);
});
Up to this point, everything works great. The problem arises when I try to use XmlHttpRequest to for a POST instead of the built-in http plugin:
let file = {
name: e.srcElement.files[0].name,
file: e.srcElement.files[0],
};
let formData: FormData = new FormData();
formData.append('file', file.file);
let xhr: XMLHttpRequest = new XMLHttpRequest();
xhr.open('POST', apiUrl, true);
console.log("setting request header: ", tokenVal); //verify that tokenVal is correct
xhr.setRequestHeader("X-XSRF-TOKEN", tokenVal);
xhr.send(formData);
If I remove the [ValidateAntiForgeryToken] attribute from the controller's action, the file is posted properly. However, nothing I have tried has worked with the attribute being included.
I believe the issue has something to do with the validation tokens being added to a cookie automatically by Ionic, and the cookie is passed along with the request from the http plugin. However, XMLHttpRequest does not pass the cookie along (and is unable to do so?).
I have read up on the subject quite a bit over the past few days but I admit that this validation is still mostly a black box to me. Is there a way to validate the request in my action using only the token which is passed up in the header?
The reason I am running into this problem is that I need to upload a file, which I was unable to do using the http plugin. There are solutions for uploading images using Ionic's file-transfer plugin, but it has been deprecated and the release notes suggest using XmlHttpRequest instead.
Other things I have tried:
I have found solutions for .net standard which use System.Web.Helpers.AntiForgery for custom validation on the server, but this namespace is not included in .net core and I could not find an equivalent.
I tried many different ways to post the file using the http plugin (since it has no issues validating the antiForgery token). Everything I tried resulted in the action being hit but the file being posted was always null. A solution which uploads a file using the http plugin would also be acceptable.
Why is it that I was able to spend two full days on this problem, but as soon as I post a question about it, I find the answer? Sometimes I think the internet gods are just messing with me.
As it turns out, the native http plugin has an uploadFile() function that I never saw mentioned anywhere else. Here's what the solution does:
Use the fileChooser plugin to select a file from the phone's storage
Use the filePath plugin to resolve the native filesystem path of the image.
Use http.uploadFile() instead of http.post()
This works because as mentioned above, I was able to properly set the validation token in the http plugin's header to be accepted by the controller.
And here is the code:
let apiUrl: string = AppConfig.apiUrl + "/UploadImage/";
this.fileChooser.open().then(
uri => {
this.filePath.resolveNativePath(uri).then(resolvedPath => {
loader.present();
this.http.uploadFile(apiUrl,{ },{ },resolvedPath, "image")
.then(result => {
loader.dismiss();
toastOptions.message = "File uploaded successfully!";
let toast = this.toastCtrl.create(toastOptions);
toast.present();
let json = JSON.parse(result.data);
this.event.imageUrl = json.imgUrl;
})
.catch(err => {
console.log("error: ", err);
loader.dismiss();
toastOptions.message = "Error uploading file";
let toast = this.toastCtrl.create(toastOptions);
toast.present();
});
});
}
).catch(
e => console.log(e)
);

Allow HTTP->HTTPS while blocking HTTPS->HTTP redirects in OkHTTP?

With OkHTTP I have two methods for configuring redirects -
followRedirects(boolean followRedirects) -> Configures whether to allow redirection at all.
followSslRedirects(boolean followProtocolRedirects) -> Configures whether to allow HTTP -> HTTPS and HTTPS -> HTTP redirects.
Though what I am looking to achieve is to allow HTTP -> HTTPS redirects while simultaneously blocking HTTPS -> HTTP redirection. The only way I can think of is to add an OkHTTP Interceptor as shown in the code below to check for request and response url protocols. Though I am not sure if it's the most optimum/correct way to achieve this as we are still making the calls to redirected url while doing chain.proceed(request). Can anyone points me toward a better approach here. Thanks.
new OkHttpClient.Builder()
.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
if (!isValidRedirect(request.url(), response.request().url())) {
throw new IOException("Invalid redirect from secure server to insecure server");
}
return response;
}
})
.build();
private static boolean isValidRedirect(HttpUrl url, HttpUrl newUrl) {
//unless it's https, don't worry about it
if (!url.url().getProtocol().equals("https")) {
return true;
}
// If https, verify that we're on the same server.
// Not being so means we got redirected from a secure link to a
// different link, which isn't acceptable.
return url.url().getHost().equals(newUrl.url().getHost());
}

org.keycloak.common.VerificationException: Invalid token issuer

I'm developing an Android app, which uses my REST backend. The backend is running on an JBoss instance, which is secured through Keycloak. Since I've updated my Keycloak from 1.0.7 to 2.1.5 I'm experiencing the following problem.
If I try to call a REST API of my backend, JBoss writes the folowing log:
[org.keycloak.adapters.BearerTokenRequestAuthenticator] (default task-39)
Failed to verify token: org.keycloak.common.VerificationException: Invalid token issuer.
Expected 'http://localhost:8180/auth/realms/myrealm', but was 'http://192.168.178.24:8180/auth/realms/myrealm'
at org.keycloak.TokenVerifier.verify(TokenVerifier.java:156)
at org.keycloak.RSATokenVerifier.verify(RSATokenVerifier.java:89)
192.168.178.24 is the right IP address. It seems to be a configuration issue, but where can I config this address?
Has anybody an idea how to fix this problem?
Very simple solution: Make sure when any of your component contact with Keycloak server, they use the same url.
Detailed explanations:
For your case (same as mine), it seems that your Android app is making http request to http://192.168.178.24:8180/... while your server is requesting (or at least configured to) http://192.168.178.24:8180/.... So change your server such that it will request http://192.168.178.24:8180/....
P.S. The exception seems to be the expected behavior to avoid some attacks.
If you take a look into the implementation, here it throws your Exception.
public static class RealmUrlCheck implements Predicate<JsonWebToken> {
private static final RealmUrlCheck NULL_INSTANCE = new RealmUrlCheck(null);
private final String realmUrl;
public RealmUrlCheck(String realmUrl) {
this.realmUrl = realmUrl;
}
#Override
public boolean test(JsonWebToken t) throws VerificationException {
if (this.realmUrl == null) {
throw new VerificationException("Realm URL not set");
}
if (! this.realmUrl.equals(t.getIssuer())) {
throw new VerificationException("Invalid token issuer. Expected '" + this.realmUrl + "', but was '" + t.getIssuer() + "'");
}
return true;
}
};
I think your Client configuration is not correct. Do you have the same clients as in your Keycloak?