Spring Boot Uygulamasını Heroku üzerinde Deploy Etme

Bu yazımızda sizlere spring boot ile yazılmış basit bir Rest api'nin heroku üzerinde nasıl deploy edebileceğimizi göstereceğim.


Önce spring boot ile basit bir rest servis yazalım ve bunun doğru bir şekilde çalıştığını onaylayalım.



import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.web.bind.annotation.*;
@SpringBootApplication
@EnableAutoConfiguration
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
view raw App.java hosted with ❤ by GitHub
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderService {
@RequestMapping("/heroku")
public String getOrder(){
return "Heroku";
}
}
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.todo</groupId>
<artifactId>hihi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>hihi</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
view raw pom.xml hosted with ❤ by GitHub



Buradan bir hesap oluşturuyoruz. Daha sonra buradan Heroku CLI'yı indirip kuruyoruz. Kurulum gerçekleştikten sonra login oluyoruz 

$ heroku login
heroku: Press any key to open up the browser to login or q to exit:
Opening browser to https://cli-auth.heroku.com/auth/browser/********
Logging in... done
Logged in as gguzelkokar.mdbf15@iste.edu.tr
view raw heroku hosted with ❤ by GitHub
Login olduktan sonra projemizin root konumuna gidiyoruz ve heroku create komutu ile yeni bir app oluşturuyoruz.

$ heroku create
Creating app... done, ⬢ calm-bayou-73911
https://calm-bayou-73911.herokuapp.com/ | https://git.heroku.com/calm-bayou-73911.git
view raw heroku hosted with ❤ by GitHub


https://calm-bayou-73911.herokuapp.com/ default olarak yüklendi.


Şimdi de projemizi git'e atıp commit edelim. Daha sonra uygulamamızı yaratırken oluşturulan "https://git.heroku.com/calm-bayou-73911.git'i" projemize bağlıyoruz. Github üzerinden boş bir repository oluşturduğunuzu düşünün ve localde'ki dosyalarınızı oluşturduğunuz uzak repoya göndermek istiyorsunuz(Github). Aynı işlem. Heroku bizim için herşeyi halletti. Git ile ilgili daha fazla bilgi almak isterseniz buradaki yazımı inceleyebilirsiniz.

$ git init
$ git add .
$ git commit -m "initial"
[master (root-commit) 68c1706] initial
24 files changed, 212 insertions(+)
...
$ git remote add heroku https://git.heroku.com/calm-bayou-73911.git
$ git push heroku master
...
...
remote: Verifying deploy... done.
To https://git.heroku.com/calm-bayou-73911.git
* [new branch] master -> master
view raw git hosted with ❤ by GitHub




Görev tamamlandı :). Bir sonraki yazıda görüşmek üzere.. İyi kodlamalar...











Birleştirmeli Sıralama (Merge Sort) Nedir ?

Birleştirme sıralama(Merge sort) algoritması adından da anlaşılacağı üzere bir sıralama algoritmasıdır. O(n log(n)) karmaşıklığına sahiptir. Girdi listesini en küçük hale gelene kadar ikili parçalara ayırır ve bu parçaları kendi aralarında sıralayarak birleştirir ve nihayetinde sıralanmış çıktı elde edilir.


Merge sort animation.gif
Wikipedia

Elimizde böyle bir liste olsun ve bu listeyi sıralamaya çalışıyor olalım.

  | 38 | 27 | 43 | 3 | 9 | 82 | 10 | 

İlk açamada listemizi 2'ye bölüyoruz. Tabi burada listemizdeki eleman sayısı tek olduğundan tam olarak bölemiyoruz.

                                                           | 38 | 27 | 43 | 3 |            | 9 | 82 | 10 | 

İşlemimizi karşılaştırabileceğimiz 2 sayı kalana kadar devam ettiriyoruz.

                                                      | 38 | 27 |         | 43 | 3 |         | 9 | 82 |        | 10 |  

Evet şimdi sayılarımızı sıralayarak birleştirebiliriz. 

                                                      | 27 | 38 |          | 3 | 43 |        | 9 | 82 |        | 10 | 

                                                          | 3 | 27 | 38 | 43 |               | 9 | 10 | 82 | 

                                                                      | 3 | 9 | 10 | 27 | 38 | 43 | 82 |




Mantığını anladığımıza göre java ile nasıl kodlayabileceğimize bakabiliriz.





package Sorts;
import static Sorts.SortUtils.print;
/**
* This method implements the Generic Merge Sort
*
* @author Varun Upadhyay (https://github.com/varunu28)
* @author Podshivalov Nikita (https://github.com/nikitap492)
* @see SortAlgorithm
*/
class MergeSort implements SortAlgorithm {
/**
* This method implements the Generic Merge Sort
*
* @param unsorted the array which should be sorted
* @param <T> Comparable class
* @return sorted array
*/
@Override
@SuppressWarnings("unchecked")
public <T extends Comparable<T>> T[] sort(T[] unsorted) {
T[] tmp = (T[]) new Comparable[unsorted.length];
doSort(unsorted, tmp, 0, unsorted.length - 1);
return unsorted;
}
/**
* @param arr The array to be sorted
* @param temp The copy of the actual array
* @param left The first index of the array
* @param right The last index of the array
* Recursively sorts the array in increasing order
**/
private static <T extends Comparable<T>> void doSort(T[] arr, T[] temp, int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
doSort(arr, temp, left, mid);
doSort(arr, temp, mid + 1, right);
merge(arr, temp, left, mid, right);
}
}
/**
* This method implements the merge step of the merge sort
*
* @param arr The array to be sorted
* @param temp The copy of the actual array
* @param left The first index of the array
* @param mid The middle index of the array
* @param right The last index of the array
* merges two parts of an array in increasing order
**/
private static <T extends Comparable<T>> void merge(T[] arr, T[] temp, int left, int mid, int right) {
System.arraycopy(arr, left, temp, left, right - left + 1);
int i = left;
int j = mid + 1;
int k = left;
while (i <= mid && j <= right) {
if (temp[i].compareTo(temp[j]) <= 0) {
arr[k++] = temp[i++];
} else {
arr[k++] = temp[j++];
}
}
while (i <= mid) {
arr[k++] = temp[i++];
}
while (j <= right) {
arr[k++] = temp[j++];
}
}
// Driver program
public static void main(String[] args) {
// Integer Input
Integer[] arr = {4, 23, 6, 78, 1, 54, 231, 9, 12};
MergeSort mergeSort = new MergeSort();
mergeSort.sort(arr);
// Output => 1 4 6 9 12 23 54 78 231
print(arr);
// String Inpu
String[] stringArray = {"c", "a", "e", "b", "d"};
mergeSort.sort(stringArray);
//Output => a b c d e
print(stringArray);
}
}
view raw MergeSort.java hosted with ❤ by GitHub
package Sorts;
import java.util.Arrays;
import java.util.List;
/**
* The class contains util methods
*
* @author Podshivalov Nikita (https://github.com/nikitap492)
**/
final class SortUtils {
/**
* Prints an array
*
* @param toPrint - the array which should be printed
*/
static void print(Object[] toPrint) {
System.out.println(Arrays.toString(toPrint));
}
}
view raw SortUtils.java hosted with ❤ by GitHub

Burada sort, doSort ve merge adında 3 fonksiyon mevcut. doSort recursive olarak çalışıyor. Main fonksiyonunda sort fonksiyonuna parametre olarak gönderilen dizinin boyutunda boş bir dizi oluşturuluyor(tmp). Sonrasın da parametler doSort fonksiyonuna gönderiliyor. Orada bölünen dizi merge fonksiyonunda sıralanarak birleştiriliyor. Kodu satır satır açıklamam epeyce bir zaman alır. Bunun yerine kod parçasını alıp debug etmenizi öneririm. Bir sonraki yazıda görüşmek üzere. İyi çalışmalar.

Ekleme Sıralaması (Insertion Sort) Nedir ?

Ekleme sıralaması (Insertion Sort) basit bir sıralama algoritmasıdır. Bu algoritmayı günlük hayatta oyun kartlarını elimizde sıralarken kullanıyoruz. Ekleme sıralamasının çok elemanlı listelerde kullanımı facia ile sonuçlanabilir. Büyük listeleri sıralarken genellikle quick, merge veya heap sort gibi algoritmalardan yararlanırız. Insertion sort küçük boyutlu listelerde(ortalama 30 ve altı) tercih ediliyor. Çünkü performansı O(n ^ 2)'dir. Bu demek oluyor ki listedeki veri miktarı arttıkça çalışma süresi n ile doğru orantılı olarak artacaktır. Java 12'de Arrays sınıfının altında hazır gelen sort fonksiyonu, Vladimir Yaroslavskiy, Jon Bentley, ve Joshua Bloch'un uyguladığı (implement ettiği) Quicksort algoritmasını kullanır. Bu algoritmanın performansı ise O(n log(n)) dir. Bu algoritmayı büyük listelerde(örneğin 10 milyon kişinin puanı)  gönül rahatlığı ile kullanılabilir.

Kaynak


Kaynak
Elimizde 8 elemanlı bir dizi var. Şekilde de gördüğümüz üzere 2.elemandan başlıyoruz ve önceki elemanlar ile karşılaştırıp sayının yeni yerini belirliyoruz. Örneğin ilk aşamada 3 ile 4'ü karşılaştırdık ve 3 < 4 olduğundan yerlerini değiştirdik. 3. elemandan devam ediyoruz. Bakıyoruz ki 2 < 4 o halde karşılaştırmaya devam ediyoruz ve 2 < 3 olduğundan ve karşılaştıracak herhangi bir eleman kalmadığından 2'nin yeni yeri belirlenmiş oluyor. Algoritmamız çalışma mantığını kavradığımıza göre Java'da nasıl uygulayacağımıza bakalım. 
package Sorts;
import static Sorts.SortUtils.less;
import static Sorts.SortUtils.print;
/**
* @author Varun Upadhyay (https://github.com/varunu28)
* @author Podshivalov Nikita (https://github.com/nikitap492)
*/
class InsertionSort implements SortAlgorithm {
/**
* This method implements the Generic Insertion Sort
* Sorts the array in increasing order
*
* @param array The array to be sorted
**/
@Override
public <T extends Comparable<T>> T[] sort(T[] array) {
for (int j = 1; j < array.length; j++) {
// Picking up the key(Card)
T key = array[j];
int i = j - 1;
while (i >= 0 && less(key, array[i])) {
array[i + 1] = array[i];
i--;
}
// Placing the key (Card) at its correct position in the sorted subarray
array[i + 1] = key;
}
return array;
}
// Driver Program
public static void main(String[] args) {
// Integer Input
Integer[] integers = {4, 23, 6, 78, 1, 54, 231, 9, 12};
InsertionSort sort = new InsertionSort();
sort.sort(integers);
// Output => 1 4 6 9 12 23 54 78 231
print(integers);
// String Input
String[] strings = {"c", "a", "e", "b", "d"};
sort.sort(strings);
//Output => a b c d e
print(strings);
}
}
package Sorts;
import java.util.Arrays;
import java.util.List;
/**
* The class contains util methods
*
* @author Podshivalov Nikita (https://github.com/nikitap492)
**/
final class SortUtils {
/**
* This method checks if first element is less then the other element
*
* @param v first element
* @param w second element
* @return true if the first element is less then the second element
*/
static <T extends Comparable<T>> boolean less(T v, T w) {
return v.compareTo(w) < 0;
}
/**
* Prints an array
*
* @param toPrint - the array which should be printed
*/
static void print(Object[] toPrint) {
System.out.println(Arrays.toString(toPrint));
}
}
view raw SortUtils.java hosted with ❤ by GitHub
Kaynak

Burada T[] (Generic, neden kullanıldığını bilmiyorsanız buraya) dönüş tipi olan sort adında bir fonksiyon ve yardımcı fonksiyonların bulunduğun bir SortUtils sınıfımız mevcut. Burada dizimizi ekrana basacak print adında bir fonksiyon ve iki değeri karşılaştırıp sonucu boolean döndürecek less adlı bir fonksiyonumuz mevcut. Son olarak fonksiyonumuzun test edildiği main fonksiyonumuz var. Basit bir unit test yazmak daha iyi olacaktır. Sort fonksiyonunda parametre olarak alınan dizimizin boyutu kadar dönen bir for döngümüz var. Döngümüz 1'den başlıyor çünkü yukarıda belirttiğimiz gibi önceki sayılar ile kıyaslayacağız. Yani 1-0, 2-1-0, 3-2-1-0 diye devam edecek. Daha sonra bir key değeri belirliyoruz ve ikinci index'imizi içine atıyoruz(array[1]). Sonrasında bir i değeri belirliyoruz ve j değerimizin bir önceki değierini içine atıyoruz.(0 => array[0] için). i değerimizin 0>= olduğu ve key(array[1]) ile array[0] less fonksiyonuna parametre olarak yolladığımız bir while döngüsüne sokuyoruz. Eğer şart sağlanırsa yani 3<4 ise döngünün içindeki işlemler ile 4<=>3 yer değiştiriyor. Mantık bu şekilde devam ediyor. Herhangi bir sorunuz olursa yorum olarak belirtebilirsiniz. İyi çalışmalar.




Bug Bounty nedir ? Nasıl çalışabilirim ?

Bu yazımda hobi olarak ilgilendiğim bug bounty'i anlatmaya çalışacağım. Daha sonra bu konu üzerinde kendimizi geliştirmek için neler yapabileceğimize bakacağız.



Bir şirketinizin olduğunu varsayın. Ürünlerinizin ve kullanıcılarınızın güvenliği hakkında tedirginsiniz. Bir bug bounty programı başlatıyorsunuz ve diyorsunuz ki, ürünlerimizde herhangi bir açık tespit eden kişileri ödüllendiriyoruz. Ödüle dahil olan ürün ve açık türlerini belirtiyorsunuz. Daha sonra hacker'lar sistemlerinizi taramaya başlıyorlar ve bir açık bulduklarında sizlere bir rapor ile bildiriyorlar. Verilen raporun seviyesi ve doğruluğu onaylandıktan sonra açığı bulan kişi şirket tarafından ödüllendiriliyor. Bu ödül şirket tarafından belirleniyor ve açığın oluşturacağı tehlike büyüdükçe ödülün miktarı da aynı seviyede büyüyor. Tabi bazı şirketlerin programları ödül vermiyor onun yerine sizi hall of fame diye adlandırdıkları listelerine dahil ediyorlar. Bu olay örgüsünün gerçekleştiği ortamlar mevcut. Örneğin en çok kullanılan hackerone ve bugcrowd gibi. Yine bu platformlar dışında bulunan şirketlerin kendi kendilerine açtıkları bug bounty programları da mevcut. Hackerone üzerinde bir programın ve raporun görüntüsü aşağıdaki gibidir.





       Peki bu işe nasıl başlanır. Öncelikle acemi olduğumu belirtmek isterim. Bilgisayar mühendiliği mezunu olduğum için temel konulara hakimim. Ben bu işe bu kitabı  okuyarak başladım. Daha sonra web güvenliği alanına yöneldim ve buradaki açıklar üzerine yoğunlaşmaya başladım. Youtube üzerinden yayınlanan bu konferansları takip etmeye çalıştım ve daha sonra yavaştan açık aramaya başladım. Bugünlerde medium.com üzerinden okuyabildiğim kadar blog yazısı okuyorum. Bu alışkanlığı yeni yeni kazanıyorum. Her blog yazısında farklı taktikler öğreniyorum. Blogları ingilizce olarak okuyor bilmediğim kalıpları ve kelimeleri not alıyorum. Böylece hem dilimi geliştiriyorum hem de bir sürü şey öğreniyorum. Eğer ingilizce bilmiyorsanız(okuduğunuz ve duyduğunuzu anlamanız yeterli) en az 1-2 senenizi ingilizceye ayırın derim. Neyse devam edelim.

    Bilgi toplama (Recon) bu işin kilit noktalarındandır. Örneğin bilgi toplarken gözüme kibana.xyz.com diye bir subdomain çıktı yapacağım ilk iş önce kibana'nın ne iş yaptığını, nasıl çalıştığını öğrenmek daha sonra buradan belgelenmiş açıklarına göz atamak olacaktır.


         Son aşama ise bilgi manyaklığı. Alanınızda yazılmış, gördüğünüz her blog yazısını okuyun, videolar izleyin özellikle de konferansları şiddetle tavsiye ederim çünkü konferansı veren kişi o işin ustasıdır.(Çok büyük ihtimal) Not alın, uygulayın, tekrar edin, deneyin ve başkalarına öğretin ki bilginiz kalıcı olsun.


       Eğer bu alanda herhangi bir bilginiz yoksa ilk önce ağ teknolojilerine hakim olmanız şart. Her nerede çalışıyor olursanız olun çalışma ortamınızı çok iyi tanımanız gerekir. Örneğin web siteleri üzerinde açık arıyorsanız bu alanda kullanılan programlama dillerini(php, javascript, jsp, aspnet, django vb.) çok iyi tanımanız gerekir. Bu dillerin hangi yanlış kullanımda hangi güvenlik açığına neden olacağını bilmeniz sizi bir adım öne atacaktır. Daha sonra işinizde daha hızlı olmak için çok iyi seviyede linux(özellikle shell scripting) bilginizin olmasını tavsiye ederim. Örneğin elinizde 3000 tane subdomain var ve bunların arasından ayakta olanları (isteğe olumlu yanıt veren, açık aranacak potansiyele mevcut) tespit etmek istiyorsunuz. Bunu manuel olarak yaparsanız en azından 1-2 saatiniz gidecek, otomatik olarak yaparsanız (istekte(request) bulunup cevabı(response) ekran görüntüsü alan bir araç gibi örn) çok daha hızlı hareket edebilirsiniz. Sosyal medyayı kullanmayı öğrenin. Örneğin twitter'da bu işi çok çok iyi yapan insanlar var onları takip edin. Etraf harika kaynaklar ile dolu, açın okuyun. Direkt açık aramaya başlamayın (ilk heyecan ile normaldir fakat sabır şart). Bu adımları uyguladıktan sonra açık arayarak güzel paralar kazanabilirsiniz fakat öncelikli hedefinizin para olmamasını öneririm. Sizlere faydası dokunabilecek kişi ve platform linklerini aşağıya bırakıyorum. Bu listeyi sürekli güncelleyeceğim. 

Kullandığım araçlar: 

Tomnomnom'un neredeyse her aracı kullanıyorum. Eğer sizlerinde bu tarz favori araçlarınız varsa ve imkanınız varsa lütfen yazılımcılara destek(sponsor) olalım. 


Full manuel arıyorum..
-------------------------
Daha fazla tool için:


İyi çalışmalar. Herhangi bir sorunuz olursa: https://twitter.com/gkhck_






KAYNAKLAR

https://hackerone.com/hacktivity

https://www.owasp.org/index.php/Category:OWASP_Application_Security_Verification_Standard_P
roject

https://regilero.github.io/

https://portswigger.net/blog

https://www.youtube.com/user/DEFCONConference

https://github.com/OWASP/Top10

https://www.cvedetails.com/

https://medium.com/bugbountywriteup

https://medium.com/hackernoon

https://medium.com/@th3g3nt3l

https://github.com/tomnomnom

https://github.com/s0md3v

https://github.com/danielmiessler

https://github.com/codingo

https://twitter.com/albinowax

https://twitter.com/codecancare

https://twitter.com/ngalongc

https://twitter.com/CVEnew

https://twitter.com/ExploitDB

https://twitter.com/NahamSec

https://twitter.com/HackRead

https://twitter.com/securitytrails

https://twitter.com/GoSecure_Inc

https://pentester.land/list-of-bug-bounty-writeups.html

https://twitter.com/samwcyo


JAX-RS (ACCESSING CONTEXT INFORMATION)

      Bu yazımızda @context ek açıklamasının bizlere sunduğu içerik bilgilerini inceleyeceğiz.

Injecting Application

   İlk olarak application'dan başlıyoruz.Burada ApplicationConfig classımızda extends ettiğimiz Application classındaki getProperties methodunu override ederek kaynak sınıfımıza enjekte edeceğiz.Bu sayede kaynak sınıflarımızı ApplicationConfig class'ımızdan kontrol edebiliriz.Şimdi bunu basitçe nasıl yapabileceğimize bakalım.


import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class ApplicationConfig extends Application {
@Override
public Map<String,Object> getProperties(){
Map<String,Object> map=new HashMap<>();
map.put("KEY_MAX_ORDER_LIMIT", "100");
return map;
}
}
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
public class OrderClient {
public static void main(String[] args) throws Exception {
Client client = ClientBuilder.newBuilder().build();
WebTarget target =
client.target("http://localhost:8080/orders");
Response response = target.request().get(Response.class);
String responseString = response.readEntity(String.class);
System.out.println("response: " + responseString);
}
}
view raw Client hosted with ❤ by GitHub
import java.util.Map;
import java.util.stream.Collectors;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;
@Path("/orders")
public class OrderResource {
@GET
public String getAllOrders(@Context Application app) {
Map<String, Object> properties = app.getProperties();
String props = properties.entrySet().stream()
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining("\n"));
System.out.println(props);
return properties.get("KEY_MAX_ORDER_LIMIT").toString();
}
}
view raw Resource hosted with ❤ by GitHub
Gördüğünüz gibi,böylece ApplicationConfig sınıfımızda yaptığımız bir değişiklik kaynak sınıfımızı da etkileyecek.Şimdi de browser ve server çıktılarına bakalım.


Injecting UriInfo

        Aynı şekilde UriInfo arayüzümüzdeki fonksiyonların kullanımına ve bunların yine aynı şekilde server'ımızda tutulan log'una bakalım.




Injecting HttpHeaders



Umarım faydalı olmuştur.Bir sonraki yazımızda görüşmek üzere.

JAX-RS (ABORTING FILTER)

     Bu yazımızda filter konusuna devam ediceğiz.Bu seferde kaynak sınıfımız için yazdığımız bir filter'ımızı bazı koşullarda kullanması,bazı koşullarda ise kullanmaması için bir filter daha yazacağız.Bir süzgeç düşünün ve orada portakal suyunu çekirdeklerinden süzüp içeceksiniz.İşte portakalın çekirdekleri ilk yazdığımız filter'a takılıyor dolayısıyla ikinci yazdığımız filterda(mide) bunu kullanmıyor. :).Burada ilk filter çekirdeği görünce,ikinci filter'ı iptal ediyor.Mesela gelen isteklerin veya herhangi bir bilginin log'lanmasını istemediğimiz zaman uygulayabiliriz.Şimdi kodlarımıza bakıp daha iyi anlayalım.


import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class ApplicationConfig extends Application {
}
view raw G1 hosted with ❤ by GitHub
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@Path("/")
public class MyResource {
@GET
@Path("{path:.*}")
public String getResponse(@PathParam("path") String path) {
return "dummy-response for " + path;
}
}
view raw G2 hosted with ❤ by GitHub
@Priority(1)
@Provider
public class InvalidRequestFilter implements ContainerRequestFilter{
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
Response resForInvalidRequest = kontrol(requestContext);
if(resForInvalidRequest!=null)
requestContext.abortWith(resForInvalidRequest);
}
private Response kontrol(ContainerRequestContext requestContext){
UriInfo uriInfo=requestContext.getUriInfo();
String path=uriInfo.getPath();
if(path.equals("orders/history")){
String msg = String.format("The feature is not yet supported: %s%n", path);
CacheControl cc=new CacheControl();
cc.setNoStore(true);
Response response=Response.status(Response.Status.NOT_IMPLEMENTED)
.cacheControl(cc)
.entity(msg)
.build();
return response;
}
return null;
}
}
view raw G3 hosted with ❤ by GitHub
import java.io.IOException;
import javax.annotation.Priority;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;
@Priority(2)
@Provider
public class LogFilter implements ContainerRequestFilter, ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext reqContext) throws IOException {
System.out.println("-- request info --");
UriInfo uriInfo = reqContext.getUriInfo();
log(uriInfo, reqContext.getHeaders());
}
@Override
public void filter(ContainerRequestContext reqContext,
ContainerResponseContext resContext) throws IOException {
System.out.println("-- response info --");
UriInfo uriInfo = reqContext.getUriInfo();
log(uriInfo, resContext.getHeaders());
}
private void log(UriInfo uriInfo, MultivaluedMap<String, ?> headers) {
System.out.println("Path: " + uriInfo.getPath());
System.out.println("HEADERS:");
headers.entrySet().forEach(h -> System.out.println(h.getKey() + ": " + h.getValue()));
}
}
view raw G4 hosted with ❤ by GitHub
Kodlarımızda gördüğünüz gibi.InvalidRequestFilter sınıfımızda yazdığımız kontrol methodunda gelen isteğe göre değer döndürülüyor.Sınıf adı Ingilizce metod Türkçe ne biçim iş yapıyorsun diyebilirsiniz :) fakat kodlar buradaki sayfaya ait ve ben bu kodları yazarken bazı yerlerde ufak oynamalar yapıyorum.Şimdi de çıktımıza bakalım. GET/orders/history isteği hariç diğer tüm istekler sunucumuzda kayıt ediliyor.Aşağıdaki çıktılarda gördüğünüz gibi.


Umarım faydalı olmuştur.Görüşmek üzere.

JAX-RS (FILTER BINDING & DYNAMIC FILTER BINDING)

     Herkese merhaba.Bu yazımızda da yine filter konusunda yazacağımız filter sadece belli kaynak fonksiyonlarına özel olacak.Bunu yaparken ilk defa kendi açıklamamızı oluşturacağız.Daha sonra yazdığımız filter ve kullanacağı kaynak fonksiyon,sınıf,interface veya her neyse,bu açıklama ile işaretlenecek.Binding olayıda tam da burada karşımıza çıkıyor.Türkçe anlamıyla bağlayıcı olan bu kelimenin görevi anlaşılacağı gibi adından geliyor.Gördüğünüz gibi filter ile belli bir kaynağı birbirine bağlayacak.Ek açıklamamızı (Annotation) kodlarken satırlarımızı tek tek açıklayacağız.Şimdi kodlama kısmına geçelim.Üzerinde duracağımız tek yer annotation'ın oluşturulduğu yer.Yazdığımız bu ek açıklama ile bağlayacağımız yerleri işaretlememiz gerekiyor.Kodlar üzerinden devam edelim.



import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.ws.rs.NameBinding;
@NameBinding
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(value=RetentionPolicy.RUNTIME)
public @interface Logged {
}
view raw Gokhan hosted with ❤ by GitHub
Şuan logged adında bir annotation oluşturduk.@target açıklaması yazdığımız logged açıklamasının nerelerde kullanılabileceğini belirtiyor.TYPE ve METHOD birlikte kullanılmış.Bunun anlamı yazdığımız annotation hem fonksiyonlar üzerinde hem de sınıf,interface,enum gibi yapılarda çalışabilir.Bir sonraki satırda ise @Retention açıklamasında bu yazdığımız açıklamaya hangi zamanda erişilsin.Bu değerin varsayılanı RetentionPolicy.CLASS'tır.Burada kullanılan RUNTIME ise bu açıklamaya sadece çalışma zamanında erişim vardır anlamındadır.Bu da java da Java Reflection API tarafından yapılır.Buradan araştırabilirsiniz.Şimdide kodlarımızın geri kalanına bakıp programımızı derleyelim.
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
@Provider
@Logged
public class LogFilter implements ContainerRequestFilter, ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext reqContext) throws IOException {
System.out.println("-- req info --");
UriInfo uriInfo = reqContext.getUriInfo();
log(uriInfo, reqContext.getHeaders());
}
@Override
public void filter(ContainerRequestContext reqContext,
ContainerResponseContext resContext) throws IOException {
System.out.println("-- res info --");
UriInfo uriInfo = reqContext.getUriInfo();
log(uriInfo, resContext.getHeaders());
}
private void log(UriInfo uriInfo, MultivaluedMap<String, ?> headers) {
System.out.println("Path: " + uriInfo.getPath());
headers.entrySet().forEach(h -> System.out.println(h.getKey() + ": " + h.getValue()));
}
}
view raw Gokhan hosted with ❤ by GitHub
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@Path("/customers")
public class MyResource {
@GET
public String getAllCustomers() {
System.out.println("in getAllCustomers()");
return "dummy-response for all customers";
}
@Logged
@GET
@Path("{id}")
public String getCustomerById(@PathParam("id") String id) {
System.out.println("in getCustomerById()");
return "dummy-response for customer " + id;
}
}
view raw Gokhan1 hosted with ❤ by GitHub
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("/")
public class ApplicationConfig extends Application{
}
view raw Gokhan2 hosted with ❤ by GitHub


Çıktımız ise şu şekilde olacak.Sadece GET/customers gibi bir istekte sunucumuza herhangi bir ek kayıt düşmeyecek.Yani filter kullanılmayacak fakat eğer GET/customers/{id} gibi bir istek gelirse filter kullanılacak.Aşağıdaki görsellerde de çok açık bir şekilde görünüyor.




Bu işi dinamik olarakta gerçekleştirebiliriz.Yani aynı şekilde istediğimiz alanlar için bir filter yazmak istiyorsak,dynamicfeature interfaceni imlement edip gerekli kontrolleri yapamız gerekir.

import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;
import java.lang.reflect.Method;
@Provider
public class FilterRegistrationFeature implements DynamicFeature {
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
if (MyResource.class.isAssignableFrom(resourceInfo.getResourceClass())) {
Method method = resourceInfo.getResourceMethod();
if (method.getName().toLowerCase().contains("order")) {
System.out.println("registering LogFilter");
context.register(new LogFilter());
}
}
}
}
view raw Gokhan hosted with ❤ by GitHub

Umarım faydalı olmuştur.Sağlıcakla kalın.

JAX-RS (FILTER PRIORITIES)

    Bu yazımızda da bir önceki yazımızda olduğu gibi filter yazmaya devam edeceğiz.Bu yazımızda bir önceki yazımıza ilaveten bir filter yazmak yerine projemizde birden fazla filter'ı nasıl yazabileceğimize değineceğiz.Burada yardımımıza koşan ek açıklama ise @priorities.Türkçe anlamı öncelik olan bu ek açıklama yazdığımız filter'ları çalışma sırasına göre sıralıyor.Bu ek açıklama aldığı integer parametre ile filter'ları sıralıyor.Şimdi timefilter ve logfilter adında iki filter yazıp bunların hangi sırada çalışacağını belirleyelim.


package com.mycompany.filterpriorities;
import java.io.IOException;
import javax.annotation.Priority;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;
@Priority(1)
@Provider
public class TimeFilter implements ContainerRequestFilter, ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext reqContext) throws IOException {
System.out.println("-- TimeFilter request --");
reqContext.setProperty("start-time", System.currentTimeMillis());
}
@Override
public void filter(ContainerRequestContext reqContext,
ContainerResponseContext resContext) throws IOException {
System.out.println("-- TimeFilter response --");
long startTime = (long) reqContext.getProperty("start-time");
System.out.printf("Time taken for request %s: %s milli secs%n",
reqContext.getUriInfo().getPath(),
System.currentTimeMillis() - startTime
);
}
}
view raw Gokhan hosted with ❤ by GitHub
package com.mycompany.filterpriorities;
import javax.annotation.Priority;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.ext.Provider;
import java.io.IOException;
@Priority(2)
@Provider
public class LogFilter implements ContainerRequestFilter, ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext reqContext) throws IOException {
System.out.println("-- req headers --");
log(reqContext.getUriInfo(), reqContext.getHeaders());
}
@Override
public void filter(ContainerRequestContext reqContext,
ContainerResponseContext resContext) throws IOException {
System.out.println("-- res headers --");
log(reqContext.getUriInfo(), resContext.getHeaders());
}
private void log(UriInfo uriInfo, MultivaluedMap<String, ?> headers) {
System.out.println("Path: " + uriInfo.getPath());
headers.entrySet().forEach(h -> System.out.println(h.getKey() + ": " + h.getValue()));
}
}
view raw Gokhan hosted with ❤ by GitHub
Gördüğünüz gibi iki filter yazıp bunlara sıra verdik.Parametre değeri düşük olan daha önce çalışacak.Şimdi de resource ve applicationconfig sınıfımızı yazıp örneğimizi çalıştıralım.

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
@Path("/")
public class MyResource {
@GET
@Path("{path:.*}")
public String getResponse(@PathParam("path") String path) {
System.out.printf("creating response for '%s'%n", path);
return "dummy-response for " + path;
}
}
view raw Gokhan hosted with ❤ by GitHub
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("")
public class ApplicationConfig extends Application {
}
view raw Gokhan hosted with ❤ by GitHub

Ve programımızı derleyip payara sunucumuzundaki çıktılarımıza göz atalım.




Gördüğünüz gibi önce time filter'ımız daha sonra log filter'ımız çalışıyor.Umarım faydalı olmuştur.Bir sonraki yazımızda görüşmek üzere.

JAX-RS (FILTERS)

         Bu yazımızda filter konusuna değineceğiz.Biz filter'ları gelen request ve giden response mesajlarını kaynak sınıfımıza erişmeden önce kontrol etmek için yazarız.Örnek verecek olursak login sayfamız için bir filter yazarsak gelen request mesajlarını kontrol ettirip bu sonuca göre kaynak sınıflarımıza erişim izni verebiliriz.Bu yazımızda basit olarak gelen her isteği kapsayan bir filter'ı nasıl yazacağımıza bakalım.Yazacağımız filter bir logfilter olup request ve response mesajları payara yerel sunucumuzda log'lanacak.Bir filter yazabilmemiz için ConteinerRequestFilter ve ConteinerResponseFilter interface'lerinden birini veya ikisini implement etmemiz gerekiyor.Şimdi bir kaynak sınıfı ve bir filter sınıfı yazarak konumuzu pekiştirelim.


@Path("/")
public class MyResource {
@GET
@Path("{path:.*}")
public String getResponse(@PathParam("path") String path) {
return "dummy-response for " + path;
}
}
view raw Gokhan hosted with ❤ by GitHub

Kaynak sınıfımız gördüğünüz gibi.Gelen her istek için kullanıcıya gösterilecek mesaj sabit (dummy-response for) olacak.Şimdide gelen mesajları inceleyebilmek için bir filter yazalım.Bu istekler yazdığımız filter'a takılacak ve sunucumuzda log'lanacak.Şimdilik yapılan isteklerde kaynaklarımıza erişim sağlanabiliyor.Bir sonraki yazımızda ise filter'ımızı geçemeyen istekler belirtilen kaynaklara erişemeyecek.

@Provider
public class LogFilter implements ContainerRequestFilter, ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext reqContext) throws IOException {
System.out.println("-- req info --");
log(reqContext.getUriInfo(), reqContext.getHeaders());
}
@Override
public void filter(ContainerRequestContext reqContext,
ContainerResponseContext resContext) throws IOException {
System.out.println("-- res info --");
log(reqContext.getUriInfo(), resContext.getHeaders());
}
private void log(UriInfo uriInfo, MultivaluedMap<String, ?> headers) {
System.out.println("Path: " + uriInfo.getPath());
headers.entrySet().forEach(h -> System.out.println(h.getKey() + ": " + h.getValue()));
}
}
view raw Gokhan hosted with ❤ by GitHub


Gördüğünüz üzere request mesajlarımız için ContainerRequestFilter ve response mesajlarımız için de ContainerResponseFilter interface'lerini implement ettik.Bu interface'lerimizde bulunan filter fonksiyonlarını override ettik.Daha sonra bir log fonksiyonu yazarak  server'ımızda görüntülenecek request ve response mesajlarımızın bazı kısımlarını getirdik.Şimdi tarayıcımızdaki ve sunucumuzdaki çıktılar bakalım.



Şimdide oluşacak bir IOException da,log'umuzda tutulacak kayıt'a bakalım.Girilen % karakterinin oluşturduğu bir exceptionda payara serverımızda aşağıdaki şekilde loglanmış.




Umarım faydalı olmuştur.




OAUTH2.0 NEDİR ? NERELERDE KULLANILIR ?

 

         Bu yazımızda OAUTH 2.0'dan bahsedeceğiz.OAUTH standartlaşmış bir yetkilendirme protokolüdür.Bir uygulamadaki kullanıcı kaynaklarının,kullanıcının izni ile belirtilen yetkilerin,bir başka uygulamaya güvenli bir şekilde verilmesini sağlıyor.

      Diyelim ki bir platform üzerinde bir sosyal medya hesabı oluşturmak istiyorsunuz.Bu uygulamaya üye olabilmeniz için facebook ile giriş yap diye bir butona tıklayıp,facebook hesabınızın kullanıcı adı ve şifre bilgilerinizi girdikten sonra,uygulamanın erişmek istediği izinleri kabul ettiniz.(Sizin yerinize paylaşım yapma veya arkadaşlarınızı görebilme gibi).İşte bu aşamalarda OAUTH 2.0 kullanılıyor.Bu protokol önceki ve sonraki sürümleriyle uyumsuz.Zaten OAUTH1.0'daki güvenlik açıklarının giderilmesi amacıyla geliştirilmiş.Bu arada oltalama adı verilen,örneğimizde verdiğimiz yetkileri değilde tüm yetkileri eline geçiren bir  hackleme olayı var.Sahte arayüz tasarım ile kullanıcının bilgileri alınıp hesabı ele geçiriliyor.Bir banka üzerinden örneklendirelim.A bankasının internet bankacılığı sitesinin bir kopyası oluşturulmuş olsun.Bu sitenin adresi www.xyzbank.com olsun.Buradan yapılan girişlerde kullanıcı bilgileri ağda şifrelenmiş olarak akar,güvenlidir.Fakat siyah şapkalı hacker diye tarif ettiğimiz hacker'lar bu sitenin template'ini kopyalayıp www.xyzbankr.com domain'i aracılığıyla erişime açıyor.Daha sonra instagram gibi reklamların kolayca verildiği sitede tanındık bir banka ismine reklam veriyor.İnternet sitemizden giriş yapan ilk 10 kişi kol saati hediye veriyoruz diye.Altınada basıyor sahte adresi :).İnstagramın saçmalık diye nitelendirdiğim bir reklam politikası.Neyse sonra buna inanan insanlar bu adresi tıklayıp sazan gibi bilgilerini giriyorlar.Neyse telefona gelen doğrulama mesajı içinde bir arayüz oluşturuyorlar.Daha sonra kullanıcı arkadaş güzelce tüm bilgilerini hacker'lara post ediyor.Bu hacker'larda hesaba anlık olarak giriş yapıyor.Daha sonra hesaptaki tüm parayı çekiyorlar.Bazıları az çekiyor bu sayede dikkat çekmeyeceğini düşünüyor.İleride bir bankada çalışacak olursam bu sorunu çözebilirim :).Bence burada ilk suçlu bu reklamı verdirtende,sonraki suçlu bilgi sahibi olmayan kullanıcıda.En büyük suçluda insanların açıklarından kar elde etmeye çalışan siyah şapkalı hacker'lar.O siyah şapkayı çıkartıp,beyaz şapka kullanmalarını tavsiye ediyoruz :).

     Kullanacağımız uygulamayı bizim sosyal medya uygulamamıza yetkilendirme yapılırken access token'ler kullanılıyor.Aşağıda bu olayı anlatan çok güzel bir animasyon mevcut.Bu animasyona ve bu konu ile ilgili daha fazla bilgiye ulaşmak istiyorsanız animasyon kaynağına buradan gidebilirsiniz.


Şimdi n11.com'a kendi facebook hesabımızdan bazı yetkiler vererek giriş yapalım.


Bu şekilde izinler doğrultusunda hesap bilgilerim kayıtlı olduğunda direkt devam et seçeneği geliyor.Ben buradan giriş yaparken erişebilecekleri yerleri kısıtladım.Her uygulamaya her yetkiyi vermeyin.Bu şekilde bu teknolojiden bahsetmeye çalıştım.Umarım faydalı olmuştur.
İYİ ÇALIŞMALAR :)

JAX-RS (CONTEXT PROVIDER)

    Bu yazımızda daha önce de bahsettiğimiz kaynak sağlayıcılarını nasıl kullanacağımızı öğreneceğiz.Bu sağlayıcılar kaynak sınıflarımıza bir bağlam nesnesi sunar.Bu cümleyi kodlarımızı inceledikten sonra çok daha iyi anlayacağız.



package com.mycompany.contextprovider;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;
@Provider
public class MyContextResolver implements ContextResolver<MyContext> {
private MyContext context=new MyContextImpl();
@Override
public MyContext getContext(Class<?> type){
if(type == String.class)
return context;
return null;
}
private static class MyContextImpl implements MyContext<String>{
@Override
public String get(String key){
return "a context value for key = "+key;
}
}
}
view raw Gokhan hosted with ❤ by GitHub
package com.mycompany.contextprovider;
public interface MyContext<T> {
T get(String key);
}
view raw Gokhan hosted with ❤ by GitHub
       Sağlayıcımızdan başlayalım.Öncelikle MyContext(içerik) adında bir generic interface oluşturup get fonksiyonumuzu tanımladık.Daha sonra MyContextResolver (içerik çözümleyici) sınıfımızı oluşturup @Provider ek açıklaması ile işaretleyip ContextResolver<T extends object> interface'imizi implement ettik.Daha sonra bu sınıfımız içerisinde bulunan ve yazdığımız MyContext sınıfımızı implement eden MyContextImpl sınıfımızı yazdık.Type'ımızı String olarak belirlediğimiz için override edilmesi gereken fonksiyonumuzun geri dönüşü tipi String oldu.Aynı şekilde ContextResolver<MyContext> olduğu için ezdiğimiz fonksiyonun geri dönüş tipi MyContext oldu.Bu şekilde sağlayıcıları yazmış olduk.Şimdide kaynak sınıfımıza bakalım.
package com.mycompany.contextprovider;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Providers;
@Path("/")
public class MyResource {
@GET
@Path("{path}")
public String create(@PathParam("path")String path,
@Context Providers providers){
ContextResolver<MyContext> cr=providers.getContextResolver(MyContext.class,MediaType.WILDCARD_TYPE);
MyContext<String> c=cr.getContext(String.class);
String r=c.get(path);
return "response: "+r;
}
}
view raw Gokhan hosted with ❤ by GitHub


 
   

      Kaynak sınıfımızda ise @GET metodu ile kullanıcıdan alınan parametre String path değişkeninde tutulmuş.Daha sonra @Context ek açıklamasıyla Providers interface'inden bir nesne türetilmiş.@Context ek açıklamasını daha ayrıntılı öğrenmek istiyorsanız buraya tıklayınız.Sonraki işlemlerde bildiğimiz klasik işlemler.Bir de WILCARD_TYPE var.WILCARD_TYPE içinde bilinmeyen bir sınıfın nesnelerini tutar.
Çıktımız ise bu şekilde 

http://localhost:8080/ContextProvider/contextprovider
response: a context value for key = contextprovider


GÖRÜŞMEK ÜZERE...



Spring Boot Uygulamasını Heroku üzerinde Deploy Etme

Bu yazımızda sizlere spring boot ile yazılmış basit bir Rest api'nin heroku üzerinde nasıl deploy edebileceğimizi göstereceğim. Önce ...