Spring Boot Security - konfiguracja z pliku

Spring Boot Security - konfiguracja z pliku
Jarek Korcek
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 4 lata
  • Postów:29
0

Backend napisany w mikroserwisach (spring boot cloud). W mikroserwisie Gateway który jest odpowiedzialny za api routing i sprawdzanie czy odpytujący ma odpowiednie uprawnienia mam obecnie zahardkodowana testową konfiguracje:

Kopiuj
@Override
	public void configure(WebSecurity webSecurity) {
		webSecurity.ignoring()
		.antMatchers("/user-service/customer/login/*")
		.antMatchers("/user-service/user/login");
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
		.antMatchers("/info").hasAuthority("ADMIN")
		//.antMatchers("/user-service/login").hasAuthority("ADMIN") 
		.antMatchers("/test3").hasRole("ADMIN")
		.and()
		.addFilter(new JwtFilter(authenticationManager()))
		.csrf().disable();
	}

W jaki sposób przenieść to do pliku? w jakiej lokalizacji taki plik powinien być?

S9
  • Rejestracja:ponad 4 lata
  • Ostatnio:ponad 2 lata
  • Lokalizacja:Warszawa
  • Postów:1092
2

Chcesz przenieść cała konfigurację do application.properties?


Korges
  • Rejestracja:około 5 lat
  • Ostatnio:około 7 godzin
  • Postów:571
1

Do głowy mi przychodzi:

Kopiuj
@Value("${path.to.cośtam}")

Ale to i tak tylko przeniesienie stringów.
Możesz też zrobić różne klasy konfiguracyjne i nadać im adnotacje @profile tak żeby odpalało się to co chcesz.

edytowany 3x, ostatnio: Korges
Jarek Korcek
Też o tym pomyślałem, ale zastanawia mnie czy juz nie ma wbudowanego takiego mechanizmu zanim zastosuje swoje rozwiazanie
E9
  • Rejestracja:ponad 8 lat
  • Ostatnio:dzień
  • Postów:216
1

Kiedyś robiłem coś takiego, w application.yml

Kopiuj
security:
  unprotectedEndpoints: /api/auth/**, /swagger-ui/**, /swagger-resources/**, /v2/api-docs

I w samym SecurityConfiguration

Kopiuj
    private final String[] unprotectedEndpoints;

    public SecurityConfiguration(@Value("${security.unprotectedEndpoints}") String unprotectedEndpoints) {
        this.unprotectedEndpoints = unprotectedEndpoints;
    }

    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers(unprotectedEndpoints);
    }

No ale z hasRole() nigdy nie widziałem takiej konfiguracji w pliku

edytowany 1x, ostatnio: Emdzej93
jarekr000000
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 5 godzin
  • Lokalizacja:U krasnoludów - pod górą
  • Postów:4708
4

Nic nie musisz robić. Już jest w pliku.


jeden i pół terabajta powinno wystarczyć każdemu
Zobacz pozostałe 4 komentarze
S9
No i? Security nie jest od tego żeby co 5 minut to zmieniać na prodzie.
danek
przecież aktualizacja konfgia i restart a przekompilować cala aplikacje i wrzucic nowa wersje to praktycznie to samo
E9
@danek: niby tak, ale w poprzedniej firmie miałem bardzo duży nacisk na to, by jak najwięcej rzeczy było wyniesione do konfiguracji w plikach których nie trzeba kompilować. Powodem był skopany proces CI/CD, który zabierał ponad godzinę, a w taki sposób nasz "lider techniczny" mógł wejść przez ssh, zmienić coś w pliku, zrestartować aplikację i gotowe. Strasznie się tylko później dziwił i denerwował, że skoro tego nie zacommitował, to po prostu następny deployment mu te konfigurację nadpisywał ;) Raz nawet uznał, że sabotujemy jego pracę, bo on coś ważnego akurat testował.
S9
@Emdzej93: to tylko świadczy o zje...nym środowisku pracy.
E9
@Aleksander32: w pełni się zgadzam, dlatego też jak nieco zmądrzałem to po prostu uciekłem do innego pracodawcy. Niemniej jednak, istnieją miejsca gdzie są takie wymagania i narzuca je architekt z 20 letnim stażem.
Jarek Korcek
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 4 lata
  • Postów:29
0

@Aleksander32: Tak do pliku .xml lub .properties.

Druga kwestia czy to dobra praktyka tego typu rzeczy miec w konfgiu

edytowany 2x, ostatnio: Jarek Korcek
S9
  • Rejestracja:ponad 4 lata
  • Ostatnio:ponad 2 lata
  • Lokalizacja:Warszawa
  • Postów:1092
2

Nie jest, chyba że lubisz dreszcz emocji pt. "Ciekawe czy ktoś zhakuje API bo ktoś zapomniał endpointu w produkcyjnej konfiguracji"


edytowany 1x, ostatnio: scibi_92
Shalom
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1

Moim zdaniem źle do tego podchodzisz jeśli chcesz to zrobić TYLKO tutaj. Bo przecież to musi być spójne z kontrolerami i pewnie też z programmatic clientem w tym serwisie, więc wszystkie te wartości powinny pochodzić z jednego miejsca! Bo co ci da ze tutaj masz hardkodowanego stringa /api1 kiedy w kontrolerze ktoś zmieni na /api2 a w kliencie ktoś przypadkiem da /api3? Tylko że nie bardzo masz jak taką wartość wstrzyknąć z konfiga, szczególnie w przypadku tego klienta, który przecież może być wciagnięty jako zależność w zupełnie innym projekcie. W efekcie moim zdaniem jedyna dobra opcja to:

  1. Robisz public static String w kliencie, gdzie hardkodujesz te stringi odpowiedzialne za endpointy
  2. W kontrolerze importujesz sobie te stringi i definiujesz endpointy
  3. W security konfig importujesz te stringi i definiujesz security rules

Dzięki temu w kodzie każdy z tych stringów występuje tylko jeden raz.

Shameless plug ale:


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
ZN
  • Rejestracja:około 6 lat
  • Ostatnio:około 2 lata
  • Postów:49
0

Da się ale wtedy nie korzystasz z magii typu Spring security :) a implementujesz to co ci potrzebne sam

Jarek Korcek
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 4 lata
  • Postów:29
0

W takim razie czy w ogóle dobrym podejściem jest sprawdzanie autentykacji i autoryzacji na poziomie api gateway czy czasem nie lepiej ta logike przenieść do każdego z serwisów i wtedy każdy z nich sprawdzałby uprawnienia tylko dla swoich endpointow? Chciałem uniknąć walidacji na każdym z serwisów poniżej gateway'a i wtedy api gateway by odrzucał już na wstępie te odpytania które nie maja tokena czy tez uprawnień do odpytywanego endpointa. (wyciagajac adresy do jakeis klasy statycznej jak podsunął pomysł Shalom byłby w tym wypadku dobrym pomysłem)

edytowany 2x, ostatnio: Jarek Korcek
Charles_Ray
  • Rejestracja:około 17 lat
  • Ostatnio:około 3 godziny
  • Postów:1875
2

Nawet jak to będzie wyciągnięte do jakiejś klasy jako static, musisz w jakiś sposób zapewnić, że zmiany zostaną wszędzie zaciągnięte w postaci wdrożenia z nową wersją biblioteki. Więc IMHO to o czym pisze Shalom albo można zapewnić zrzucając odpowiedzialność za rejestrację route na zespół opiekujący się danym serwisem, albo jakiś mechanizm automatycznej aktualizacji routy w api-gateway.

Odnośnie sprawdzania uprawnień, skalowalnym podejściem jest autoryzacja na poziomie określonej domeny, której dotyczą te uprawnienia. Inaczej w api-gateway zrobi się śmietnik.


”Engineering is easy. People are hard.” Bill Coughran
Szymek
  • Rejestracja:ponad 22 lata
  • Ostatnio:prawie 3 lata
1

Moim zdaniem dobrą praktyką jest kontrola uprawnień jak najbliżej kodu wykonującego opreację lub danych (przydaje się w dużych projektach). Jeżeli będziesz sprawdzać uprawnienia na poziomie api gateway, to zawsze ktoś się może wstrzelić z boku. Często też wersje samych serwisów mogą sie rozjechać i nagle API jest dostępne dla wszystkich po niefortunnym wdrożeniu.

Jeśli chodzi o sprawdzanie uprawnień użytkownika to polecam użyć @EnableGlobalMethodSecurity(prePostEnabled=true) i pisać kod tak:

Kopiuj
@Controller
public UserManagementController {

  @RequestMapping(method = RequestMethod.GET)
  @PreAuthorize("hasAuthority('CAN_LIST_USERS')")
  public List<RestUser> listUsers() {
    // ...
  }

  @RequestMapping(method = RequestMethod.POST)
  @PreAuthorize("hasAuthority('CAN_SUSPEND_USER')")
  public void suspendUser(@RequestParam UUID userId) {
    // ...
  }

}

Dodatkowo polecam używać ról jako kontenerów na uprawnienia (authorities). I w samym kodzie sprawdzać authorities. Przykładowo:

  • ROLE_USER_MANAGEMENT zawiera
  • CAN_LIST_USERS
  • CAN_SUSPEND_USER
  • CAN_CHANGE_USER_ROLES
  • etc.

Dzięki temu zyskujesz elastyczność. Jeżeli trzeba dodać nową rolę to nie trzeba przerabiać wszystkich aplikacji, tylko definiujesz nową rolę i przypisane do niej uprawnienia.

edytowany 1x, ostatnio: Szymek
Zobacz pozostały 1 komentarz
Szymek
Możesz rozwinąć swój komentarz? Jak zrobisz typo w adnotacji, to się do endpointa nie dostaniesz. Dodatkowo to można bardzo prosto (a nawet trzeba!) przetestować.
Shalom
Żeby daleko nie szukać, a dzisiaj: https://4programmers.net/Forum/Java/347876-spring_boot_security_unautorized_401_konfiguracja_nie_dziala?p=1736088#id1736088 :D podobny problem, wynikający z pisania stringów w kodzie i opierania się na nich.
Szymek
Nie widzę związku z moim przykładem. Typo w parametrze adnotacji spowoduje, że endpoint przestanie być dostępny. Napisanie testu automatycznego weryfikujące poprawność adnotacji jest bardzo proste - chyba nie muszę nikogo przekonywać, że warto takie rzeczy testować. Chcę od razu zaznaczyć, że nie jestem fanem SpELa. Coś bardziej skomplikowanego niż to co jest moim przykładzie (rozbudowane wyrażenia logiczne) stanowczo odradzam.
Shalom
Ale to jest dokładnie taki sam problem -> masz kod który zależy od stringa w kodzie. Tam też błąd w stringu powodował ze coś nie działało (401). Sęk w tym, że lepiej kiedy o błędach mówi kompilator, a nie test, szczególnie że tutaj potrzebujesz test integracyjny który to wszystko odpali, a jest nadal wielu wyznawców mocków, którzy takiego testu nigdy nie napiszą. No i znów taki sam problem jak w podanym przeze mnie wątku -> autor zauważył że coś nie działa ale nie był w stanie stwierdzić co.
Szymek
Zgadzam się, że najlepiej kiedy kompilator mówi o błędzie, ale niestety rola lub uprawnienie muszą gdzieś wystąpić jako String. Typo zawsze może się tam wkrać. Zasadnicza różnica jest tylko taka, że String zaproponowany przeze mnie jest dłuższy - tak dwukrotnie - w dalszym ciagu można do stałych wyciągnąć jeżeli te nazwy się bardzo często powtarzają (głownie role, bo w przypadku uprawnień - nie powinny). Jeśli chodzi o test, to kontroler i tak trzeba integracyjnym testem przejechać, żeby uprawnić się, że wszystko pomapowane poprawnie.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.